Syntax highlighting is one of the best features of a modern IDE or IDE-lite (such as VSCode). Things like IntelliSense, tab completion, matching token highlighting, go-to-definition, and more are all fantastic and make coding faster, easier, and more efficient (not to mention more accurate and consistent); however, a field of white text on a black background (or worse, black text on a white background) just makes everything look the same and hard to follow. Highlighting different tokens with different colors makes them stand out and makes it easier to tell what something is at a glance.
What The Theme's Got To Do With It
Out of the box, VSCode uses the Dark+ theme, which is decent but isn't my favorite. You should already have the PowerShell extension installed which will give you access to the ISE theme, but I'm personally not a fan of that one either (light themes make it harder to hibernate). If you're used to working in the ISE, though, it could help to make the transition to VSCode smoother as it copies both the theme and the syntax highlighting from the ISE.
My personal preference is Material Theme's "Darker High Contrast" variant. It is available on the Visual Studio marketplace here, or you can install it directly by searching for Material Theme in the Extensions panel from within VSCode.
I'm not writing this to tell you about my favorite VSCode theme. This is about syntax highlighting. I'm bringing up themes because they make a big difference as each theme can define its own syntax highlighting rules. PowerShell has a lot of syntax tokens to colorize and a lot of themes don't bother doing much with it (PowerShell is still often treated as an afterthought for a lot of developers, if it's acknowledged at all), so you'll likely wind up with minimal syntax highlighting with many themes. The Material themes are great examples of good looking themes that have fairly minimal syntax highlighting pre-defined for PowerShell, but even the default Dark+ and ISE themes leave some tokens un-highlighted or highlighted the same as others, keeping them from standing out.
Highlighting the Variables
In this post, I'm going to be focusing entirely on variables. While there's more that can be highlighted, such as keywords and symbols, variables have a surprising amount they can tell you with good highlighting; additionally, the same principals work for all highlightable tokens.
Examples
As I said before, the default Dark+ theme has decent syntax highlighting, but it doesn't really convey much about variables beyond the basics:
Visual Studio Code's default Dark+ theme
By default, however, Material Theme Darker has very poor variable highlighting for PowerShell and tells you almost nothing:
Material Theme's Darker High Contrast theme
Fortunately, VSCode's built-in TextMate highlighter lets you define your own syntax highlighting, and with a little effort, that highlighting will communicate a lot about your variables:
Material Theme's Darker High Contrast theme with added TextMate rules
However much or little syntax highlighting you prefer is personal to you and your workflow, but if you like some of what you see here, you can use what I've done as a jumping off point.
Explanation of examples
I will tell you what the highlighting I've set up here tells me, though, and why I like it:
- It clearly differentiates between the variable name and property names (such as with
$multipart.object.example
) - It highlights drive and scope modifiers (
$env:
is a drive modifier and$global:
is a scope modifier) - It makes automatic variables stand out (
$this
,$matches
, and$PSScriptRoot
in the examples)
That last one is useful both when you are trying to use an automatic variable and when you're not: the number of times I've tried to use $this
as a regular variable while coding and wasted time trying to figure out why it wasn't working is significant enough to be memorable, so having it show up orange like this is a great reminder that I'm trying to do something I shouldn't. It's also useful if you mistype an auto variable, like if I typed $match
instead of $matches
.
Scopes I've defined
Here are the TextMate scopes I've used to make this work:
variable.other.readwrite
controls regular variablessupport.variable.automatic
controls automatic variables (like$this
and$matches
)support.variable.drive
controls the special drive variables (like$env:
)variable.other.member
andvariable.other.property
controls object/variable properties; which one is used seemed to change over time and in different contexts, so I just define both of them the same and found that works consistentlycomment
isn't shown above, but if you're using "Material Theme Darker High Contrast", I recommend setting this scope; the default for comments is really hard to readkeyword.control
also isn't shown, but in "Material Theme Darker High Contrast" they're just blue and italic which makes them blend in too much for my eyes and the italics both look out of place and at the same time are not distinct enough for me, so I set them to a green for better contrast and disable italics
Obviously the settings I've chosen are what I like, but they might give you some ideas of a direction to go in if you want to customize your own syntax highlighting; and obviously, this is useful for languages other than PowerShell, but that's what I do most of my work in so it's what I'm showing here.
Identifying scopes using the Scope Inspector
If you find something that you think should be colorized a certain way and want to know what scope would target it, press F1 (or Ctrl+Shift+P) to bring up your command palette in VSCode and type "Developer: Inspect Editor Tokens and Scopes" (or enough of that to get it to show) and hit enter. That will bring up a window that will follow wherever your cursor is and display details about the token currently in front of your cursor, like this:
The Token Highlighter gives you all you need to define your own rules
The important part is after "textmate scopes". You can use the entire scope to target just that token type, or you can use part of the scope to target tokens that share a common parent scope. For example, instead of defining both support.variable.automatic
and support.variable.drive
with different colors, if you want them to be the same color you can do that by targeting support.variable
(which will also target anything else under support.variable
).
For more information about the scope inspector, check out the official documentation.
If you find things that aren't tokenized by default that you'd like to highlight, you can go deeper and even define your own grammar, which is far outside the scope of this article, but the Syntax Highlight Guide documentation for this is a great place to start.
Configs used
Here are the configs I've set up for my own editor. It's great to use as-is or as a jumping off point to set up your syntax highlighting exactly the way you want:
Conclusion
Syntax highlighting is an incredibly powerful way to make the elements of your code stand out, and can even help you to avoid mistakes (such as trying to use an auto-variable as a regular variable). Not only that, but it makes your code look nicer, and nice looking code is easier to work with (monkey brains like shiny things; being a bear I wouldn't know, but the colors are still pretty).
Joking aside, though, it does make it easier to follow as it gives our eyes more to lock onto, more "landmarks" in your code to help you navigate by. You don't need it, but for myself after using it for so long, I wouldn't want to code without it, and making it work the way I want just makes it that much better.
Note about header image
The code in the header image is part of the build script I wrote for PoshMailKit. I used it simply because it demonstrates a number of common tokens and what real code looks like when syntax highlighting is applied.