[VS Code]跟我一起在Visual Studio Code 添加自定义snippet(代码段),附详细配置

来源:互联网 发布:手机淘宝取消私人定制 编辑:程序博客网 时间:2024/05/01 02:31

Add code snippets for CLANG in VS Code

前记:今天试着用了下 Atom,发现 Atom 居然预装了 CLANG 的 snippets,而且远比 VSCode 的已有拓展「C/C++ Snippets」中的丰富!身为 VSCode 的死忠粉,我决定立马把 Atom 的 C snippets 搬到 VSCode 上来。


  • Add code snippets for CLANG in VS Code
    • 什么是 snippet
    • 如何配置 snippet
      • 操作流程
      • VSCode 中 snippet 的文法 1
      • 有用的建议
    • 附录

既然你点开了这个页面,就说明要么你不知道 VSCode 上已有拓展「C/C++ Snippets」,要么你对这个拓展失望透顶。对于后者,本文将为你介绍如何在 VSCode 上设置 snippets,并为你提供一套可以直接用的C语言 snippets。

什么是 snippet

snippet[ˈsnɪpɪt],或者说「code snippet」,指的是能够帮助输入重复代码模式串,比如循环或条件语句,的模板。通过 snippet ,我们仅仅输入一小段代码就可以生成预定义的模板代码,甚至可以通过内部跳转快速补全模板。

当然,看图更易懂:
snippet示例

图中将 atc 替换成了定义 ActiveSupport::TestCase (简称 ATC )子类的模板,并跳转到「case_name」处进行了修改。

如何配置 snippet

操作流程

  1. 进入 snippet 设置文件
    这里提供了两种方法:
    1. 按「Alt」键切换菜单栏,通过文件 > 首选项 > 用户代码片段,选择进入目的语言的代码段设置文件;
    2. 通过快捷键「Ctrl + Shift + P」打开命令窗口(all command window),输入「snippet」,通过候选栏中的选项进入目的语言的代码段设置文件。
  2. 填写 snippets

VSCode 中 snippet 的文法 1

设置文件头部的一个块注释给出了设置 snippet 的格式,了解过「json」就不会对此感到奇怪。

 // Place your snippets for C here. Each snippet is defined under a snippet name and has a prefix, body and  // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are: // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the  // same ids are connected. // Example: "Print to console": {    "prefix": "log",,    "body": [        "console.log('$1');",        "$2"    ],    "description": "Log output to console"}

:上例 snippet 的功能为,在输入 log 并确认后,可将原文本替换为console.log('');,效果预览如下:
log

snippet 由三部分组成:

  • prefix:前缀,定义了 snippets 从 IntelliSense 中呼出的关键字;
  • body: 主体,即模板的主体内容,其中每个字符串表示一行;
  • description:说明,会在 IntelliSense 候选栏中出现。未定义的情况下直接显示对象名,上例中将会显示 Print to console

其中 body 部分可以使用特殊结构来控制光标和要插入的文本。 支持的功能及其文法如下:

  • Tabstops:制表符

    用「Tabstops」可以让编辑器的指针在 snippet 内跳转。使用 $1$2 etc. 指定光标位置。这些数字指定了Tabstops将被访问的顺序,特别地,$0表示最终光标位置。相同序号的「Tabstops」被链接在一起,将会同步更新,比如下列用于生成头文件封装的 snippet 被替换到编辑器上时,光标就将同时出现在所有$1位置。

    "#ifndef $1""#define $1""#end // $1"
  • Placeholders:占位符

    「placeholder」是带有默认值的「Tabstops」,如${1:foo}。「placeholder」文本将被插入「Tabstops」位置,并在跳转时被全选,以方便修改。占位符还可以嵌套,例如${1:another ${2:placeholder}}

    比如,结构体的 snippet 主体可以这样写:

    struct ${1:name_t} {\n\t$2\n};

    作为「Placeholder」的name_t一方面可以提供默认的结构名称,另一方面可以作为输入的提示。

  • Variables:变量

    使用$name${name:default}可以插入变量的值。 当未设置变量时,将插入其缺省值或空字符串。 当varibale未知(即,其名称未定义)时,将插入变量的名称,并将其转换为「placeholder」。 可以使用以下「Variable」:

    • TM_SELECTED_TEXT:当前选定的文本或空字符串
    • TM_CURRENT_LINE:当前行的内容
    • TM_CURRENT_WORD:光标下的单词的内容或空字符串
    • TM_LINE_INDEX:基于零索引的行号
    • TM_LINE_NUMBER:基于一索引的行号
    • TM_FILENAME:当前文档的文件名
    • TM_DIRECTORY:当前文档的目录
    • TM_FILEPATH:当前文档的完整文件路径

    注意,这些都是变量名,不是宏,在实际使用的时候还是要加上$符的。

拓展阅读:官网也给出了 snippet 的 EBNF 范式的正则文法,注意,使用\(反斜杠)转义\$, ,, }\

any ::= tabstop | placeholder | variable | text
tabstop ::= '$' int | '${' int '}'
placeholder ::= '${' int ':' any '}'
variable ::= '$' var | '${' var }' | '${' var ':' any '}'
var ::= [_a-zA-Z] [_a-zA-Z0-9]*
int ::= [0-9]+
text ::= .*

有用的建议

默认情况下 snippet 在 IntelliSense 中的显示优先级并不高,而且在 IntelliSense 中选择相应 snippet 需要按「enter」键,这对于手指短的人来说并不是什么很好的体验。所幸,VSCode 意识到了这一点,并为我们提供了改进的方式。

在 VSCode 的用户设置(「Ctrl+P」在输入框中写「user settings」后点选)中,检索代码段,然后根据提示修改,设置建议优先显示,并且可以通过「TAB」补全 snippet。

修改设置

修改后设置文件中会多出这两行:

"editor.snippetSuggestions": "top","editor.tabCompletion": true

附录

:我对 Atom 的 C snippet2 作了修改,使之更适合我的习惯,若有兴致你可自行修改,反正也不难。

{/*     // Place your snippets for C here. Each snippet is defined under a snippet name and has a prefix, body and      // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:     // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the      // same ids are connected.     // Example:     "Print to console": {        "prefix": "log",,        "body": [            "console.log('$1');",            "$2"        ],        "description": "Log output to console"    }*/  "#ifndef … #define … #endif":{    "prefix": "def",    "body": "#ifndef ${1:SYMBOL}\n#define $1 ${2:value}\n#endif\t// ${1:SYMBOL}"  },  "#include <>":{    "prefix": "Inc",    "body": "#include <${1:.h}>"  },  "#include \"\"":{    "prefix": "inc",    "body": "#include \"${1:.h}\""  },  "#pragma mark":{    "prefix": "mark",    "body": "#if 0\n${1:#pragma mark -\n}#pragma mark $2\n#endif\n\n$0"  },  "main()":{    "prefix": "main",    "body": "int main(int argc, char const *argv[]) {\n\t$1\n\treturn 0;\n}"  },  "For Loop":{    "prefix": "for",    "body": "for (${1:i} = 0; ${1:i} < ${2:count}; ${1:i}${3:++}) {\n\t$4\n}"  },  "Define and For Loop":{    "prefix": "dfor",    "body": "size_t ${1:i};\nfor (${1:i} = ${2:0}; ${1:i} < ${3:count}; ${1:i}${4:++}) {\n\t$5\n}"  },  "Header Include-Guard":{    "prefix": "once",    "body": "#ifndef ${1:SYMBOL}\n#define $1\n\n${2}\n\n#endif /* end of include guard: $1 */\n"  },  "Typedef":{    "prefix": "td",    "body": "typedef ${1:int} ${2:MyCustomType};"  },  "Typedef Struct":{    "prefix": "tst",    "body": "typedef struct ${1:StructName} {\n\t$2\n}${3:MyCustomType};"  },  "Do While Loop":{    "prefix": "do",    "body": "do {\n\t$0\n} while($1);"  },  "While Loop":{    "prefix": "while",    "body": "while ($1) {\n\t$2\n}"  },  "fprintf":{    "prefix": "fprintf",    "body": "fprintf(${1:stderr}, \"${2:%s}\\\\n\", $3);$4"  },  "If Condition":{    "prefix": "if",    "body": "if ($1) {\n\t$2\n}"  },  "If Else":{    "prefix": "ife",    "body": "if ($1) {\n\t$2\n} else {\n\t$3\n}"  },  "If ElseIf":{    "prefix": "iff",    "body": "if ($1) {\n\t$2\n} else if ($3) {\n\t$4\n}"  },  "If ElseIf Else":{    "prefix": "iffe",    "body": "if ($1) {\n\t$2\n} else if ($3) {\n\t$4\n} else {\n\t$5\n}"  },  "Switch Statement":{    "prefix": "sw",    "body": "switch ($1) {\n$2default:\n\t${3:break;}\n}$0"  },  "case break":{    "prefix": "cs",    "body": "case $1:\n\t$2\n\tbreak;\n$0"  },  "printf":{    "prefix": "printf",    "body": "printf(\"${1:%s }\\n\", $2);$3"  },  "scanf":{    "prefix": "scanf",    "body": "scanf(\"${1:%s}\\n\", $2);$3"  },  "Struct":{    "prefix": "st",    "body": "struct ${1:name_t} {\n\t$2\n};"  },  "void":{    "prefix": "void",    "body": "void ${1:name}($2) {\n\t$3\n}"  },  "any function":{    "prefix": "func",    "body": "${1:int} ${2:name}($3) {\n\t$5\n\treturn ${4:0};\n}"  },  "write file":{    "prefix": "wf",    "body": "FILE *${1:fp};\n${1:fp} = fopen (\"${2:filename.txt}\",\"w\");\nif (${1:fp}!=NULL)\n{\n\tfprintf(${1:fp},\"${3:Some String\\\\n}\");\n\tfclose (${1:fp});\n}"  },  "read file":{    "prefix": "rf",    "body": "FILE *${1:fp};\n${1:fp} = fopen (\"${2:filename.txt}\",\"r\");\nif (${1:fp}!=NULL)\n{\n\tfscanf(${1:fp},\"${3:Some String\\\\n}\", ${3:&var});\n\tfclose (${1:fp});\n}",    "description": "read file opeartion including fopen, fscanf and fclose."  }}

  1. https://code.visualstudio.com/Docs/customization/userdefinedsnippets ↩
  2. https://github.com/atom/language-c/blob/master/snippets/language-c.cson ↩
0 0
原创粉丝点击