qlstephen: Add support for dynamic and unknown UTI types
I get a lot of plain text files with various extensions such as .1
or .inc
and currently they only show the icon in QuickLook. Looking at one such file with mdls
I see it has a dynamic type. But the content type tree includes public.data. Would it be possible to extend support to ALL filetypes?
$ mdls wget-log.2
...
kMDItemContentType = "dyn.ah62d4rv4ge8xe"
kMDItemContentTypeTree = (
"dyn.ah62d4rv4ge8xe",
"public.data",
"public.item"
)
...
$ mdls function.inc
...
kMDItemContentType = "dyn.ah62d4rv4ge80w5xd"
kMDItemContentTypeTree = (
"dyn.ah62d4rv4ge80w5xd",
"public.item",
"dyn.ah62d4rv4ge80w5xd",
"public.data"
)
...
About this issue
- Original URL
- State: open
- Created 5 years ago
- Comments: 37 (10 by maintainers)
Commits related to this issue
- đ żď¸[P] 2 apps to allow previewing of custom, text-based file extensions This is a feature to address Issue #87: "Add support for dynamic and unknown UTI types": https://github.com/whomwah/qlstephen/i... — committed to NSGod/qlstephen by NSGod 3 years ago
- QL: update qlstephen to preview Rmd, Rout files https://github.com/whomwah/qlstephen/issues/87#issuecomment-831399689 — committed to plpxsk/dotfiles by plpxsk 3 years ago
- Next: migration to zsh from bash on main MBP (#3) Lots of changes, not just bash to zsh, but also general improvements Log of commits: * Mv .bash_profile .zprofile * Commit .emacs.d/init.el ... — committed to plpxsk/dotfiles by pavopax 2 years ago
- the fix for known/unknown child UTIs to be handled by QLStephen, resolves #87 So cheaply pretending to be a QLGenerator from Apple seems to be the way to make Quick Look use QLStephen also for UTIs w... — committed to toy/qlstephen by toy 2 years ago
As another solution, I wrote a Fish script that automatically detect the UTI type of a given file and append the
dyn.*
type to QLStephen:Usage for Fish shell:
So, Iâve come up with what I think might be a workable solution, though Iâm looking for thoughts and feedback on it.
Rather than having to worry about generating
dyn.*
UTIs, etc., all we really need to do is simply have a way to tell the system that an unknown filename extension (e.g..map
) conforms topublic.plain-text
. By doing so, we then allow the systemâs built-in text quicklook plugin to be used to preview the contents.The solution I came up with is based on the assumption that only the end-user is going to know what filename extensions they come across and whether those files are text-based or not. It uses 2 different apps:
QLStephen.app
: the primary app you interact with. It holds a list of the filename extensions that youâve mapped to being treated as text. To map a particular filename extension to be treated as text, we declare that it conforms to âpublic.plain-textâ. By doing so, we then allow the systemâs built-in text quicklook plugin to be used to preview the contents. To implement these file mappings on the system, QLStephen.app uses a second application, âQLStephen Dummy.appâ, in which the mappings are declared in theUTExportedTypeDeclarations
of its Info.plist file. QLStephen.app also adds a Service so that you can right-click/control-click on any file in the Finder, and choose âQuick Look with QLStephen â â (yes, this is a bit misleading, I guess). This automatically opens it in QLStephen.app, and if itâs found to be text-based, is added to the list of file extension mappings. Then, after updating the dummy app, you can deselect and then reselect the file in the Finder to preview its contents as text.QLStephen Dummy.app
: This app is created in the ~/Applications/ folder. As mentioned previously, this is a dummy app that declares the file extension mappings in its âUTExportedTypeDeclarations` key in its Info.plist file. After modifying the Info.plist of the installed app, it is codesigned to run locally.To be clear, these 2 apps exist separately from the QuickLook plugin which is still installed into
~/Library/QuickLook
.Some notes/known issues: ⢠Despite having a âKindâ column for you to fill out a file extensionâs description, it appears the Finder will always refer to the kind as âPlain Text Documentâ. (I think declaring the documents in the
CFBundleDocumentTypes
as well might convince Launch Services to use their descriptions). ⢠There are some filename extensions that still wonât preview even though they are text-based:.css
files and.strings
files are 2 examples Iâve encountered.I have a
qlstephen.app
branch where I pushed this to in my fork: https://github.com/NSGod/qlstephen/tree/qlstephen.app.A link to a compiled and signed binary: https://markdouma.com/developer/QLStephen.zip I welcome any feedback.
To summarize the current workaround, below are instructions to quick look a given file or file type (
*.Rmd
in the below example).This was tested on macOS Big Sur 11.3 Terminal (zsh).
Run the following command on an existing file of interest to find a string that begins with
dyn.a...
:Open
Info.plist
to edit it, at~/Library/QuickLook/QLStephen.qlgenerator/Contents
.To navigate there, you can right click
QLstephen.qlgenerator
and âShow Package Contentsâ or use a code editor to get thereAdd the relevant
dyn.a...
toInfo.plist
like in the following:Reset quick look with a)
qlmanage -r
and b) Relaunch Finder:Apple menu - Force Quit ... - Finder - Relaunch
.Ok, so according to the source I references above, I would do the following:
?0=6:1=sql
.Though I am not sure if the
6
is correct or if it should be7
. Where numbers are substituted as follows:Next you put this string into a custom base32 converter. E.g. this website
Input:
?0=6:1=sql
Variant:
Custom
Alphabet:
abcdefghkmnpqrstuvwxyz0123456789
Padding: â Delete if there is any â
The output should be
h62d4rv4ge81g6pq
. If you have any trailing=
delete it, thats the padding.Prepend
dyn.a
and that is your final string.What you should insert in the Info.plist is
dyn.ah62d4rv4ge81g6pq
PS. You dont need to remove the extension, you can also right-click and âShow Package Contentsâ
After several evenings Iâve stumbled upon a fix and would appreciate a confirmation.
First to showcase the problem: https://github.com/whomwah/qlstephen/compare/master...toy:extensions-problem-showcase?expand=1
toy.explicit
extensions.app
with the goal to define UTIs:toy.explicit
(for.toy-explicit
extension) conforming topublic.plain-text
toy.a0
(for.toy-a0
extension) conforming topublic.plain-text
toy.a1
(for.toy-a1
extension) conforming totoy.a0
toy.a2
(for.toy-a2
extension) conforming totoy.a1
toy.l0
(for.toy-l0
extension) conforming topublic.data
toy.l1
(for.toy-l1
extension) conforming totoy.l0
toy.l2
(for.toy-l2
extension) conforming totoy.l1
.toy-unknown
To test checkout extensions-problem-showcase and run
make && make install
, in this state only.toy-a0
,.toy-a1
,.toy-a2
and.toy-explicit
should have preview/thumbnail generated (first 3 by Text.qlgenerator, last by QLStephen because it is explicitly in its list of UTIs).Fix: https://github.com/toy/qlstephen/compare/extensions-problem-showcase...toy:extensions-showcase-fix?expand=1 Just change the bundle id so that it starts with
com.apple.
and suddenly all test files get the preview/tumbnail. To test checkout extensions-showcase-fix and runmake && make install
(wait forqlmanage -m
to show the list, sometimes repeatingmake && make install
is needed).If confirmed #135 is the fix unless someone has a better idea
Fun with UTIs Found this to be very helpful in understanding what is happening.
Right now the plugin registers itself at the highest point that makes sense in both the physical and functional hierarchies. public.data and public.content
There is a good case to be made for changing public.content to public.text but thatâs not a discussion we need to have here. Letâs figure out how we can get this plugin working for more files.
Execute
mdls -name kMDItemContentType ~/path/to/file.ext
to get thedyn
value, add it to the plistFor anyone wanting the bash/zsh version of the fish function posted by @xupefei
Add it to your
~/.bashrc
or~/.zshrc
to have it available when a new shell is opened.Works fine, thanks!
Note: command
killall Finder
equal to Relaunch Finder.My current understanding of the issue is that:
kMDItemContentTypeTree
kMDItemContentType
is used to assign the corresponding QL plugin.dyn.*
UTIWhich means, we would need a list of extensions that should be supported by QLStephen. That implies that QLStephen can potentially override another QL plugin that does a better job in representing a known extension. E.g., there are specialised markdown plugins and I would be pissed if QLStephen would break them for me. Not sure how QuickLook handles plugin precedence.
Some plugins will define âImported Type UTIsâ. That basically replaces the âunkownâ
dyn.*
UTIs with a developer set UTI. For example, in my extension I registerorg.opml.opml
for*.opml
files. On my system, for opml files,mdls
returns that UTI instead ofdyn.ah62d4rv4ge8086drru
.kMDItemContentType = "org.opml.opml"
This might be crazy talk, but Iâd be happy if qlstephen showed me a text view of any file for which it canât otherwise distinguish. (At least the first few kilobytes of larger files.) Not sure if this is possible.
So we still donât have a solution ? For now Iâm just adding the dyn.foobar entries into the plist
The LICENSE I happened to be trying did indeed have executable permissions (
654
) for some reason. Changing it to 644 solved the issue with that file. Thanks.But I do have some actual unix executables (e.g. little extension-less shell scripts in a bin/ directory) that Iâd like to see working.
Also, I tried creating a custom
dyn.*
adopting thepublic.data
UTI without any extension. But that didnât work either. Setting the extension to*
or nothing at all, also didnât work.Somehow the UTI is not recognized as being inherited from
public.data
although the type tree clearly shows that it is. It also correctly displays the preview if the generator is specified directly:qlmanage -g ~/Library/QuickLook/QLStephen.qlgenerator -c "_" -p MANIFEST.in
So the problem really is, that macOS canât seem to map
dyn.ah62d4rv4ge80w5u
(*.in
) topublic.data
. And therefore skips QLStephen because it does not seem to apply to the extension. Which is funny, because it clearly works for*.m
files and theText.qlgenerator
.