This is the first part of a two part series on deploying your own touchbar extension for Visual Studio Code, designed mainly to work with Markdown notes. This post gives you a shortcut method with zero code! The next post will details a more “correct” method. If you don’t already realize - this applies to MacBooks with Touch bars running macOS only.
You may be interested to also read my previous post, Customizing VS Code for Markdown note-taking.
Touchbar
I have an updated post, with my current touch bar and using a newer beta version of SF Symbols 3. This post explains every step in more detail, but do visit the newer post too.
First up, screenshots of my touchbar.
When dealing with markdown files in my notes workspace, my touchbar contains:
- bold
- italics
- highlight (mark)
- bullets
- numbered list
- command palette
- toggle bottom panel (terminal, output, problems, debugger)
- find next
- quick fix (for Spell Right spelling corrections)
- indent
- word wrap
When dealing with other files, don’t show the markdown group. You can customize the taskbar for each different file language!
- command palette
- toggle bottom panel
- toggle sidebar (explorer, search, source control, run and debug, extensions)
- find next
- find previous
- quick fix
- indent
- outdent
- word wrap
When no file is open, both the markdown group and the editor group are not relevant. More important is a “New untitled file” button.
Pre-requisites
There are a few pre-requisites, including VS Code (at time of writing v1.58.2) with the Markdown Extended extension (v1.0.19) and a touchbar setting changed. Plus you need to get or create icons for your touchbar.
Important: this is a tutorial to make and customize your own extension. It is not available in the VS Code Marketplace. The reason is this: if you want to change the touchbar items, you need to manually the Extension Manifest source file!
Markdown Extended Extension
This extension requires Markdown Extended extension to be installed and enabled. This is because I prefer my custom touchbar to to trigger the Markdown Extended’s commands. To customize VS Code and Markdown Extended for note-taking, see my previous post.
VS Code Settings
I have the VS Code setting keyboard.touchbar.ignored
is configured to hide all default touchbar buttons. This gives me more space to customize my own buttons.
You can do this either via the user settings or workspace settings - refer to my previous post on workspace-specific settings in .vscode/settings.json
"keyboard.touchbar.ignored": [
"workbench.action.navigateBack",
"workbench.action.navigateForward",
"workbench.action.debug.start",
"workbench.action.debug.run"
]
If you don’t ignore the default touchbar buttons, you will simply have less space for custom touchbar items. The touchbar will look something like this, in my case with only 5 additional touchbar items (the last two groups are omitted due to insufficient space):
The commands hidden in keyboard.touchbar.ignored
can no longer be used even in the custom Extension Manifest!
Icons
The last pre-requisite is PNG icons for each touchbar item.
Here is a tip to get icons from Apple directly:
- download and install Apple’s SF Symbols Library 3 Beta for macOS,
- using the app, search for icons you like, select them View > Copy Image (this copies all images),
- in a Finder folder, paste (Cmd+V) and you’ll get one or more PNG icon files!
You need PNG, SVG will not work (despite the documentation). Refer to command icon specifications for the correct sizes.
The icon file name must end with @2x
to be considered a retina icon.
One thing you must do is invert the icon colors - the icons in SF Symbols are black, but white works better with the touchbar. You can use Preview invert the colors this way:
- Open the icon, hit Tools > Adjust Color
- Just below the histogram, swap the first and last pointers - move the first black pointer all the way to the right, and the right white pointer all the way to the left):
Shotcut Method to Create a custom Touchbar Extension
To create an extension the “easy” way do this:
- In
~/.vscode/extensions
, create a folder to store your extension source code, e.g.~/.vscode/extensions/mybyways.touchbar-1.0.0/
if you want to follow the standard naming convention. - Create the Extension Manifest, called
package.json
, as below:- modify the Commands (
contributes.commands
) section to trigger other commands, - modify the Menus (
contributes.menus.touchBar
) section to specify the icons and order of items in the touchbar.
- modify the Commands (
- Place all icons in this same folder (no sub-folder required, although you can if you prefer).
- Re-start VS Code to test and if prompted, re-load the window to reflect the extension change:
Experts will notice there is no main
below and no extension.js
file - this is a zero-code method!
{
"name": "mybyways-touchbar",
"displayName": "MyByways Touchbar",
"publisher": "MyByways.com",
"version": "0.0.1",
"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": "underline@2x.png", "title": "Markdown: ToggleUList", "command": "markdownExtended.toggleUList" },
{ "icon": "list.bullet@2x.png", "title": "Markdown: ToggleOList", "command": "markdownExtended.toggleOList" },
{ "icon": "123.rectangle.fill@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": "increase.indent@2x.png", "title": "Indent Line", "command": "editor.action.indentLines" },
{ "icon": "decrease.indent@2x.png", "title": "Outdent Line", "command": "editor.action.outdentLines" },
{ "icon": "magnifyingglass@2x.png", "title": "Find Next", "command": "editor.action.nextMatchFindAction" },
{ "icon": "magnifyingglass.flip@2x.png", "title": "Find Previous", "command": "editor.action.previousMatchFindAction" },
{ "icon": "rectangle.righthalf.filled@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": "textformat.abc.dottedunderline@2x.png", "title": "Quick Fix...", "command": "editor.action.quickFix" },
{ "icon": "terminal@2x.png", "title": "Show All Commands", "command": "workbench.action.showCommands" },
{ "icon": "rectangle.bottomhalf.filled@2x.png", "title": "View: Toggle Panel", "command": "workbench.action.togglePanel" },
{ "icon": "rectangle.lefthalf.filled@2x.png", "title": "View: Toggle Side Bar Visibility","command": "workbench.action.toggleSidebarVisibility" },
{ "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" }
],
"menus": {
"touchBar": [
{ "command": "markdownExtended.toggleBold", "group": "a@1", "when":"editorLangId==markdown" },
{ "command": "markdownExtended.toggleItalics", "group": "a@2", "when":"editorLangId==markdown" },
{ "command": "markdownExtended.toggleMark", "group": "a@3", "when":"editorLangId==markdown" },
{ "command": "markdownExtended.toggleUList", "group": "a@4", "when":"editorLangId==markdown" },
{ "command": "markdownExtended.toggleOList", "group": "a@5", "when":"editorLangId==markdown" },
{ "command": "workbench.action.showCommands", "group": "b@1" },
{ "command": "workbench.action.togglePanel", "group": "b@2" },
{ "command": "workbench.action.toggleSidebarVisibility", "group": "b@3", "when": "editorIsOpen&&editorLangId!=markdown" },
{ "command": "workbench.action.files.newUntitledFile", "group": "b@5", "when": "!editorIsOpen" },
{ "command": "editor.action.nextMatchFindAction", "group": "b@6", "when": "editorIsOpen" },
{ "command": "editor.action.previousMatchFindAction", "group": "b@7", "when": "editorIsOpen&&editorLangId!=markdown" },
{ "command": "workbench.action.editor.changeLanguageMode", "group": "b@8", "when": "editorLangId==plaintext" },
{ "command": "editor.action.quickFix", "group": "c@1", "when": "editorHasCodeActionsProvider" },
{ "command": "editor.action.indentLines", "group": "c@2", "when": "editorIsOpen" },
{ "command": "editor.action.outdentLines", "group": "c@3", "when": "editorIsOpen&&editorLangId!=markdown" },
{ "command": "editor.action.toggleWordWrap", "group": "c@4", "when": "editorIsOpen" }
]
}
}
}
To remove the extension, simply remove the whole folder.
Commands
The commands section contains any (and all) items that could appear in the touchbar. What I show above is a superset of some items that are relevant to me. These can be built-in commands e.g. editor.action.*
or commands contributed by extensions like markdownExtended.*
.
Each command
comprises an icon, a title and a command ID:
{
"icon": "bold@2x.png",
"title": "Markdown: Toggle Bold",
"command": "markdownExtended.toggleBold"
},
To add more commands, simply add a line with the command title and command ID. Here’s a tip to determine an existing command ID:
- open Code > Preferences > Keyboard Shortcuts
- search for a command, e.g. "bold" and once found...
- right-click on the item and Copy Command ID.
I make sure the command title is exactly as displayed, otherwise the extension will override the original command name, e.g. if you use { "icon": "b@2x.png", "title": "B", "command": "markdownExtended.toggleBold" },
then the command name will become just "B" which also affects the Command Palette!
It is not possible to use the in-built Codicons in the touchbar. At least in version 1.58.x, specifying e.g. "icon"="$(bold)"
does not work as expected.
Menus
The menus.touchbar section specifies what items appear in the touchbar, and when.
Each touchbar item comprises:
- a command ID, which much match a command in the previous section,
- a
group
that breaks up the touchbar items into sections- by default, touchbar items are sorted by the command title - to change the order use the
group
attribute with thea@1
,a@2
,a@3
... notation. - touchbar groups are also sorted by the group name, hence, I start mine with
a
,b
,c
... so that the markdown group nameda@*
appears beforeb@*
, etc.
- by default, touchbar items are sorted by the command title - to change the order use the
- and optionally,
when
which is the condition wherein the touchbar item is visible i.e. visiblewhen
the document language is Markdown:
{
"command": "markdownExtended.toggleBold",
"group": "a@1",
"when":"editorLangId==markdown"
},
On the touchbar on a 16" MacBook Pro, I can display only about 11 items, with the keyboard.touchbar.ignored
setting, depending on the width of team item (text or icon) and the number of groups. If the items exceed the space available on the touchbar, then the entire group will not be shown. You have to experiment.
You may be interested to know the standard two groups are named navigation
and 9_debug
- see the VS Code source code, editor.contribution.ts and debug.contribution.ts respectively.
Conclusion
I find that Nasc VSCode Touchbar and other Markdown touchbar extensions don’t fit my needs, and especially don’t leverage commands from other extensions. In my case, I prefer to use Markdown Extended’s key bindings to commands, hence my touchbar should leverage those same commands too.
With this simple method, you can also create your own touchbar that leverages any extension you use, for the language(s) of your choice!
The next post will detail how I actually implemented the touchbar extension properly, just so I remember myself (before I realized this simple, zero-code shortcut method worked equally well).
I have an updated post, with my current touch bar and using a newer beta version of SF Symbols 3. This post explains every step in more detail, but do visit the newer post too.