https://snippet-generator.app/
在 Visual Studio Code (VS Code) 中,代码片段(snippets)是一种便捷的工具,用于快速插入常用的代码模式。代码片段以 JSON 格式定义,并存储在特定语言的代码片段文件中,例如 javascript.json。下面是代码片段格式的详细解释。
代码片段基本结构
代码片段的基本结构
一个代码片段文件包含一个或多个代码片段,每个代码片段都有一个唯一的键(名称),其值是一个对象,该对象定义了代码片段的详细信息。以下是代码片段的基本结构:
{
  "Snippet Name": {
    "prefix": "trigger",
    "body": [
      "line1",
      "line2",
      "line3"
    ],
    "description": "Description of the snippet"
  }
}
代码片段字段解释
Snippet Name:
- 代码片段的名称,用于在代码片段文件中唯一标识每个代码片段。这个名称不会在 VS Code 中显示,但在文件中必须是唯一的。
 
prefix:
- 触发该代码片段的前缀。用户在编辑器中输入这个前缀并按下 
Tab键或其他触发键时,代码片段会被插入。前缀通常是简短且易记的。 
- 触发该代码片段的前缀。用户在编辑器中输入这个前缀并按下 
 body:
- 代码片段的主体,是一个字符串数组。每个数组元素表示代码片段中的一行代码。可以使用特殊占位符和变量来增强代码片段的功能。
 - 可以使用 
$1,$2, ... 表示光标位置或占位符,用户可以按Tab键在这些位置之间跳转。 $0表示最终光标位置。${varName}表示变量,可以在代码片段插入时进行替换。${1:default}表示带有默认值的占位符。
description:
- 对代码片段的描述,显示在代码片段选择列表中,帮助用户理解该代码片段的用途。
 
以下是一个完整的示例,展示了如何定义一个 JavaScript 代码片段:
{
  "Log to console": {
    "prefix": "log",
    "body": [
      "console.log('$1');",
      "$2"
    ],
    "description": "Log output to console"
  },
  "Function template": {
    "prefix": "func",
    "body": [
      "function ${1:functionName}(${2:params}) {",
      "  ${3:// TODO: implement}",
      "}"
    ],
    "description": "Create a function template"
  }
}
解释示例:
Log to console:
- prefix: 
log - body: 插入两行代码。第一行是 
console.log('$1');,其中$1是一个占位符,用户可以在插入代码片段后立即输入内容。第二行是$2,表示第二个光标位置,用户可以在这里继续输入内容。 - description: "Log output to console"
 
- prefix: 
 Function template:
- prefix: 
func - body: 插入一个函数模板。
function ${1:functionName}(${2:params}) {定义了函数名和参数,其中${1:functionName}和${2:params}是带有默认值的占位符。$3是函数体的注释部分,用户可以在这里实现函数逻辑。 - description: "Create a function template"
 
- prefix: 
 
使用代码片段
创建或编辑代码片段文件:
- 打开 VS Code,按 
Ctrl+Shift+P(Windows/Linux)或Cmd+Shift+P(Mac)打开命令面板。 - 输入 
Preferences: Configure User Snippets并选择你要创建或编辑代码片段的语言(例如javascript)。 
- 打开 VS Code,按 
 添加代码片段:
- 在打开的 JSON 文件中添加你的代码片段定义,保存文件。注意:在
javascript.json中保存的代码片段通常在.js文件中才会提示 
- 在打开的 JSON 文件中添加你的代码片段定义,保存文件。注意:在
 使用代码片段:
- 在编辑器中输入代码片段的前缀(例如 
log或func),然后按Tab键,代码片段会被插入到光标位置。 
- 在编辑器中输入代码片段的前缀(例如 
 
通过这种方式,你可以快速插入常用的代码模式,提高编码效率。
写脚本注入代码片段到VS Code
bin.js
#!/usr/bin/env node
const program = require('commander')
const { input, confirm, select, rawlist, number, editor } = require('@inquirer/prompts')
program.command('setSnippet')
  .description('write snippet to vscode')
  .action(async () => {
    try {
      const answerInfo = {
        snippetType: await rawlist({
          message: `请选择代码片段类型`,
          choices: [
            {
              name: 'ts',
              value: 'typescript',
            },
            {
              name: 'tsx',
              value: 'typescriptreact',
            },
            {
              name: 'js',
              value: 'javascript',
            },
            {
              name: 'jsx',
              value: 'javascriptreact',
            },
            {
              name: 'scss',
              value: 'scss',
            },
            {
              name: 'vue',
              value: 'vue',
            },
          ],
        }),
        snippetPrefix: await input({ message: "请输入代码片段的唯一标识:", required: true }),
        codeContent: await editor({
          message: '请输入代码片段(将转换并注入到vscode中):',
          required: true,
        }),
      }
      
      serviceInstance.setSnippet(answerInfo)
    } catch (error) {
      if (error.isTtyError) {
        console.error('当前环境不支持');
      } else if (error.message === 'User force closed the prompt with 0 null') {
        console.log('用户中断了输入');
      } else {
        console.error('发生错误:', error);
      }
    }
  })
/**
 * 注入代码片段到VS Code
 */
setSnippet(info) {
  let snippets
  // 转换为snippet格式
  let newSnippet = convertToSnippet(info.codeContent, info.snippetPrefix)
  // 获取 VS Code 用户代码片段文件路径
  const snippetDirPath = path.join(process.env.HOME, 'Library', 'Application Support', 'Code', 'User', 'snippets')
  const snippetFilePath = path.join(snippetDirPath, `${info.snippetType}.json`)
  // 确保文件存在
  fs.access(snippetFilePath, fs.constants.F_OK, (err) => {
    if (err) {
      // 文件不存在,创建文件
      shell.cd(snippetDirPath)
      shell.touch(`${info.snippetType}.json`)
      snippets = newSnippet
    } else {
      // 文件存在
      // 读取现有的代码片段文件
      let fileContent = fs.readFileSync(snippetFilePath, 'utf8')
      if (fileContent) {
        // 添加新的代码片段
        snippets = JSON.parse(fileContent)
        Object.assign(snippets, newSnippet)
      } else {
        snippets = newSnippet
      }
    }
    // 写回文件
    fs.writeFileSync(snippetFilePath, JSON.stringify(snippets, null, 2), 'utf8')
    const map = {
      'typescript': 'ts',
      'typescriptreact': 'tsx',
      'javascript': 'js',
      'javascriptreact': 'jsx',
      'scss': 'scss',
      'vue': 'vue',
    }
    console.log(`注入成功,快去${map[info.snippetType]}文件中使用吧`)
  });
}
function convertToSnippet(code, prefix, description) {
  if (!description) description = `${prefix}Snippet`;
  // 将代码按行分割成数组
  const codeLines = code.split('\n');
  // 生成代码片段的主体
  const snippetBody = codeLines.map(line => line.trim());
  // 创建代码片段对象
  const snippet = {
    [description]: {
      "prefix": prefix,
      "body": snippetBody,
      "description": description
    }
  };
  return snippet;
  // 将对象转换为 JSON 字符串并格式化
  // return JSON.stringify(snippet, null, 2);
}
module.exports = {
  convertToSnippet,
}