An introduction to Visual Studio Code
tech

The first "real" code editor I ever used was the minimalist Proton for Windows, with a size of just over 800kb, smaller that many images on the web these days. Over the last decade or so, I went from TextWrangler to Coda2 to SublimeText, before finally settling for GitHub's Atom. I still love Atom for being 100% hackable, but it would frequently become incredibly slow, to the point where I had to restart it several times a day. This seems to be a very common problem.

So a few weeks ago, I finally made the switch to Microsoft's Visual Studio Code. I'm not gonna lie, abandoning Atom broke my heart. But it turned out VSCode wasn't just a rebound – it's really fast, comes with a bunch of great, built-in features and can be surprisingly pretty, given the right configuration. In this post, I'll show you some of my favourite settings, features and extensions, and share a tips on how to customise it even further – including how to implement my favourite Atom feature, custom stylesheets.

Favourite features and settings

Visual Studio Code comes with an integrated terminal, version control, a powerful set of debugging tools, intelligent code completion, a range of accessibility options and all of the usual perks like split panels, customisable key bindings, syntax highlighting, snippets and an open marketplace for extensions.

Like Atom, VSCode lets you configure the settings via a JSON file. The available settings are searchable and organised in categories, and each setting comes with a button to copy-paste it over to your user settings.

Adding to the user settings
Adding to the user settings

Integrated terminal

No more switching between windows when I'm developing in Python or Node, serving a static site via Harp or deploying my projects. You can set your favourite shell via the terminal.integrated.shell.osx settings, so I get to use zsh, together with Oh My Zsh's custom themes and plugins.

Integrated terminal using iTerm and zsh
Integrated terminal using iTerm and zsh

You can also change the default external terminal application via the terminal.external.osxExec setting, and use iTerm2 or Hyper instead of the standard macOS Terminal app.

Native Git integration

If your project uses Git, you'll be able see its status and quickly sync and switch branches from the editor's status bar. You can even commit straight from the Git panel. I still prefer GitHub Desktop for commits, though, as it gives me a better overview of my repos and makes it easy to compare diffs, do partial commits and undo commits with one click.

Markdown preview with custom styles

Most of the time I'm writing Markdown in my editor, I'm actually writing Readmes and other documents for GitHub. The GitHub Markdown theme is pretty nice, so I've put together my own version of it based on this template. It's a bit hacky and I had to add a few !important declarations to colours here and there, but it works and I can now preview files almost exactly like they'll appear on GitHub.

GitHub-style Markdown preview
GitHub-style Markdown preview

Emmet support

Emmet provides shortcuts for writing nested HTML and CSS. You define the structure in one line, for example div>p*4 for a div with four nested paragraphs, hit tab and the full markup is generated automatically. To see it in action, check out this example from CSS Tricks:

Creating a module with lorem ipsum content using Emmet
Creating a module with lorem ipsum content using Emmet

I still haven't managed to get it to work for my ideal use case, nested Jade/Pug mixins. While it works fine for regular markup, it fails on mixins prefixed by +. Eventually, I'd love to be able to do something like +table(["Name", "Description"])>+row*3>+cell*2, using my own pre-defined table mixins. I still have high hopes for getting this to work with a custom extension.

Application zoom

This sounds like a pretty minor and trivial setting, but it actually made a huge difference for me. The default UI is just way too large for my taste. On my 13" screen, I like to work with two panels of around 80 characters wide, plus a sidebar with a tree view of the current working directory and VSCode's "activity bar" that lets me switch between the tree-view explorer and the search panel. With the right combination of application zoom ("window.zoomLevel": -0.77) and editor font size ("editor.fontSize": 15), I've managed to get the sizing just right. (Admittedly, my eyesight is pretty good and I don't mind small text.)

Extensions

Extensions and themes can be downloaded from the official Visual Studio Marketplace and via the extensions panel from within the editor. For a curated overview of some of the best packages and resources, check out the awesome-vscode repo. I'm currently using the following extensions:

  • Active File in StatusBar — Shows the full (or shortened) path to the current file it the status bar.
  • Clock in status bar — Shows the current time in the status bar. I usually swipe between two or three editors in different spaces, and it's easy to forget the time when working in fullscreen mode.
  • colorize — Adds a background to all colour values. In CSS files, colours are displayed in a little box next to the values, but I haven't yet managed to enable this for Sass and other file formats. So this extension helps a lot.
  • Custom CSS and JS loader — Modifies the editor's look and behaviour by loading it with custom CSS and JS – I'm explaining more about how this works in detail below.
  • Panda Syntax Theme — My absolute favourite syntax theme, hands down.
  • Python, MagicPython, Sass — Adds more language-specific capabilities, including syntax highlighting and formatting.
  • REST Client — Allows you to send HTTP requests and view the response straight from the editor. This is the latest addition to my extensions, and I haven't used it much yet, but it looks like it might be the solution to a lot of my HTTP request frustrations.
  • reStructuredText — Adds support and previews for .rst files (which I hate with a passion). But for Readmes to be rendered nicely on pypi, they have to be formatted as reStructuredText, and it's almost impossible to get complex markup right without previewing it frequently.
  • seti-icons — My favourite icon theme that adds small and non-obtrusive file icons to the tree-view explorer and tabs.
  • Shell — Runs shell commands from the command palette. I mainly use the included shortcut to run commands from the current file's location to optimise SVGs with svgo.
  • SVG viewer — Allows you to view SVGs from within the editor and export them as PNGs.
  • TravisCI Status — Shows the build status of the current project in the status bar.

Custom CSS Stylesheets

One of the biggest downsides of VSCode is that it currently doesn't allow custom stylesheets to modify the editor contents and UI. While you can do it the hacky way by modifying the source files, it's is obviously not recommended, and you'll lose all your modifications once you update the application.

It might sound petty, but what eventually prompted me to look into this and find a better solution was the blue and purple status bar (and apparently I'm not the only one). It looks like custom stylesheets might be supported natively in a future release, but in the meantime, here's another solution.

Simple solution: Custom theme extension

Using Custom theme for VSCode, you can speficy custom colours for a range of UI components, including tabs, the activity bar and the status bar. You can even hide the little smiley face in the bottom right corner, which acts as the "Send feeback" button. All options are available as handy user settings, for example theme.dark.tabs.background.color.

Custom UI themes using the custom theme extension
Custom UI themes using the custom theme extension

Note that this extension still modifies the source and will set your editor to "unsupported mode". This doesn't actually to have an impact on the editor's performance or functionality (it only adds "[Unsupported]" to your title bar), but it's important to keep this in mind for when you're experiencing issues or filing a support request.

Fully custom solution: Custom CSS and JS loader extension

I finally stumbled across an extension that lets you load the editor with custom CSS and JavaScript files. The usage is a little unintuitive and not well-documented, but it turned out to work pretty smoothly. In your settings, you simply specify an array of URLs or local paths to the files (for local paths, prefix them with file:///). I keep my custom modifications in the .vscode directory in my home folder, which by the way also contains all installed extensions.

"vscode_custom_css.imports": ["file:///Users/ines/.vscode/custom.css"]

From the command palette (cmd + P), you can now select "Enable Custom CSS and JS" (or "Update" to reload). You might still get a notification saying that your source files are corrupted (as you do if you actually modify the source), but it seems pretty safe to ignore this. If you need some inspiration, these are my current modifications:

/* Set background of status bar and activity bar */

.monaco-workbench>.part.statusbar,
.monaco-workbench>.activitybar>.content,
.monaco-tree .monaco-tree-row>.content.actions.more>.primary-action-bar {
    background: #1A1E24 !important;
}

/* Hide "send feeback" button in status bar */

.dropdown.send-feedback {
    display: none !important;
}

My next mission will be to find a way to set custom styles for specific tokens. I recently made the switch from Fira Code to Operator Mono, but I miss the amazing code ligatures. Atom lets you combine the two, and according to this Gist, the same approach should work in VSCode. But it still didn't make a difference when I added it to my custom CSS, so this might require some more digging into the source.

Update #1 on using font combinations (2017-02-07)

It turned out the above issue was be related to a change in the latest v1.9 release that included flattening the TextMate theme scopes. While this makes customisation a little harder, it improves overall consistency, theme compatibility and performance.

Instead of scopes like .token.keyword.operator being assigned directly (which would make them accessible via CSS), the scopes defined in the TextMate colour theme are flattened and assigned to the tokens using class names like .mtk1. Unfortunately, the TextMate syntax seems to only allow colours and font styles, not font families.

The token rendering shown in the developer tools (toggle them via the command palette)
The token rendering shown in the developer tools (toggle them via the command palette)

In theory, setting .mtk1 and .mtk5 to font-family: "Fira Code" brings back the ligatures for operators and arrow functions. But because third-party themes often differ in the scopes they use (and sometimes even contain bugs), this fix is definitely not recommended and can cause inconsistent and unpredictable results. For example, using the Panda theme in JavaScript, Fira Code is also applied to variable declarations, numbers, booleans, class names and attributes.

Update #2 on using font combinations (2017-02-09)

I finally managed to achieve my (almost) ideal setup by using a custom @font-face declaration for only a specific unicode range. If the unicode character is part of that range, it's displayed in Fira Code. Otherwise, the fallback font, Operator Mono, is used.

@font-face {
    font-family: 'Fira Code Ligatures';
    src: local('Fira Code');
    unicode-range: U+0021-0026, U+002A-002B, U+002D-002F, U+003A-003E, U+007B-007E;
}

.view-lines {
    font-family: 'Fira Code Ligatures', 'Operator Mono' !important;
}

Note that the above example doesn't cover all characters that can be transformed into code ligatures. Instead, I decided to only include the ones that are relevant to my main programming languages. For a nice overview of all unicode characters and ranges, see this list.

Download Visual Studio Code

Latest Posts