vscode语言支持插件开发

安装脚手架

npm install -g yo generator-code

生成插件模板

yo code

配置语言支持

我这里就自定义一种以.da结尾的语言,修改根目录下的package.json文件的contributes处的属性

{
  "contributes": {
    "languages": [
      {
        "id": "da",
        "aliases": [
          "DA"
        ],
        "extensions": [
          ".da"
        ],
        "icon": {
          "dark": "logo.png",
          "light": "logo.png"
        },
        "configuration": "language.json"
      }
    ],
    "grammars": [
      {
        "language": "da",
        "scopeName": "source.da",
        "path": "grammars.json"
      }
    ],
    "snippets": [
      {
        "language": "da",
        "path": "snippets.json"
      }
    ],
  }
}

自动补全括号、注释

在根目录创建language.json文件,填入以下内容,该文件是用来自动补全括号,单行和多行注释用什么符号,我这里注释用-

{
    "comments": {
        "blockComment": [
            "---",
            "---"
        ],
        "lineComment": "-"
    },
    "brackets": [
        [
            "(",
            ")"
        ],
        [
            "[",
            "]"
        ],
        [
            "{",
            "}"
        ]
    ],
    "autoClosingPairs": [
        [
            "(",
            ")"
        ],
        [
            "[",
            "]"
        ],
        [
            "{",
            "}"
        ]
    ],
    "surroundingPairs": [
        [
            "(",
            ")"
        ],
        [
            "[",
            "]"
        ],
        [
            "{",
            "}"
        ]
    ]
}

语言高亮

在根目录创建grammars.json文件,填入以下内容patterns里面对应repository里面的内容patterns.match就是匹配规则,颜色的话我也没怎么研究明白,交给你们研究了

{
  "name": "da",
  "scopeName": "source.da",
  "patterns": [
    {
      "include": "#keywords"
    },
    {
      "include": "#strings"
    },
    {
      "include": "#numbers"
    },
    {
      "include": "#comments"
    },
    {
      "include": "#variables"
    },
    {
      "include": "functions"
    }
  ],
  "repository": {
    "keywords": {
      "patterns": [
        {
          "name": "keyword.control.da",
          "match": "\\b(?:def|print|class|if|for|while|do)\\b"
        }
      ]
    },
    "strings": {
      "name": "string.quoted.double.da",
      "begin": "\"",
      "end": "\"",
      "patterns": [
        {
          "name": "constant.character.escape.da",
          "match": "\\\\."
        }
      ]
    },
    "numbers": {
      "name": "constant.numeric.da",
      "match": "\\b\\d+(\\.\\d+)?\\b"
    },
    "comments": {
      "name": "comment.line.double-slash.da",
      "begin": "-",
      "end": "$"
    },
    "variables": {
      "name": "variable.other.da",
      "match": "\\b\\w+\\b"
    },
    "functions": {
      "name": "entity.name.function.da",
      "match": "\\b\\w+\\(.?\\)\\b"
    }
  }
}

代码片段

在根目录下创建snippets.json文件,在里面填入以下内容,prefix是输入的前缀,出现这个前缀就会有提示,body是片段内容,$n是片段生成后光标停留的位置

{
    "da": {
        "prefix": "da",
        "body": [
            "da is very good"
        ],
        "description": "da提示片段"
    },
    "love": {
        "prefix": "i",
        "body": [
            "i",
            "love",
            "$1"
        ],
        "description": "love提示片段"
    }
}

提示补全

extension.tsactivate方法中注册自定义的CompletionItemProvider

context.subscriptions.push(vscode.languages.registerCompletionItemProvider('da', new MyCompletionItemProvider))

代码提示实现类

// 关键字
const keys = ['def', 'print', 'class', 'if', 'for', 'while', 'do']

// 代码提示
class MyCompletionItemProvider implements vscode.CompletionItemProvider {
	provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
		// 提示关键字
    return keys.map(key => {
			return new vscode.CompletionItem(key, vscode.CompletionItemKind.Keyword)
		})
	}
	resolveCompletionItem?(item: vscode.CompletionItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CompletionItem> {
		throw new Error('Method not implemented.')
	}
}

悬浮提示

extension.tsactivate方法中注册自定义的HoverProvider

context.subscriptions.push(vscode.languages.registerHoverProvider('da', new MyHoverProvider))

悬浮提示实现类

class MyHoverProvider implements vscode.HoverProvider {
	provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult<vscode.Hover> {
		// 通过position获取到鼠标悬浮位置单词的Range
		const wordRange = document.getWordRangeAtPosition(position)
		// 通过Range获取到这个单词
		const word = document.getText(wordRange)
		if(keys.includes(word)){
			return new vscode.Hover(`${word}是关键字`)
		}
	}
}

代码检查

extension.tsactivate方法中注册自定义的编辑器文本改变事件

const diagnosticCollection = vscode.languages.createDiagnosticCollection('caseChecker')
context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => {
  diagnosticCollection.set(event.document.uri, checkText(event.document))
}))

检查文本,显示告警信息

const checkText = (document: vscode.TextDocument) => {
	const diagnostics = []
	const text = document.getText()
	const regex = /\b[A-Z]{2,}\b/g
	let match
	while ((match = regex.exec(text)) !== null && keys.includes(match[0].toLocaleLowerCase())) {
		const startPos = document.positionAt(match.index)
		const endPos = document.positionAt(match.index + match[0].length)
		diagnostics.push(new vscode.Diagnostic(
			new vscode.Range(startPos, endPos),
			`${match[0]}关键字需要小写`,
			vscode.DiagnosticSeverity.Warning
		))
	}
	return diagnostics
}

代码修复

extension.tsactivate方法中注册自定义的CodeActionProvider

context.subscriptions.push(vscode.languages.registerCodeActionsProvider('da', new MyCodeActionProvider))

处理警告信息的字符实现类

class MyCodeActionProvider implements vscode.CodeActionProvider {
	provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> {
		// 获取所有的告警信息
		const diagnostics = context.diagnostics
		const actions: vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> = []
		// 遍历所有的信息
		diagnostics.forEach(diagnostic => {
			// 处理 Warning 信息
			if (diagnostic.severity === vscode.DiagnosticSeverity.Warning) {
				const action = new vscode.CodeAction(`修复 ${diagnostic.message}`, vscode.CodeActionKind.QuickFix)
				action.edit = new vscode.WorkspaceEdit()
				// 获取警告的字符
				const word = document.getText(range).toLocaleLowerCase()
				// 替换原来位置上的字符
				action.edit.replace(document.uri, diagnostic.range, word)
				actions.push(action)
			}
		})
		return actions
	}
	resolveCodeAction?(codeAction: vscode.CodeAction, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CodeAction> {
		throw new Error('Method not implemented.')
	}
}

代码格式化

extension.tsactivate方法中注册自定义的DocumentFormattingEditProvider

context.subscriptions.push(vscode.languages.registerDocumentFormattingEditProvider('da', new MyDocumentFormattingEditProvider()))

代码格式化实现类

const format = (source: string): string => {
	let output = ''
	const lines = source.split("\r\n").map(line => line.trim()).filter(Boolean)
	for (let i = 0; i < lines.length; i++) {
		if (lines[i].startsWith('def')) {
			output += `\r\n${lines[i]}\r\n`
			let j = i + 1
			while (true) {
				if (lines[j].startsWith("}")) {
					output += `${lines[j]}\r\n\r\n`
					i = j + 1
					break
				}
				output += `    ${lines[j]}\r\n`
				j++
			}
		}
		output += `${lines[i]}\r\n`
	}
	return output
}

class MyDocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider {
	provideDocumentFormattingEdits(document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {
		const text = document.getText()
		const range = new vscode.Range(
			document.positionAt(0),
			document.positionAt(text.length)
		)
		return Promise.resolve([new vscode.TextEdit(range, format(text))])
	}
}	

跳转到定义

extension.tsactivate方法中注册自定义的DefinitionProvider

context.subscriptions.push(vscode.languages.registerDefinitionProvider('da', new MyDefinitionProvider))

跳转到当前文件的实现处,我这里是处理以()结尾的方法和let定义的变量

// 查找点击单词在文档中的第一个位置
const findStringPosition = (document: vscode.TextDocument, search: string) => {
	const text = document.getText() 
	const lines = text.split(/\r?\n/)
	for (let lineNumber = 0; lineNumber < lines.length; lineNumber++) {
		const line = lines[lineNumber]
		const position = line.indexOf(`def ${search}`)
		if (position !== -1) {
			// vscode.Position 的构造函数参数是:行号(从0开始),列号(从0开始)
			return new vscode.Position(lineNumber, position);
		}
	}
	// 如果没有找到返回null
	return null;
}

class MyDefinitionProvider implements vscode.DefinitionProvider {
	provideDefinition(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult<vscode.Definition | vscode.LocationLink[]> {
		const wordRange = document.getWordRangeAtPosition(position)
		const word = document.getText(new vscode.Range(wordRange?.start!, new vscode.Position(
			wordRange?.end.line!,
			wordRange?.end.character! + 2
		)))
		if (word.endsWith("()")) {
			const pos = findStringPosition(document, word)
			if (pos) {
				return new vscode.Location(document.uri, pos)
			}
		}
	}
}

本地打包插件

为什么不发布到插件市场?
因为注册账号什么的太麻烦了,这里篇幅已经很长了,以后单独发怎么打包发布。
安装依赖

npm i vsce -g

本地打包
切记要用npm安装依赖,不然本地打包不成功

vsce package
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值