指南1.基礎
Code Sinpets是一種使得輸入重複性代碼的模板,比如循環和條件判斷之類的。VSCode中的Sinppets遵循TextMate語法,除了不支持插值shell代碼
和\u的使用
。
下面是一個簡單的sinppets。
{
"For-Loop":{
"prefix":"for",
"body":[
"for ${2:element} of ${1:array} {",
"\t$0",
"}"
],
"description":"For-Loop"
}
}
上面的字段解釋:
- For-Loop:這是snippets的名稱
- prefix:定義了這個snippets如何被觸發,在這個case中是for
- body:內容是一個可以被插入的單字符串或者一個字符串數組
- description:是snippets的描述
上面的例子中有兩個空格:${1:array}
和${2:element}
。我們可以按照數字的順序很快地讓過他們。數字之後的字符串和:
(colon)可以被用作初始值。
下面就讓我們學習一下Snippest Syntax的語法。
Snippets Syntax
sinppets的body
部分可以使用特別的結構體來控制光標和插入的文件。下面的是支持的特性和他們的語法:
Tabstops
通過tabstops,你可以使編輯光標移動進一個sinppets。使用$1
,$2
來指定光標位置。數字是tabstops訪問的順序。而(whereas)$0
表示的是光標最終的定位。發生在多行的相同tabstop會被同步關聯和更新。
佔位符(Placeholders)
佔位符是帶有值的tabstops,就像${1:foo}
。佔位符文本可以被插入和選中,這樣的話可以很容易被修改。佔位符可以嵌套使用,就像${1:another ${2:placeholder}}
。
選擇(Choice)
佔位符可以是有選擇的值 , 語法是獨立的枚舉值 ,用|
符號進行關閉 ,比如${1|one,two,three|}
。當snippets被插入並且站位符被選中的時候,選擇會彈出一共用戶選擇 。
變量
通過$name
或者${name:default}
,你可以插入變量的值 。當變量沒有被設置的時候,默認值或者空字符串會被插入。當一個變量是未知的(也就是變量爲定義),變量名將會被插入並且將會被轉換成一個佔位符。
下面是可用的變量:
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
基於行號的0-索引(The zero-index based line number)
TM_LINE_NUMBER
基於行號的1-索引(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)
插入當前日期和時間:
CURRENT_YEAR
當前年份(The current year)
CURRENT_YEAR_SHORT
當前年份的最後兩位數字(The current year’s last two digits)
CURRENT_MONTH
用兩位數表示的月份(The month as two digits (example ‘02’))
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
當前月份中當前日期,例如1/23,返回的值爲23(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
用24時表示的當前小時數(The current hour in 24-hour clock format)
CURRENT_MINUTE
當前分鐘數(The current minute)
CURRENT_SECOND
當前秒鐘數(The current second)
用來按行插入內容或者按塊插入內容,可以選擇當前語言(For inserting line or block comments, honoring the current language):
BLOCK_COMMENT_START
(Example output: in PHP /* or in HTML )
LINE_COMMENT
(Example output: in PHP // or in HTML )
下面的snippet在JS文件和HTML文件中插入了1hello world
:
{
“hello”: {
“scope”: “javascript,html”,
“prefix”: “hello”,
“body”: “$BLOCK_COMMENT_START Hello World $BLOCK_COMMENT_END”
}
}
變量變形(Variable transforms)
變形允許你在插入值之前調整值,變形的定義由三部分組成:
一個常規的表達式是這樣的:var variable = value
, 或者這樣var variable = " "
。一個format string
被允許應用符合常規表達式的組。這個格式化字符串允許條件插入和簡單的調整。
選項被傳遞給常規表達式。
下面的例子插入了當前文件的文件名,並且去掉了文件後綴名。
${TM_FILENAME/(.*)\\..+$/$1/}
| | | |
| | | |-> no options
| | |
| | |-> references the contents of the first
| | capture group
| |
| |-> regex to capture everything before
| the final `.suffix`
|
|-> resolves to the filename
佔位符變形(Placeholder-Transform)
和一個變量變形一樣,佔位符變形允許改變佔位符插入的文本內容當轉移到下一個tab stop的時候。插入的文本符合常規的表達式並且依賴選項達到的匹配將會被具體的格式化文本替代。每一個出現的佔位符可以獨立地定義自己的轉換信息使用第一個佔位符的值。佔位符轉換的格式和變量轉換的格式一樣。
轉換例子(Transform examples)
下面的例子均用雙引號展示,因爲他們將出現在snippet的body
部分。下面的例子和結果輸出爲filename example-123.456-TEST.js
。
例子 | 輸出 | 解釋 |
---|---|---|
“${TM_FILENAME/[\.]/_/}” | example-123_456-TEST.js | Replace the first . with _ |
“${TM_FILENAME/[\.-]/_/g}” | example_123_456_TEST_js | Replace each . or - with _ |
“KaTeX parse error: Expected '}', got 'EOF' at end of input: …_FILENAME/(.*)/{1:/upcase}/}” | EXAMPLE-123.456-TEST.JS | Change to all uppercase |
“${TM_FILENAME/[0-9a-z]//gi}” | example123456TESTjs | Remove non-alphanumeric characters |
語法(Grammar)
下面就是EBNF(extended Backus-Naur form)。通過反斜槓,你可以轉義$
、}
、和選擇元素內的\.
,反斜槓也可以轉義逗號(,)和|
(管道符號)。
any ::= tabstop | placeholder | choice | variable | text
tabstop ::= '$' int
| '${' int '}'
| '${' int transform '}'
placeholder ::= '${' int ':' any '}'
choice ::= '${' int '|' text (',' text)* '|}'
variable ::= '$' var | '${' var '}'
| '${' var ':' any '}'
| '${' var transform '}'
transform ::= '/' regex '/' (format | text)+ '/' options
format ::= '$' int | '${' int '}'
| '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}'
| '${' int ':+' if '}'
| '${' int ':?' if ':' else '}'
| '${' int ':-' else '}' | '${' int ':' else '}'
regex ::= JavaScript Regular Expression value (ctor-string)
options ::= JavaScript Regular Expression option (ctor-options)
var ::= [_a-zA-Z] [_a-zA-Z0-9]*
int ::= [0-9]+
text ::= .*
Note: 什麼是EBNF?什麼是BNF?
首先講一下BNF。BNF是巴科斯-諾爾範式(Backus–Naur Form),是一種形式化的語法表示方法,用來描述語法的一種形式體系,是一種典型的元語言。BNF表示語法規則的方式爲
:
非終結符用尖括號括起。每條規則的左部是一個非終結符,右部是由非終結符和終結符組成的一個符號串,中間一般以::=
分開。具有相同左部的規則可以共用一個左部,各右部之間以直豎|
隔開。其中:
- 在雙引號中的字(“word”)代表着這些字符本身。而double_quote用來代表雙引號。
- 在雙引號外的字(有可能有下劃線)代表着語法部分。
- 尖括號( < > )內包含的爲必選項。
- 方括號( [ ] )內包含的爲可選項。
- 大括號( { } )內包含的爲可重複0至無數次的項。
- 豎線( | )表示在其左右兩邊任選一項,相當於"OR"的意思。
- ::= 是“被定義爲”的意思。
再來說下EBNF。EBNF是擴展巴科斯範式。這裏只是簡單的做個科普,詳細的可以參考EBNF
下面就用上面例子進行簡單講解
experssion explian any ::= tabstop | placeholder | choice | variable | text
any
被定義爲tabstop
或者placeholder
或者choice
或者variable
或者text
tabstop::= '$' int| '${' int '}'| '${' int transform '}'
這裏 int
和transform
在下面都有定義,替換一下就可以理解了例子就寫這兩個,如果有不清楚的,歡迎在在評論中留言探討。
使用TextMate
snippets(Using TextMate snippets)
你也可以通過VSCode使用存在的TextMate
snippets(.tmSnippets)。看(Using TextMate Snippets)[https://code.visualstudio.com/api/language-extensions/snippet-guide#using-textmate-snippets]章節來學習更多。
Note: 更詳細的關於(TextMate)[https://macromates.com/textmate/manual/snippets]。
給snippets綁定快捷鍵(Assign keybindings to snippets)
你可以創建自定義的快捷鍵去插入具體的snippets。打開keybindings.json
,添加一個快捷鍵,傳遞一個snippet
作爲一個參數。
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "console.log($1)$0"
}
}
快捷鍵會調用插入snippet命令,但是不是通過確認讓你選擇一個snippet,它會插入提供的snippet。
同樣的,你可以通過langId
和name
作爲參數引用一個存在的snippet,而不是使用snippet參數值去定義你的內聯snippet。
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"langId": "csharp",
"name": "myFavSnippet"
}
}