Consume File-Icons' element-icon service#1146
Consume File-Icons' element-icon service#1146nathansobo merged 21 commits intoatom:masterfrom Cutlery-Drawer:file-icons
Conversation
nathansobo
left a comment
There was a problem hiding this comment.
This is going to be cool. I agree 100% that monkey patching should be replaced by services, and you're doing the exact right thing here from ecosystem standpoint. Bravo.
I have some questions about the specific implementation. One is inline about the IconServices object. I'm also curious why you structured the service to imperatively assign an icon on a DOM element rather than returning it. Is it because you want to adjust other properties of the containing element? Could these be returned as an object or something?
My main concern is someday we want to move this old tree view code to more of a declarative virtual-DOM based structure. Accessing the icon as a value rather than an imperative function would probably make that transition easier. Forgive me if you've already explained your reasoning for the imperative API elsewhere and I've missed it.
| 'file-icons': new DefaultFileIcons | ||
| 'element-icons': null | ||
|
|
||
| class IconServices |
There was a problem hiding this comment.
Do you use the flexibility of the dynamic service naming in this class? If not, I think I'd prefer explicit methods for setting the file icons and element icons services just to keep things super clear.
There was a problem hiding this comment.
I'm pretty sure this class can be axed, actually. I kept it because our current implementation uses it: lib/file-icons.coffee. I renamed it IconServices to disambiguate. This class isn't necessary to integrate with our package, and we can easily do without it.
There was a problem hiding this comment.
Oh! Wait, no, scratch that. I forgot the IconServices class is being used to "select" the most appropriate icon service that's available. Where file-icons is, confusingly enough, the old, pre-2017 service that was too limited for the file-icons package, and element-icons is the service which points to, well, file-icons's service.
Confusing, eh? 😀
We use hard DOM references in order to update them in future when changes are detected (such as when a hashbang or modeline is picked up in a file's header, or when a user changes the package settings). We don't return references to an I've kept our implementation as minimalist as possible, and it's working perfectly fine. I'm not sure what it could be lacking...? |
|
Okay, cool. I can see the logic in inverting control and letting the service reassign the icon as needed. If you want to eliminate the unnecessary flexibility around managing icons of different types with that class, I'm down to merge the imperative implementation and see how it goes. |
|
Sorry, scratch that. I remember now what the
I'm not sure what you mean. The class is essentially a fractured |
I just think the interface of the It could have a method like In general I'd really like to avoid methods that take strings because you can't tell by looking at the method how many possible strings might be passed in. |
|
Fair enough. I'll inline it then. I guess a circular dependency between Also, just to help you understand what's going on under the hood on our side, here's a grossly simplified diagram illustrating what the package is doing when it's consuming the service. Blue stuff is async. |
|
I'm not sure what you mean by inline it... I just think you could simplify the interface and make it more specific and less general, as in not take strings. And maybe push more logic about deciding between the two services into it while you're at it. That's a really nice diagram! What did you make it in? |
| else | ||
| iconClass = 'icon-file-submodule' if @directory.submodule | ||
| @directoryName.classList.add(iconClass) | ||
|
|
There was a problem hiding this comment.
@nathansobo Concerning your recommendation with the updateIcon method... how do you propose I handle this logic? It sounded like you wanted the bulk of the class-assignment logic handled in the TreeViewPackage controller, but it feels counter-intuitive for a DirectoryView instance to pass itself as an argument to TreeViewPackage.updateIcon and have TreeViewPackage inspect its properties before adding an icon
EDIT: Wait, never mind. I misunderstood. My head is all over the place tonight...
There was a problem hiding this comment.
Yeah, give it a try and see if we can simplify this interface to just be about assigning services and updating the icon with the best service. I think we're pretty close here.
|
Ah right, I misunderstood. Sorry.
Heh. I just hacked it together in Adobe Illustrator. :) My background is graphic design/multimedia. Somehow I ended up in web programming instead. |
|
Alrighty, how's this look? =) |
|
Looks really good. It's easier for me to understand what is going on with less flexibility. Thanks for the quick turnaround! I'll wait on a green build and merge. |
|
Thank you so much!! (Don't forget to squash merge, haha) |
|
Normally don't squash-merge, but for you, I did it. 😉 |
|
Published as 0.221.0 and upgraded to that version in atom/atom@32e9547. Hold on to your butts. |
|
We're 20% of the way there. :D Thank you! I'm currently updating the other PRs to include your earlier requests: |
|
Cool. I will add them all to my queue. I need to deal with this file watcher emergency on Linux but then they're next. |
|
Hi. I should have asked you to add some tests before merging this. Would you be cool following up with a test that exercises the basic functionality of the icon service case? I'm worried that this could break in the future without any coverage. |
|
I'm following up on the others. Sorry about the slowish response, Internet's been crap the last couple days... |
|
@nathansobo To test this reliably, we should merge At a minimum, I'd like to add what atom/fuzzy-finder#330 adds, but I don't know which spec to add to. What do you recommend? |
|
@Alhadis Thanks for asking. I think we should expand on Ideally, the Thanks again. |
|
I'm sorry this took so long. 😞 Submitted in #1198. |


Redux of #1009 after the original PR, copied below, was derailed by a (now blocked) user.
Just to clarify, this is integrating Atom's core with a community package, rather than the other way around. Though it seems strange, it is being handled smoothly through the
service-hub. So if this package magically disappears all of a sudden, no Atom packages will break - it'll just mean there's no service-provider offering theelement-iconsservice.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:
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...
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-iconsservice, 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):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
atom/tree-view#1146atom/tabs#412atom/find-and-replace#870atom/fuzzy-finder#281atom/archive-view#47