Updated 10122022-013451
The TextMate Wiki (at GitHub) is meant as a knowledge base for users of and contributors to TextMate.
While TextMate is under development, things will generally be documented first in the change log, then this wiki, and finally the manual. (Presently, the manual hasn’t been updated for 2.0.)
defaults
command..tm*properties
filesAs of this writing, the Issue Tracker is not public.
See http://macromates.com/support to contact support or report an issue.
The issue tracker at GitHub is for tracking bugs. If you wish to report a bug, please first read how we want bug reports written.
Use one of the following:
You can also use any of these for bug reports.
If you’re not sure if something is really a bug, or how to reproduce it, or if it’s already known, etc., please use one of the above channels (instead of the issue tracker).
The Issue Tracker has some overhead (for the development team, presently just one person) that the above channels do not.
With the issue tracker, something as simple as replying to a known issue with “yeah, we know about that, thanks!” becomes surprisingly complex. It requires into visiting the issue in a web browser, assigning it a label, doing a search on GitHub Issues (which is nothing like Google’s) to mark references to the old issue(s), and finally closing the new one.
Perhaps it doesn’t sound like much, but after about a thousand issues in half a year, it does feel like an unnecessary distraction. It’s also something that is difficult to outsource, as Pull Requests also come in via the Issue Tracker. Further complicating the matter is that we reference Issue numbers for bugfix commits.
To keep the Issue Tracker useful, we generally close issues which are not bug reports. We may not always comment, but generally a label should be assigned.
Here’s an explanation of some of the typical labels used to close issues:
feedback
: The issue created is considered “general feedback”. While you may have made a specific request, the issue may still be closed, as using the issue tracker as a list of everything everyone ever requested (that has not yet been implemented) is just making the issue tracker less useful for its main purpose: tracking bugs.
bundle-issue
: The issue isn’t related to the core application, but instead to some bundle item. We’ll often add a comment pointing to the relevant bundle, though. (Each bundle has its own issue tracker.)
too-vague
: The issue created is too vague. Please see writing bug reports.
question
: You should have used the mailing list, IRC channel, or contacted MacroMates.
won’t fix
: There are a bunch of reasons why even actual bugs won’t be fixed. It’s generally better to close an issue with this label (if we don’t plan to address it), than to keep it open for all of eternity.
Also, please remember that while TextMate is developed in a fairly open way, the program’s evolution is **not*- dictated by users (via the issues they open).
Before reporting a bug try first [[reverting to defaults]]
A bug report should contain these 4 things:
Steps to reproduce: Give **detailed*- steps on how to reproduce the problem.
Expected result: It’s important to include the result you’re expecting, as it might differ from how the program was designed to work.
Actual result: This is also important, since it’s possible that following your steps on a different system doesn’t reproduce the issue.
Environment: This includes:
See this great article (by Jakob Nielsen) on writing headlines, page titles, and subject lines.
As they say, “a picture is worth a thousand words”…but that is **not*- what we want in a succinct bug report! (Not to mention the plethora of other issues related to submitting bug reports as images.)
Only include pictures or movies as extra material, when it clarifies your bug report in ways that cannot be expressed in text. (For example, if text is garbled, it’s useful to include an image of *how- exactly it gets garbled.)
Opening an issue saying “syntax highlight is incorrect” with nothing besides a screenshot is not acceptable.
Unless you have steps to reproduce, there’s generally no need to report a crash. We already get crash reports from users who haven’t opted out. (You can change this in Preferences → Software Update.)
If you’re opening an issue about TextMate crashes, please include the corresponding crash report.
You can find a list of submitted reports in Notification Center. Just click the entry to open an online version. This also provides you with a URL to include in the issue (please do!).
You can also find crash reports for your system online under my crashes.
Hangs are different than crashes. If the program locks up, you should find (or create) a “spin report”. Normally, you can find these here:
/Library/Logs/DiagnosticReports/TextMate*«time»*«host».hang
If you need to *generate- a spin report while TextMate is locked up, here’s how:
TextMate has a few settings which are not exposed in the GUI.
You can change these with the defaults
shell command. (Make sure you do this while TextMate is **not*- running!)
Set a key:
defaults write com.macromates.TextMate «key» «value»
Reset a key to its default:
defaults delete com.macromates.TextMate «key»
Read a key’s value:
defaults read com.macromates.TextMate «key»
Key | Description | Type |
---|---|---|
disableTypingPairs |
When you type an opening brace, parenthesis, quote character, or similar, TextMate will insert the closing character. | boolean |
disableFolderStateRestore |
When opening a folder TextMate will restore open tabs and file browser state from the last time you had this folder open. | boolean |
disableAntiAlias |
Disable font anti-alias. | boolean |
disablePersistentClipboardHistory |
Don’t store clipboard history in ~/Library/Application Support/TextMate/ClipboardHistory.db . |
boolean |
disableTabAutoClose |
Don’t close excess tabs when the tab bar overflows. | boolean |
fileBrowserOpenAnimationDisabled |
This is for the zoom animation shown when opening items via TextMate’s file browser. | boolean |
alwaysFindInDocument |
Set this if you want ⌘F to always set the “in” pop-up to “document” (by default it searches “selection” when there is a multi-line selection. | boolean |
fileBrowserStyle |
Set this key to SourceList if you want TextMate’s file browser to use the “source list” style as seen in Finder’s sidebar. |
string |
hideStatusBar |
Disable the status bar shown below the text area. | boolean |
fontAscentDelta |
Increase/decrease TextMate’s default line ascend | float or integer |
fontLeadingDelta |
Increase/decrease TextMate’s default line lead | float or integer |
environmentWhitelist |
Colon-separated list of environment variables that TextMate should pass to a child process. Items with an asterisk are treated as a glob. You can use $default for the default whitelist. Example: $default:MANPATH:*EDITOR . TextMate sets up HOME , PATH , TMPDIR , LOGNAME , and USER . If you whitelist any of these, then the variable (if set) will inherit from the parent process instead. |
string |
lineNumberFontName |
Allows the use of a different font for the line number display. | string |
lineNumberScaleFactor |
Allows shrinking of the line number display, defaults to 0.8 | float or integer |
showFavoritesInsteadOfUntitled |
Show Recent Projects/Favorites window on startup and re-activation (instead of having an untitled window created), defaults to false. | boolean |
enableLoopFilterList |
In the chooser lists (fuzzy file finder, bundle item chooser, and symbol list) it is now possible to make the selection loop around, that is, move from first to last item with arrow up, etc. Defaults to false. | boolean |
tabItemMinWidth |
Minimum tab width, defaults to 120. | integer |
tabItemMaxWidth |
Maximum tab width, defaults to 250. | integer |
tabItemLineBreakStyle |
Tab truncation style, defaults to 5. Possible values: 2 = Simply clip 3 = Truncate at head of line: "...wxyz" 4 = Truncate at tail of line: "abcd..." 5 = Truncate middle of line: "ab...yz" |
integer |
For the integer and float keys, you **must*- use -float
or -integer
when setting the value.
These are settings that macOS uses to trigger some features on a per-app basis and can be used to enable or disable the feature in TextMate.
Key | Description | Type |
---|---|---|
NSAutomaticPeriodSubstitutionEnabled |
Allows using double-space to end a sentence and add a period, disabled by default. | boolean |
TextMate use extended attributes to store caret position, etc.
On file systems which don’t support extended attributes (most network file systems), OS X will create an auxiliary file with a dot-underscore prefix (e.g., .«*filename»
).
If you don’t want these files, you can disable the use of extended attributes. This is presently controlled with the volumeSettings
key. Its values are:
extendedAttributes
is supported.)*Example:- If we wanted to disable extended attributes for files under /net/
:
defaults write com.macromates.TextMate volumeSettings '{ "/net/" = { extendedAttributes = 0; }; }'
Font smoothing refers to sub-pixel anti-alias on LCD screens. Apple’s font smoothing algorithm will often make light text on dark backgrounds appear bolder than the same text on a bright background.
For this reason, TextMate disables font smoothing for dark themes on high-DPI displays (retina Mac).
You can control the behavior with:
defaults write com.macromates.TextMate fontSmoothing «value»
Here «value»
can be:
0
: Always disabled.1
: Always enabled.2
: Disabled for dark themes.3
: Disabled for dark themes on high-DPI displays (default).If you wish to restore the default value (3
) it’s better to run the following, rather than explicitly setting the value to 3
:
defaults delete com.macromates.TextMate fontSmoothing
Key bindings are consulted in the following order (first file with a binding wins):
~/Library/Application Support/TextMate/KeyBindings.dict
/path/to/TextMate.app/Contents/Resources/KeyBindings.dict
~/Library/KeyBindings/DefaultKeyBinding.dict
/Library/KeyBindings/DefaultKeyBinding.dict
/System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict
If you edit any these files, you’ll need to relaunch TextMate (⌃⌘Q) for changes to take effect.
These two action methods find the next/previous occurrence of the Find clipboard’s contents and selects it, while preserving the existing selection:
findNextAndModifySelection:
findPreviousAndModifySelection:
One could, for example, add this to the key bindings:
"@d" = ( "copySelectionToFindPboard:", "findNextAndModifySelection:" );
If you want ⌘⇠, ⇧⌘⇠, ⌘⇢, ⇧⌘⇢, ⌘⌫, and ⌘⌦ to ignore leading indentation, add the following to your key bindings file:
"@\UF702" = "moveToBeginningOfIndentedLine:";
"$@\UF702" = "moveToBeginningOfIndentedLineAndModifySelection:";
"@\UF703" = "moveToEndOfIndentedLine:";
"$@\UF703" = "moveToEndOfIndentedLineAndModifySelection:";
"@\U007F" = "deleteToBeginningOfIndentedLine:";
"@\UF728" = "deleteToEndOfIndentedLine:";
$var
, @var
, and var
as differentThis article explains how (word) “units” are setup in 2.0. This is what completion uses. For example :symbol
is different than symbol
, so one isn’t suggested when completing the other.
If you do not wish for punctuation to be considered part of (completion) units, then:
punctuation.separator
to punctuation
Be aware that definition of units are also used for word movement (⌥←/⌥→) and word selection (⌃W).
When determining what constitutes a word, the characterClass
setting is first consulted (see the previous FAQ item). If this doesn't apply, then the wordCharacters
setting is consulted.
You can set wordCharacters
by creating a new settings item in the bundle editor with the value:
{ wordCharacters = `«value»`; }
The «value»
is a string of which characters should be considered word characters; these are *in addition to- those already defined as word characters. If you wish, you can set the scope selector to limit the scope in which the characters should be considered a word character.
This is used for completion, word movement (⌥←/⌥→) and word selection (⌃W).
There are currently two possible ways to do this (both of which use the semantic class system):
callback.document.export
, which will filter the document that’s saved to disk (but *won’t- update the copy inside TextMate)callback.document.will-save
(which will update the copy in TextMate *before- saving)Here is a bundle to strip whitespace that makes use of the callback.document.will-save
class.
The **View*- menu has a setting to toggle soft wrap. (It stores the setting for the “current file type”.)
*Even with soft wrap disabled,- there are settings in the Source bundle to enable indented soft wrap for comments in source files. These can be disabled by unchecking the “Enable this item” checkbox in the bundle editor.
For more info see this mailing list post about indented soft wrap.
See hidden settings.
{}
was treated specially, giving you an indented caret on a blank line. This no longer works in the alpha.This is a complicated issue, explained best in this mailing list post.
The indentation rules have been given a higher importance in TextMate 2. As a result, some language rules aren’t up-to-date with the new precedence.
For bundle authors (or anyone who wants to get their hands dirty), the guide to indentation rules is in the 1.x manual.
Of course, indentation rules make no sense in certain languages; Python’s indentation, for example, is what determines scope, rather than delimiters. For these languages, you can disable the auto correction of indentation by adding a new settings item (scoped to the language) as follows:
{ disableIndentCorrections = :true; }
If you’d rather disable it for all languages, do the same thing without giving it a scope.
Explicit project files aren’t currently supported.
When you open a folder, the folder is treated as a project. Thus, the file chooser (⌘T) and folder search (⇧⌘F) default to the folder. (See the manual for more details.)
You can customize folder settings with a .tm*properties
file.
Allan’s written a couple posts in a longer thread about this:
With the directory-centered focus, this is no longer directly possible. A simple workaround, however, is simply to add symlinks to the various other directories and files.
(*Note:- By default, *Find in Folder- does not follow symlinks. See other FAQs on how to make it follow symlinks.)
In the file browser, single-clicking the icon will open the file.
If you think the click-target is too small, you can enable the single-click behavior for the text instead. Simply run the following in a terminal:
defaults write com.macromates.TextMate fileBrowserSingleClickToOpen -bool true
If you wish to select items, you must either click to the left of the text, or hold down command (⌘) when clicking the item’s text.
This is similar to how Finder treats links. There’s currently no way to have them expand inline.
For standard bundles you should install via Preferences → Bundles.
Third party bundles can be double-clicked which installs them in:
~/Library/Application Support/TextMate/Pristine Copy/Bundles
If you wish to edit the bundles and share your changes you should install (git clone
) them to:
~/Library/Application Support/TextMate/Bundles
This way, TextMate won’t create delta files (which aren’t useful for sharing).
If you manually install bundles and they do not show up, your file system may lack support for fs-events
. If this is the case, you will need to delete the cache and relaunch TextMate:
rm ~/Library/Caches/com.macromates.TextMate/BundlesIndex.plist
The current plan is to generalize the update mechanism through the semantic class system, so it can be used in more cases.
However, this isn’t yet implemented, and subject to change.
No—rmate
simply sends a file back and forth. Opening a folder is way more complex.
Within the *Find in Folder- window, there’s a drop-down menu above the results. Enable “Follow Symbolic Links” in this menu.
*Note:- This *will not- resolve aliases created with Finder.
Duplicate Line is implemented as a command. Currently, commands aren’t supported (per sé) for multiple carets.
*Use this method to migrate your personally created bundles. To install *other*- bundles, check Preferences → Bundles
.
Beta versions of TextMate required you to move your personal bundles into an Avian
-bundle directory. This is no longer deemed necessary, since there is no longer a reason to open TextMate 1.x.
Note:
~
character refers to your home directory (/Users/«yourname»/
).Library
folder may be hidden by default. If so, access it from the Finder’s Go
while holding down option (⌥).Application Support
may not exist on your system. If they don’t, you should create them.Many problems can be solved by reverting to default settings. To do so, quit TextMate, then remove the following files and folders:
~/Library/Application Support/TextMate
~/Library/Caches/com.macromates.TextMate/BundlesIndex.binary
~/Library/Preferences/com.macromates.TextMate.plist
~/.tm*properties
*Note:- Not all of these files/folders may exist, and any potential customizations will be lost.
*Note:- As .tm*properties
files can be in arbitrary folders, you may have more than the one in your home folder. But if you never created any, there is no reason to go hunting for them; TextMate doesn’t create these by itself.
*See also:- Troubleshooting for TextMate 1.x.
By default, TextMate writes errors to the standard error (STDERR) file descriptor.
Unfortunately, this means that it is not visible anywhere, unless you are running TextMate from a terminal (i.e., /path/to/TextMate.app/Contents/MacOS/TextMate
, NOT just mate
).
To redirect logging, set the LOG*PATH
environment variable before launching TextMate. TextMate will then create TextMate.log
in the LOG*PATH
location.
It’s easy:
launchctl setenv LOG*PATH "$HOME/Library/Logs"
That’s it!
If you want to verify, run this in your terminal:
tail -f ~/Library/Logs/TextMate.log
*NOTE:- Each time you launch TextMate, the log file is recreated. Thus, output from previous sessions is lost.
binary
— If set for a file, file browser will open it with external program when double clicked. Mainly makes sense when targetting specific globs.encoding
— Set to the file’s encoding. This will be used during save but is also fallback during load (when file is not UTF-8). Load encodinng heuristic is likely going to change. The value for the encoding must be one of the libiconv codes (e.g., for "Windows - Western", use "CP1252").fileType
— The file type given as scope, e.g. text.plain.useBOM
— Used during save to add BOM (for those who insist on putting BOMs in their UTF-8 files).lineEndings
— Used during save to specify the line endings to use, value should be "\n" or "\r\n".atomicSave
- See below for possible values and explaination.disableExtendedAttributes
- Disable extended attributes when saving files.showInvisibles
— Sets the initial value. Can also be changed via View menu.softTabs
, tabSize
spellChecking
, spellingLanguage
— Enable/disable spelling and set language. (See below for spellingLanguage
values.)projectDirectory
— the project directory, generally set to $CWD in a .tm*properties file at the root of the project. This affects TM*PROJECT*DIRECTORY
and default folder for ⇧⌘F.windowTitle
— override the window title. The default is $TM*DISPLAYNAME
but could e.g. be changed to $TM*FILEPATH
. Should add a $TM*SCM*BRANCH
.excludeSCMDeleted
- Set to true
to hide the “ghost” items that appear after deleting a file on disk which is still tracked by your version control system.tabTitle
- Set the title of tabs (defaults to $TM*DISPLAYNAME)scopeAttributes
— The value is added to the scope of the current file.These are all globs and perhaps a bit arcane.
The file browser, if it has a file, checks that file against the first key with a value in this order: excludeFilesInBrowser
, excludeInBrowser
, excludeFiles
, exclude
. If neither match, it then does the same with include keys, and if one match, it is included. Directories work the same, except using the Directories
InFileChooser
is "Go → Go To File… ⌘T"InBrowser
is the sidebar.InFolderSearch
is "Edit → Find → Find in Project ⇧⌘F"The default include key is - (so no hidden files, although see the default .tm*properties
which include .htaccess
and .tm*properties
). The default exclude key is the empty string (nothing matches).
exclude
excludeFiles
excludeDirectories
excludeInBrowser
excludeInFolderSearch
excludeInFileChooser
excludeFilesInBrowser
excludeDirectoriesInBrowser
include
includeFiles
includeDirectories
includeInBrowser
includeInFileChooser
includeFilesInBrowser
includeDirectoriesInBrowser
includeFilesInFileChooser
spellingLanguage
ValuesThese values depend on which dictionaries you have installed so not all may be available. (You can see a list of what is available from the Edit → Spelling menu.)
en → English
enAU → English (Australia)
enGB → English (United Kingdom)
enCA → English (Canada)
da → Danish
fr → French
de → German
es → Spanish
it → Italian
pt → Portuguese
ptBR → Portuguese (Brazil)
nl → Dutch
sv → Swedish
ru → Russian
pl*PL → Polish (Poland)
atomicSave
ValuesTextMate has been using exchangedata
for atomic saving. This API allows writing an updated file to a new location and then swap the data part atomically with the old file’s. This ensures that the saved file is never in a partially written state, it preserves all file metadata (of which there is a lot), it preserves the file’s inode, so any potential hardlinks are not broken, etc.
Unfortunately APFS, the new default file system for macOS, does not support exchangedata
.
TextMate falls back on rename
when exchangedata
is unavailable.
This require that all metadata of the old file be copied to the new one, but there is no way to preserve the inode, so hardlinks will break, furthermore, as this is effectively a completely new file, the date of its parent diretory will be updated. Some software will monitor directories for new files and do a rescan each time the directory is updated, which previously would only be when files were created or deleted, but now each save may also trigger such rescan.
For this reason, there is a new setting to control when and how TextMate should use atomic saving. It can be controlled by setting atomicSave
in .tm*properties
to one of the following values:
always
: Using NSFileManager
API (so no inode preservation even on HFS+).externalVolumes
: Disable atomic saving only for internal disks.remoteVolumes
: This is the default, uses atomic saving only for remote drives (e.g. network mounts).never
: Never use atomic saving.legacy
: This will use exchangedata
when available and fallback on rename
. This option will be removed in the future.Many settings can be specified per folder and even per file type, here are the default values:
exclude = "{*.{o,pyc},Icon\r,CVS,*darcs,*MTN,\{arch\},blib,*~.nib}"
include = "{.tm*properties,.htaccess}"
TM*HG = "/opt/local/bin/hg"
TM*GIT = "/opt/local/bin/git"
[ "/usr/include/{**/,}*" ]
tabSize = 8
[ *.{txt,md,mdown,markdown} ]
softWrap = true
[ .git/COMMIT*EDITMSG ]
softWrap = true
spellChecking = true
spellingLanguage = 'en'
[ *.{icns,ico,jpg,jpeg,m4v,nib,pdf,png,psd,pyc,rtf,tif,tiff,xib} ]
binary = true
[ source.ruby ]
softTabs = true
tabSize = 2
[ "/System/Library/Frameworks/**/Headers/**/*" ]
encoding = "MACROMAN"
[ "{README,INSTALL,LICENSE,TODO}" ]
fileType = "text.plain"
It will read from current folder and up until either it reaches ~ or /. If it reaches / then it will additionally read ~/.tm*properties. This means you can have “global” settings in that file and they work even when opening stuff not under your home folder.
In the file you can do sections with a glob against full path to restrict the following settings to just those which match the glob.
In the variable part you have a few variables, the usual $TM*FILEPATH
and friends, but you also have $CWD
, this is the folder containing the property file. This is useful if you put a .tm*properties
file in the root of your project, for example I use this file with TextMate:
# Settings
tabSize = 3
projectDirectory = "$CWD"
windowTitle = "$TM*DISPLAYNAME — ${CWD/^.*\///}"
excludeInFileChooser = "{$exclude,*.xib}"
# Variables
TM*ORGANIZATION*NAME = 'MacroMates'
TM*SYS*HEADER*PATH = '${TM*SYS*HEADER*PATH:?$TM*SYS*HEADER*PATH:/usr/include/c++/4.0.0:/usr/include:/System/Library/Frameworks}:$CWD/Shared/include:${BUILD*DIR:-$CWD/build}/TextMate/public'
TM*TODO*IGNORE = '/(disabled(-src)?|onig-.*|build|cache|CxxTest|(FScript|BWToolkitFramework).framework)/'
TM*MAKE*FILE = '${CWD}/Makefile'
TM*MAKE*TARGET = 'TextMate/run'
[ target ]
fileType = "source.tm-properties"
[ *.{h,pch} ]
fileType = "source.objc++"
[ Makefile.- ]
fileType = "source.makefile"
[ attr.untitled ]
fileType = 'source.c++'
[ "tests/*.{cc,mm}" ]
scopeAttributes = 'attr.test.cxxtest'
TM*MAKE*TARGET = '${TM*FILEPATH/^.*?([^\/]*)\/tests\/.*$/$1/}/test'
[ "rmate/*" ]
TM*MAKE*TARGET = rate
[ vendor/MASPreferences/**/*.{m,h} ]
tabSize = 4
softTabs = true
TM*C*POINTER = " *"
As you can see I set the Makefile
via CWD
— here I can’t use TM*FILEPATH
or similar, because those will be the “current file”, not the project root.
Some things of interest is how e.g. test files get the scope augmented, this is because I have unit test snippets I only want active in test files. Additionally I change the make target for test files.
While the .tm*properties
can contain both settings and environment variables, while interpreting the file, TextMate doesn’t distingish between the two, so it is possible to mix them in the value part and also reference already set variables, e.g. if we want to extend the default exclude setting we can do:
exclude = '{$exclude,*.o}'
The value is a glob so we use brace expansion to add the *.o extension.
The following is a quick list of issues that should be doable without too much familiarity with the codebase and which do not require “design discussions” per se (in random order):
BundlesPreferences.mm
source is currently using the BundlesManager
singleton as storage for its progress strings. It should instead use a local dictionary or similar for this.NSEvent.h
(like Apple do). This could likely be handled in ns::normalize*event*string
though it might also be nice to use the symbolic names when generating event strings (which are stored in bundle items).NSComboBox
instances and OakPasteboardSelector
should be retired. The only advantage that this class has (over the regular history menu) is that the user can delete items from the list.- moveSelectedRowByOffset:extendingSelection:
does not correctly extend the selection. Try e.g. shift page up/down in a dialog that uses this code. This is because it only adds a single index to the selection, rather than a range. I don’t think we can replicate proper behavior because we do not know where the search is anchored, but we can definitely do better than now.LF
-delimited. Relevant code though this one probably requires a bit of refactoring.kSelectionExtendToWordOrTypingPair
does not account for identical typing pairs (like quotes). This could likely be done by looking if left/right of the typing pair is whitespace, and/or which side of the typing pair has the “deepest” scope (similar to Select Scope).volume::settings
that reads from user defaults. This should be changed to use the settings*t
system (i.e. .tm*properties
), ideally with “migration code” for anyone who has disabled extended attributes for a volume.NSTextFinder
can be used for this).An older item (still somewhat relevant):
Implement OakTabTriggerImage
This should be an NSImage
subclass which simply renders a tab trigger. It would be used in the menus and bundle item selector (and probably, also bundle editor).
Making it an NSImage
subclass should allow embedding it in attributed strings. This is what we use for the menu items, since it isn’t really possible to augment menu rendering in Cocoa. (The only workaround is to replace the full item with a custom view.)
For how to do this, check out the implementation of OakFileIconImage.mm
.
irc://irc.freenode.net/#textmate ↩︎