A few posts back, I described my no-code approach to customizing my MacBook touch bar in Visual Studio Code, where I used Apple’s SF Symbols 3 Beta icon library. Now, Apple has release a new beta of SF Symbols that makes the process easier!
Customizing Icons with SF Symbols
Download and install Apple’s SF Symbols 3 Beta. The UI looks like this:
One can:
- search for icons you want to re-use, e.g. “bold”,
- display icons in dark or light theme - touch bar icons are always light on dark, so choose View > Appearance > Dark,
- render icons in “multicolor” or monochrome (or palette or hierarchical, don’t ask me),
- alter the line weight (thickness) - I use Light instead of Regular,
- edit custom icons, duplicated from the original - right click and select Duplicate as Custom Symbol to create a copy in the Custom Symbols library section,
For a custom (duplicated) multicolor icon, it is possible to set the color of each constituent layer, like for this icon:
However, most icons do not have layers, so here is how to change the color of a specific part of an icon.
A vector icon (SVG) comprises multiple “subpaths”, so you need to create a new layer with the path you want to change the color for:
- make sure the color sidebar on the right is visible - from the menu View > Inspectors > Show Color Sidebar.
- copy the icon’s subpaths into a new layer with the + button at the bottom of the Color sidebar - do this for each color required!
- in the original layer, uncheck all items you want to change the color for - here my layer color is “Accent” and subpath 3 is disabled, so that only subpaths 1 and 2 have the accent color.
- in the duplicated layer(s), change the color and check the subpaths you want to have that color - here subpath 3 will be shown in pink.
Note that you can only edit the layer colors for custom symbols. If you can’t, then remember to “Duplicate as Custom Symbol”!
Finally, to export as PNG:
- select one or more icons (you can export all in one go), right click > Copy Image
- in a Finder folder, paste with Ctrl+V
Viola, a custom colored icon! I no longer have to edit the icon, e.g. to invert the icon from black to white!
For the really lazy, this bash command will remove the custom.
prefix from all PNG filenames, for f in custom.*.png; do mv $f ${f/custom./}; done
One last tip: I compress my PNGs with ImageOptim. All but 3 of my icons are under 1,000 bytes!
Creating the VS Code Touch Bar
Now to create the touch bar custom extension in Microsoft Visual Studio Code, which I’ve described in detail before. In short:
- Create a folder
~/.vscode/extensions/mybyways.touchbar-1.0.0
, - Copy the icons to that folder,
- Create a file
package.json
in that folder with the content below, - Re-start VS code, and enable the extension if it isn’t already enabled.
{
"name": "mybyways-touchbar",
"displayName": "MyByways Touchbar",
"publisher": "MyByways.com",
"version": "0.0.2",
"engines": { "vscode": "^1.50.0" },
"contributes": {
"commands": [
{ "icon": "bold@2x.png", "title": "Markdown: Toggle Bold", "command": "markdownExtended.toggleBold" },
{ "icon": "italic@2x.png", "title": "Markdown: Toggle Italics", "command": "markdownExtended.toggleItalics" },
{ "icon": "list.bullet@2x.png", "title": "Markdown: ToggleUList", "command": "markdownExtended.toggleUList" },
{ "icon": "list.number@2x.png", "title": "Markdown: ToggleOList", "command": "markdownExtended.toggleOList" },
{ "icon": "highlighter@2x.png", "title": "Markdown: Toggle Mark", "command": "markdownExtended.toggleMark" },
{ "icon": "strikethrough@2x.png", "title": "Markdown: Toggle Strikethrough", "command": "markdownExtended.toggleStrikethrough" },
{ "icon": "underline@2x.png", "title": "Markdown: Toggle UnderLine", "command": "markdownExtended.toggleUnderline" },
{ "icon": "textformat.subscript@2x.png", "title": "Markdown: Toggle Superscript", "command": "markdownExtended.toggleSuperscript" },
{ "icon": "textformat.superscript@2x.png", "title": "Markdown: Toggle Subscript", "command": "markdownExtended.toggleSubscript" },
{ "icon": "tablecells@2x.png", "title": "Markdown: Paste As Table", "command": "markdownExtended.pasteAsTable" },
{ "icon": "increase.indent@2x.png", "title": "Indent Line", "command": "editor.action.indentLines" },
{ "icon": "decrease.indent@2x.png", "title": "Outdent Line", "command": "editor.action.outdentLines" },
{ "icon": "terminal@2x.png", "title": "View: Toggle Terminal", "command": "workbench.action.terminal.toggleTerminal" },
{ "icon": "sidebar.right@2x.png", "title": "View: Toggle Minimap", "command": "editor.action.toggleMinimap" },
{ "icon": "arrow.turn.down.left@2x.png", "title": "View: Toggle Word Wrap", "command": "editor.action.toggleWordWrap" },
{ "icon": "arrowshape.turn.up.left@2x.png", "title": "Undo", "command": "undo" },
{ "icon": "textformat.abc.dottedunderline@2x.png", "title": "Quick Fix...", "command": "editor.action.quickFix" },
{ "icon": "plus.magnifyingglass@2x.png", "title": "Find Next", "command": "editor.action.nextMatchFindAction" },
{ "icon": "minus.magnifyingglass@2x.png", "title": "Find Previous", "command": "editor.action.previousMatchFindAction" },
{ "icon": "curlybraces@2x.png", "title": "Select to Bracket", "command": "editor.action.selectToBracket" },
{ "icon": "line.3.horizontal.decrease@2x.png", "title": "Toggle Fold", "command": "editor.fold" },
{ "icon": "command.square@2x.png", "title": "Show All Commands", "command": "workbench.action.showCommands" },
{ "icon": "rectangle.bottomhalf.inset.filled@2x.png", "title": "View: Toggle Panel", "command": "workbench.action.togglePanel" },
{ "icon": "sidebar.squares.left@2x.png", "title": "View: Toggle Activity Bar Visibility", "command": "workbench.action.toggleActivityBarVisibility" },
{ "icon": "sidebar.left@2x.png", "title": "View: Toggle Side Bar Visibility", "command": "workbench.action.toggleSidebarVisibility" },
{ "icon": "arrow.left.and.right.circle@2x.png", "title": "View: Toggle Side Bar Position", "command": "workbench.action.toggleSidebarPosition" },
{ "icon": "arrowtriangle.up.square@2x.png", "title": "View: Previous Side Bar View", "command": "workbench.action.previousSideBarView" },
{ "icon": "arrowtriangle.down.square@2x.png", "title": "View: Next Side Bar View", "command": "workbench.action.nextSideBarView" },
{ "icon": "gearshape@2x.png", "title": "Preferences: Open Settings (UI)", "command": "workbench.action.openSettings2" },
{ "icon": "keyboard@2x.png", "title": "Preferences: Open Keyboard Shortcuts", "command": "workbench.action.openGlobalKeybindings" },
{ "icon": "heart@2x.png", "title": "Preferences: Color Theme", "command": "workbench.action.selectTheme" },
{ "icon": "doc.circle.fill@2x.png", "title": "Explorer: Focus on Open Editors View", "command": "workbench.files.action.focusOpenEditorsView" },
{ "icon": "folder.circle.fill@2x.png", "title": "Explorer: Focus on Folders View", "command": "workbench.explorer.fileView.focus" },
{ "icon": "bookmark.circle.fill@2x.png", "title": "Explorer: Focus on Outline View", "command": "outline.focus" },
{ "icon": "calendar.circle.fill@2x.png", "title": "Explorer: Focus on Timeline View", "command": "timeline.focus" },
{ "icon": "character.cursor.ibeam@2x.png", "title": "Explorer: Rename File", "command": "renameFile" },
{ "icon": "doc.badge.plus@2x.png", "title": "File: New File", "command": "explorer.newFile" },
{ "icon": "folder.badge.plus@2x.png", "title": "File: New Folder", "command": "explorer.newFolder" },
{ "icon": "trash@2x.png", "title": "Explorer: Move File to Trash", "command": "moveFileToTrash" },
{ "icon": "questionmark.folder@2x.png", "title": "File: Reveal in Finder", "command": "revealFileInOS" },
{ "icon": "doc.badge.plus@2x.png", "title": "File: New Untitled File", "command": "workbench.action.files.newUntitledFile" },
{ "icon": "character.bubble@2x.png", "title": "Change Language Mode", "command": "workbench.action.editor.changeLanguageMode" },
{ "icon": "plus.magnifyingglass@2x.png", "title": "Terminal: Find Next", "command": "workbench.action.terminal.findNext" },
{ "icon": "minus.magnifyingglass@2x.png", "title": "Terminal: Find Previous", "command": "workbench.action.terminal.findPrevious" },
{ "icon": "clear@2x.png", "title": "Terminal: Clear", "command": "workbench.action.terminal.clear" },
{ "icon": "square.split.2x1@2x.png", "title": "Terminal: Split Terminal", "command": "workbench.action.terminal.split" },
{ "icon": "square.on.square@2x.png", "title": "Terminal: New Integrated Terminal", "command": "workbench.action.terminal.new" },
{ "icon": "trash.square@2x.png", "title": "Terminal: Kill the Active Terminal Instance", "command": "workbench.action.terminal.kill" },
{ "icon": "chevron.down.square@2x.png", "title": "Terminal: Focus Next Terminal", "command": "workbench.action.terminal.focusNext" },
{ "icon": "chevron.up.square@2x.png", "title": "Terminal: Focus Previous Terminal", "command": "workbench.action.terminal.focusPrevious" },
{ "icon": "chevron.right.square@2x.png", "title": "Terminal: Focus Next Terminal Pane", "command": "workbench.action.terminal.focusNextPane" },
{ "icon": "chevron.left.square@2x.png", "title": "Terminal: Focus Previous Terminal Pane", "command": "workbench.action.terminal.focusPreviousPane" }
],
"menus": {
"touchBar": [
{ "command": "workbench.action.showCommands", "group": "a@1" },
{ "command": "workbench.action.terminal.toggleTerminal", "group": "a@2" },
{ "command": "workbench.action.toggleActivityBarVisibility", "group": "a@3" },
{ "command": "workbench.action.toggleSidebarVisibility", "group": "a@4", "when": "sideBarFocus" },
{ "command": "editor.action.toggleMinimap", "group": "a@5", "when": "sideBarFocus" },
{ "command": "workbench.action.previousSideBarView", "group": "a@6", "when": "sideBarFocus" },
{ "command": "workbench.action.nextSideBarView", "group": "a@7", "when": "sideBarFocus" },
{ "command": "markdownExtended.toggleBold", "group": "b@1", "when":"editorFocus&&editorLangId==markdown" },
{ "command": "markdownExtended.toggleItalics", "group": "b@2", "when":"editorFocus&&editorLangId==markdown" },
{ "command": "markdownExtended.toggleMark", "group": "b@3", "when":"editorFocus&&editorLangId==markdown" },
{ "command": "markdownExtended.toggleUList", "group": "b@4", "when":"editorFocus&&editorLangId==markdown" },
{ "command": "markdownExtended.toggleOList", "group": "b@5", "when":"editorFocus&&editorLangId==markdown" },
{ "command": "editor.action.toggleWordWrap", "group": "c@1", "when": "editorFocus&&editorLangId!=markdown" },
{ "command": "editor.action.indentLines", "group": "c@2", "when": "editorFocus&&editorLangId!=markdown" },
{ "command": "editor.action.selectToBracket", "group": "c@3", "when": "editorFocus&&editorLangId!=markdown" },
{ "command": "editor.fold", "group": "c@4", "when": "editorFocus&&editorLangId!=markdown&&foldingEnabled" },
{ "command": "editor.action.quickFix", "group": "d@1", "when": "editorFocus&&editorHasCodeActionsProvider" },
{ "command": "undo", "group": "c@2", "when": "editorFocus&&editorLangId!=markdown" },
{ "command": "editor.action.nextMatchFindAction", "group": "d@3", "when": "editorFocus||findInputFocussed" },
{ "command": "editor.action.previousMatchFindAction", "group": "d@4", "when": "editorFocus&&editorLangId!=markdown" },
{ "command": "workbench.action.terminal.findNext", "group": "d@5", "when": "terminalFindFocused||terminalFocus" },
{ "command": "workbench.action.terminal.clear", "group": "e@1", "when": "terminalFocus" },
{ "command": "workbench.action.terminal.split", "group": "e@2", "when": "terminalFocus" },
{ "command": "workbench.action.terminal.new", "group": "e@3", "when": "terminalFocus" },
{ "command": "workbench.action.terminal.kill", "group": "e@4", "when": "terminalFocus" },
{ "command": "workbench.action.terminal.focusNextPane", "group": "e@5", "when": "terminalFocus" },
{ "command": "workbench.action.terminal.focusNext", "group": "e@6", "when": "terminalFocus" },
{ "command": "renameFile", "group": "f@1", "when": "focusedView=='workbench.explorer.fileView'&&!explorerResourceIsRoot&&!explorerResourceReadonly" },
{ "command": "revealFileInOS", "group": "f@1", "when": "focusedView=='workbench.explorer.fileView'" },
{ "command": "explorer.newFile", "group": "f@2", "when": "focusedView=='workbench.explorer.fileView'" },
{ "command": "explorer.newFolder", "group": "f@3", "when": "focusedView=='workbench.explorer.fileView'" },
{ "command": "workbench.action.files.newUntitledFile", "group": "g@1", "when": "!editorIsOpen" },
{ "command": "workbench.action.openSettings2", "group": "g@2", "when": "!editorIsOpen" },
{ "command": "workbench.action.openGlobalKeybindings", "group": "g@3", "when": "!editorIsOpen" },
{ "command": "workbench.action.selectTheme", "group": "g@4", "when": "!editorIsOpen" }
]
}
}
}
You can inspect the code to discover:
- which icons I use - the filenames match SF Symbols,
- the icon assignment to existing command IDs in the
contributes.commands
section - I have more than needed in the example above, just in case you want to change them, but its better to remove anything you don’t use. - the order of touch bar items, sorted by
group
name, in themenus.touchBar
section, - and most importantly, the
when
clause, which defines when each item is displayed. This is where the magic happens, to make the touch bar items context sensitive!
I’m using Markdown commands from an Extension called Markdown Extended by jebbs. Read more about my VS Code setup for markdown note-taking here. You will have to change these if this is not installed in your setup.
My VS Code Touch Bar
I keep tweaking my touch bar, and as of now, it looks like this.
Remember that if there is insufficient space for all the items in a group, then entire group will not be displayed!
No Editor
When no editor is opened, my touch bar is:
The first “global” group is:
- command palette
- toggle terminal
- toggle activity bar - I often hide this when just taking markdown notes
The second group is shown only when there is no document open:
- new document
- show settings UI
- show keyboard bindings UI
- show theme picker dropdown
Markdown
When editing a markdown file, a markdown specific group appears after the global group:
- bold
- italic
- mark (highlight)
- bullet list
- numbered list
Followed by a “tools” touch bar group:
- quick fix
- find
Code
When editing other files, commands I find useful for general coding appear next:
- word wrap
- indent
- match braces
- toggle fold
Followed by the expanded tools group:
- quick fix
- undo
- find next
- find previous
Debugging
When debugging first group is VS Code’s default, followed by my global group.
Terminal
When terminal has focus, Terminal specific stuff appears after the global group:
- clear (not close!)
- split
- new (tabbed) terminal
- close
- next split terminal
- next (tabbed) terminal
Nothing much is left of tools group, except:
- find in terminal
Folder Explorer and Side Bars
When the sidebar has focus, the global group expands with more UI-related commands:
- toggle sidebar (on the left, after the activity bar)
- toggle minimap (on the right)
- next sidebar view in the activity bar
- previous sidebar view in the activity bar
Then, file-related stuff when specifically the folder explorer side bar has focus:
- rename file or folder
- open in finder
- new file
- new folder
Closing
Cool? Remember to give credit where credit is due, as far as I know, I’m the first person to figure this out!