Rush Snippets - Speed Up Your Coding in VS Code
Tags: vscode, typescript, productivity, opensource
Published: 2021-06-30 14:23:34

Code Snippets extensions are gaining popularity with VS Code developers. These extensions help developers generate common blocks of code using easy-to-recall shortcut sequences. 

The Marketplace now offers a large number of extensions that contain entire libraries of ready-to-use snippets for different languages and frameworks.

These snippets can help declare code more efficiently, with:

* Fewer keystrokes,
* Fewer mistakes,
* Reduced physical strain, and
* An overall lower cognitive load.

Some of you may already be familiar with [CodeRush for Visual Studio](https://marketplace.visualstudio.com/items?itemName=DevExpress.CodeRushforRoslyn). Our snippets are called [Code Templates](https://docs.devexpress.com/CodeRushForRoslyn/115904/coding-assistance/code-templates) in this product. CodeRush Templates generate code in a similar way, but also provide significantly more power than what you would find in a typical collection of snippets.

In our new [Rush Snippets](https://devexpress.com/rush) product, we brought decades of experience to give VS Code developers the powerful functionality CodeRush developers have enjoyed for years.

Here's how we've bypassed the **following drawbacks** found in traditional snippet engines with **[Rush Snippets](https://devexpress.com/rush)**:

**1. Traditional snippets are largely ignorant of context**.

One of the things we've learned over the years is that more context (e.g., having a greater understanding of the surrounding code) leads to significant gains in snippet usability. 

Traditional snippets might specify in which file or project they should be available, and this is typically the most context aware they will be.

Hovewer, this file/project context is insufficient to filter unnecessary snippets depending on the caret's position as you move through the file. As a result, all installed snippets appear in the IntelliSence window, regardless of where you are in the code. This puts the burden of filtering the noise on the developer, and makes it harder to use the snippets.

A second concern with having context-ignorant snippets, is that you need to have unique snippet shortcut names for every minor variation you want to support (or you simply don't support intelligent alternatives based on surrounding code).

In **Rush Snippets**, we always check the context - the code surrounding the caret. So if the caret is inside a method's parameter declaration, then only snippets for generating parameters and type references will be listed in Intellisense.

![](https://i.imgur.com/3KFyBwh.gif)

Similarly, snippets that generate react components will never appear in IntelliSence if the corresponding react library is not installed.

Our team has worked hard to ensure the IntelliSense window always contains only the code snippets you may really need in the moment.


**2. Traditional snippet shortcuts are hard to remember**.

It's not easy recalling hundreds of differenct shortcuts.

Most users can memorize 10-20 prefixes for their favorite constructs, but that's about it. The rest of the traditional snippet library just clutters up IntelliSence and are almost never used.

To address this challenge in **Rush Snippets**, we decided to use **two different kinds** of shortcuts: **short**, and **descriptive**. Short prefixes are for developers who find it easy to memorize short mnemonics or for those who keep in mind a small stock of their favorite constructs.

With our descriptive shortcuts, we use meaningful expressions in a standardized format. This allows you to quickly find the desired snippet in the list. 

Here are a few examples:

If you want to generate a read-only boolean property, you can use the short prefix - "**rb**", or you can use the long prefix - "**readonly property bool**". Once you enter "**read**", IntelliSense will contain only the snippets you need.

![](https://i.imgur.com/WN6K7em.gif)

Here's another example. When working with React, just type "**react**" to see all snippets related to this framework that are available in the surrounding context.  IntelliSence will show only the templates that make sense here and nothing more.

![](https://i.imgur.com/w7wdHsS.gif)


If you mostly use short mnemonics, then we have done everything to ensure you do not have to remember unnecessary information.

Checking context in snippets allows us to use the same prefixes to insert different constructs depending on the caret's position. 

For example, the "**vn**" snippet (for **v**ariable of type **n**umber) will:

* add a parameter of type number if you're inside a method's parameters.
* add a local variable of type number if you're inside a method body or a property. 
* add a field variable if you're inside a class (but not inside a member). 

Additionally, this same snippet, when used to declare parameters, will automatically add any missing commas needed for the parameter list.

In other words, you just need to memorize one "vn" prefix, and the snippet determines which of six different constructs to add based where you are in the code.

![](https://i.imgur.com/OILHg8q.gif)

The same approach allows us to generate functions in different ways depending on context. You use the same "f" snippet, but it creates different constructs in classes, in interfaces, and in the file root.

![](https://i.imgur.com/zIlgiSv.gif)

And there's a third aspect to the Rush Snippets design that makes it easier to exploit the power of snippets: **Snippet Combos**. 

Just like in popular video games, where you can link together combinations of button presses to unleash a powerful action, you can do the same with Rush Snippets.

In fact, in the examples above, we've already seen a few of these combo parts: "**f**" for **function**, and "**v**" for **variable**. These are the **things** we want to create.

We've also seen "**b**" for **boolean** and "**n**" for **number**. These are the **types** of the things we want to create.

We can create a new combo just by entering the shortcut for the thing we want to create followed by a shortcut for its type.

So to create a function that returns a **boolean**, just use "**fb**". To create a function that returns a **number**, use "**fn**". It's simple and it works across hundreds of snippet combos.

**3. Traditional snippets are just text**.

The fact is that traditional snippet engines rarely include an understanding of the language or the framework. And as such they are often unable to correctly build language or framework-related constructs. For example, if a traditional snippet builds a TypeScript language construct that requires imports, then the imports are typically  generated along with the snippet's main text. And if the snippet is expanded in the middle of a file, then the imports will be generated right there, in the middle of the file, even if those imports have already been declared.

The burden of cleanup (deleting duplicated imports) and/or moving these imports to the top of the file is now on the developer, slowing down any potential gains offered by the traditional snippet in the first place.

**Rush Snippets** gets around all this with snippets that can declare language constructs (like import dependencies) separately from the snippet expansion. 

The bottom line is that Rush Snippets will correctly add **only the required dependent imports** (and place them in the correct location at the top of the file where they belong).

![](https://i.imgur.com/O0FRXzv.gif)


**4. Traditional snippets require too many unnecessary actions**. 

Expanding a traditional snippet typically involves the following steps:  
* Bring up Intellisense
* Find the desired snippet in the list (if you remember its prefix, the IntelliSence text filtering will help you, otherwise, it may take a long time).
* Press Enter or Tab to apply the snippet

It is often easier to write short constructs manually rather than apply the appropriate snippet.

**Rush Snippets** makes it super easy to expand a snippet you know. Just type the shortcut, wherever you need it, and press **Space**.

For example, type "**c**" (to create a new **c**lass) followed by the **Space**. 
 
Or you could type "**rpc**" (to create a new **R**eact **P**ure**C**omponent) followed by the **Space**, like this:

![](https://i.imgur.com/VfzglSh.gif)

You can also expand snippets immediately with the **Tab** key or a different keyboard shortcut if you prefer.


**5. Traditional placeholders are unreliable**.

To mark a section for change, traditional snippets use [tabstops and placeholders](https://code.visualstudio.com/docs/editor/userdefinedsnippets#_tabstops).

Traditional placeholders will link identical tabstops. This allows you to rename sections with the same text (for example, variable names). This is a a somewhat useful solution, however, as we noticed, it does not always work reliably.

For example, if you move the caret out of the placeholder, all the placeholders are immediately deleted from the editor.

Or if you change text outside the placeholder, multi-caret locations are shifted, making subsequent renaming impossible.

In **Rush Snippets**, we made a few improvements to this mechanism:

* We use **fields** as an analogue to placeholders, and we use **links** to bind placeholders containing identical text. The fields are drawn as a yellow frame around the text in the editor. And unlike traditional placeholders, Rush Snippets field remain in the code, even if you navigate through the file or switch to another document.
* We also save all links when you edit text and correctly update their position. So, you can make any changes in the code (even outside of the fields) and the links will remain where they belong and they will stay in sync, just like you expect from a professional developer tool.

![](https://i.imgur.com/f97oMZL.gif)


**Your Feedback Matters** 

As always, we look forward to your feedback on our shiny new Rush Snippets. Let us know how we can better address your development needs going forward. 

Share your thoughts with us on [Github](https://github.com/DevExpress/vscode-rushsnippets).