atom / fuzzy-finder

Find and open files quickly
MIT License
275 stars 138 forks source link

Consume File-Icons' element-icon service #281

Closed Alhadis closed 6 years ago

Alhadis commented 7 years ago

This PR applies to the tabs package what's been described in atom/tree-view#1146 for the tree-view package. The PR's updated wording describes this scenario best, so I'll just copy+paste:


I realised too late that your icon-service fulfils a different purpose from what our package needed. We wrote our own instead, which is built on a dubious but (currently) stable foundation of monkey-patches.

Opinions differ on the subject, but mine is that monkey-patching code you didn't write is bad, and should only be used as a last resort (DOM polyfills notwithstanding). Which is precisely what I've been forced to do to get dynamic icon-assignment working.

This needs to be fixed at a formal level, because:

  1. Patches don't persist if File-Icons is deactivated and reactivated.
    I've actually chosen not to fix this, because it would step outside the expected lifecycle of the package. E.g., when a user deactivates a package, they expect it to leave no traces in the workspace. I also can't imagine this happening too often, but still...

  2. Any innocent change to your packages could break stuff.
    The obvious danger of monkey-patching what wasn't expected or supposed to be changed. We have specs to alert us of breakage, but there's no telling what would be involved in the repair. We both know this is the wrong approach.

Now, I don't know how the Atom team would feel about adding support for third-party package services. Ideally, this would be addressed on the level of Atom's core icon-API. However, the differences of our needs (as well as the specific use-case of our needs) make me hesitant to propose a change to your existing service, especially because @as-cii has stressed he prefers keeping its functionality simple for the time being. In light of that, it would be more appropriate and ergonomic to support a third-party service in the interim, should a mutually-compatible solution be realised in future.

What this service does

The file-icons.element-icons service, when consumed, provides a function to add dynamic icons to DOM elements. The function is to be called by the package on any element that's supposed to represent a filesystem resource (either files, or directories):

let fileIcon = document.querySelector("li.file-entry > span.icon");
addIconToElement(fileIcon, "/path/to/file.txt");

Calling the function returns a Disposable that clears the icon-node instance from memory, which should be done once the view is destroyed.

Note there's no requirement to specify whether a path is a file or directory. Our heavy-duty filesystem API takes care of the heavy lifting... I've even plans to separate it from File-Icons in the form of a standalone Node module, so other package authors can benefit from my hard work too. :)

Related pull-requests

Alhadis commented 7 years ago

I can imagine how busy the Atom team are right now smoothing over bugs with the recent docked-views feature, as well as concentrating on fixing a pretty severe memory issue in the 1.18 beta.

That being said, I really don't wanna come off sounding naggy or impatient... but could somebody give me an update on this? The rotten monkey-patches I wrote have been allowed to exist for exactly half-a-year now (at least in my timezone, which officially ticked over to June over an hour ago....)

/cc @lee-dohm / @50Wliu / @as-cii

lee-dohm commented 7 years ago

Thanks for the ping @Alhadis ... I'm going to get some :eyes: on this :+1:

lee-dohm commented 7 years ago

@Alhadis we've added this (and its related PRs) to the list for prioritization. I noticed that file-icons was mentioned as a potential performance issue in https://github.com/atom/fuzzy-finder/issues/269. Would you mind doing some testing to see if this change helps or hurts performance in that scenario?

Alhadis commented 7 years ago

Certainly! :D Which settings do you prefer I use when recording the timeline snapshot? I tend to get them all confused... 😞 Or is there another method you'd prefer I try to compare performance?

Alhadis commented 7 years ago

Atom hanged when it was trying to save the recorded CPU profile, but that's what it usually does when I have my machine's root or home directory opened as a project... :( I managed to screen-cap the first profile, which was recording performance without this PR's changes in effect:

screen shot 2017-06-09 at 3 51 17 am screen shot 2017-06-09 at 3 52 15 am screen shot 2017-06-09 at 3 53 49 am

I wish I knew how to read these things better. I'm still getting my head around what each graph means...

lee-dohm commented 7 years ago

@Alhadis if you can manage to save the profile, zip it up and email it to me at lee-dohm@github.com? I believe saving the profile saves all the data and then I can fiddle with it on my end :+1:

Thanks very much for helping out :bow:

Alhadis commented 7 years ago

I already tried, but it saved a blank file. :( As a matter of fact, this is what it always gives me whenever I try saving the CPU profile... :(

50Wliu commented 7 years ago

You'll need to test on Atom 1.19.0-dev in order to get a non-blank profile.

lee-dohm commented 7 years ago

What @50Wliu said :grinning: https://github.com/atom/atom/issues/13767

Alhadis commented 7 years ago

Ugh... good grief. 😞

Should I profile the other packages while I'm running a HEAD-build of Atom v1.19, then...?

lee-dohm commented 7 years ago

Yes, please :pray:

Alhadis commented 7 years ago

Damn. Opening my user directory as an Atom project already shows how bad an issue this is... I'll e-mail you the first CPU profile I captured. It was done using dev-mode and no forked packages.

Please let me know if you have difficulties extracting it: it's a 23.3 MBs file I had to 7-Zip.

Alhadis commented 7 years ago

Profiling the other packages hasn't really revealed much of a difference. The hit to performance is mostly at startup, when file-icons has to load and hack certain files.

Alhadis commented 6 years ago

Conflicts fixed, and the bitter taste of CoffeeScript washed away.

lee-dohm commented 6 years ago

Thanks @Alhadis :grinning: I'm going to take a look at these next week when I'm on vacation and decompressing.

Alhadis commented 6 years ago

The 'hell's this...?

standard.cmd : standard: Use JavaScript Standard Style (https://standardjs.com)
At line:158 char:13
+             & "$standardpath" lib/**/*.js
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (standard: Use J...standardjs.com):String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

standard: Run `standard --fix` to automatically fix some problems.
  C:\projects\fuzzy-finder\lib\icon-services.js:44:76: Extra semicolon.

Yet there were no lint errors locally:

λ FuzzyFinder (file-icons): ./node_modules/.bin/standard .
λ FuzzyFinder (file-icons):
Alhadis commented 6 years ago

/cc @nathansobo for review

nathansobo commented 6 years ago

I appreciate your patience and dedication to making Atom better!

nathansobo commented 6 years ago

Published as 1.7.0 and upgraded in atom/atom@d035e41f378497cc2d23b9f7983adebc1bd1820e.

I should have asked you to write some basic tests for this. Would you be willing to do a follow up PR that adds some basic tests so we don't break this in the future? I'm going to hold off on the other 3 PRs until there's some test coverage in place.

Thanks @Alhadis.

nathansobo commented 6 years ago

Whoops, I had to revert the upgrade commit because there's an issue in with v8 snapshot generation, which you can see in this Circle build. I'll take a look.

nathansobo commented 6 years ago

Okay, I fixed the snapshot issue in 2c1fe65802860aa6c85a891e0ed58f390f493f8f and re-upgraded to 1.7.1 in atom/atom@058a42f7c2ff1a5ac35578b9b28ef32862f0d158. Basically, you can't interact with the atom require at eval-time in snapshotted code, and constructing the IconServices object at eval time was causing that to happen. I replaced the eval-time construction with a lazy getter function.

Alhadis commented 6 years ago

Oh, you guys are using mksnapshot. That's clever. Should the other PRs be amended too?

I should have asked you to write some basic tests for this. Would you be willing to do a follow up PR that adds some basic tests so we don't break this in the future?

Ah, I never notice that. Sure thing!

nathansobo commented 6 years ago

Should the other PRs be amended too?

Yeah, maybe you already got to it, but we need to avoid eval-time references to the atom require or any built-in node modules in any package that's going to be bundled.

Alhadis commented 6 years ago

What about the complementary DefaultFileIcons class? That's being exported as a singleton instance in much the same way. Should that use lazy getters too?

nathansobo commented 6 years ago

If it's not accessing any built-in modules it should be technically okay, but might be nice to make things consistent. Even better than a lazy getter would be dependency injection, but that's more work.

Alhadis commented 6 years ago

Think I'll leave it for now. DefaultFileIcons feels like it should be merged into the IconServices singleton more than anything else. I'd prefer not to make any more changes this late, however.