VSCode插件开发指南之Snippets Syntax(1)

指南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 '}' 这里inttransform在下面都有定义,替换一下就可以理解了

例子就写这两个,如果有不清楚的,欢迎在在评论中留言探讨。

使用TextMatesnippets(Using TextMate snippets)

你也可以通过VSCode使用存在的TextMatesnippets(.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。

同样的,你可以通过langIdname作为参数引用一个存在的snippet,而不是使用snippet参数值去定义你的内联snippet。

{
  "key": "cmd+k 1",
  "command": "editor.action.insertSnippet",
  "when": "editorTextFocus",
  "args": {
    "langId": "csharp",
    "name": "myFavSnippet"
  }
}

你可能感兴趣的:(VScode)