Фрагменти коду Visual Studio - остаточний посібник з фрагментів коду VS для початківців

Фрагменти можуть додати у ваш редактор нотки магії. Це як заклинання. Вимовіть коротку фразу (введіть префікс), помахайте паличкою (натисніть Enterабо Tab) і presto! Перед вами розгортається чудова подія. ✨

Більшість редакторів коду підтримують фрагменти коробки. Редактором коду, який я буду використовувати для демонстрації фрагментів, є Visual Studio Code (VS Code), найпопулярніший редактор цього дня.

Крім того, є деякі програми "розширення тексту", які дозволяють використовувати фрагменти у всьому світі (у всіх програмах). Я коротко розповім, як ви можете використовувати ці програми, щоб отримати ще більше користі від фрагментів.

Давайте зануримось у всі фрагменти речей. ?

Визначення

Фрагмент - це шаблон, який можна вставити в документ. Він вставляється за допомогою команди або через якийсь текст запуску.

За допомогою фрагментів ви можете створити шаблонний файл та вставити часто використовувані блоки тексту. Загальна ідея полягає в тому, щоб заощадити, щоб ви вводили ці самі речі повністю знову і знову, і знову. ?

Чому ви повинні використовувати фрагменти?

Я не буду шокувати вас цим твердженням: в Інтернеті багато суперечливих думок! Фрагменти не уникнуть цієї позорності, але я не думаю, що це тема, яка змушує людей підвищувати кров'яний тиск!

Для збалансованості я наведу тут переріз цих думок.

Вам не потрібно вибирати табір і бути "все-за" чи "проти" фрагментами. Я пропоную вам прийняти їх у такій мірі, яка найкраще вам підходить.

Yay Camp?

  • Фрагменти можуть підвищити вашу продуктивність, заощаджуючи натискання клавіш та зменшуючи помилки введення.
  • Фрагменти залишають у мене більше розумового процесора та задоволення, яке я витрачаю на написання коду, про який я дбаю і на якому хочу зосередитися.
  • Фрагменти можуть допомогти вам не забути включити щось важливе!
  • Інтеграція фрагментів у ваш робочий процес неявно заохочує рідше користуватися мишею. Добре написані фрагменти пропонують логічний шлях, по якому ви можете прокласти вкладки, зупиняючись редагувати по дорозі, щоб заповнити шаблон саме так, як ви хочете, а коли закінчите, ви прийдете з іншого боку, готові написати ваш наступний рядок

Най табір?

  • Я утримуюсь від їх використання, здебільшого тому, що мені не подобається покладатися на якийсь інструмент.
  • Я ніколи не використовую фрагменти. Я вважаю за краще інвестувати час, уникаючи повторень, а не полегшуючи його.
  • Я виявив, що в якийсь момент забув, як писати код, не використовуючи фрагмент. Щодо тривіальних речей, які я розумію, це нормально, але я не хочу забувати деякі інші речі!
  • Більшість, якщо не всі, фрагменти, які я бачив в Інтернеті, для коду, який я шукаю, мають помилки. Я жодного разу не зміг знайти числовий алгоритм, в якому не було помилок з плаваючою комою. Я не уявляю, що існує якийсь ресурс абсолютно чистих фрагментів коду.

Коли слід використовувати фрагменти?

Дональд Кнут, один з великих чарівників інформатики, сказав, що "передчасна оптимізація [коду] - корінь усього зла".

Я думаю, це стосується і фрагментів. Фрагменти - це оптимізація виробництва коду. Якщо ви погано знаєте мову чи фреймворк, впровадження безлічі фрагментів для цієї мови чи фреймворку, швидше за все, буде передчасним кроком.

Якщо вам комфортно, спробуйте!

Для чого я використовую фрагменти

Особисто я часто використовую фрагменти, але розсудливо. Я використовую набір фрагментів для Markdown та більшості мов, з якими я працюю.

Я мало використовував фрагменти для фреймворків. Я почав використовувати деякі фрагменти для Vue нещодавно, але я використовую лише шаблонний фрагмент. Можливо, я прийму їх більше, як тільки підніметься рівень IQ Vue.

Я не використовував фрагменти для алгоритмів.

Типи фрагментів

Фрагменти можна класифікувати за обсягом інтерактивності між фрагментом та редактором.

Статичні фрагменти

Ви можете сприймати це як копіювання та вставлення певного вихідного тексту як одну команду.

Динамічні фрагменти

Динамічний фрагмент можна налаштувати, щоб забезпечити майстер-подібний досвід для заповнення фрагмента.

Він може включати:

  • Зупинки вкладок : Ви можете пронумерувати зупинки, за якими можна перекласти вкладки,
  • Зеркальні вкладки зупиняються : Бувають випадки, коли вам потрібно вказати одне і те ж значення у кількох місцях у вставленому тексті. Щоб досягти цього, ви можете віддзеркалити вкладку, і будь-яке редагування буде негайно відображено у відповідних вкладках.
  • Заповнювачі : Це зупинка табуляції зі значенням за замовчуванням, яке можна замінити на фокус.
  • Варіанти : На вкладці вам буде запропоновано випадаючий список значень на вибір.
  • Змінні : вводяться значення із середовища, такі як: виділений текст у редакторі, системні дати або вміст з буфера обміну.

Ось приклад фрагмента знижки, який додає список завдань із 2 завданнями. Він використовує зупинки табуляції , заповнювачі та вибір для перевірки завдання.

завдання

Макрокоманди

Найвищий рівень чаклунства - мати можливість трансформувати введення. Трансформації дозволяють змінити значення змінної до їх вставки або змінити заповнювач після внесення змін.

Наприклад, можливо, ви захочете записати велику назву класу після введення.

Як правило, можливо все, що ви можете подумати зробити із регулярним виразом. Деякі редактори пропонують розширені можливості створення сценаріїв.

Фрагменти в Visual Studio Code

In VS Code, snippets appear in IntelliSense (Ctrl+Space gives you a suggestion list), they are mixed in with other suggestions.

You can also access them in a dedicated snippet picker by using the 'Insert Snippet' command. This combines all user, extension, and built-in snippets for that language into a single list.

insert-snippet-list

Emmet is integrated into VS Code and has it's own CSS-selector inspired syntax for inserting HTML and CSS snippets.

Emmet is it's own thing really, but the mechanics are the same. You can learn about Emmet with the Emmet in Visual Studio Code guide.

Related User Settings

Snippets will appear as quick suggestions if the setting editor.quickSuggestions is set to true for the language you are working in. Quick suggestions are enabled by default for most languages except markdown.

швидкі пропозиції-js

Snippets support tab-completion. You can type a snippet prefix (the trigger text), and press Tab to insert a snippet. You can enable it with the setting editor.tabCompletion.

The values are:

  • on: Tab completion is enabled for all sources.
  • off: Disable tab completions. This is the default value.
  • onlySnippets: Tab completion only for snippets.
"editor.tabCompletion": "onlySnippets", 

If you would like to control how snippets suggestions are shown, you can edit the setting editor.snippetSuggestions.

The values are:

  • top: Show snippet suggestions on top of other suggestions. I use this value.
  • bottom: Show snippet suggestions below other suggestions.
  • inline: Show snippets suggestions with other suggestions. This is the default value.
  • none: Do not show snippet suggestions.
"editor.snippetSuggestions": "top", 

These are the most important settings for snippets, but there are a few more. You can check out this list of the default settings to explore more, or do a search in the Settings UI.

Are there built-in snippets?

Yes!

They aren't documented in the VS Code docs, though. And inside VS Code, there is no central point to browse them. So, you may not know what they are.

So, how can you find out what languages have built-in snippets?

Long story short, I was frustrated by this scenario, so I wrote an extension called Snippets Ranger to give a nice UI to explore snippets easily. Think of it as a Marauder's Map for snippets!

фрагменти-рейнджер

But I want to find the snippets for myself?

You can, it just requires a bit more effort.

As I mentioned earlier, the 'Insert Snippet' command will show you all snippets for the language of the active document.

Remember though, this is an aggregate of all of the user, extension, and built-in snippets. So, if you want to find out if a particular language has built-in snippets, you need to open a file for that language, and run the command to see that list.

If you have an snippets extension installed for that language that makes it too hard to identify which is which, you could disable it to ensure that only the built-in snippets are showing. ?

If you want to track down the source file yourself, the built-in snippets live inside each individual language extension directory. The file is located at «app root»\resources\app\extensions\«language»\snippets\«language».code-snippets on Windows. The location is similar for Mac and Linux.

Snippets Extensions

The Visual Studio Marketplace has a snippets category where you can find snippets for almost anything.

A lot of Programming Language Pack extensions include snippets also (Python, C#, Go, Java, and C/C++ amongst others).

How do I write my own?

Snippets files are written in JSON. You can also add C-style comments if you wish (technically it is Microsoft's "JSONC" format).

You can create snippets for different scopes: global, workspace, and for a particular language.

To create the snippets file, run the 'Preferences: Configure User Snippets' command, which opens a quickpick dialog as below. Your selection will open a file for editing.

фрагменти користувачів

If you would prefer to write a snippet in a GUI, you can use the snippet generator web app.

генератор фрагментів

Let's look at an example to get familiar with the syntax.

Example

Here is a markdown snippet that comes with VS Code.

{ "Insert heading level 1": { "prefix": "heading1", "body": ["# ${1:${TM_SELECTED_TEXT}}$0"], "description" : "Insert heading level 1" } } 

This snippet inserts a level 1 heading which wraps the markdown around the current selection (if there is one).

A snippet has the following properties:

  1. "Insert heading level 1" is the snippet name. This is the value that is displayed in the IntelliSense suggestion list if no description is provided.
  2. Theprefix property defines the trigger phrase for the snippet. It can be a string or an array of strings (if you want multiple trigger phrases). Substring matching is performed on prefixes, so in this case, typing "h1" would match our example snippet.
  3. The body property is the content that is inserted into the editor. It is an array of strings, which is one or more lines of content. The content is joined together before insertion.
  4. The description property can provide more information about the snippet. It is optional.
  5. The scope property allows you to target specific languages, and you can supply a comma-separated list in the string. It is optional. Of course, it is redundant for a language-specific snippet file.

The body of this snippet has 2 tab stops and uses the variable ${TM_SELECTED_TEXT}.

Let's get into the syntax to understand this fully.

Snippet syntax

VS Code's snippet syntax is the same as the TextMate snippet syntax. However, it does not support 'interpolated shell code' and the use of the \u transformation.

The body of a snippet supports the following features:

1. Tab Stops

Tab stops are specified by a dollar sign and an ordinal number e.g. $1 . $1 will be the first location, $2 will the second location, and so on. $0 is the final cursor position, which exits the snippet mode.

For example, let's say we want to make an HTML div snippet and we want the first tab stop to be between the opening and closing tags. We also want to allow the user to tab outside of the tags to finish the snippet.

Then we could make a snippet like this:

{ "Insert div": { prefix: "div", body: [" ","$1"," ", "$0"] } } 

2. Mirrored Tab Stops

There are times when you need to provide the same value in several places in the inserted text. In these situations you can re-use the same ordinal number for tab stops to signal that you want them mirrored. Then your edits are synced.

A typical example is a for loop which uses an index variable multiple times. Below is a JavaScript example of a for loop.

{ "For Loop": { "prefix": "for", "body": [ "for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", "\tconst ${3:element} = ${2:array}[${1:index}];", "\t$0", "}" ] } } 

3. Placeholders

Placeholders are tab stops with default values. They are wrapped in curly braces, for example ${1:default}. The placeholder text is selected on focus such that it can be easily edited. Placeholders can be nested, like this: ${1:first ${2:second}}.

4. Choices

Choices present the user with a list of values at a tab stop. They are written as a comma-separated list of values enclosed in pipe-characters e.g. $1.

This is the code for the markdown example shown earlier for inserting a task list. The choices are 'x' or a blank space.

{ "Insert task list": { "prefix": "task", "body": ["- [$1] ${2:text}", "${0}"] } 

5. Variables

There is a good selection of variables you can use. You simply prefix the name with a dollar sign to use them, for example $TM_SELECTED_TEXT.

For example, this snippet will create a block comment for any language with today's date:

{ "Insert block comment with date": { prefix: "date comment", body: ["${BLOCK_COMMENT_START}", "${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE} ${1}", "${BLOCK_COMMENT_END}"] } } 

You can specify a default for a variable if you wish, like ${TM_SELECTED_TEXT:default}. If a variable does not have a value assigned, the default or an empty string is inserted.

If you make a mistake and include a variable name that is not defined, the name of the variable is transformed into a placeholder.

The following workspace variables can be used:

  • TM_SELECTED_TEXT: The currently selected text or the empty string,
  • TM_CURRENT_LINE: The contents of the current line,
  • TM_CURRENT_WORD: The contents of the word under cursor or the empty string,
  • TM_LINE_INDEX: The zero-index based line number,
  • TM_LINE_NUMBER: The one-index based line number,
  • TM_FILENAME: The filename of the current document,
  • TM_FILENAME_BASE: The filename of the current document without its extensions,
  • TM_DIRECTORY: The directory of the current document,
  • TM_FILEPATH: The full file path of the current document,
  • CLIPBOARD: The contents of your clipboard,
  • WORKSPACE_NAME: The name of the opened workspace or folder.

The following time-related variables can be used:

  • CURRENT_YEAR: The current year,
  • CURRENT_YEAR_SHORT: The current year's last two digits,
  • CURRENT_MONTH: The month as two digits (example '07'),
  • CURRENT_MONTH_NAME: The full name of the month (example 'July'),
  • CURRENT_MONTH_NAME_SHORT: The short name of the month (example 'Jul'),
  • CURRENT_DATE: The day of the month,
  • CURRENT_DAY_NAME: The name of day (example 'Monday'),
  • CURRENT_DAY_NAME_SHORT: The short name of the day (example 'Mon'),
  • CURRENT_HOUR: The current hour in 24-hour clock format,
  • CURRENT_MINUTE: The current minute,
  • CURRENT_SECOND: The current second,
  • CURRENT_SECONDS_UNIX: The number of seconds since the Unix epoch.

The following comment variables can be used. They honour the syntax of the document's language:

  • BLOCK_COMMENT_START: For example, in HTML,
  • LINE_COMMENT: For example, // in JavaScript.

6. Transformations

Transformations can be applied to a variable or a placeholder. If you are familiar with regular expressions (regex), most of this should be familiar.

The format of a transformation is: ${«variable or placeholder»/«regex»/«replacement string»/«flags»}. It is similar to String.protoype.replace() in JavaScript. The "parameters" do the following:

  • «regex»: This is a regular expression that is matched against the value of the variable or placeholder. The JavaScript regex syntax is supported.
  • «replacement string»: This is the string you want to replace the original text with. It can reference capture groups from the «regex», perform case formatting (using the special functions: /upcase, /downcase, and /capitalize), and perform conditional insertions. See TextMate Replacement String Syntax for more in-depth information.
  • «flags»: Flags that are passed to the regular expression. The JavaScript regex flags can be used:
    • g : Global search,
    • i : Case-insensitive search,
    • m : Multi-line search,
    • s : Allows . to match newline characters,
    • u : Unicode. Treat the pattern as a sequence of Unicode code points,
    • y : Perform a "sticky" search that matches starting at the current position in the target string.

To reference a capture group, use $n where n is the capture group number. Using $0 means the entire match.

This can be a bit confusing since tab stops have the same syntax. Just remember that if it is contained within forward slashes, then it is referencing a capture group.

The easiest way to understand the syntax fully is to check out a few examples.

Snippet bodyInputOutputExplanation
["${TM_SELECTED_TEXT/^.+$/• $0/gm}"]line1

line2

• line1

• line2

Put a bullet point before each non-empty line of the selected text.
["${TM_SELECTED_TEXT/^(\\w+)/${1:/capitalize}/}"]the cat is on the mat.The cat is on the mat.Capitalize the first word of selected text.
["${TM_FILENAME/.*/${0:/upcase}/}"]example.jsEXAMPLE.JSInsert the filename of the current file uppercased.
[

"[",

"${CLIPBOARD/^(.+)$/'$1',/gm}",

"]"

]

line1

line2

['line1', 'line2',]Turn the contents of the clipboard into a string array. Each non-empty line is an element.

As you can see from the second example above, metacharacter sequences must be escaped, for example insert \\w for a word character.

Placeholder Transformations

Placeholder transforms do not allow a default value or choices! Maybe it is more suitable to call them tab stop transformations.

The example below will uppercase the text of the first tab stop.

перетворення заповнювача

{ "Uppercase first tab stop": { "prefix": "up", "body": ["${1/.*/${0:/upcase}/}", "$0"] } } 

You can have a placeholder and perform a transformation on a mirrored instance. The transformation will not be performed on the initial placeholder. ?

Would you use this behaviour somewhere? I find it confusing initially, so it may have the same affect on others.

{ "Uppercase second tab stop instance only": { "prefix": "up", "body": ["${1:title}", "${1/(.*)/${1:/upcase}/}", "$0"] } } 

How do I assign Keyboard Shortcuts for snippets?

By adding your shortcuts to keybindings.json . You can open the file by running the 'Preferences: Open Keyboard Shortcuts File (JSON)' command.

For example, to add a shortcut for the built-in markdown snippet "Insert heading level 1":

{ "key": "ctrl+m ctrl+1", "command": "editor.action.insertSnippet", "when": "editorTextFocus && editorLangId == markdown", "args": { "langId": "markdown", "name": "Insert heading level 1" } } 

You define a shortcut by specifying the key combination you want to use, the command ID, and an optional when clause context for the context when the keyboard shortcut is enabled.

Through the args object, you can target an existing snippet by using the langId and name properties. The langId argument is the language ID of the language that the snippets were written for. The name is the snippet's name as it is defined in the snippet file.

You can define an inline snippet if you wish using the snippet property.

[ { "key": "ctrl+k 1", "command": "editor.action.insertSnippet", "when": "editorTextFocus", "args": { "snippet": "${BLOCK_COMMENT_START}${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE} ${1} ${BLOCK_COMMENT_END}" } } ] 

You can use the Keyboard Shortcuts UI also, but it does not have the ability to add a new shortcut.

Another downside of the UI is that it does not show the args object, which makes it more difficult to find and edit your custom shortcuts. ?

ярлики-ui

A question of style

Something that I found offputting initially with snippets was the propensity for people to create snippets with abbreviated prefixes. Do I have to learn a big list of gibberish acronyms to use someone else's snippets?

What do I mean by abbreviated prefixes? The table below list a few of the snippets from the JavaScript (ES6) code snippets VS Code extension. You can see in the Trigger column, the prefixes listed are abbreviations, for example fre to represent a "for each" loop.

уривок фрагментів es6

This is unnecessary in two ways.

Firstly, the quick suggestions offered by VS Code are produced from a fuzzy substring search. If I type "fe" and the prefix of a snippet is "foreach", this will match and be offered as a quick suggestion.

As you can see below, this is the second match.

швидка пропозиція

The first match is fre, which is a snippet from the extension. Which suggestion is more descriptive? ?

If you use the "Insert Snippet" command for snippets, it does not make much of a difference. The description field makes amends for this shortcoming. I don't use snippets in this way, so I would prefer a more descriptive prefix.

вставити фрагмент foreach

Secondly, fre is a duplicate of the built-in snippet foreach.

Some people turn off quick suggestions for snippets and use tab completion only. In this case, you need to type a prefix out without getting visual feedback. Some people may prefer to use an abbreviated prefix to save keystrokes here.

The same fuzzy substring search is being performed in the background, so the first snippet match is inserted when you hit tab.

фрагмент-вкладка-заповнення

Looking at the example above, you can see that typing "fr" and hitting tab inserts the fre snippet. Typing "fore" and hitting tab inserts the foreach snippet.

So, you do not need to type out the entire prefix, if you really don't want to! ? If you have many similarly named snippet prefixes for a language, it would be impractical I imagine.

It is more practical to learn the prefixes properly, and type them out entirely before hitting tab.

There are some trade-offs depending on your preferences for using snippets.

Personally, I like to use quick suggestions as I like the visual feedback. I have snippets set to be the top suggestions, that way I can type abbreviated versions of the prefixes without needing to memorise them.

Some snippet authors have rigid patterns to overcome this, but that's just something I can't get into easily.

If you use a lot of snippets for a language, you may want to choose snippets that are written in a similar style.

If you use snippets for different frameworks and libraries in a language, they can add up and overlap. I haven't needed to do this, but you may need to do it eventually.

Global Snippets

Outside of your code editor, you can benefit from snippets also. Having snippets available in every app offers more possibilities.

Common use cases are:

  • canned responses for messages,
  • autocorrecting common typos,
  • adding contact information or signatures to documents,
  • inserting dates,
  • formatting of selected text and pasted text,
  • inserting search phrases for your search engine or app,
  • HTML snippets available inside your email client,
  • adding different templates to documents.

Most of the apps for snippets are touted as "text expanders", but quite a few task and productivity apps also include snippet-esque features.

Global snippets are bit more limited that code editor snippets, as you cannot use tab stops and placeholders. In most apps you can use some dynamic variables such as dates.

App Review

Autohotkey (Windows)

AutoHotkey is a free, open-source scripting language for Windows to do all kinds of tasks.

It has it's own unique syntax. You can install the AutoHotKey extension to add language support to VS Code for a better editing experience.

For defining prefixes to trigger a snippet insertion, you use the following format: ::<>::<>. The following script will insert Rob's email address when you type "robmail" and hit space or tab or enter.

::robmail::[email protected] 

The following script will insert the text "This is the snippet text" when you press Ctrl+D.

^d:: Send This is the snippet text 

You can read the docs to learn more.

PhraseExpress (Windows, Mac, iOS)

PhraseExpress is "a text expander software, that manages frequently used text templates for insertion into any program".

It is a freemium, GUI-based app. It is aimed at a wider audience than AutoHotKey.

It is quite polished and easy to use. You set it to run on start-up and it will be active in the background.

Your snippets can be organized into custom folders and synced using cloud services.

словосполучення-експрес

Espanso (Windows, Mac, Linux)

This is a open-source, cross-platform text expander written in Rust.

It uses a file-based configuration approach. The config files are written in YAML.

The default.yml file contains the main configuration. The config below will insert Rob's email address when you type "robmail" .

matches: - trigger: ":robmail" replace: "[email protected]" 

You can specify the initial cursor position, however you cannot define tab stops.

Ви можете додати розширення, щоб збільшити можливості Espanso. Існують розширення для запуску зовнішніх сценаріїв, включаючи дати, генерування випадкового тексту та включення даних буфера обміну.

І все про це! Сподіваюся, ви сьогодні щось дізналися про фрагменти, і ви можете використовувати їх, щоб зробити себе більш продуктивним.