vscode 插件开发

当时阐明

  • 该插件提供以下能力

    1. 在编辑器中选中的内容下一行增加 console.log('content', content)

      命令行操作: Insert Log快捷键:     win: ctrl+w    mac: cmd+shift+w
    2. 删除以后文件中所有的console

      命令行操作: Del all Logs快捷键:    win: ctrl+r    mac: cmd+shift+r
    3. 删除以后文件所有正文

      命令行操作: Remove all comments快捷键:    win: ctrl+t    mac: cmd+shift+t
  • 该文档记录一下 从插件代码初始化, 到插件工程目录阐明, 到package.json字段阐明, 到extension.ts文件阐明, 到性能实现, 到azure devops插件市场账号申请, 到插件公布的过程

工程初始化

// 当时全局装置yo(脚手架工具, 生成模板) generator-code(vscode拓展生成器, 配合yo应用构建我的项目)npm install yo generator-code -g
yo code   // 找个目录初始化我的项目

? What type of extension do you want to create(您想要创立什么类型的扩大?)? New Extension (TavaScript)
? What's the name of your extension(你的分机名是什么,也就是我的项目名)? auto-log
? What's the identifier of your extension(你的扩大的标识符是什么)? auto-log
? What's the description of your extension(什么是您的扩大的形容)? auto-log
? Initialize a git repository(初始化一个git仓库)? Yes
? bundel the source code with webpack (是否用webpack打包源码)? No
? Which package manager to use(应用哪个包管理器)? npm

初始化工程目录阐明

初始化package.json字段阐明(后续新增的字段, 后续阐明)

{    "name": "auto-log",// 插件工程名称    "displayName": "auto-log",    // 插件市场显示的名字    "description": "auto-log",    // 插件形容    "version": "0.0.1",    // 插件版本号    "engines": {    // 示意插件最低反对的vscode版本        "vscode": "^1.73.0"    },    "categories": [        // 插件利用市场分类        "Other"    ],    "activationEvents": [        // 插件的被动激活事件,可配*来放弃在后盾继续运行        "onCommand:auto-log.helloWorld"    ],    "main": "./out/extension.js",        // 插件性能的主入口文件    "contributes": {    // 奉献点,整个插件最重要最多的配置项        "commands": [            {                "command": "auto-log.helloWorld",                "title": "Hello World"            }        ]    },    "scripts": {        // 执行命令        "vscode:prepublish": "npm run compile",        "compile": "tsc -p ./",        "watch": "tsc -watch -p ./",        "pretest": "npm run compile && npm run lint",        "lint": "eslint src --ext ts",        "test": "node ./out/test/runTest.js"    },    "devDependencies": {        // 依赖        "@types/vscode": "^1.73.0",        "@types/glob": "^7.2.0",        "@types/mocha": "^9.1.1",        "@types/node": "16.x",        "@typescript-eslint/eslint-plugin": "^5.27.0",        "@typescript-eslint/parser": "^5.27.0",        "eslint": "^8.16.0",        "glob": "^8.0.3",        "mocha": "^10.0.0",        "typescript": "^4.7.2",        "@vscode/test-electron": "^2.1.3"    }}

在这package.json文件中,重点关注的次要有三局部内容:activationEvents、main以及contributes,其是整个文件中的重中之重。

1、main
指明了该插件的主入口在哪,只有找到主入口整个我的项目能力失常的运行

2、activationEvents
指明该插件在何种状况下才会被激活,因为只有激活后插件能力被失常应用,官网曾经指明了激活的机会 (opens new window),这样咱们就能够按需设置对应机会。(具体每个机会用的时候具体查看即可)

onLanguage 关上解析为特定语言文件时被激活,例如"onLanguage:python"
onCommand 在调用命令时被激活
onDebug 在启动调试话之前被激活
onDebugInitialConfigurations
onDebugResolve
workspaceContains 每当关上文件夹并且该文件夹蕴含至多一个与 glob 模式匹配的文件时
onFileSystem 每当读取来自特定计划的文件或文件夹时
onView 每当在 VS Code 侧栏中开展指定 id 的视图
onUri 每当关上该扩大的零碎范畴的 Uri 时
onWebviewPanel
onCustomEditor
onAuthenticationRequest
只有一启动vscode,插件就会被激活
onStartupFinished
3、contributes
通过扩大注册contributes用来扩大Visual Studio Code中的各项技能,其有多个配置,如下所示:

breakpoints 断点
colors 主题色彩
commands 命令
configuration 配置
configurationDefaults 默认的特定于语言的编辑器配置
customEditors 自定义编辑器
debuggers
grammars
iconThemes
jsonValidation
keybindings 快捷键绑定
languages
menus 菜单管制
problemMatchers
problemPatterns
productIconThemes
resourceLabelFormatters
snippets 特定语言的片段
submenus
taskDefinitions
themes 色彩主题
typescriptServerPlugins
views
viewsContainers
viewsWelcome
walkthroughs

extension.ts文件阐明

// The module 'vscode' contains the VS Code extensibility API// Import the module and reference it with the alias vscode in your code below// 依赖导入import * as vscode from 'vscode';// this method is called when your extension is activated// your extension is activated the very first time the command is executed// 总的来说该文件须要导出两个办法 activate和deactivate    // 其中 activate 是插件被激活时执行的函数 // deactivate 是插件被销毁时调用的办法,比方开释内存等    export function activate(context: vscode.ExtensionContext) {        // Use the console to output diagnostic information (console.log) and errors (console.error)    // This line of code will only be executed once when your extension is activated    console.log('Congratulations, your extension "auto-log" is now active!');    // The command has been defined in the package.json file    // Now provide the implementation of the command with registerCommand    // The commandId parameter must match the command field in package.json    let disposable = vscode.commands.registerCommand('auto-log.helloWorld', () => {        // The code you place here will be executed every time your command is executed        // Display a message box to the user        vscode.window.showInformationMessage('Hello World from auto-log!');    });    context.subscriptions.push(disposable);}// this method is called when your extension is deactivatedexport function deactivate() {}

性能实现

package.json

{    "name": "auto-log",    "displayName": "auto-log",    "description": "auto-log",    "version": "0.0.2",    "publisher": "jianting-wu",    "engines": {        "vscode": "^1.73.0"    },    "categories": [        "Other"    ],    "activationEvents": [ // 注册命令        "onCommand:auto-log.insert",        "onCommand:auto-log.del",        "onCommand:auto-log.remove-comments"    ],    "main": "./out/extension.js",    "contributes": {        "commands": [            {                "command": "auto-log.insert",                "title": "Insert Log"    // cmd+shift+p 命令行中输出的命令, 也是右键显示的命令            },            {                "command": "auto-log.del",                "title": "Del all Logs"            },            {                "command": "auto-log.remove-comments",                "title": "Remove all comments"            }        ],        "keybindings": [    // 绑定快捷键            {                "command": "auto-log.insert",                "key": "ctrl+w",                "mac": "cmd+shift+w",                "when": "editorTextFocus"            },            {                "command": "auto-log.del",                "key": "ctrl+r",                "mac": "cmd+shift+r",                "when": "editorTextFocus"            },            {                "command": "auto-log.remove-comments",                "key": "ctrl+t",                "mac": "cmd+shift+t",                "when": "editorFocus"            }        ],        "menus": {            "editor/context": [        // 配置右键显示                {                    "when": "editorTextFocus",                    "command": "auto-log.insert",                    "group": "navigation"                },                {                    "when": "editorTextFocus",                    "command": "auto-log.del",                    "group": "navigation"                },                {                    "when": "editorFocus",                    "command": "auto-log.remove-comments",                    "group": "navigation"                }            ]        }    },    "scripts": {        "vscode:prepublish": "npm run compile",        "compile": "tsc -p ./",        "watch": "tsc -watch -p ./",        "pretest": "npm run compile && npm run lint",        "lint": "eslint src --ext ts",        "test": "node ./out/test/runTest.js"    },    "devDependencies": {        "@types/vscode": "^1.73.0",        "@types/glob": "^7.2.0",        "@types/mocha": "^9.1.1",        "@types/node": "16.x",        "@typescript-eslint/eslint-plugin": "^5.27.0",        "@typescript-eslint/parser": "^5.27.0",        "eslint": "^8.16.0",        "glob": "^8.0.3",        "mocha": "^10.0.0",        "typescript": "^4.7.2",        "@vscode/test-electron": "^2.1.3"    },    "repository": {        "type": "git",        "url": "https://github.com/ulahala/auto-log.git"    }}

src/extension.ts

import * as vscode from 'vscode';import insert from './insert';import del from './del';import remove from './remove';const commandList = [    {command: 'auto-log.insert', handler: insert},    {command: 'auto-log.del',handler: del},    {command: 'auto-log.remove-comments',handler: remove}];export function activate(context: vscode.ExtensionContext) {    console.log('activated inter');    commandList.forEach(({command, handler}) => {        context.subscriptions.push(vscode.commands.registerCommand(command, handler));    });}export function deactivate() {}

src/insert.ts

import * as vscode from 'vscode';function insertText(str: string) {    const editor = vscode.window.activeTextEditor;    if(!editor) {return vscode.window.showErrorMessage('Can\'t insert log becase no document is opened');};    const selection = editor.selection;    const lineOfSelectionVar = selection.active.line;    editor.edit(editBuilder => {        // todo: 插入地位和选中行 头部对齐        editBuilder.insert(new vscode.Position(lineOfSelectionVar + 1, 0), str);    });}export default () => {    const editor = vscode.window.activeTextEditor;    if(!editor) {return;}    const selection = editor.selection;    const text = editor.document.getText(selection);    const logToInsert = `console.log('${text}', ${text});\n`;    text ? insertText(logToInsert) : insertText('console.log();\n');};

src/del.ts

import * as vscode from 'vscode';function getAllLogs() {    const editor = vscode.window.activeTextEditor;    if(!editor) {return [];};    const document = editor.document;    const documentText = document.getText();    const allLogs = [];    const logRegex = /console.(log|debug|info|warn|error|assert|dir|dirxml|trace|group|groupEnd|time|timeEnd|profile|profileEnd|count)\((.*)\);?/g;    let match;    while(match = logRegex.exec(documentText)) {        let matchRange = new vscode.Range(document.positionAt(match.index), document.positionAt(match.index + match[0].length));        if(!matchRange.isEmpty) {allLogs.push(matchRange);};    }    return allLogs;}export default () => {    const editor = vscode.window.activeTextEditor;    if(!editor) {return;};    const workspaceEdit = new vscode.WorkspaceEdit();    const document = editor.document;    const allLogs = getAllLogs();    allLogs.forEach(log => {        workspaceEdit.delete(document.uri, log);    });    vscode.workspace.applyEdit(workspaceEdit).then(() => {        vscode.window.showInformationMessage(`${allLogs.length} console deleted`);    });};

src/remove.ts

import * as vscode from 'vscode';export default () => {    const editor = vscode.window.activeTextEditor;    if(!editor) {return;}    editor.edit(editBuilder => {        let text= editor.document.getText();        text = text.replace(/((\/\*([\w\W]+?)\*\/)|(\/\/(.(?!"\)))+)|(^\s*(?=\r?$)\n))/gm, '')                    .replace(/(^\s*(?=\r?$)\n)/gm, '')                    .replace(/\\n\\n\?/gm, '');        const end = new vscode.Position(editor.document.lineCount + 1, 0);        editBuilder.replace(new vscode.Range(new vscode.Position(0, 0), end), text);        vscode.commands.executeCommand('editor.action.formatDocument');    });};

azure devops插件市场账号申请

简略阐明一下:
Visual Studio Code的利用市场基于微软本人的Azure DevOps,插件的身份验证、托管和治理都是在这里。

  • 要公布到利用市场首先得有利用市场的publisher账号;
  • 而要有公布账号首先得有Azure DevOps组织;
  • 而创立组织之前,首先得创立Azure账号;
  • 创立Azure账号首先得有Microsoft账号;

而且

  • 一个Microsoft账号能够创立多个Azure组织;
  • 一个组织能够创立多个publisher账号;
  • 同时一个组织能够创立多个PAT(Personal Access Token,集体拜访令牌);
  1. 申请Microsoft账号
    登录Microsoft , 没有的话注册一个

  2. 创立Azure DevOps组织

https://aka.ms/SignupAzureDevOps


点击continue 创立组织

  1. 创立令牌

进入组织的主页后,点击右上角的Security,点击创立新的集体拜访令牌,这里特地要留神Organization要抉择all accessible organizations,Scopes要抉择Full access,否则前面发布会失败。

点击Create创立token, token要本人存一下, 在公布的时候要用的, 没存的话公布的时候得从新生成

  1. 创立公布账号

拜访https://aka.ms/vscode-create-publisher


把name 和 id 这俩必填的填上就行 这个name要和你插件的package.json中的 'publisher' 字段保持一致

点击下方Create创立公布账号, 这块如果你用的google浏览器会有个 无奈加载recaptcha 的报错, 这是google的人机验证, 头铁的多试几次, 头肿了了用火狐搞, 解决办法的话查一下 无奈加载recaptcha 不细讲了, 反正我头铁过来了

到这了账号的问题根本搞完了, 接下来就是搞公布的事了

  1. 公布到利用市场

先全局装置vsce, 这个是vscode插件的打包工具

npm install vsce -g

而后本地创立一个发布者

vsce create-publisher jianting-wu // 这个名字要和创立公布账号的那个name统一, 和package.json中的 'publisher' 字段统一

而后在我的项目根目录下执行

vsce publish

第一次执行会让你输出下面生成的token, 还遇到提醒package.json中没有repository字段, 根目录下没有LICENSE...爱补就补上

而后等个几分钟, 在利用市场上就能看到你公布的利用了

完事, 先到这...