-
Notifications
You must be signed in to change notification settings - Fork 364
Allow file-icons service to set multiple class names #825
Conversation
If the package providing the service needs additional information on the file, they can't do so without querying the filesystem. For instance, an author may need a link-icon shown for symlinked files. Without providing a direct file reference, this becomes much more cumbersome.
This provides developers with much more information beyond a simple file reference, which can always be accessed through the DOM node anyway.
@lee-dohm Anything I can do to move this along? |
@50Wliu, any progress? I don't mean to come across as impatient, but two months of solid silence does tend to leave one feeling uncomfortable. |
I'm not the person to ask about progress generally. All I do is add the appropriate labels and move on. |
Ah, right. Sorry to bother. I guess I'll just keep waiting then.. |
@@ -19,7 +19,11 @@ class FileView extends HTMLElement | |||
@fileName.dataset.name = @file.name | |||
@fileName.dataset.path = @file.path | |||
|
|||
@fileName.classList.add(FileIcons.getService().iconClassForPath(@file.path)) | |||
iconClass = FileIcons.getService().iconClassForPath(@file.path, this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why we need to pass the current FileView
instance to the file icons service? Maybe it's not a huge deal, but seems like the service shouldn't need it in order to provide an icon. What am I missing? 💭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It allows the provider to understand the context of where the icon is being requested. To give a concrete example, File-Icons has a "Show in tabs" setting that should determine whether an icon gets displayed in a tab or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I wonder if we should put that setting on the individual packages instead of customizing every package UI via File-Icons
. Both tree-view and tabs could expose a disableCustomIcons
setting which, if enabled, wouldn't call the file icons service at all, keeping its default icons.
What do you think? Seems like this would be more customizable and would allow File-Icons
to not implement a setting for every package that uses it. 💭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a bad idea, actually. =) Want me to tackle that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be 🆒! How about avoiding to pass this
in the current pull-request and open a new one with the new config parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a quick glance, it doesn't seem to have any reference to a File object,
Here:
TabView.item?.buffer.file
What I am worried about is inconsistency, though
To be honest, inconsistency is a trivial sacrifice to make until Atom has a formal API for interacting with the filesystem. And yes, you're 100% right. Furthermore, I believe that API should be the one consuming the icon-class service... that way, there's only one point of info, and services can deal with that without having to care about where the class is being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems like the only alternative to return a correct result that is also consistent across calls is to bake fs queries into the file icons service package
And no, I think it's a harsh burden that's being placed on package authors, particularly those who have to consider scalability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a stopgap measure, I guess we could hand some metadata about the file to the service, like:
service.iconClassForPath(path, {symlink: false})
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with that. I'll even see if I can tie it in with what #859 uses.
FYI, that IS an addition I took delicate measures to shield against complications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@as-cii Okay, it's done! :D You'll notice I've passed a @stats
property from the newly-added File
method, which will be smoothly taken care of by #859.
The metadata includes atomic values with no dangling references. I only included stuff that was strictly filesystem-related, and not in any way related to the tree-view itself (which I believe was your point in abstracting the consumer's logic from the provider's).
@@ -67,3 +67,6 @@ class File | |||
|
|||
isPathEqual: (pathToCompare) -> | |||
@path is pathToCompare or @realPath is pathToCompare | |||
|
|||
# Return a snapshot of the instance's filesystem properties for API consumption | |||
getMetadata: -> {@symlink, @realPath, @status, @stats} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I am a little worried about consistency. In this package we have access to stats
and status
, but what about the tabs
package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*cough*
UH, well... at the moment, it's returning a reference to the calling TabView
element, which I'll obviously tend to once we're done with this PR
Access to the tab's File
instance is available through @item.buffer.file
, but that's an instance of one of these, which doesn't have the cool extras of filesystem stats the Tree-View's File
class has.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm aware it's not 100% consistent, but how about storing a reference to the buffer's File
instance on the second argument? stats
won't be available, but the source file can be keyed to bufferFile
or just file
.
tree-view: { symlink, realPath, status, stats }
tabs: { symlink, realPath, sourceFile }
To be honest, I think we can probably justify having an extra filesystem call to return the missing info to stay consistent with tree-view
's handling. Let's face it: there won't be nearly as many icon-displaying tabs as there will be icon-displaying file listings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@as-cii What's happening here? The sudden silence has me rather worried.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I think we can probably justify having an extra filesystem call to return the missing info to stay consistent with tree-view's handling. Let's face it: there won't be nearly as many icon-displaying tabs as there will be icon-displaying file listings.
That's fair, although this feels like a clear indicator that this interface is inconsistent and more complex than it should need to be. I think we should try to design services in an elegant manner, so I am 👎 on passing different arguments based on the package, and I think we should issue fs.stat
calls directly in the FileIcons
service, delegating to it all the concerns related to the filesystem.
The only reasonable alternative I could think of (that doesn't involve a major redesign in Atom core) is to provide an alternative iconClassForPath
method that returns a Promise
, so that the UI thread never blocks and we can do whatever I/O is needed on that function. It would make the calling code a little more complex, but it's probably worth a try if fs.statSync
makes file-icons a lot slower.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what's wrong with passing different arguments as a temporary solution until a formal API is developed? When it is, you can just use Grim to deprecate usage of the second argument so package authors know to use the more elegant approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually never mind. I've lost patience during all this bikeshedding. I'll kill the second argument and write whatever craploads more code I need to write in order to get things off the ground. Seriously.
@as-cii Actually, I'm beginning to think having a There'd be no logical in-between, and package authors would (again) be reduced to using ugly hackery. I think in the long-term, the setting would introduce more complications than it'd solve. My gut feeling says "no, don't…" and my guts are usually pretty good about this kinda stuff. Real-world example. The ever-popular Seti UI theme comes with icons included. It has a setting to disable them for users who have a dedicated package installed (like File Icons, obviously). It doesn't use the icons API, but this is a classic case of what I'm talking about. |
Could you explain why having a setting on each package wouldn't solve this? Like, users could set |
Well, a package or theme (like Seti) might offer users a way to disable custom icons specifically to allow other packages to display their icons instead. Seti and File-Icons have had problems in the past with overlapping icon rules, and this is precisely one of the issues the icon-service exists to solve. |
I've removed the second parameter, but if I were to suggest a solution to the "disabling icons per package" issue, it'd be to simply pass the package's name as an argument: iconClassForPath(path, "tree-view"); That way, packages can decide for themselves whether they want to provide an icon class or not. |
Thanks for the changes, @Alhadis! 🙇
I see, so if for instance we have a
Or, if they want only standard icons for the tree-view, they would need to:
Is that accurate? If so, it still seems like having a per-package setting provides a high degree of customization while still being pretty easy to change, also allowing new consumers of the file-icons service to pass just a path. Then from the tree-view all we have to do is (pseudocode): if (atom.config.get('tree-view.enableCustomIcons')) {
someElement.classList.add(fileIconsService.iconForPath(path))
} I guess you're more concerned about not having the That said, I am not totally opposed to pass the context, but seems worth exploring other solutions that make the file-icons service highly reusable as well as keeping the API consistent and clean. Thanks for your patience on this! If in the meantime you'd like to change this pull-request to introduce only the change you mentioned in the title (i.e. allowing multiple class names to be passed), I think we can merge that right away! 👍 |
The issue here is that you're trying to predict and solve issues on behalf of package authors, instead of entrusting them to tailor their package's logic. There is no logical reason to obfuscate the context of the API's call for the sake of keeping things "clean". |
I'll remove the context from this PR temporarily so this bullshit bug can finally be fixed. But I'll be adding it in a follow-up PR. |
Packages that provide the
atom.file-icons
service are currently limited to setting only one class name per file. This is because any attempt to add a DOMTokenList item with a whitespace character will trigger an exception, as per the spec.However, this is particularly limiting for packages that need flexibility. For example, the File Icons package will be adding two different classes: one for the icon, and another for its colour.
I've amended the service consumption routine to allow a list of classes to be specified as either an array or a whitespace-delimited string (analogous to jQuery's approach).
So this:
will now lead to this:
... instead of, well, this:
![](https://cloud.githubusercontent.com/assets/2346707/14926664/8ca0248c-0e90-11e6-823e-c32042ec7e65.png)