├── pnpm-workspace.yaml ├── assets └── kv.png ├── .vscode ├── settings.json ├── extensions.json ├── tasks.json └── launch.json ├── .github ├── FUNDING.yml └── workflows │ ├── release.yml │ └── ci.yml ├── src ├── toUri.ts ├── reloadWindow.ts ├── createCompletionKind.ts ├── getLocale.ts ├── getCopyText.ts ├── createMarkdownString.ts ├── isDark.ts ├── setCopyText.ts ├── createHover.ts ├── openExternalUrl.ts ├── setCommandParams.ts ├── createSnippetString.ts ├── executeCommand.ts ├── getActiveTextEditor.ts ├── getActiveText.ts ├── createOutputChannel.ts ├── util.ts ├── createCodeLens.ts ├── executeCommands.ts ├── getActiveTextEditorLanguageId.ts ├── getLineText.ts ├── useVisibleRange.ts ├── registerCommands.ts ├── registerCommand.ts ├── scrollInToView.ts ├── openSpecialFile.ts ├── getWordRangeAtPosition.ts ├── nextTick.ts ├── createStyle.ts ├── getKeyWords.ts ├── getPositionAfterCode.ts ├── unFold.ts ├── getPositionBeforeCode.ts ├── createTerminal.ts ├── onFold.ts ├── rename.ts ├── useDark.ts ├── createDefinitionLocation.ts ├── getVisibleRange.ts ├── createSquare.ts ├── getConfiguration.ts ├── getCurrentFileUrl.ts ├── openFile.ts ├── createInlineCompletionList.ts ├── getOffsetFromPosition.ts ├── saveFile.ts ├── registerDefinitionProvider.ts ├── createProgress.ts ├── registerCodeLensProvider.ts ├── createCompletionList.ts ├── setConfiguration.ts ├── getCalcPosition.ts ├── getRootPath.ts ├── getRefConfigutation.ts ├── createExtension.ts ├── watchFiles.ts ├── createDebugTerminal.ts ├── registerTerminalLinkProvider.ts ├── registerCodeActionsProvider.ts ├── setStyle.ts ├── setSelections.ts ├── getPosition.ts ├── registerHoverProvider.ts ├── registerInlineCompletionItemProvider.ts ├── useConfiguration.ts ├── watchFile.ts ├── registerInlayHintsProvider.ts ├── createInlayHint.ts ├── createStyleAnimation.ts ├── updateText.ts ├── createPosition.ts ├── createInlineCompletionItem.ts ├── getSelection.ts ├── createStyleAnimations.ts ├── addEventListeners.ts ├── createInput.ts ├── createFakeProgress.ts ├── useTheme.ts ├── createBottomBar.ts ├── registerCompletionItemProvider.ts ├── isInPosition.ts ├── createCompletionItem.ts ├── jumpToLine.ts ├── createEvents.ts ├── insertText.ts ├── createLog.ts ├── createSelection.ts ├── createRange.ts ├── setSelection.ts ├── createSelect.ts ├── index.ts ├── message.ts ├── types.ts └── addEventListener.ts ├── .npmrc ├── test └── index.test.ts ├── .editorconfig ├── .gitignore ├── tsdown.config.ts ├── .prettierignore ├── eslint.config.mjs ├── tsconfig.json ├── .prettierrc.json ├── license ├── scripts └── verifyCommit.ts ├── package.json ├── README_zh.md └── README.md /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - playground 3 | - examples/* 4 | -------------------------------------------------------------------------------- /assets/kv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vscode-use/utils/HEAD/assets/kv.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.inlineSuggest.showToolbar": "always" 3 | } 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Simon-He95 2 | custom: ['https://github.com/Simon-He95/sponsor'] 3 | -------------------------------------------------------------------------------- /src/toUri.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export function toUri(absolutePath: string) { 4 | return vscode.Uri.file(absolutePath) 5 | } 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ignore-workspace-root-check=true 2 | shamefully-hoist=true 3 | strict-peer-dependencies=false 4 | auto-install-peers=true 5 | node-options=--no-warnings 6 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest' 2 | 3 | describe('should', () => { 4 | it('exported', () => { 5 | expect(1).toEqual(1) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /src/reloadWindow.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export function reloadWindow() { 4 | return vscode.commands.executeCommand('workbench.action.reloadWindow') 5 | } 6 | -------------------------------------------------------------------------------- /src/createCompletionKind.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export function createCompletionKind(v: keyof typeof vscode.CompletionItemKind) { 4 | return vscode.CompletionItemKind[v] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/getLocale.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 获取当前 vscode 的语言环境 5 | * @returns vscode.env.language 6 | */ 7 | export function getLocale() { 8 | return vscode.env.language 9 | } 10 | -------------------------------------------------------------------------------- /src/getCopyText.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 获取剪贴板内容 5 | * @returns Thenable 6 | */ 7 | export function getCopyText() { 8 | return vscode.env.clipboard.readText() 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | node_modules 3 | *.log 4 | idea/ 5 | *.local 6 | .DS_Store 7 | dist 8 | .cache 9 | .idea 10 | .history 11 | logs 12 | &-debug.log 13 | *-error.log 14 | .eslintcache 15 | tmp 16 | 17 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "amodio.tsl-problem-matcher" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/createMarkdownString.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export function createMarkdownString() { 4 | const md = new vscode.MarkdownString() 5 | md.isTrusted = true 6 | md.supportHtml = true 7 | return md 8 | } 9 | -------------------------------------------------------------------------------- /src/isDark.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 判断当前主题色 5 | * @returns boolean 6 | */ 7 | export function isDark(): boolean { 8 | return vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Dark 9 | } 10 | -------------------------------------------------------------------------------- /src/setCopyText.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 设置剪贴板内容 5 | * @param text 内容 6 | * @returns Promise 7 | */ 8 | export function setCopyText(text: string) { 9 | return vscode.env.clipboard.writeText(text) 10 | } 11 | -------------------------------------------------------------------------------- /src/createHover.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export function createHover(contents: vscode.MarkdownString | vscode.MarkedString | Array, range?: vscode.Range) { 4 | return new vscode.Hover(contents, range) 5 | } 6 | -------------------------------------------------------------------------------- /src/openExternalUrl.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 打开外部的一个地址 5 | * @param uri 链接 6 | * @returns Thenable 7 | */ 8 | export function openExternalUrl(uri: string) { 9 | return vscode.env.openExternal(vscode.Uri.parse(uri)) 10 | } 11 | -------------------------------------------------------------------------------- /tsdown.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsdown' 2 | 3 | export default defineConfig({ 4 | target: 'node14', 5 | format: ['cjs', 'esm'], 6 | external: [ 7 | 'vscode', 8 | ], 9 | dts: true, 10 | clean: true, 11 | platform: 'node', // 明确指定为 Node.js 平台 12 | }) 13 | -------------------------------------------------------------------------------- /src/setCommandParams.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 设置命令参数 3 | * @param params 4 | * @usage [xxx](`command:a.b?${setCommandParams([1, 2, 3])}`) 5 | * @returns string 6 | */ 7 | export function setCommandParams(params: any[]) { 8 | return encodeURIComponent(JSON.stringify(params)) 9 | } 10 | -------------------------------------------------------------------------------- /src/createSnippetString.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 创建代码片段 5 | * @param str 6 | * @returns SnippetString 7 | */ 8 | export function createSnippetString(str: string | string[]) { 9 | return new vscode.SnippetString(typeof str === 'string' ? str : str.join('\n')) 10 | } 11 | -------------------------------------------------------------------------------- /src/executeCommand.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 执行命令 5 | * @param name 6 | * @param params 7 | * @returns Thenable 8 | */ 9 | export function executeCommand(name: string, ...params: any[]) { 10 | return vscode.commands.executeCommand(name, ...params) 11 | } 12 | -------------------------------------------------------------------------------- /src/getActiveTextEditor.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | /** 3 | * 获取激活的编辑器 4 | */ 5 | export function getActiveTextEditor() { 6 | const activeTextEditor = vscode.window.activeTextEditor 7 | if (activeTextEditor?.document.fileName === 'exthost') 8 | return 9 | return activeTextEditor 10 | } 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | packages/*/CHANGELOG.md 2 | playground-temp/ 3 | dist/ 4 | temp/ 5 | LICENSE.md 6 | pnpm-lock.yaml 7 | pnpm-workspace.yaml 8 | playground/tsconfig-json-load-error/has-error/tsconfig.json 9 | playground/html/invalid.html 10 | playground/html/valid.html 11 | playground/worker/classic-worker.js 12 | .history 13 | -------------------------------------------------------------------------------- /src/getActiveText.ts: -------------------------------------------------------------------------------- 1 | import { getActiveTextEditor } from './getActiveTextEditor' 2 | 3 | /** 4 | * 获取当前激活文件的文本 5 | * @returns string 6 | */ 7 | export function getActiveText() { 8 | const activeTextEditor = getActiveTextEditor() 9 | if (activeTextEditor) 10 | return activeTextEditor.document.getText() 11 | } 12 | -------------------------------------------------------------------------------- /src/createOutputChannel.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 创建外部输出管道 5 | * @param name string 6 | * @param languageId string 7 | * @returns Terminal 8 | */ 9 | export function createOutputChannel(name: string, languageId?: string) { 10 | return vscode.window.createOutputChannel(name, languageId) 11 | } 12 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | // 自动收集函数副作用 3 | export const effectMaps: vscode.Disposable[] = [] 4 | export function createEffectDeps() { 5 | effectMaps.length = 0 6 | return effectMaps 7 | } 8 | export function addEffect(effect: vscode.Disposable) { 9 | effectMaps.push(effect) 10 | return effect 11 | } 12 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import antfu from '@antfu/eslint-config' 3 | 4 | export default antfu( 5 | { 6 | ignores: [ 7 | // eslint ignore globs here 8 | 'test/**/*', 9 | ], 10 | }, 11 | { 12 | rules: { 13 | // overrides 14 | 'no-irregular-whitespace': 'off', 15 | }, 16 | }, 17 | ) 18 | -------------------------------------------------------------------------------- /src/createCodeLens.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 创建一个代码镜头 5 | * @param range Range 代码镜头的范围 6 | * @param command Command 代码镜头的指令 7 | * @returns TextEditorDecorationType 8 | */ 9 | export function createCodeLens(range: vscode.Range, command?: vscode.Command) { 10 | return new vscode.CodeLens(range, command) 11 | } 12 | -------------------------------------------------------------------------------- /src/executeCommands.ts: -------------------------------------------------------------------------------- 1 | import { executeCommand } from './executeCommand' 2 | 3 | /** 4 | * 执行多条命令 5 | * @param options Array<[string, ...any[]]> 6 | * @returns Array> 7 | */ 8 | export function executeCommands(options: Array<[string, ...any[]]>) { 9 | return options.map(([name, ...params]) => executeCommand(name, ...params)) 10 | } 11 | -------------------------------------------------------------------------------- /src/getActiveTextEditorLanguageId.ts: -------------------------------------------------------------------------------- 1 | import { getActiveTextEditor } from './getActiveTextEditor' 2 | 3 | /** 4 | * 获取当前激活文件的语言 5 | * @returns string 6 | */ 7 | export function getActiveTextEditorLanguageId() { 8 | const activeTextEditor = getActiveTextEditor() 9 | if (activeTextEditor) 10 | return activeTextEditor.document.languageId 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "lib": ["esnext"], 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "resolveJsonModule": true, 8 | "strict": true, 9 | "strictNullChecks": true, 10 | "esModuleInterop": true, 11 | "skipDefaultLibCheck": true, 12 | "skipLibCheck": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/getLineText.ts: -------------------------------------------------------------------------------- 1 | import { getActiveTextEditor } from './getActiveTextEditor' 2 | 3 | /** 4 | * 获取传入行数所在行的文本 5 | * @param lineNumber 行数 6 | * @returns 该行文本 7 | */ 8 | export function getLineText(lineNumber: number) { 9 | const activeTextEditor = getActiveTextEditor() 10 | if (activeTextEditor) 11 | return activeTextEditor.document.lineAt(lineNumber).text 12 | } 13 | -------------------------------------------------------------------------------- /src/useVisibleRange.ts: -------------------------------------------------------------------------------- 1 | import { signal } from 'alien-signals' 2 | import { addEventListener } from './addEventListener' 3 | import { getVisibleRange } from './getVisibleRange' 4 | 5 | export function useVisibleRange() { 6 | const range = signal(getVisibleRange()) 7 | addEventListener('text-visible-change', () => { 8 | range(getVisibleRange()) 9 | }) 10 | return range 11 | } 12 | -------------------------------------------------------------------------------- /src/registerCommands.ts: -------------------------------------------------------------------------------- 1 | import { registerCommand } from './registerCommand' 2 | 3 | /** 4 | * 注册多个指令 5 | * @param options Array<[string, (...args: any[]) => any]> 6 | * @returns Disposable[] 7 | */ 8 | export function registerCommands( 9 | options: Array<[string, (...args: any[]) => any]>, 10 | ) { 11 | return options.map(([name, callback]) => registerCommand(name, callback)) 12 | } 13 | -------------------------------------------------------------------------------- /src/registerCommand.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | import { addEffect } from './util' 3 | 4 | /** 5 | * 注册指令 6 | * @param name 指令名 7 | * @param callback 回调函数 8 | * @returns Disposable 9 | */ 10 | export function registerCommand( 11 | name: string, 12 | callback: (...args: any[]) => any, 13 | ) { 14 | return addEffect(vscode.commands.registerCommand(name, callback)) 15 | } 16 | -------------------------------------------------------------------------------- /src/scrollInToView.ts: -------------------------------------------------------------------------------- 1 | import type { Range, TextEditorRevealType } from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | 4 | export function scrollInToView(range: Range, viewColumn: TextEditorRevealType = 1) { 5 | const activeTextEditor = getActiveTextEditor() 6 | if (!activeTextEditor) 7 | return 8 | 9 | activeTextEditor.revealRange(range, viewColumn) 10 | } 11 | -------------------------------------------------------------------------------- /src/openSpecialFile.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 打开特殊文件 5 | * @description openFile 只能打开纯文本文件,如果是图片、音频、视频等文件,可以使用 openPureFile 6 | * @param fileUri 文件路径 7 | * @returns Promise 8 | */ 9 | export function openSpecialFile(fileUri: string): Promise { 10 | return Promise.resolve(vscode.commands.executeCommand('vscode.open', vscode.Uri.file(fileUri))) 11 | } 12 | -------------------------------------------------------------------------------- /src/getWordRangeAtPosition.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | /** 4 | * 根据position位置的关键词的range 5 | */ 6 | export function getWordRangeAtPosition(position: vscode.Position) { 7 | const activeTextEditor = getActiveTextEditor() 8 | if (activeTextEditor) 9 | return activeTextEditor.document.getWordRangeAtPosition(position) 10 | } 11 | -------------------------------------------------------------------------------- /src/nextTick.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 当进去文件更新(增删改查等)时,需要等到文件变化后执行函数 5 | * @param fn 更新后待执行的函数 6 | * @returns Thenable 7 | */ 8 | export function nextTick(fn?: (result: boolean) => void) { 9 | return new Promise((resolve) => { 10 | vscode.workspace.applyEdit(new vscode.WorkspaceEdit()).then((result) => { 11 | resolve(fn?.(result)) 12 | }) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/createStyle.ts: -------------------------------------------------------------------------------- 1 | import type { DecorationRenderOptions } from 'vscode' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 创建样式 6 | * @param options 7 | * @returns TextEditorDecorationType 8 | */ 9 | export function createStyle(options: DecorationRenderOptions) { 10 | return vscode.window.createTextEditorDecorationType({ rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed, ...options }) 11 | } 12 | -------------------------------------------------------------------------------- /src/getKeyWords.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | /** 4 | * 根据position获取关键词 5 | */ 6 | export function getKeyWords(position: vscode.Position) { 7 | const activeTextEditor = getActiveTextEditor() 8 | if (activeTextEditor) 9 | return activeTextEditor.document.getText(activeTextEditor.document.getWordRangeAtPosition(position)) 10 | } 11 | -------------------------------------------------------------------------------- /src/getPositionAfterCode.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | import { getActiveText } from './getActiveText' 3 | import { getOffsetFromPosition } from './getOffsetFromPosition' 4 | /** 5 | * 根据offset获取行列 6 | */ 7 | export function getPositionAfterCode(position: vscode.Position, code: string = getActiveText()!) { 8 | const offset = getOffsetFromPosition(position, code) 9 | return code.slice(offset) 10 | } 11 | -------------------------------------------------------------------------------- /src/unFold.ts: -------------------------------------------------------------------------------- 1 | import type { Range } from 'vscode' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 展开指定的 range 6 | * @param rangesToFold 7 | * @returns unknown[] 8 | */ 9 | export function unFold(rangesToFold: Range[]) { 10 | return rangesToFold.map(range => 11 | vscode.commands.executeCommand('editor.unfold', { 12 | selectionLines: [range.start.line, range.end.line], 13 | }), 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /src/getPositionBeforeCode.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | import { getActiveText } from './getActiveText' 3 | import { getOffsetFromPosition } from './getOffsetFromPosition' 4 | /** 5 | * 根据offset获取行列 6 | */ 7 | export function getPositionBeforeCode(position: vscode.Position, code: string = getActiveText()!) { 8 | const offset = getOffsetFromPosition(position, code) 9 | return code.slice(0, offset) 10 | } 11 | -------------------------------------------------------------------------------- /src/createTerminal.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * @name createTerminal 创建终端 5 | * @param name 终端名称 6 | * @param options TerminalOptions | ExtensionTerminalOptions 7 | * @returns Terminal 8 | */ 9 | export function createTerminal(name: string, options?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions) { 10 | return vscode.window.createTerminal({ 11 | name, 12 | ...options, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/onFold.ts: -------------------------------------------------------------------------------- 1 | import type { Range } from 'vscode' 2 | import * as vscode from 'vscode' 3 | /** 4 | * 折叠指定的 range 5 | * @param rangesToFold Range[] 需要被折叠的 range 6 | * @returns Promise[] 7 | */ 8 | export function onFold(rangesToFold: Range[]) { 9 | return rangesToFold.map(range => 10 | vscode.commands.executeCommand('editor.fold', { 11 | selectionLines: [range.start.line, range.end.line], 12 | }), 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/rename.ts: -------------------------------------------------------------------------------- 1 | import type { Uri } from 'vscode' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 重命名文件 6 | * @param oldUri 原始文件路径 7 | * @param newUri 新的文件路径 8 | * @param options { overwrite?: boolean } 9 | * @param options.overwrite 是否覆盖 10 | * @returns Promise 11 | */ 12 | export function rename(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean }) { 13 | return vscode.workspace.fs.rename(oldUri, newUri, options) 14 | } 15 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "printWidth": 80, 6 | "trailingComma": "all", 7 | "overrides": [ 8 | { 9 | "files": ["*.json5"], 10 | "options": { 11 | "singleQuote": false, 12 | "quoteProps": "preserve" 13 | } 14 | }, 15 | { 16 | "files": ["*.yml"], 17 | "options": { 18 | "singleQuote": false 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/useDark.ts: -------------------------------------------------------------------------------- 1 | import type { WriteableSignal } from './types' 2 | import { signal } from 'alien-signals' 3 | import { addEventListener } from './addEventListener' 4 | import { isDark } from './isDark' 5 | 6 | /** 7 | * 判断当前主题色 8 | * @returns boolean 9 | */ 10 | export function useDark(): WriteableSignal { 11 | const color = signal(isDark()) 12 | addEventListener('theme-change', () => { 13 | color(isDark()) 14 | }) 15 | return color 16 | } 17 | -------------------------------------------------------------------------------- /src/createDefinitionLocation.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 创建定义的位置 5 | * @param url 路径 6 | * @param position 位置 7 | * @returns Location 8 | */ 9 | export function createDefinitionLocation(url: string, position: vscode.Position | number) { 10 | if (typeof position === 'number') 11 | position = new vscode.Position(position, 0) 12 | 13 | return new vscode.Location( 14 | // 定义所在的文件路径 15 | vscode.Uri.file(url), 16 | // 定义所在的行列信息 17 | position, 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/getVisibleRange.ts: -------------------------------------------------------------------------------- 1 | import { getActiveTextEditor } from './getActiveTextEditor' 2 | 3 | export function getVisibleRange() { 4 | const editor = getActiveTextEditor() 5 | if (!editor) 6 | return null 7 | const visibleRanges = editor.visibleRanges 8 | if (visibleRanges.length === 0) 9 | return null 10 | const start = visibleRanges[0].start 11 | const end = visibleRanges[visibleRanges.length - 1].end 12 | return { 13 | start, 14 | end, 15 | ranges: visibleRanges, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/createSquare.ts: -------------------------------------------------------------------------------- 1 | import type { ThemeColor } from 'vscode' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 创建一个方块 6 | * @param backgroundColor 7 | * @returns TextEditorDecorationType 8 | */ 9 | export function createSquare(backgroundColor: string | ThemeColor) { 10 | return vscode.window.createTextEditorDecorationType({ 11 | before: { 12 | contentText: '', 13 | margin: '0 0.2em', 14 | width: '0.8em', 15 | height: '0.8em', 16 | backgroundColor, 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/getConfiguration.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 获取配置 5 | * @param name 配置名,支持直接获取到xx.a下的value 6 | * @returns any 7 | */ 8 | export function getConfiguration(name: string, defaultValue?: T): any { 9 | const splitIndex = name.indexOf('.') 10 | if (splitIndex === -1) 11 | return vscode.workspace.getConfiguration(name) 12 | 13 | const scopedName = name.slice(0, splitIndex) 14 | const propName = name.slice(splitIndex + 1) 15 | return vscode.workspace.getConfiguration(scopedName).get(propName, defaultValue) 16 | } 17 | -------------------------------------------------------------------------------- /src/getCurrentFileUrl.ts: -------------------------------------------------------------------------------- 1 | import type { Uri } from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | 4 | /** 5 | * 获取当前激活文件的路径 6 | * @returns string 7 | */ 8 | export function getCurrentFileUrl(isUri?: T): undefined | (T extends true ? Uri : string) { 9 | const activeTextEditor = getActiveTextEditor() 10 | 11 | if (!activeTextEditor) 12 | return 13 | return (isUri 14 | ? activeTextEditor.document.uri 15 | : activeTextEditor.document.uri.fsPath) as T extends true ? Uri : string 16 | } 17 | -------------------------------------------------------------------------------- /src/openFile.ts: -------------------------------------------------------------------------------- 1 | import type { TextDocumentShowOptions, TextEditor } from 'vscode' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 打开文件 6 | * @param fileUri 文件路径 7 | * @param showOptions 参数控制在哪一个窗口打开,比如侧边栏,是否需要选中某一个区域等 8 | * @returns Promise 9 | */ 10 | export function openFile(fileUri: string, showOptions?: TextDocumentShowOptions): Promise { 11 | return Promise 12 | .resolve(vscode.workspace.openTextDocument(fileUri)) 13 | .then(doc => Promise.resolve(vscode.window.showTextDocument(doc, showOptions))) 14 | } 15 | -------------------------------------------------------------------------------- /src/createInlineCompletionList.ts: -------------------------------------------------------------------------------- 1 | import type { InlineCompletionItemOptions } from './createInlineCompletionItem' 2 | import * as vscode from 'vscode' 3 | import { createInlineCompletionItem } from './createInlineCompletionItem' 4 | 5 | /** 6 | * 创建补全项组 7 | * @param items InlineCompletionItemOptions[] 8 | * @returns InlineCompletionList 9 | */ 10 | export function createInlineCompletionList(items: (InlineCompletionItemOptions & { params?: string | string[] })[]) { 11 | return new vscode.InlineCompletionList(items.map(createInlineCompletionItem)) 12 | } 13 | -------------------------------------------------------------------------------- /src/getOffsetFromPosition.ts: -------------------------------------------------------------------------------- 1 | import type { Position } from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | /** 4 | * 根据position计算出offset位置 5 | * @param position 6 | * @param code 可选参数,如果传入了code,则会根据code计算出offset,如果不填会用当前激活的文档 7 | */ 8 | export function getOffsetFromPosition(position: Position, code?: string) { 9 | if (code) 10 | return code.split('\n').slice(0, position.line).reduce((prev, cur) => prev + cur.length + 1, 0) + (position.character || 0) 11 | 12 | return getActiveTextEditor()?.document.offsetAt(position) 13 | } 14 | -------------------------------------------------------------------------------- /src/saveFile.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | import { nextTick } from './nextTick' 4 | 5 | /** 6 | * 保存文件 7 | * @description 默认保存当前激活的文件,如果传入true,则保存所有文件 8 | * @param isAll Boolean default: false 9 | */ 10 | export function saveFile(isAll: boolean = false) { 11 | const activeTextEditor = getActiveTextEditor() 12 | nextTick(() => { 13 | // 文件已更新,调用保存 14 | if (isAll) 15 | vscode.workspace.saveAll() 16 | else 17 | activeTextEditor?.document.save() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/registerDefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import type { DefinitionProvider, DocumentSelector } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册cmd选中关键词的事件 7 | * @param selector 针对哪一类文件 8 | * @param provideDefinition 回调函数,可返回一个location控制跳转到哪一个路径 9 | * @returns Disposable 10 | */ 11 | export function registerDefinitionProvider(selector: DocumentSelector, provideDefinition: DefinitionProvider['provideDefinition']) { 12 | return addEffect(vscode.languages.registerDefinitionProvider(selector, { provideDefinition })) 13 | } 14 | -------------------------------------------------------------------------------- /src/createProgress.ts: -------------------------------------------------------------------------------- 1 | import type { ProgressOptions } from './types' 2 | import * as vscode from 'vscode' 3 | 4 | export function createProgress(options: ProgressOptions) { 5 | const { title, location = vscode.ProgressLocation.Notification, cancellable = false, cancel, done } = options 6 | return vscode.window.withProgress({ 7 | location, 8 | title, 9 | cancellable, 10 | }, (progress, token) => { 11 | token.onCancellationRequested(() => cancel && cancel()) 12 | progress.report({ increment: 0 }) 13 | return done(progress.report.bind(progress)) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/registerCodeLensProvider.ts: -------------------------------------------------------------------------------- 1 | import type { CodeLensProvider, DocumentSelector } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册代码镜头提供商。多个提供商可以注册一种语言。在这种情况下,供应商被要求在并行,结果被合并。失败的提供商(被拒绝的承诺或例外)将不会导致整个操作失败。 7 | * @param selector 定义此提供商适用的文档的选择器。 8 | * @param provider 代码镜头提供商。 9 | * @return A {@link Disposable} 在处置时取消注册此提供商。 10 | */ 11 | export function registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider) { 12 | return addEffect(vscode.languages.registerCodeLensProvider(selector, provider)) 13 | } 14 | -------------------------------------------------------------------------------- /src/createCompletionList.ts: -------------------------------------------------------------------------------- 1 | import type { CompletionItemOptions, CreatedCompletionItem } from './createCompletionItem' 2 | import * as vscode from 'vscode' 3 | import { createCompletionItem } from './createCompletionItem' 4 | 5 | /** 6 | * 创建补全项组 7 | * @param items CompletionItemOptions[] 8 | * @returns CompletionList 9 | */ 10 | export function createCompletionList(items: (CompletionItemOptions & { params?: TParams })[]): vscode.CompletionList> { 11 | return new vscode.CompletionList(items.map(item => createCompletionItem(item))) 12 | } 13 | -------------------------------------------------------------------------------- /src/setConfiguration.ts: -------------------------------------------------------------------------------- 1 | import type { ConfigurationTarget } from 'vscode' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 设置配置 6 | * @param name 配置名 7 | * @param value 值 8 | * @param configurationTarget 范围 9 | * @param overrideInLanguage 是否覆盖默认 10 | * @returns Promise 11 | */ 12 | export function setConfiguration(name: string, value: any, configurationTarget?: ConfigurationTarget | boolean | null, overrideInLanguage?: boolean) { 13 | const config = vscode.workspace.getConfiguration() 14 | return config.update(name, value, configurationTarget, overrideInLanguage) 15 | } 16 | -------------------------------------------------------------------------------- /src/getCalcPosition.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption1, PositionOption2 } from './types' 2 | import { createPosition } from './createPosition' 3 | import { getActiveText } from './getActiveText' 4 | import { getOffsetFromPosition } from './getOffsetFromPosition' 5 | import { getPosition } from './getPosition' 6 | /** 7 | * 根据 position 和 offset 得到计算后的 position 8 | */ 9 | export function getCalcPosition(position: PositionOption2 | PositionOption1, offset: number, content: string = getActiveText()!) { 10 | const pos = createPosition(position) 11 | const realOffset = getOffsetFromPosition(pos)! + offset 12 | return getPosition(realOffset, content) 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "dev", 9 | "isBackground": true, 10 | "presentation": { 11 | "reveal": "never" 12 | }, 13 | "problemMatcher": [ 14 | { 15 | "base": "$tsc", 16 | "background": { 17 | "activeOnStart": true, 18 | "beginsPattern": "Build start", 19 | "endsPattern": "Build success" 20 | } 21 | } 22 | ], 23 | "group": "build" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/getRootPath.ts: -------------------------------------------------------------------------------- 1 | import type { Uri } from 'vscode' 2 | import { workspace } from 'vscode' 3 | import { getActiveTextEditor } from './getActiveTextEditor' 4 | /** 5 | * 获取当前工作区的根目录 6 | * @returns 返回当前工作区的根目录 7 | */ 8 | export function getRootPath(isUri?: T): undefined | (T extends true ? Uri : string) { 9 | const activeEditor = getActiveTextEditor() 10 | if (workspace.workspaceFolders && activeEditor) { 11 | const activeFolder = workspace.getWorkspaceFolder(activeEditor.document.uri) 12 | if (activeFolder) { 13 | return (isUri 14 | ? activeFolder.uri 15 | : activeFolder.uri.fsPath) as T extends true ? Uri : string 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/getRefConfigutation.ts: -------------------------------------------------------------------------------- 1 | import { addEventListener } from './addEventListener' 2 | import { getConfiguration } from './getConfiguration' 3 | 4 | /** 5 | * 获取配置 6 | * @param name 配置名,支持直接获取到xx.a下的value 7 | * @returns any 8 | */ 9 | export function getRefConfiguration(name: string, defaultValue?: T): any { 10 | const scopedName = name.split('.')[0] 11 | 12 | let value = getConfiguration(name, defaultValue) 13 | 14 | return { 15 | get value() { 16 | return value 17 | }, 18 | dispose: addEventListener('config-change', (e) => { 19 | if (e.affectsConfiguration(scopedName)) { 20 | value = getConfiguration(name, defaultValue) 21 | } 22 | }), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/createExtension.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | import { createEffectDeps } from './util' 3 | 4 | export function createExtension(activate: (context: vscode.ExtensionContext, disposals?: vscode.Disposable[]) => void | vscode.Disposable[] | Promise, deactivate?: (ext: any) => void) { 5 | const wrapperActivate = async (context: vscode.ExtensionContext) => { 6 | const disposals: vscode.Disposable[] = createEffectDeps() 7 | const dispose = await activate(context, disposals) 8 | if (dispose) 9 | disposals.push(...dispose) 10 | 11 | context.subscriptions.push(...disposals) 12 | } 13 | return { 14 | activate: wrapperActivate, 15 | deactivate, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/watchFiles.ts: -------------------------------------------------------------------------------- 1 | import type { GlobPattern } from 'vscode' 2 | import type { WatchFilesOptions } from './types' 3 | import { watchFile } from './watchFile' 4 | 5 | /** 6 | * 监听多个文件变化 7 | * @param globPatterns 过滤规则数组 8 | * @param options 参数 可监听文件的变化、删除等 9 | * @returns 取消监听的函数 10 | */ 11 | export function watchFiles(globPatterns: GlobPattern[], options: WatchFilesOptions) { 12 | const { onCreate, onChange, onDelete, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents } = options 13 | const disposals = globPatterns.map(globPattern => watchFile(globPattern, { onCreate, onChange, onDelete, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents })) 14 | 15 | return () => disposals.forEach(disposal => disposal()) 16 | } 17 | -------------------------------------------------------------------------------- /src/createDebugTerminal.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | /** 4 | * 创建一个调试终端 5 | * @param command 参数 6 | * @param name 终端名称 7 | * @param request 调试会话的请求类型 'launch' | 'attach' 默认 'launch' 8 | * @returns Thenable 9 | */ 10 | export function createDebugTerminal(command: string, name = 'Javascript Debug Terminal', request: 'launch' | 'attach' = 'launch') { 11 | const _command = command.trim().split(' ') 12 | const runtimeExecutable = _command[0] 13 | const runtimeArgs = _command.slice(1).filter(Boolean) 14 | return vscode.debug.startDebugging(undefined, { 15 | type: 'node', 16 | request, 17 | name, 18 | runtimeExecutable, 19 | runtimeArgs, 20 | console: 'integratedTerminal', 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /src/registerTerminalLinkProvider.ts: -------------------------------------------------------------------------------- 1 | import type { ProviderResult } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册终端链接提供者 7 | * @param provideTerminalLinks 回调函数,可返回终端中可点击的链接 8 | * @param handleTerminalLink 回调函数,处理链接点击事件 9 | * @returns Disposable 10 | */ 11 | export function registerTerminalLinkProvider( 12 | provideTerminalLinks: (context: vscode.TerminalLinkContext, token: vscode.CancellationToken) => ProviderResult, 13 | handleTerminalLink: (link: vscode.TerminalLink) => void, 14 | ): vscode.Disposable { 15 | return addEffect(vscode.window.registerTerminalLinkProvider({ 16 | provideTerminalLinks, 17 | handleTerminalLink, 18 | })) 19 | } 20 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/dist/**/*.js" 18 | ], 19 | "preLaunchTask": "npm: dev" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/registerCodeActionsProvider.ts: -------------------------------------------------------------------------------- 1 | import type { CodeActionProvider, CodeActionProviderMetadata, DocumentSelector } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册代码动作提供程序。 7 | * 8 | * 一种语言可注册多个提供程序。在这种情况下 9 | * 并行询问,然后合并结果。失败的提供程序(被拒绝的承诺或异常)不会导致整个操作失败。 10 | * 不会导致整个操作失败。 11 | * 12 | * @param selector 一个选择器,用于定义此提供程序适用的文档。 13 | * @param provider 一个代码操作提供程序。 14 | * @param metadata 关于提供者提供的代码操作类型的元数据。 15 | * @return 一个{@link Disposable},当该提供程序被弃置时会取消注册。 16 | */ 17 | export function registerCodeActionsProvider(selector: DocumentSelector, provider: CodeActionProvider, metadata?: CodeActionProviderMetadata) { 18 | return addEffect(vscode.languages.registerCodeActionsProvider(selector, provider, metadata)) 19 | } 20 | -------------------------------------------------------------------------------- /src/setStyle.ts: -------------------------------------------------------------------------------- 1 | import type { Range, TextEditorDecorationType } from 'vscode' 2 | import type { ClearStyle } from './types' 3 | import { getActiveTextEditor } from './getActiveTextEditor' 4 | 5 | /** 6 | * 设置样式 7 | * @param decorationType 8 | * @param range 9 | * @returns ClearStyle 10 | */ 11 | export function setStyle(decorationType: TextEditorDecorationType, range?: Range | Range[]): ClearStyle | undefined { 12 | const activeTextEditor = getActiveTextEditor() 13 | if (!activeTextEditor) 14 | return 15 | 16 | const rangeOrOptins = range 17 | ? Array.isArray(range) 18 | ? range 19 | : [range] 20 | : [] 21 | activeTextEditor.setDecorations(decorationType, rangeOrOptins as Range[]) 22 | return () => activeTextEditor.setDecorations(decorationType, []) 23 | } 24 | -------------------------------------------------------------------------------- /src/setSelections.ts: -------------------------------------------------------------------------------- 1 | import type { ISelections } from './types' 2 | import * as vscode from 'vscode' 3 | import { createRange } from './createRange' 4 | import { getActiveTextEditor } from './getActiveTextEditor' 5 | 6 | /** 7 | * 设置多个选中区域 8 | * @param selectionsOptions 9 | */ 10 | export function setSelections(selectionsOptions: ISelections) { 11 | const selections = selectionsOptions.map(({ start, end, position }) => { 12 | const range = createRange(start, end) 13 | const selection = (position || 'right') === 'left' 14 | ? new vscode.Selection(range.end, range.start) 15 | : new vscode.Selection(range.start, range.end) 16 | return selection 17 | }) 18 | const activeTextEditor = getActiveTextEditor() 19 | if (activeTextEditor) 20 | activeTextEditor.selections = selections 21 | } 22 | -------------------------------------------------------------------------------- /src/getPosition.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | import { getActiveText } from './getActiveText' 3 | /** 4 | * 根据offset获取行列 5 | */ 6 | export function getPosition(offset: number, content: string = getActiveText()!) { 7 | const contents = content.split('\n') 8 | const max = contents.length 9 | let num = 0 10 | let line = 0 11 | let column = 0 12 | for (let n = 0; n < max; n++) { 13 | const cur = num + contents[n].length + (n > 0 ? 1 : 0) 14 | line = n 15 | column = offset - num - (n > 0 ? 1 : 0) 16 | if (num <= offset && cur >= offset) 17 | break 18 | 19 | num = cur 20 | } 21 | 22 | column = Math.min(column, contents[line].length) 23 | return { 24 | line, 25 | column, 26 | character: column, 27 | offset, 28 | position: new vscode.Position(line, column), 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/registerHoverProvider.ts: -------------------------------------------------------------------------------- 1 | import type { DocumentSelector, HoverProvider } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册鼠标悬停事件 7 | * @param selector 针对哪一类文件 8 | * @param provideHover 回调函数,可返回一个Hover控制鼠标悬停时显示的内容 9 | * @returns Disposable 10 | */ 11 | export function registerHoverProvider(selector: DocumentSelector, provideHover: HoverProvider['provideHover'], output?: boolean) { 12 | const provideHoverWrapper: HoverProvider['provideHover'] = (document, position, token) => { 13 | // 不处理 hover output 时的事件 14 | if (!output && document.uri.scheme === 'output') 15 | return 16 | 17 | return provideHover(document, position, token) 18 | } 19 | return addEffect(vscode.languages.registerHoverProvider(selector, { provideHover: provideHoverWrapper })) 20 | } 21 | -------------------------------------------------------------------------------- /src/registerInlineCompletionItemProvider.ts: -------------------------------------------------------------------------------- 1 | import type { DocumentSelector, InlineCompletionItem, InlineCompletionList, ProviderResult } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册内联自动补全 7 | * @param provideInlineCompletionItems 回调函数,可返回一个InlineCompletionItem控制显示的内容 8 | * @returns Disposable 9 | */ 10 | export function registerInlineCompletionItemProvider( 11 | provideInlineCompletionItems: (document: vscode.TextDocument, position: vscode.Position, context: vscode.InlineCompletionContext, token: vscode.CancellationToken) => ProviderResult, 12 | selector: DocumentSelector = { pattern: '**' }, 13 | ) { 14 | return addEffect(vscode.languages.registerInlineCompletionItemProvider(selector, { 15 | provideInlineCompletionItems, 16 | })) 17 | } 18 | -------------------------------------------------------------------------------- /src/useConfiguration.ts: -------------------------------------------------------------------------------- 1 | import type { WriteableSignal } from './types' 2 | import { signal } from 'alien-signals' 3 | import { addEventListener } from './addEventListener' 4 | import { getConfiguration } from './getConfiguration' 5 | 6 | /** 7 | * 获取配置 8 | * @param name 配置名,支持直接获取到xx.a下的value 9 | * @returns any 10 | */ 11 | type ScopedName = `${string}.${string}` 12 | 13 | export function useConfiguration(name: ScopedName, defaultValue?: T): WriteableSignal { 14 | const splitIndex = name.indexOf('.') 15 | const scopedName = name.slice(0, splitIndex) 16 | const initialValue = getConfiguration(name, defaultValue) 17 | 18 | const config = signal(initialValue as T) 19 | addEventListener('config-change', (e) => { 20 | if (e.affectsConfiguration(scopedName)) 21 | config(getConfiguration(name, defaultValue) as T) 22 | }) 23 | return config 24 | } 25 | -------------------------------------------------------------------------------- /src/watchFile.ts: -------------------------------------------------------------------------------- 1 | import type { GlobPattern } from 'vscode' 2 | import type { WatchFilesOptions } from './types' 3 | import { workspace } from 'vscode' 4 | import { addEffect } from './util' 5 | 6 | /** 7 | * 监听文件变化 8 | * @param globPattern 过滤规则 9 | * @param options 参数 可监听文件的变化、删除等 10 | * @returns 取消监听的函数 11 | */ 12 | export function watchFile(globPattern: GlobPattern, options: WatchFilesOptions) { 13 | const { onCreate, onChange, onDelete, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents } = options 14 | const watcher = workspace.createFileSystemWatcher(globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents) 15 | 16 | if (onCreate) 17 | watcher.onDidCreate(onCreate) 18 | if (onChange) 19 | watcher.onDidChange(onChange) 20 | if (onDelete) 21 | watcher.onDidDelete(onDelete) 22 | 23 | addEffect(watcher) 24 | 25 | return () => watcher.dispose() 26 | } 27 | -------------------------------------------------------------------------------- /src/registerInlayHintsProvider.ts: -------------------------------------------------------------------------------- 1 | import type { DocumentSelector } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册inlayHints事件 7 | * @param filter 针对哪一类文件 8 | * @param callback 回调函数,可返回一个InlayHint控制显示的内容 9 | * @returns Disposable 10 | */ 11 | export function registerInlayHintsProvider(filter: DocumentSelector, callback: (document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken) => vscode.ProviderResult) { 12 | class MyInlayHintsProvider implements vscode.InlayHintsProvider { 13 | provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): vscode.ProviderResult { 14 | return callback(document, range, token) 15 | } 16 | } 17 | return addEffect(vscode.languages.registerInlayHintsProvider(filter, new MyInlayHintsProvider())) 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | id-token: write 5 | contents: write 6 | 7 | on: 8 | push: 9 | tags: 10 | - 'v*' 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | - uses: pnpm/action-setup@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: lts/* 23 | registry-url: https://registry.npmjs.org/ 24 | 25 | - run: pnpm dlx changelogithub 26 | env: 27 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | 29 | # # Uncomment the following lines to publish to npm on CI 30 | # 31 | # - run: pnpm install 32 | # - run: pnpm publish -r --access public 33 | # env: 34 | # NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 35 | # NPM_CONFIG_PROVENANCE: true 36 | -------------------------------------------------------------------------------- /src/createInlayHint.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | export interface InlayHintOptions { 4 | position: vscode.Position 5 | label: string | vscode.InlayHintLabelPart[] 6 | tooltip?: string | vscode.MarkdownString | undefined 7 | kind?: vscode.InlayHintKind 8 | textEdits?: vscode.TextEdit[] 9 | paddingLeft?: boolean 10 | paddingRight?: boolean 11 | } 12 | 13 | /** 14 | * 创建InlayHint 15 | * @param options InlayHintOptions 16 | * @param options.position 位置 17 | * @param options.label 标签 18 | * @param options.tooltip 提示 19 | * @param options.kind 类型 20 | * @param options.textEdits 文本编辑 21 | * @param options.paddingLeft 是否左边填充 22 | * @param options.paddingRight 是否右边填充 23 | * @returns InlayHint 24 | */ 25 | export function createInlayHint(options: InlayHintOptions) { 26 | const { position, label, kind } = options 27 | return Object.assign(new vscode.InlayHint(position, label, kind), options) 28 | } 29 | -------------------------------------------------------------------------------- /src/createStyleAnimation.ts: -------------------------------------------------------------------------------- 1 | import type { DecorationRenderOptions, Range } from 'vscode' 2 | import type { ClearStyle } from './types' 3 | import { createStyle } from './createStyle' 4 | import { setStyle } from './setStyle' 5 | 6 | /** 7 | * createStyleAnimation 8 | * @param s1 DecorationRenderOptions 9 | * @param s2 DecorationRenderOptions 10 | * @param options { duration?: number; range: Range; delay?: number } 11 | * @param options.duration number 动画持续时间 12 | * @param options.range Range 范围 13 | * @param options.delay number 动画延迟时间 14 | * @returns 第二个动画的清除函数 15 | */ 16 | export function createStyleAnimation(s1: DecorationRenderOptions, s2: DecorationRenderOptions, options: { duration?: number, range: Range, delay?: number }): Promise { 17 | const { duration = 1000, range, delay = 0 } = options 18 | return new Promise((resolve) => { 19 | setTimeout(() => { 20 | const dispose = setStyle(createStyle(s1), range) 21 | setTimeout(() => { 22 | dispose?.() 23 | resolve(setStyle(createStyle(s2), range)) 24 | }, duration) 25 | }, delay) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Simon He 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scripts/verifyCommit.ts: -------------------------------------------------------------------------------- 1 | // Invoked on the commit-msg git hook by simple-git-hooks. 2 | 3 | import { readFileSync } from 'node:fs' 4 | import process from 'node:process' 5 | import colors from 'picocolors' 6 | 7 | // get $1 from commit-msg script 8 | const msgPath = process.argv[2] 9 | const msg = readFileSync(msgPath, 'utf-8').trim() 10 | 11 | const releaseRE = /^v\d/ 12 | const commitRE 13 | = /^(?:revert: )?(?:feat|fix|docs|dx|refactor|perf|test|workflow|build|ci|chore|types|wip|release|deps)(?:\(.+\))?!?: .{1,50}/ 14 | 15 | if (!releaseRE.test(msg) && !commitRE.test(msg)) { 16 | console.log() 17 | console.error( 18 | ` ${colors.bgRed(colors.white(' ERROR '))} ${colors.red( 19 | 'invalid commit message format.', 20 | )}\n\n${colors.red( 21 | ' Proper commit message format is required for automated changelog generation. Examples:\n\n', 22 | )} ${colors.green('feat: add \'comments\' option')}\n` 23 | + ` ${colors.green( 24 | 'fix: handle events on blur (close #28)', 25 | )}\n\n${colors.red( 26 | ' See .github/commit-convention.md for more details.\n', 27 | )}`, 28 | ) 29 | process.exit(1) 30 | } 31 | -------------------------------------------------------------------------------- /src/updateText.ts: -------------------------------------------------------------------------------- 1 | import type { TextEditor, TextEditorEdit } from 'vscode' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | 4 | /** 5 | * 操作当前激活文件的数据比如更新、替换、新增等 6 | * @param callback 回调函数,接收一个 TextEditorEdit 对象作为参数 7 | * @param options 可选参数对象 8 | * @param options.undoStopBefore 添加撤销停止点 9 | * @param options.undoStopAfter 添加撤销停止点 10 | * @param options.textEditor 指定的文本编辑器,默认为当前激活的编辑器 11 | * @returns Promise 12 | */ 13 | export function updateText(callback: (editBuilder: TextEditorEdit) => void, options: { 14 | /** 15 | * Add undo stop before making the edits. 16 | */ 17 | readonly undoStopBefore?: boolean 18 | /** 19 | * Add undo stop after making the edits. 20 | */ 21 | readonly undoStopAfter?: boolean 22 | /** 23 | * The active text editor. 24 | */ 25 | readonly textEditor?: TextEditor 26 | } = { undoStopBefore: false, undoStopAfter: false, textEditor: getActiveTextEditor() }) { 27 | const activeTextEditor = options.textEditor 28 | if (activeTextEditor) 29 | return activeTextEditor.edit(callback, options as { undoStopBefore: boolean, undoStopAfter: boolean }) 30 | 31 | return Promise.resolve(false) 32 | } 33 | -------------------------------------------------------------------------------- /src/createPosition.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption1, PositionOption2 } from './types' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 创建位置 6 | * @description create position 7 | * @returns Position 8 | */ 9 | export function createPosition(pos: number, pos1: number, offsetLine?: number, offsetColumn?: number): vscode.Position 10 | export function createPosition(pos: PositionOption2 | PositionOption1, offsetLine?: number, offsetColumn?: number): vscode.Position 11 | export function createPosition(pos: PositionOption2 | PositionOption1 | number, pos1?: number, offsetLine: number = 0, offsetColumn: number = 0) { 12 | if (Array.isArray(pos)) 13 | return new vscode.Position(pos[0] - offsetLine, pos[1] - offsetColumn) 14 | 15 | if (typeof pos === 'number') 16 | return new vscode.Position(pos - offsetLine, pos1! - offsetColumn) 17 | 18 | const columnArgProvided = arguments.length >= 4 19 | const lineOffset = typeof pos1 === 'number' ? pos1 : 0 20 | const columnOffset = columnArgProvided ? offsetColumn : offsetLine || 0 21 | return new vscode.Position((pos as PositionOption2).line - lineOffset, ((pos as PositionOption2).character ?? (pos as PositionOption2).column!) - columnOffset) 22 | } 23 | -------------------------------------------------------------------------------- /src/createInlineCompletionItem.ts: -------------------------------------------------------------------------------- 1 | import type { Command, Range, SnippetString } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { createSnippetString } from './createSnippetString' 4 | 5 | export interface InlineCompletionItemOptions { 6 | insertText: string | SnippetString 7 | filterText?: string 8 | range?: Range 9 | command?: Command 10 | insertAsSnippet?: boolean 11 | } 12 | 13 | /** 14 | * 创建补全项 15 | * @param options InlineCompletionItemOptions 16 | * @param options.insertText string | SnippetString 补全项的内容 17 | * @param options.filterText string 补全项的过滤文本 18 | * @param options.range Range 补全项的范围 19 | * @param options.command Command 补全项的命令 20 | * @returns InlineCompletionItem 21 | */ 22 | export function createInlineCompletionItem(options: InlineCompletionItemOptions & { params?: TParams }) { 23 | const { insertText, range, command, insertAsSnippet } = options 24 | const normalizedInsertText = typeof insertText === 'string' && insertAsSnippet 25 | ? createSnippetString(insertText) 26 | : insertText 27 | 28 | return Object.assign(new vscode.InlineCompletionItem(normalizedInsertText, range, command), options) 29 | } 30 | -------------------------------------------------------------------------------- /src/getSelection.ts: -------------------------------------------------------------------------------- 1 | import { createRange } from './createRange' 2 | import { getActiveTextEditor } from './getActiveTextEditor' 3 | import { getLineText } from './getLineText' 4 | import { getOffsetFromPosition } from './getOffsetFromPosition' 5 | 6 | /** 7 | * 获取选中区域的一些信息 8 | * @returns 选中区域的一些信息 9 | */ 10 | export function getSelection() { 11 | const activeTextEditor = getActiveTextEditor() 12 | if (activeTextEditor) { 13 | const { line, character } = activeTextEditor.selection.active 14 | const code = activeTextEditor.document.getText() 15 | return { 16 | line, 17 | character, 18 | lineText: activeTextEditor.document.lineAt(line).text, 19 | selection: activeTextEditor.selection, 20 | selectedTextArray: activeTextEditor.selections.map(selection => 21 | code.slice(getOffsetFromPosition(selection.start, code), getOffsetFromPosition(selection.end, code)), 22 | ), 23 | selectionArray: activeTextEditor.selections.map(s => Object.assign(s, { 24 | lineText: getLineText(s.active.line)!, 25 | text: code.slice(getOffsetFromPosition(s.start, code), getOffsetFromPosition(s.end, code)), 26 | selection: createRange(s.start, s.end), 27 | })), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/createStyleAnimations.ts: -------------------------------------------------------------------------------- 1 | import type { DecorationRenderOptions, Range } from 'vscode' 2 | import type { ClearStyle } from './types' 3 | import { createStyle } from './createStyle' 4 | import { setStyle } from './setStyle' 5 | 6 | /** 7 | * createStyleAnimations 8 | * @param styles { style: DecorationRenderOptions; duration?: number; delay?: number }[] 样式组 9 | * @param options { duration?: number; range: Range; delay?: number } 10 | * @param options.duration number 动画持续时间 11 | * @param options.range Range 范围 12 | * @param options.delay number 动画延迟时间 13 | * @returns 最后一个动画的清除函数 14 | */ 15 | export async function createStyleAnimations(styles: { style: DecorationRenderOptions, duration?: number, delay?: number }[], options: { duration?: number, range: Range, delay?: number }): Promise { 16 | let lastClearStyle!: ClearStyle 17 | for (const s of styles) { 18 | if (lastClearStyle) 19 | lastClearStyle() 20 | const style = createStyle(s.style) 21 | const duration = s.duration ?? options.duration ?? 0 22 | const delay = s.delay ?? options.delay ?? 0 23 | await new Promise(resolve => 24 | setTimeout(() => { 25 | lastClearStyle = setStyle(style, options.range)! 26 | setTimeout(resolve, duration) 27 | }, delay), 28 | ) 29 | } 30 | return lastClearStyle 31 | } 32 | -------------------------------------------------------------------------------- /src/addEventListeners.ts: -------------------------------------------------------------------------------- 1 | import type * as vscode from 'vscode' 2 | import type { authenticationMap, eventMap, workspaceMap } from './addEventListener' 3 | import type { EventCallbackMap, WorkspaceCallbackMap } from './types' 4 | import { addEventListener } from './addEventListener' 5 | 6 | /** 7 | * 添加多个事件监听 8 | * @param options Array<[T, 9 | T extends keyof EventCallbackMap 10 | ? EventCallbackMap[T] 11 | : T extends keyof WorkspaceCallbackMap 12 | ? WorkspaceCallbackMap[T] 13 | : T extends keyof typeof authenticationMap 14 | ? (providerId: string, getSession: (name: string) => Promise) => void 15 | : never,]> 16 | * @returns 17 | */ 18 | 19 | type EventListenerTuple = { 20 | [K in keyof typeof eventMap]: [K, EventCallbackMap[K]] 21 | }[keyof typeof eventMap] 22 | 23 | type WorkspaceListenerTuple = { 24 | [K in keyof typeof workspaceMap]: [K, WorkspaceCallbackMap[K]] 25 | }[keyof typeof workspaceMap] 26 | 27 | type AuthListenerTuple = { 28 | [K in keyof typeof authenticationMap]: [K, (providerId: string, getSession: (name: string) => Promise) => void] 29 | }[keyof typeof authenticationMap] 30 | 31 | type ListenerTuple = EventListenerTuple | WorkspaceListenerTuple | AuthListenerTuple 32 | 33 | export function addEventListeners(options: ListenerTuple[]) { 34 | return options.map(([type, callback]) => addEventListener(type as any, callback as any)) 35 | } 36 | -------------------------------------------------------------------------------- /src/createInput.ts: -------------------------------------------------------------------------------- 1 | import type { CreateInputOptions } from './types' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 创建输入框 6 | * @param options { 7 | ignoreFocusOut?: boolean 8 | password?: boolean 9 | prompt?: string 10 | title?: string 11 | value: string 12 | selection?: [number, number] 13 | placeHolder?: string 14 | validate?: (value: string) => string | InputBoxValidationMessage | undefined | null | 15 | Thenable 16 | } 17 | * @param options.ignoreFocusOut boolean 是否忽略焦点 18 | * @param options.password boolean 是否是密码输入框 19 | * @param options.prompt string 提示 20 | * @param options.title string 标题 21 | * @param options.value string 默认值 22 | * @param options.selection [number, number] 默认选中范围 23 | * @param options.placeHolder string 占位符 24 | * @param options.validate (value: string) => string | InputBoxValidationMessage | undefined | null | Thenable 验证函数 25 | * @returns Thenable 26 | */ 27 | export function createInput(options: CreateInputOptions) { 28 | return vscode.window.showInputBox({ 29 | prompt: options.prompt, 30 | password: options.password, 31 | title: options.title, 32 | value: options.value, 33 | valueSelection: options.selection, 34 | placeHolder: options.placeHolder, 35 | validateInput: options.validate, 36 | ignoreFocusOut: options.ignoreFocusOut ?? true, 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /src/createFakeProgress.ts: -------------------------------------------------------------------------------- 1 | import { createProgress } from './createProgress' 2 | 3 | export function createFakeProgress(options: { 4 | title: string 5 | interval?: number 6 | message?: (increment: number) => string | void 7 | callback: (resolve: (value?: unknown) => void, reject: (msg?: string) => void) => void 8 | }) { 9 | const { title, interval = 10, message, callback } = options 10 | createProgress({ 11 | title, 12 | async done(report) { 13 | try { 14 | let timer 15 | await new Promise((_resolve, _reject) => { 16 | let increment = 0 17 | callback(_resolve, _reject) 18 | timer = setInterval(() => { 19 | if (increment < 99) { 20 | increment++ 21 | report({ 22 | message: message?.(increment) || `Progress bar ${increment}% completed`, 23 | increment, 24 | }) 25 | } 26 | }, interval) 27 | }) 28 | 29 | clearInterval(timer) 30 | report({ 31 | message: message?.(100) || `Progress bar 100% completed`, 32 | increment: 100, 33 | }) 34 | 35 | await new Promise((resolve) => { 36 | setTimeout(() => { 37 | resolve(true) 38 | }, 100) 39 | }) 40 | } 41 | catch (error) { 42 | report({ 43 | message: String(error) || '❌ Something Wrong', 44 | increment: 100, 45 | }) 46 | } 47 | }, 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /src/useTheme.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | 3 | function getCurrentTheme() { 4 | const config = vscode.workspace.getConfiguration() 5 | return config.get('workbench.colorTheme') as string 6 | } 7 | 8 | function getAllTheme() { 9 | const extensions = vscode.extensions.all 10 | const themeColors: { label: string, path: string, id: string, uiTheme: string }[] = [] 11 | 12 | // 遍历所有已安装的扩展 13 | for (const extension of extensions) { 14 | const packageJSON = extension.packageJSON 15 | 16 | // 检查扩展是否定义了主题色 17 | if (packageJSON && packageJSON.contributes && packageJSON.contributes.themes) { 18 | const themes = packageJSON.contributes.themes 19 | 20 | // 遍历扩展中的主题色 21 | for (const theme of themes) { 22 | if (theme.label && theme.path) 23 | themeColors.push(theme) 24 | } 25 | } 26 | } 27 | 28 | return themeColors 29 | } 30 | 31 | function setTheme(theme: string) { 32 | const config = vscode.workspace.getConfiguration() 33 | return Promise.all( 34 | [ 35 | config.update('workbench.colorTheme', theme, vscode.ConfigurationTarget.Global), 36 | config.update('workbench.preferredLightColorTheme', theme, vscode.ConfigurationTarget.Global), 37 | config.update('workbench.preferredDarkColorTheme', theme, vscode.ConfigurationTarget.Global), 38 | ], 39 | ) 40 | } 41 | 42 | /** 43 | * 获取和操作当前主题色相关信息 44 | * @returns 主题色相关操作 45 | */ 46 | export function useTheme() { 47 | return { 48 | getCurrentTheme, 49 | getAllTheme, 50 | setTheme, 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/createBottomBar.ts: -------------------------------------------------------------------------------- 1 | import type { BarOptions } from './types' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 创建底部栏 6 | * @param options { 7 | position?: 'left' | 'right' // 栏的位置 8 | offset?: number // 栏的偏移量 9 | text: string // 栏的文本 10 | tooltip?: string // 栏的提示 11 | color?: string | ThemeColor | undefined // 栏的颜色 12 | backgroundColor?: ThemeColor | undefined // 栏的背景颜色 13 | command?: string | Command | undefined // 栏的命令 14 | accessibilityInformation?: AccessibilityInformation | undefined // 栏的辅助信息 15 | } 16 | * @param options.position 'left' | 'right' 栏的位置 17 | * @param options.offset number 栏的偏移量 18 | * @param options.text string 栏的文本 19 | * @param options.tooltip string 栏的提示 20 | * @param options.color string | ThemeColor | undefined 栏的颜色 21 | * @param options.backgroundColor ThemeColor | undefined 栏的背景颜色 22 | * @param options.command string | Command | undefined 栏的命令 23 | * @param options.accessibilityInformation AccessibilityInformation | undefined 栏的辅助信息 24 | * @returns StatusBarItem 25 | */ 26 | export function createBottomBar(options: BarOptions) { 27 | const { position = 'left', offset, text, tooltip, color, backgroundColor, accessibilityInformation, command } = options 28 | const positionMap = { 29 | left: 1, 30 | right: 2, 31 | } 32 | const statusBarItem = vscode.window.createStatusBarItem(positionMap[position], offset) 33 | statusBarItem.text = text 34 | statusBarItem.tooltip = tooltip 35 | statusBarItem.color = color 36 | statusBarItem.backgroundColor = backgroundColor 37 | statusBarItem.accessibilityInformation = accessibilityInformation 38 | statusBarItem.command = command 39 | 40 | return statusBarItem 41 | } 42 | -------------------------------------------------------------------------------- /src/registerCompletionItemProvider.ts: -------------------------------------------------------------------------------- 1 | import type { CancellationToken, CompletionItem, CompletionItemProvider, CompletionList, ProviderResult } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 注册自动补全 7 | * @param filter 设置针对什么语言才会触发自动补全 8 | * @param provideCompletionItems 为给定的职位和文件提供完成项目 9 | * @param resolveOrTrigger 给定一个完成项,填写更多数据或直接传入触发字符 10 | * @param triggerCharacters 触发条件比如通过输入某一个字符触发(在显式提供 resolve 时使用) 11 | * @returns Disposable 12 | */ 13 | export function registerCompletionItemProvider( 14 | filter: string | string[], 15 | provideCompletionItems: (document: vscode.TextDocument, position: vscode.Position) => ProviderResult>, 16 | resolveOrTrigger?: ((item: T, token: CancellationToken) => ProviderResult) | string | string[], 17 | triggerCharacters: string | string[] = [], 18 | ) { 19 | let resolveCompletionItem: ((item: T, token: CancellationToken) => ProviderResult) | undefined 20 | let characters: string[] 21 | 22 | if (typeof resolveOrTrigger === 'function') { 23 | resolveCompletionItem = resolveOrTrigger 24 | characters = Array.isArray(triggerCharacters) ? triggerCharacters : [triggerCharacters] 25 | } 26 | else { 27 | const provided = resolveOrTrigger ?? triggerCharacters 28 | characters = Array.isArray(provided) ? provided : [provided] 29 | } 30 | 31 | const provider: CompletionItemProvider = resolveCompletionItem 32 | ? { provideCompletionItems, resolveCompletionItem } 33 | : { provideCompletionItems } 34 | 35 | return addEffect(vscode.languages.registerCompletionItemProvider( 36 | filter, 37 | provider, 38 | ...characters, 39 | )) 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Install pnpm 19 | uses: pnpm/action-setup@v4 20 | 21 | - name: Set node 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: lts/* 25 | 26 | - name: Setup 27 | run: npm i -g @antfu/ni 28 | 29 | - name: Install 30 | run: nci 31 | 32 | - name: Lint 33 | run: nr lint:fix 34 | 35 | typecheck: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | 40 | - name: Install pnpm 41 | uses: pnpm/action-setup@v4 42 | 43 | - name: Set node 44 | uses: actions/setup-node@v4 45 | with: 46 | node-version: lts/* 47 | 48 | - name: Setup 49 | run: npm i -g @antfu/ni 50 | 51 | - name: Install 52 | run: nci 53 | 54 | - name: Typecheck 55 | run: nr typecheck 56 | 57 | test: 58 | runs-on: ${{ matrix.os }} 59 | 60 | strategy: 61 | matrix: 62 | node: [lts/*] 63 | os: [ubuntu-latest, windows-latest, macos-latest] 64 | fail-fast: false 65 | 66 | steps: 67 | - uses: actions/checkout@v4 68 | 69 | - name: Install pnpm 70 | uses: pnpm/action-setup@v4 71 | 72 | - name: Set node ${{ matrix.node }} 73 | uses: actions/setup-node@v4 74 | with: 75 | node-version: ${{ matrix.node }} 76 | 77 | - name: Setup 78 | run: npm i -g @antfu/ni 79 | 80 | - name: Install 81 | run: nci 82 | 83 | - name: Build 84 | run: nr build 85 | 86 | - name: Test 87 | run: nr test 88 | -------------------------------------------------------------------------------- /src/isInPosition.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption2, RangeLoc } from './types' 2 | import { createPosition } from './createPosition' 3 | import { getActiveText } from './getActiveText' 4 | import { getOffsetFromPosition } from './getOffsetFromPosition' 5 | 6 | /** 7 | * 判断一个位置是否在另一个位置的范围内 8 | * @param parentLoc 父位置 9 | * @param childLoc 子位置 10 | * @param offset 偏移量 11 | * @param offsetLine 行偏移量,默认1 12 | * @param startOffset 起始位置的额外偏移量,默认0 13 | * @param endOffset 结束位置的额外偏移量,默认0 14 | * @returns boolean 15 | */ 16 | export function isInPosition(parentLoc: RangeLoc, childLoc: PositionOption2, offset = 0, offsetLine = 1, startOffset = 0, endOffset = 0) { 17 | if (offset === 0) { 18 | const { start, end } = parentLoc 19 | const startLine = start.line 20 | const startcharacter = start.column || start.character 21 | const endcharacter = end.column || end.character 22 | const endLine = end.line 23 | const { line } = childLoc 24 | const character = childLoc.column || childLoc.character 25 | if (line + offsetLine === startLine && character! <= startcharacter! - 1 + startOffset) 26 | return false 27 | if (line + offsetLine === endLine && character! > endcharacter! - 1 + endOffset) 28 | return false 29 | if (line + offsetLine < startLine) 30 | return false 31 | if (line + offsetLine > endLine) 32 | return false 33 | } 34 | else { 35 | const code = getActiveText()!.slice(offset) 36 | const startOffset = getOffsetFromPosition(createPosition(parentLoc.start.line - offsetLine, (parentLoc.start.character || parentLoc.start.column)!), code)! 37 | const childOffset = getOffsetFromPosition(createPosition(childLoc))! 38 | if (childOffset < startOffset + offset) 39 | return false 40 | const endOffset = getOffsetFromPosition(createPosition(parentLoc.end.line - offsetLine, (parentLoc.end.character || parentLoc.end.column)!), code)! 41 | if (childOffset > endOffset + offset) 42 | return false 43 | } 44 | return true 45 | } 46 | -------------------------------------------------------------------------------- /src/createCompletionItem.ts: -------------------------------------------------------------------------------- 1 | import type { Command, CompletionItemKind, MarkdownString, Range, SnippetString } from 'vscode' 2 | import * as vscode from 'vscode' 3 | import { createSnippetString } from './createSnippetString' 4 | 5 | export interface CompletionItemOptions { 6 | content: string 7 | snippet?: string | SnippetString 8 | detail?: string 9 | type?: CompletionItemKind 10 | documentation?: string | MarkdownString 11 | sortText?: string 12 | filterText?: string 13 | preselect?: boolean 14 | keepWhitespace?: boolean 15 | command?: Command 16 | range?: Range | { 17 | /** 18 | * The range that should be used when insert-accepting a completion. Must be a prefix of `replaceRange`. 19 | */ 20 | inserting: Range 21 | /** 22 | * The range that should be used when replace-accepting a completion. 23 | */ 24 | replacing: Range 25 | } 26 | [key: string]: any 27 | } 28 | 29 | export type CreatedCompletionItem = vscode.CompletionItem & CompletionItemOptions & { params?: TParams } 30 | 31 | /** 32 | * 创建补全项 33 | * @param options CompletionItemOptions 34 | * @param options.content string 补全项的内容 35 | * @param options.snippet string | SnippetString 补全项的代码片段 36 | * @param options.detail string 补全项的详细信息 37 | * @param options.type CompletionItemKind 补全项的类型 38 | * @param options.documentation string | MarkdownString 补全项的文档 39 | * @param options.sortText string 补全项的排序文本 40 | * @param options.filterText string 补全项的过滤文本 41 | * @param options.preselect boolean 补全项是否预选 42 | * @param options.keepWhitespace boolean 补全项是否保留空格 43 | * @param options.command Command 补全项的命令 44 | * @param options.range Range 补全项的范围 45 | * @returns CompletionItem 46 | */ 47 | export function createCompletionItem(options: CompletionItemOptions & { params?: TParams }): CreatedCompletionItem { 48 | const { content, snippet, type } = options 49 | const completionItem = new vscode.CompletionItem(content, type) 50 | Object.assign(completionItem, options, { 51 | insertText: typeof snippet === 'string' 52 | ? createSnippetString(snippet) 53 | : snippet, 54 | }) 55 | return completionItem as CreatedCompletionItem 56 | } 57 | -------------------------------------------------------------------------------- /src/jumpToLine.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption1 } from './types' 2 | import * as vscode from 'vscode' 3 | import { createRange } from './createRange' 4 | import { getActiveTextEditor } from './getActiveTextEditor' 5 | import { getCurrentFileUrl } from './getCurrentFileUrl' 6 | import { openFile } from './openFile' 7 | import { setSelection } from './setSelection' 8 | 9 | /** 10 | * 跳入某个文件的某一行的位置 11 | * @param lineNumber 行数或者 range 范围 12 | * @param filepath 路径 默认使用当前激活的文件 13 | * @returns Promise 14 | */ 15 | export function jumpToLine(lineNumber: number | PositionOption1 | [PositionOption1, PositionOption1] | vscode.Range | vscode.Position, filepath = getCurrentFileUrl(), options?: { oneBased?: boolean }) { 16 | let range: vscode.Range 17 | if (typeof lineNumber === 'number') { 18 | const zeroBasedLine = options?.oneBased ? Math.max(lineNumber - 1, 0) : lineNumber 19 | range = createRange([zeroBasedLine, 0], [zeroBasedLine, 0]) 20 | } 21 | else if (lineNumber instanceof vscode.Range) { 22 | range = lineNumber 23 | } 24 | else if (lineNumber instanceof vscode.Position) { 25 | range = createRange(lineNumber, lineNumber) 26 | } 27 | else if (Array.isArray(lineNumber)) { 28 | if (typeof lineNumber[0] === 'number') { 29 | const _lineNumber = lineNumber as PositionOption1 30 | range = createRange(_lineNumber, _lineNumber) 31 | } 32 | else { 33 | const _lineNumber = lineNumber as [PositionOption1, PositionOption1] 34 | range = createRange(_lineNumber[0], _lineNumber[1]) 35 | } 36 | } 37 | else { 38 | range = createRange([0, 0], [0, 0]) 39 | } 40 | if (filepath === getCurrentFileUrl()) { 41 | return toLine(range) 42 | } 43 | return openFile(filepath as string, { selection: range }) 44 | } 45 | 46 | /** 47 | * 跳到当前文件的某一行 48 | * @param lineNumber 行数 49 | */ 50 | export function toLine(lineNumber: number | [number, number] | vscode.Range) { 51 | let range 52 | if (lineNumber instanceof vscode.Range) { 53 | range = lineNumber 54 | } 55 | else if (Array.isArray(lineNumber)) { 56 | range = createRange([lineNumber[0] - 1, lineNumber[1]], [lineNumber[0], 0]) 57 | } 58 | else { 59 | range = createRange([lineNumber - 1, 0], [lineNumber, 0]) 60 | } 61 | const editor = getActiveTextEditor() 62 | if (editor) { 63 | setSelection(range.start, range.end) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/createEvents.ts: -------------------------------------------------------------------------------- 1 | type EventsMap = Record 2 | 3 | interface DefaultEvents extends EventsMap { 4 | [event: string]: (...args: any) => void 5 | } 6 | 7 | export interface Unsubscribe { 8 | (): void 9 | } 10 | 11 | export declare class Emitter { 12 | /** 13 | * Event names in keys and arrays with listeners in values. 14 | * 15 | * ```js 16 | * emitter1.events = emitter2.events 17 | * emitter2.events = { } 18 | * ``` 19 | */ 20 | events: Partial<{ [E in keyof Events]: Events[E][] }> 21 | 22 | /** 23 | * Add a listener for a given event. 24 | * 25 | * ```js 26 | * const unbind = ee.on('tick', (tickType, tickDuration) => { 27 | * count += 1 28 | * }) 29 | * 30 | * disable () { 31 | * unbind() 32 | * } 33 | * ``` 34 | * 35 | * @param event The event name. 36 | * @param cb The listener function. 37 | * @returns Unbind listener from event. 38 | */ 39 | on(this: this, event: K, cb: Events[K]): Unsubscribe 40 | 41 | /** 42 | * Calls each of the listeners registered for a given event. 43 | * 44 | * ```js 45 | * ee.emit('tick', tickType, tickDuration) 46 | * ``` 47 | * 48 | * @param event The event name. 49 | * @param args The arguments for listeners. 50 | */ 51 | emit( 52 | this: this, 53 | event: K, 54 | ...args: Parameters 55 | ): void 56 | } 57 | 58 | /** 59 | * 用于订阅事件通信的工具 60 | */ 61 | export function createEvents(): Emitter { 62 | const events: Partial<{ [E in keyof Events]: Events[E][] }> = {} 63 | 64 | return { 65 | events, 66 | emit(event, ...args) { 67 | (events[event] ?? []).forEach(listener => listener(...args)) 68 | }, 69 | on(event, cb) { 70 | const bucket = events[event] ?? [] 71 | bucket.push(cb) 72 | events[event] = bucket 73 | return () => { 74 | const scopedListeners = events[event] 75 | if (!scopedListeners) 76 | return 77 | events[event] = scopedListeners.filter(listener => listener !== cb) 78 | } 79 | }, 80 | } 81 | } 82 | 83 | // const event = createEvents() 84 | // const off = event.on('nihao',(data)=>{ 85 | // console.log('12',data) 86 | // }) 87 | 88 | // event.emit('nihao','xxx') 89 | 90 | // off() 91 | -------------------------------------------------------------------------------- /src/insertText.ts: -------------------------------------------------------------------------------- 1 | import type { Position, TextEditor } from 'vscode' 2 | import { Range, SnippetString } from 'vscode' 3 | import { createRange } from './createRange' 4 | import { createSnippetString } from './createSnippetString' 5 | import { getActiveTextEditor } from './getActiveTextEditor' 6 | import { scrollInToView } from './scrollInToView' 7 | 8 | type Location = Position | Range | readonly Position[] | readonly Range[] 9 | type Snippet = string | SnippetString 10 | export interface InsertTextOptions { 11 | readonly undoStopBefore?: boolean 12 | readonly undoStopAfter?: boolean 13 | readonly textEditor?: TextEditor 14 | readonly scrollInToView?: boolean 15 | } 16 | export async function insertText(snippet: Snippet, location: Location, options?: InsertTextOptions): Promise 17 | export async function insertText(location: Location, snippet: Snippet, options?: InsertTextOptions): Promise 18 | /** 19 | * 插入文本或代码片段到指定位置 20 | * @param {Snippet | Location} snippet - 要插入的文本或代码片段 21 | * @param {Location | Snippet} location - 插入位置,可以是 Position、Range 或它们的数组 22 | * @param {object} [options] - 插入选项 23 | * @param {boolean} [options.undoStopBefore] - 插入前是否创建撤销停止点 24 | * @param {boolean} [options.undoStopAfter] - 插入后是否创建撤销停止点 25 | * @param {TextEditor} [options.textEditor] - 指定的文本编辑器,默认为当前激活的编辑器 26 | * @param {boolean} [options.scrollInToView] - 是否滚动到插入位置 27 | * @returns {Promise} - 插入是否成功 28 | */ 29 | export async function insertText(snippet: Snippet | Location, location: Snippet | Location, options: InsertTextOptions = { undoStopBefore: false, undoStopAfter: false, textEditor: getActiveTextEditor(), scrollInToView: true }) { 30 | const activeTextEditor = options.textEditor 31 | if (!activeTextEditor) 32 | return false 33 | 34 | if (typeof snippet !== 'string' && !(snippet instanceof SnippetString)) { 35 | const temp = snippet 36 | snippet = location 37 | location = temp 38 | } 39 | 40 | if (typeof snippet === 'string') 41 | snippet = createSnippetString(snippet) 42 | 43 | const res = await activeTextEditor.insertSnippet(snippet as SnippetString, location as Location, options as { undoStopBefore: boolean, undoStopAfter: boolean }) 44 | if (res && options.scrollInToView && !Array.isArray(location)) { 45 | scrollInToView(location instanceof Range ? location : createRange(location as Position, location as Position)) 46 | } 47 | return res 48 | } 49 | -------------------------------------------------------------------------------- /src/createLog.ts: -------------------------------------------------------------------------------- 1 | import { createOutputChannel } from './createOutputChannel' 2 | 3 | /** 4 | * 创建一个日志记录器 5 | * @param {string} name - 日志记录器的名称 6 | * @param {object} options - 日志选项 7 | * @param {string} options.warn - 警告日志的前缀 8 | * @param {string} options.info - 信息日志的前缀 9 | * @param {string} options.error - 错误日志的前缀 10 | * @param {string} options.debug - 调试日志的前缀 11 | * @param {string} [options.languageId] - 语言ID(可选) 12 | * @returns {object} 日志记录器对象 13 | */ 14 | export function createLog(name: string, options: { 15 | warn: string 16 | info: string 17 | error: string 18 | debug: string 19 | languageId?: string 20 | } = { 21 | warn: '🟡', 22 | info: '🔵', 23 | error: '🔴', 24 | debug: '🟢', 25 | }) { 26 | const outputChannel = createOutputChannel(name, options.languageId) 27 | return { 28 | /** 29 | * 显示日志输出通道 30 | */ 31 | show: () => { 32 | outputChannel.show() 33 | }, 34 | /** 35 | * 释放日志输出通道 36 | */ 37 | dispose: () => { 38 | outputChannel.dispose() 39 | }, 40 | /** 41 | * 清除日志输出通道 42 | */ 43 | clear: () => { 44 | outputChannel.clear() 45 | }, 46 | /** 47 | * 追加消息到日志输出通道 48 | * @param {string} message - 要追加的消息 49 | */ 50 | append: (message: string) => { 51 | outputChannel.append(message) 52 | }, 53 | /** 54 | * 追加消息并换行到日志输出通道 55 | * @param {string} message - 要追加的消息 56 | */ 57 | appendLine: (message: string) => { 58 | outputChannel.appendLine(message) 59 | }, 60 | /** 61 | * 隐藏日志输出通道 62 | */ 63 | hide: () => { 64 | outputChannel.hide() 65 | }, 66 | /** 67 | * 记录信息日志 68 | * @param {string} message - 信息消息 69 | */ 70 | info: (message: string) => { 71 | outputChannel.appendLine(`${options.info} [INFO] ${message}`) 72 | }, 73 | /** 74 | * 记录警告日志 75 | * @param {string} message - 警告消息 76 | */ 77 | warn: (message: string) => { 78 | outputChannel.appendLine(`${options.warn} [WARN] ${message}`) 79 | }, 80 | /** 81 | * 记录错误日志 82 | * @param {string} message - 错误消息 83 | */ 84 | error: (message: string) => { 85 | outputChannel.appendLine(`${options.error} [ERROR] ${message}`) 86 | }, 87 | /** 88 | * 记录调试日志 89 | * @param {string} message - 调试消息 90 | */ 91 | debug: (message: string) => { 92 | outputChannel.appendLine(`${options.debug} [DEBUG] ${message}`) 93 | }, 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vscode-use/utils", 3 | "type": "module", 4 | "version": "0.1.61", 5 | "packageManager": "pnpm@10.24.0", 6 | "description": "A collection of utility functions for VS Code extensions. Enhance your VS Code extension development with reusable, well-tested utilities.", 7 | "author": "Simon He", 8 | "license": "MIT", 9 | "funding": "https://github.com/sponsors/Simon-He95", 10 | "homepage": "https://github.com/vscode-use/utils#readme", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/vscode-use/utils.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/vscode-use/utils/issues" 17 | }, 18 | "keywords": [ 19 | "vscode-use", 20 | "@vscode-use/utils", 21 | "utils", 22 | "vscode", 23 | "vscode-extension", 24 | "vscode utilities", 25 | "typescript", 26 | "node", 27 | "productivity", 28 | "developer-tools" 29 | ], 30 | "sideEffects": false, 31 | "exports": { 32 | ".": { 33 | "import": "./dist/index.js", 34 | "require": "./dist/index.cjs" 35 | }, 36 | "./index": { 37 | "import": "./dist/index.js", 38 | "require": "./dist/index.cjs" 39 | } 40 | }, 41 | "main": "./dist/index.js", 42 | "module": "./dist/index.js", 43 | "types": "./dist/index.d.ts", 44 | "typesVersions": { 45 | "*": { 46 | "*": [ 47 | "./dist/*", 48 | "./dist/index.d.ts" 49 | ] 50 | } 51 | }, 52 | "files": [ 53 | "dist" 54 | ], 55 | "engines": { 56 | "vscode": "^1.92.0" 57 | }, 58 | "activationEvents": [ 59 | "onStartupFinished" 60 | ], 61 | "scripts": { 62 | "build": "tsdown src/index.ts", 63 | "dev": "tsdown --watch src", 64 | "format": "prettier --write --cache .", 65 | "lint": "eslint . --cache", 66 | "lint:fix": "nr lint --fix", 67 | "prepublishOnly": "nr build", 68 | "release": "bumpp && npm publish", 69 | "test": "vitest", 70 | "typecheck": "tsc --noEmit" 71 | }, 72 | "dependencies": { 73 | "alien-signals": "^1.0.13" 74 | }, 75 | "devDependencies": { 76 | "@antfu/eslint-config": "^4.19.0", 77 | "@antfu/ni": "^0.21.12", 78 | "@types/node": "^18.19.130", 79 | "@types/vscode": "1.92.0", 80 | "bumpp": "^8.2.1", 81 | "eslint": "^9.39.1", 82 | "picocolors": "^1.1.1", 83 | "prettier": "^2.8.8", 84 | "tsdown": "^0.9.9", 85 | "typescript": "^5.9.3", 86 | "vitest": "^3.2.4" 87 | }, 88 | "lint-staged": { 89 | "*": [ 90 | "prettier --write --cache --ignore-unknown" 91 | ], 92 | "*.{vue,js,ts,jsx,tsx,md,json}": "eslint . --fix" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/createSelection.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption1, PositionOption2 } from './types' 2 | import * as vscode from 'vscode' 3 | import { createPosition } from './createPosition' 4 | 5 | /** 6 | * 创建一个 selectionRange 7 | */ 8 | export function createSelection(startLine: number, startChar: number, endLine: number, endChar: number): vscode.Range 9 | export function createSelection(startLine: number, startChar: number, end: PositionOption2 | PositionOption1 | vscode.Position): vscode.Range 10 | export function createSelection(start: PositionOption2 | PositionOption1 | vscode.Position, endLine: number, endChar: number): vscode.Range 11 | export function createSelection(start: PositionOption2 | PositionOption1 | vscode.Position, end: PositionOption2 | PositionOption1 | vscode.Position): vscode.Range 12 | export function createSelection(start: PositionOption2 | PositionOption1 | number, end: PositionOption2 | PositionOption1 | number, v1?: PositionOption2 | PositionOption1 | number, v2?: number) { 13 | let _start!: vscode.Position 14 | let _end!: vscode.Position 15 | if (start instanceof vscode.Position && end instanceof vscode.Position) { 16 | _start = start 17 | _end = end 18 | } 19 | else if (start instanceof vscode.Position && typeof end === 'number' && typeof v1 === 'number') { 20 | _start = start 21 | _end = createPosition(end, v1) 22 | } 23 | else if (start instanceof vscode.Position && Array.isArray(end)) { 24 | _start = start 25 | _end = createPosition(end) 26 | } 27 | else if (typeof start === 'number' && typeof end === 'number' && typeof v1 === 'number' && typeof v2 === 'number') { 28 | _start = createPosition(start, end) 29 | _end = createPosition(v1, v2) 30 | } 31 | else if (typeof start === 'number' && typeof end === 'number' && Array.isArray(v1)) { 32 | _start = createPosition(start, end) 33 | _end = createPosition(v1) 34 | } 35 | else if (typeof start === 'number' && typeof end === 'number' && v1 instanceof vscode.Position) { 36 | _start = createPosition(start, end) 37 | _end = v1 38 | } 39 | else if (Array.isArray(start) && typeof end === 'number' && typeof v1 === 'number') { 40 | _start = createPosition(start) 41 | _end = createPosition(end, v1) 42 | } 43 | else if (Array.isArray(start) && end instanceof vscode.Position) { 44 | _start = createPosition(start) 45 | _end = end 46 | } 47 | else if (Array.isArray(start) && Array.isArray(end)) { 48 | _start = createPosition(start) 49 | _end = createPosition(end) 50 | } 51 | 52 | if (_start && _end) 53 | return new vscode.Selection(_start, _end) 54 | throw new Error('createSelection parameter error') 55 | } 56 | -------------------------------------------------------------------------------- /src/createRange.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption1, PositionOption2 } from './types' 2 | import * as vscode from 'vscode' 3 | import { createPosition } from './createPosition' 4 | 5 | function isRangeLike(value: unknown): value is { position: vscode.Position } { 6 | return typeof value === 'object' 7 | && value !== null 8 | && 'position' in value 9 | && (value as { position?: unknown }).position instanceof vscode.Position 10 | } 11 | 12 | /** 13 | * 创建一个 range 14 | */ 15 | export function createRange(startLine: number, startChar: number, endLine: number, endChar: number): vscode.Range 16 | export function createRange(startLine: number, startChar: number, end: PositionOption2 | PositionOption1 | vscode.Position): vscode.Range 17 | export function createRange(start: PositionOption2 | PositionOption1 | vscode.Position, endLine: number, endChar: number): vscode.Range 18 | export function createRange(start: PositionOption2 | PositionOption1 | vscode.Position, end: PositionOption2 | PositionOption1 | vscode.Position): vscode.Range 19 | export function createRange(start: PositionOption2 | PositionOption1 | number, end: PositionOption2 | PositionOption1 | number, v1?: PositionOption2 | PositionOption1 | number, v2?: number) { 20 | let _start!: vscode.Position 21 | let _end!: vscode.Position 22 | if (start instanceof vscode.Position && end instanceof vscode.Position) { 23 | _start = start 24 | _end = end 25 | } 26 | else if (start instanceof vscode.Position && typeof end === 'number' && typeof v1 === 'number') { 27 | _start = start 28 | _end = createPosition(end, v1) 29 | } 30 | else if (start instanceof vscode.Position && Array.isArray(end)) { 31 | _start = start 32 | _end = createPosition(end) 33 | } 34 | else if (typeof start === 'number' && typeof end === 'number' && typeof v1 === 'number' && typeof v2 === 'number') { 35 | _start = createPosition(start, end) 36 | _end = createPosition(v1, v2) 37 | } 38 | else if (typeof start === 'number' && typeof end === 'number' && Array.isArray(v1)) { 39 | _start = createPosition(start, end) 40 | _end = createPosition(v1) 41 | } 42 | else if (typeof start === 'number' && typeof end === 'number' && v1 instanceof vscode.Position) { 43 | _start = createPosition(start, end) 44 | _end = v1 45 | } 46 | else if (Array.isArray(start) && typeof end === 'number' && typeof v1 === 'number') { 47 | _start = createPosition(start) 48 | _end = createPosition(end, v1) 49 | } 50 | else if (Array.isArray(start) && end instanceof vscode.Position) { 51 | _start = createPosition(start) 52 | _end = end 53 | } 54 | else if (Array.isArray(start) && Array.isArray(end)) { 55 | _start = createPosition(start) 56 | _end = createPosition(end) 57 | } 58 | else if (isRangeLike(start) && isRangeLike(end)) { 59 | _start = start.position 60 | _end = end.position 61 | } 62 | 63 | if (_start && _end) 64 | return new vscode.Range(_start, _end) 65 | throw new Error('createRange parameter error') 66 | } 67 | -------------------------------------------------------------------------------- /src/setSelection.ts: -------------------------------------------------------------------------------- 1 | import type { PositionOption1, PositionOption2 } from './types' 2 | import * as vscode from 'vscode' 3 | import { createRange } from './createRange' 4 | import { getActiveTextEditor } from './getActiveTextEditor' 5 | 6 | /** 7 | * Sets the selection in the active text editor. 8 | * 9 | * @param range - The range to set the selection to. 10 | * @param position - Optional. The position of the selection cursor. Can be 'left' or 'right'. Defaults to 'right'. 11 | * @param revealType - Optional. The type of reveal to use. Defaults to `vscode.TextEditorRevealType.Default`. 12 | */ 13 | export function setSelection(range: vscode.Range, position?: 'left' | 'right', revealType?: vscode.TextEditorRevealType): void 14 | /** 15 | * Sets the selection in the active text editor. 16 | * 17 | * @param start - The start position of the selection. 18 | * @param end - The end position of the selection. 19 | * @param position - Optional. The position of the selection cursor. Can be 'left' or 'right'. Defaults to 'right'. 20 | * @param revealType - Optional. The type of reveal to use. Defaults to `vscode.TextEditorRevealType.Default`. 21 | */ 22 | export function setSelection(start: PositionOption2 | PositionOption1, end: PositionOption2 | PositionOption1, position?: 'left' | 'right', revealType?: vscode.TextEditorRevealType): void 23 | /** 24 | * Sets the selection in the active text editor. 25 | * 26 | * @param start - The start position or range of the selection. 27 | * @param end - Optional. The end position of the selection or the position of the selection cursor if `start` is a range. 28 | * @param position - Optional. The position of the selection cursor if `start` is a range. Can be 'left' or 'right'. Defaults to 'right'. 29 | * @param revealType - Optional. The type of reveal to use if `start` is a range. Defaults to `vscode.TextEditorRevealType.Default`. 30 | */ 31 | export function setSelection(start: T, end?: T extends vscode.Range ? 'left' | 'right' : PositionOption2 | PositionOption1, position?: T extends vscode.Range ? vscode.TextEditorRevealType : 'left' | 'right', revealType?: vscode.TextEditorRevealType) { 32 | let range: vscode.Range 33 | let cursorPosition: 'left' | 'right' 34 | let reveal: vscode.TextEditorRevealType 35 | if (start instanceof vscode.Range) { 36 | range = start 37 | cursorPosition = typeof end === 'string' ? end : 'right' 38 | reveal = (typeof position === 'number' ? position : revealType) ?? vscode.TextEditorRevealType.Default 39 | } 40 | else { 41 | range = createRange(start, end as PositionOption2) 42 | cursorPosition = (position as 'left' | 'right' | undefined) ?? 'right' 43 | reveal = revealType ?? vscode.TextEditorRevealType.Default 44 | } 45 | const selection = cursorPosition === 'left' 46 | ? new vscode.Selection(range.end, range.start) 47 | : new vscode.Selection(range.start, range.end) 48 | const activeTextEditor = getActiveTextEditor() 49 | if (activeTextEditor) { 50 | activeTextEditor.selection = selection 51 | activeTextEditor.revealRange(range, reveal) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/createSelect.ts: -------------------------------------------------------------------------------- 1 | import type { quickPickOptions as QuickPickOptions } from './types' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 创建选择框 6 | * @param options 7 | * @param quickPickOptions 8 | * @returns Thenable 9 | */ 10 | export function createSelect( 11 | options: (string | vscode.QuickPickItem)[], 12 | quickPickOptions?: QuickPickOptions & Partial>, 13 | ): Promise { 14 | return new Promise((resolve) => { 15 | const noop = () => { } 16 | const quickPick = vscode.window.createQuickPick() 17 | const fixedOptions = options.map((item: any) => 18 | typeof item === 'string' ? { label: item } : item, 19 | ) as vscode.QuickPickItem[] 20 | 21 | quickPick.items = fixedOptions 22 | const { 23 | onDidChange, 24 | onDidAccept, 25 | onDidTriggerButton, 26 | onDidTriggerItemButton, 27 | onDidChangeActive, 28 | onDidChangeValue, 29 | onDidHide, 30 | ...quickPickProps 31 | } = quickPickOptions ?? {} 32 | Object.assign(quickPick, quickPickProps) 33 | 34 | if (quickPickOptions?.activeItems && quickPick.items.length > 0) { 35 | let activeItem = quickPick.items[0] 36 | quickPickOptions.activeItems.find((item) => { 37 | const target = quickPick.items.find(i => i.label === item) 38 | if (target) { 39 | activeItem = target 40 | return true 41 | } 42 | return false 43 | }) 44 | quickPick.activeItems = [activeItem] 45 | } 46 | else if (quickPick.items.length > 0) { 47 | const presetSelections = fixedOptions.filter((item: any) => item.picked) 48 | if (presetSelections.length > 0) { 49 | const quickPickWithSelection = quickPick as vscode.QuickPick & { selectedItems: vscode.QuickPickItem[] } 50 | quickPickWithSelection.selectedItems = presetSelections 51 | quickPick.activeItems = [presetSelections[0]] 52 | } 53 | else { 54 | quickPick.activeItems = [quickPick.items[0]] 55 | } 56 | } 57 | 58 | let selection: readonly vscode.QuickPickItem[] = [] 59 | let resolved = false 60 | const resolveOnce = (value: any) => { 61 | if (resolved) 62 | return 63 | resolved = true 64 | resolve(value) 65 | } 66 | quickPick.onDidChangeSelection((_selection) => { 67 | selection = _selection 68 | ; (onDidChange || noop)(_selection) 69 | }) 70 | quickPick.onDidAccept(() => { 71 | if (quickPickOptions?.canSelectMany) 72 | resolveOnce(selection.map(item => item.label) as T extends true ? string[] : string | undefined) 73 | else 74 | resolveOnce((selection[0]?.label ?? quickPick.value) as T extends true ? string[] : string | undefined) 75 | ; (onDidAccept || noop)() 76 | quickPick.hide() 77 | }) 78 | quickPick.onDidTriggerButton(onDidTriggerButton || noop) 79 | quickPick.onDidTriggerItemButton(onDidTriggerItemButton || noop) 80 | quickPick.onDidChangeActive(onDidChangeActive || noop) 81 | quickPick.onDidChangeValue(onDidChangeValue || noop) 82 | quickPick.onDidHide((e) => { 83 | (onDidHide || noop)(e) 84 | resolveOnce(undefined) 85 | quickPick.dispose() 86 | }) 87 | quickPick.show() 88 | }) 89 | } 90 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './addEventListener' 2 | export * from './addEventListeners' 3 | export * from './createBottomBar' 4 | export * from './createCodeLens' 5 | export * from './createCompletionItem' 6 | export * from './createCompletionKind' 7 | export * from './createCompletionList' 8 | export * from './createDebugTerminal' 9 | export * from './createDefinitionLocation' 10 | export * from './createEvents' 11 | export * from './createExtension' 12 | export * from './createFakeProgress' 13 | export * from './createHover' 14 | export * from './createInlayHint' 15 | export * from './createInlineCompletionItem' 16 | export * from './createInlineCompletionList' 17 | export * from './createInput' 18 | export * from './createLog' 19 | export * from './createMarkdownString' 20 | export * from './createOutputChannel' 21 | export * from './createPosition' 22 | export * from './createProgress' 23 | export * from './createRange' 24 | export * from './createSelect' 25 | export * from './createSelection' 26 | export * from './createSnippetString' 27 | export * from './createSquare' 28 | export * from './createStyle' 29 | export * from './createStyleAnimation' 30 | export * from './createStyleAnimations' 31 | export * from './createTerminal' 32 | export * from './executeCommand' 33 | export * from './executeCommands' 34 | export * from './getActiveText' 35 | export * from './getActiveTextEditor' 36 | export * from './getActiveTextEditorLanguageId' 37 | export * from './getCalcPosition' 38 | export * from './getConfiguration' 39 | export * from './getCopyText' 40 | export * from './getCurrentFileUrl' 41 | export * from './getKeyWords' 42 | export * from './getLineText' 43 | export * from './getLocale' 44 | export * from './getOffsetFromPosition' 45 | export * from './getPosition' 46 | export * from './getPositionAfterCode' 47 | export * from './getPositionBeforeCode' 48 | export * from './getRootPath' 49 | export * from './getSelection' 50 | export * from './getVisibleRange' 51 | export * from './getWordRangeAtPosition' 52 | export * from './insertText' 53 | export * from './isDark' 54 | export * from './isInPosition' 55 | export * from './jumpToLine' 56 | export * from './message' 57 | export * from './nextTick' 58 | export * from './onFold' 59 | export * from './openExternalUrl' 60 | export * from './openFile' 61 | export * from './openSpecialFile' 62 | export * from './registerCodeActionsProvider' 63 | export * from './registerCodeLensProvider' 64 | export * from './registerCommand' 65 | export * from './registerCommands' 66 | export * from './registerCompletionItemProvider' 67 | export * from './registerDefinitionProvider' 68 | export * from './registerHoverProvider' 69 | export * from './registerInlayHintsProvider' 70 | export * from './registerInlineCompletionItemProvider' 71 | export * from './registerTerminalLinkProvider' 72 | export * from './reloadWindow' 73 | export * from './rename' 74 | export * from './saveFile' 75 | export * from './scrollInToView' 76 | export * from './setCommandParams' 77 | export * from './setConfiguration' 78 | export * from './setCopyText' 79 | export * from './setSelection' 80 | export * from './setSelections' 81 | export * from './setStyle' 82 | export * from './toUri' 83 | export * from './types' 84 | export * from './unFold' 85 | export * from './updateText' 86 | export * from './useConfiguration' 87 | export * from './useDark' 88 | export * from './useTheme' 89 | export * from './useVisibleRange' 90 | export * from './watchFile' 91 | export * from './watchFiles' 92 | -------------------------------------------------------------------------------- /src/message.ts: -------------------------------------------------------------------------------- 1 | import type { MessageOption } from './types' 2 | import * as vscode from 'vscode' 3 | 4 | /** 5 | * 消息弹窗 6 | * @param options { 7 | * message: string 8 | * type?: 'info' | 'error' | 'warn' 9 | * buttons?: string[] | string 10 | * modal?: boolean 11 | * detail?: string 12 | * } 13 | * @returns Thenable 14 | */ 15 | export function message(options: MessageOption | string) { 16 | let type = 'info' 17 | let message = '' 18 | let buttons: string[] = [] 19 | const messageOptions: any = {} 20 | if (typeof options === 'string') { 21 | message = options 22 | } 23 | else { 24 | const { 25 | type: _type = 'info', 26 | message: _message, 27 | buttons: _buttons = [], 28 | modal = false, 29 | detail, 30 | } = options 31 | type = _type 32 | message = _message 33 | buttons = Array.isArray(_buttons) ? _buttons : [_buttons] 34 | messageOptions.modal = modal 35 | messageOptions.detail = detail 36 | } 37 | 38 | return type === 'info' 39 | ? vscode.window.showInformationMessage(message, messageOptions, ...buttons) 40 | : type === 'error' 41 | ? vscode.window.showErrorMessage(message, messageOptions, ...buttons) 42 | : vscode.window.showWarningMessage(message, messageOptions, ...buttons) 43 | } 44 | 45 | message.info = function ( 46 | options: string | { message: string, buttons: string[] | string, modal?: boolean, detail?: string }, 47 | ) { 48 | let message = '' 49 | let buttons: string[] = [] 50 | const messageOptions: any = {} 51 | if (typeof options === 'string') { 52 | message = options 53 | } 54 | else { 55 | const { message: _message, buttons: _buttons = [], modal, detail } = options 56 | message = _message 57 | buttons = Array.isArray(_buttons) ? _buttons : [_buttons] 58 | messageOptions.modal = modal 59 | messageOptions.detail = detail 60 | } 61 | return vscode.window.showInformationMessage(message, messageOptions, ...buttons) 62 | } 63 | 64 | message.error = function ( 65 | options: string | { message: string, buttons: string[] | string, modal?: boolean, detail?: string }, 66 | ) { 67 | let message = '' 68 | let buttons: string[] = [] 69 | const messageOptions: any = {} 70 | 71 | if (typeof options === 'string') { 72 | message = options 73 | } 74 | else { 75 | const { message: _message, buttons: _buttons = [], modal, detail } = options 76 | message = _message 77 | buttons = Array.isArray(_buttons) ? _buttons : [_buttons] 78 | messageOptions.modal = modal 79 | messageOptions.detail = detail 80 | } 81 | return vscode.window.showErrorMessage(message, messageOptions, ...buttons) 82 | } 83 | 84 | message.warn = function ( 85 | options: string | { message: string, buttons: string[] | string, modal?: boolean, detail?: string }, 86 | ) { 87 | let message = '' 88 | let buttons: string[] = [] 89 | const messageOptions: any = {} 90 | 91 | if (typeof options === 'string') { 92 | message = options 93 | } 94 | else { 95 | const { message: _message, buttons: _buttons = [], modal, detail } = options 96 | message = _message 97 | buttons = Array.isArray(_buttons) ? _buttons : [_buttons] 98 | messageOptions.modal = modal 99 | messageOptions.detail = detail 100 | } 101 | return vscode.window.showWarningMessage(message, messageOptions, ...buttons) 102 | } 103 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { AccessibilityInformation, ColorTheme, Command, ConfigurationChangeEvent, FileCreateEvent, FileDeleteEvent, FileRenameEvent, InputBoxValidationMessage, ProgressLocation, QuickInputButton, QuickPickItem, Terminal, TextDocument, TextDocumentChangeEvent, TextEditor, TextEditorSelectionChangeEvent, TextEditorViewColumnChangeEvent, TextEditorVisibleRangesChangeEvent, ThemeColor, Uri, WindowState, WorkspaceFoldersChangeEvent } from 'vscode' 2 | 3 | export interface MessageOption { 4 | message: string 5 | type?: 'info' | 'error' | 'warn' 6 | buttons?: string[] | string 7 | modal?: boolean 8 | detail?: string 9 | } 10 | 11 | export interface EventCallbackMap { 12 | 'terminal-close': (terminal: Terminal) => void 13 | 'terminal-open': (terminal: Terminal) => void 14 | 'terminal-change': (terminal: Terminal) => void 15 | 'theme-change': (colorTheme: ColorTheme) => void 16 | 'selection-change': (e: TextEditorSelectionChangeEvent) => void 17 | 'editor-visible': (editors: TextEditor[]) => void 18 | 'activeText-change': (editor: TextEditor | undefined) => void 19 | 'text-visible-change': (e: TextEditorVisibleRangesChangeEvent) => void 20 | 'text-column-change': (e: TextEditorViewColumnChangeEvent) => void 21 | 'onfocus': (e: WindowState) => void 22 | } 23 | export interface WorkspaceCallbackMap { 24 | 'text-change': (e: TextDocumentChangeEvent) => void 25 | 'text-open': (doc: TextDocument) => void 26 | 'text-save': (doc: TextDocument) => void 27 | 'workspace-change': (e: WorkspaceFoldersChangeEvent) => void 28 | 'file-create': (e: FileCreateEvent) => void 29 | 'file-delete': (e: FileDeleteEvent) => void 30 | 'rename': (e: FileRenameEvent) => void 31 | 'config-change': (e: ConfigurationChangeEvent) => void 32 | 'text-close': (doc: TextDocument) => void 33 | } 34 | 35 | export interface BarOptions { 36 | position?: 'left' | 'right' 37 | offset?: number 38 | text: string 39 | tooltip?: string 40 | color?: string | ThemeColor | undefined 41 | backgroundColor?: ThemeColor | undefined 42 | command?: string | Command | undefined 43 | accessibilityInformation?: AccessibilityInformation | undefined 44 | } 45 | 46 | export interface ProgressOptions { 47 | title: string 48 | location?: ProgressLocation.Notification | ProgressLocation.Window | ProgressLocation.SourceControl 49 | cancellable?: boolean 50 | cancel?: () => void 51 | done: (report: ProgressReport) => Promise 52 | } 53 | export type ProgressReport = (value: { 54 | message?: string | undefined 55 | increment?: number | undefined 56 | }) => void 57 | 58 | export type PositionOption1 = [number, number] 59 | export type PositionOption2 = { 60 | line: number 61 | character?: number 62 | column: number 63 | [key: string]: any 64 | } | { 65 | line: number 66 | character: number 67 | column?: number 68 | [key: string]: any 69 | } 70 | 71 | export interface WatchFilesOptions { 72 | onCreate?: (e: Uri) => any 73 | onChange?: (e: Uri) => any 74 | onDelete?: (e: Uri) => any 75 | ignoreCreateEvents?: boolean 76 | ignoreChangeEvents?: boolean 77 | ignoreDeleteEvents?: boolean 78 | } 79 | 80 | export interface RangeLoc { 81 | start: PositionOption2 82 | end: PositionOption2 83 | [key: string]: any 84 | } 85 | 86 | export interface CreateInputOptions { 87 | ignoreFocusOut?: boolean 88 | password?: boolean 89 | prompt?: string 90 | title?: string 91 | value: string 92 | selection?: [number, number] 93 | placeHolder?: string 94 | validate?: (value: string) => string | InputBoxValidationMessage | undefined | null 95 | | Thenable 96 | } 97 | 98 | export type ISelections = { start: PositionOption2 | PositionOption1, end: PositionOption2 | PositionOption1, position?: 'left' | 'right' }[] 99 | 100 | export type ClearStyle = () => void 101 | 102 | export interface quickPickOptions { 103 | canSelectMany?: boolean 104 | title?: string 105 | value?: string 106 | placeholder?: string 107 | buttons?: QuickInputButton[] 108 | matchOnDescription?: boolean 109 | keepScrollPosition?: boolean 110 | activeItems?: string[] 111 | ignoreFocusOut?: boolean 112 | onDidTriggerButton?: (e: any) => any 113 | onDidTriggerItemButton?: (e: any) => any 114 | onDidChangeActive?: (e: any) => any 115 | onDidChangeValue?: (value: string) => any 116 | onDidChange?: (items: readonly QuickPickItem[]) => any 117 | onDidAccept?: () => any 118 | onDidHide?: (e: any) => any 119 | } 120 | 121 | export interface WriteableSignal { 122 | (): T 123 | (value: T): void 124 | } 125 | -------------------------------------------------------------------------------- /src/addEventListener.ts: -------------------------------------------------------------------------------- 1 | import type { EventCallbackMap, WorkspaceCallbackMap } from './types' 2 | import * as vscode from 'vscode' 3 | import { addEffect } from './util' 4 | 5 | /** 6 | * 添加事件监听 7 | * @param type 事件类型 8 | * @param callback 回调函数 9 | * @d 时,你可以取消注册 10 | * 事件类型: 11 | * - terminal-close: 终端关闭 12 | * - terminal-open: 终端打开 13 | * - terminal-change: 终端切换 14 | * - theme-change: 主题切换 15 | * - selection-change: 选择变化 16 | * - editor-visible: 编辑器可见 17 | * - activeText-change: 激活文件变化 18 | * - text-visible-change: 文本可见范围变化 19 | * - text-column-change: 文本编辑器视图列变化 20 | * - text-change: 文本变化 21 | * - text-open: 文本打开 22 | * - text-save: 文本保存 23 | * - workspace-change: 文件夹变化 24 | * - file-create: 文件创建 25 | * - file-delete: 文件删除 26 | * - rename: 文件重命名 27 | * - config-change: 配置变化 28 | * - text-close: 文本关闭 29 | * - auth-change: 认证变化 30 | * @returns 31 | */ 32 | export const eventMap = { 33 | 'terminal-close': 'onDidCloseTerminal', 34 | 'terminal-open': 'onDidOpenTerminal', 35 | 'terminal-change': 'onDidChangeActiveTerminal', 36 | 'theme-change': 'onDidChangeActiveColorTheme', 37 | 'selection-change': 'onDidChangeTextEditorSelection', 38 | 'editor-visible': 'onDidChangeVisibleTextEditors', 39 | 'activeText-change': 'onDidChangeActiveTextEditor', 40 | 'text-visible-change': 'onDidChangeTextEditorVisibleRanges', 41 | 'text-column-change': 'onDidChangeTextEditorViewColumn', 42 | 'onfocus': 'onDidChangeWindowState', 43 | } 44 | export const workspaceMap = { 45 | 'text-change': 'onDidChangeTextDocument', 46 | 'text-open': 'onDidOpenTextDocument', 47 | 'text-save': 'onDidSaveTextDocument', 48 | 'workspace-change': 'onDidChangeWorkspaceFolders', 49 | 'file-create': 'onDidCreateFiles', 50 | 'file-delete': 'onDidDeleteFiles', 51 | 'rename': 'onDidRenameFiles', 52 | 'config-change': 'onDidChangeConfiguration', 53 | 'text-close': 'onDidCloseTextDocument', 54 | } 55 | export const authenticationMap = { 56 | 'auth-change': 'onDidChangeSessions', 57 | } 58 | 59 | type AuthCallback = (providerId: string, getSession: (name: string) => Promise) => void 60 | type WindowEventRegister = (listener: (...args: any[]) => any, thisArgs?: any) => vscode.Disposable 61 | 62 | export function addEventListener(type: T, callback: EventCallbackMap[T]): vscode.Disposable 63 | export function addEventListener(type: T, callback: WorkspaceCallbackMap[T]): vscode.Disposable 64 | export function addEventListener(type: T, callback: AuthCallback): vscode.Disposable 65 | export function addEventListener( 66 | type: keyof typeof eventMap | keyof typeof workspaceMap | keyof typeof authenticationMap, 67 | callback: (...args: any[]) => any, 68 | ): vscode.Disposable { 69 | if (type in eventMap) { 70 | const name = eventMap[type as keyof typeof eventMap] 71 | const target = (vscode.window as unknown as Record)[name] 72 | if (type === 'activeText-change') { 73 | return addEffect(target?.((e: vscode.TextEditor | undefined) => { 74 | if (!e) 75 | return 76 | (callback as EventCallbackMap['activeText-change'])(e) 77 | }) ?? new vscode.Disposable(() => { })) 78 | } 79 | return addEffect(target?.(callback) ?? new vscode.Disposable(() => { })) 80 | } 81 | if (type in workspaceMap) { 82 | const name = workspaceMap[type as keyof typeof workspaceMap] 83 | const target = (vscode.workspace as unknown as Record)[name] 84 | if (type === 'text-change') { 85 | return addEffect(target?.(({ contentChanges, document, reason }: vscode.TextDocumentChangeEvent) => { 86 | if (contentChanges.length === 0) 87 | return 88 | (callback as WorkspaceCallbackMap['text-change'])({ contentChanges, document, reason } as vscode.TextDocumentChangeEvent) 89 | }) ?? new vscode.Disposable(() => { })) 90 | } 91 | return addEffect(target?.(callback) ?? new vscode.Disposable(() => { })) 92 | } 93 | if (type in authenticationMap) { 94 | const name = authenticationMap[type as keyof typeof authenticationMap] 95 | const target = (vscode.authentication as unknown as Record)[name] 96 | return addEffect(target?.((e: { provider: { id: string } }) => { 97 | const getSession = async (name: string) => await vscode.authentication.getSession(name, ['user:read']) 98 | ; (callback as AuthCallback)(e.provider.id, getSession) 99 | }) ?? new vscode.Disposable(() => { })) 100 | } 101 | return addEffect(new vscode.Disposable(() => { })) 102 | } 103 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 |

2 | css selector 3 |

4 |

English | 简体中文

5 | 🐰 vscode use 针对 vscode api 进行了二次的封装,提供了大量精简实用的函数,并且让函数名更贴近实际意义,就如 vscode 中的 lodash。 6 | 7 | ## [📘 Documentation](https://vscode-use-docs.netlify.app/) 8 | 9 | ## 📍 Install 10 | ``` 11 | npm i @vscode-use/utils -d 12 | ``` 13 | 14 | ## 推荐 VSCode 启动模板 15 | - https://github.com/Simon-He95/vitesse-vscode 16 | 17 | ### [Example](https://github.com/Simon-He95/vitesse-vscode) 18 | 19 | ## 📝 Api 20 | 21 | - registerCommand: ***注册指令*** 22 | - executeCommand: ***触发指令*** 23 | - getConfiguration: ***获取 workspace configuration*** 24 | - message {type:'info'|'error',message:string,buttons:['ok']}: ***弹出消息*** 25 | - openFile: ***打开某一个文件*** 26 | - addEventListener: ***监听vscode中的文件切换、终端、内容变更、新增、删除等事件*** 27 | - createTerminal: ***快速创建一个终端*** 28 | - createCompletionItem: ***生成registerCompletionItemProvider的提示内容*** 29 | - registerCompletionItemProvider: ***根据输入生成对应的提示*** 30 | - isDark: ***判断当前vscode主题是否是dark*** 31 | - getSelection: ***获取当前鼠标所在行的信息*** 32 | - getActiveTextEditorLanguageId: ***获取当前文件的一个类型 javascriptreact | typescriptreact | vue 等*** 33 | - createProgress: ***创建一个vscode中的执行进度条*** 34 | - registerInlayHintsProvider: ***给出一个类似copilot的hint提示*** 35 | - getCopyText: ***读取粘贴板中的内容*** 36 | - setCopyText 往粘贴板中塞入内容*** 37 | - updateText: ***修改文本内容*** 38 | - jumpToLine: ***打开文件并跳转到某一行*** 39 | - createBottomBar: ***创建底部栏按钮*** 40 | - nextTick: ***修改文本内容更新后的回调*** 41 | - createSquare: ***创建一个方形小块*** 42 | - watchFiles: ***监听文件内容和删除的变化*** 43 | - createEvents: ***用于订阅事件通信的工具*** 44 | - getActiveText: ***获取到当前激活tab的文本内容*** 45 | - fold: ***折叠代码*** 46 | - unFold: ***展开代码*** 47 | - registerDefinitionProvider: ***提供了 option+click,实现快速跳转的功能*** 48 | - registerHoverProvider: ***为鼠标悬停提供回调*** 49 | - registerCodeActionsProvider ***注册代码动作提供程序*** 50 | - openExternalUrl: ***在浏览器中打开外部网址*** 51 | - getLineText: ***获取某一行的文本*** 52 | - useTheme: ***主题信息获取和操作*** 53 | - isInPosition: ***判断一块区域是否是另一块的子区域*** 54 | - getCurrentFileUrl: ***获取当前激活文件的路径*** 55 | - createInput: ***创建一个输入框*** 56 | - getLocale: ***获取本地的语言环境*** 57 | - rename: ***快速给文件重命名*** 58 | - createDefinitionLocation ***创建按下 option 后左键点击后的跳转地址数据*** 59 | - setStyle ***给某一块区域增加样式*** 60 | - createStyle ***创建样式*** 61 | - getActiveTextEditor ***获取当前激活的编辑器*** 62 | - getKeyWords ***获取 position 位置处的关键词*** 63 | - setCommandParams ***设置 MarkdownString 的点击 command 参数*** 64 | - getOffsetFromPosition ***根据 position 计算 offset*** 65 | - getRootPath ***获取项目根目录路径*** 66 | - registerCodeLensProvider ***注册文本中头部的文字按钮并绑上事件*** 67 | - createCodeLens ***快速创建 provideCodeLenses 中的 item*** 68 | - saveFile ***保存文件*** 69 | - createStyleAnimation ***添加样式动画*** 70 | - createStyleAnimations ***添加样式动画组*** 71 | - getWordRangeAtPosition ***获取所在位置的关键词的区域*** 72 | 73 | ## 📖 @vscode-use/utils api 说明 74 | 75 | ### 注册指令,需要在 package.json 中声明 右下角弹出提示 76 | ``` 77 | registerCommand('vscode-use.hello', () => { 78 | message.info('Hello World!') 79 | }) 80 | ``` 81 | 82 | ### 注册指令,需要在 package.json 中声明 右下角弹出错误提示 83 | ``` 84 | registerCommand('vscode-use.error', () => { 85 | message.error('Hello World!') 86 | }) 87 | ``` 88 | 89 | ### 注册指令,需要在 package.json 中声明 打开百度 90 | ``` 91 | registerCommand('vscode-use.openExternalUrl', () => { 92 | openExternalUrl('http://www.baidu.com') 93 | }) 94 | ``` 95 | 96 | ### 获取当前语言 97 | ``` 98 | const isZh = getLocale().includes('zh') 99 | message.info(`当前语言:${isZh ? '中文' : '英文'}`) 100 | ``` 101 | 102 | ### 监听 切换活动的文本编辑器 103 | ``` 104 | addEventListener('activeText-change', (e) => {}) 105 | ``` 106 | 107 | ### 监听 登录状态变化 108 | ``` 109 | addEventListener('auth-change', (e) => {}) 110 | ``` 111 | 112 | ### 监听 配置变化(包括:插件配置、用户配置、工作区配置) 113 | ``` 114 | addEventListener('config-change', (e) => {}) 115 | ``` 116 | 117 | ### 监听 编辑器可见性变化 118 | ``` 119 | addEventListener('editor-visible', (e) => {}) 120 | ``` 121 | 122 | ### 监听 文件创建 123 | ``` 124 | addEventListener('file-create', (e) => {}) 125 | ``` 126 | 127 | ### 监听 文件删除 128 | ``` 129 | addEventListener('file-delete', (e) => {}) 130 | ``` 131 | 132 | ### 监听 文件夹创建和删除 133 | ``` 134 | addEventListener('folder-change', (e) => {}) 135 | ``` 136 | 137 | ### 监听 文件重命名 138 | ``` 139 | addEventListener('rename', (e) => {}) 140 | ``` 141 | 142 | ### 监听 选中内容变化 143 | ``` 144 | addEventListener('selection-change', (e) => {}) 145 | ``` 146 | 147 | ### 监听 终端变化 148 | ``` 149 | addEventListener('terminal-change', (e) => {}) 150 | ``` 151 | 152 | ### 监听 终端关闭 153 | ``` 154 | addEventListener('terminal-close', (e) => {}) 155 | ``` 156 | 157 | ### 监听 终端创建 158 | ``` 159 | addEventListener('terminal-open', (e) => {}) 160 | ``` 161 | 162 | ### 监听 文本修改 163 | ``` 164 | addEventListener('text-change', (e) => {}) 165 | ``` 166 | 167 | ### 监听 新开文本 168 | ``` 169 | addEventListener('text-open', (e) => {}) 170 | ``` 171 | 172 | ### 监听 文本保存 173 | ``` 174 | addEventListener('text-save', (e) => {}) 175 | ``` 176 | 177 | ### 监听 文本可见性变化 178 | ``` 179 | addEventListener('text-visible-change', (e) => {}) 180 | ``` 181 | 182 | ### 监听 主题变化 183 | ``` 184 | addEventListener('theme-change', (e) => {}) 185 | ``` 186 | 187 | ### 跳到某个文件的某一行 188 | ``` 189 | jumpToLine(10, 'path/Uri') 190 | ``` 191 | 192 | ### 折叠起始行和结束行之间的所有行 193 | ``` 194 | onFold([ 195 | createRange([1, 0], [5, 0]), 196 | createRange([5, 0], [10, 0]) 197 | ]) 198 | ``` 199 | 200 | ### 展开起始行和结束行之间的所有行 201 | ``` 202 | unFold([ 203 | createRange([1, 0], [5, 0]), 204 | createRange([5, 0], [10, 0]) 205 | ]) 206 | ``` 207 | 208 | ### 更新文本 209 | ``` 210 | updateText(edit=>{ 211 | // 在第一行插入文本 212 | edit.insert(new vscode.Position(0, 0), 'Hello World!') 213 | 214 | // 删除第一行的前5个字符 215 | edit.delete(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 5))) 216 | 217 | // 将第一行的前5个字符替换为 Hello World! 218 | edit.replace(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 5)), 'Hello World!') 219 | }) 220 | ``` 221 | 222 | ### 获取当前激活的编辑器文本 223 | ``` 224 | const activeText = getActiveText() 225 | ``` 226 | 227 | ### 获取某一行的文本 228 | ``` 229 | const lineText = getLineText(0) 230 | ``` 231 | 232 | ### 读取config 233 | ``` 234 | const mode1 = getConfiguration('vscode-use').get('mode') 235 | const mode2 = getConfiguration('vscode-use.mode') 236 | ``` 237 | 238 | ### 更新config 239 | ``` 240 | setConfiguration('vscode-use.mode', 'dev') 241 | ``` 242 | 243 | ### 创建终端 244 | ``` 245 | createTerminal('test') 246 | ``` 247 | 248 | ### 创建底部栏 249 | ``` 250 | createBottomBar({ 251 | position: 'left', 252 | text: '我是底部栏', 253 | color: '#fff', 254 | backgroundColor: '#000', 255 | }) 256 | ``` 257 | 258 | ### 根据offset获取位置 259 | ``` 260 | const pos = getPosition(100) 261 | ``` 262 | 263 | ### 获取copy的内容 264 | ``` 265 | getCopyText().then(text=>{}) 266 | ``` 267 | 268 | ### 往剪贴板写入内容 269 | ``` 270 | setCopyText('Hello World!') 271 | ``` 272 | 273 | ### 获取当前激活文本的路径 274 | ``` 275 | const currentFileUrl = getCurrentFileUrl() 276 | ``` 277 | 278 | ### 设置选中内容 279 | ``` 280 | setSelection([0, 0], [0, 5]) 281 | ``` 282 | 283 | ### 设置多选 284 | ``` 285 | setSelections([{ 286 | start: [0, 0], 287 | end: [0, 5], 288 | position: 'left' // 控制光标位置 289 | }, { 290 | start: [1, 0], 291 | end: [1, 5], 292 | position: 'right' 293 | }]) 294 | ``` 295 | 296 | ### 监听文件变化 297 | ``` 298 | watchFiles('filepath', (e) => {}) 299 | ``` 300 | 301 | ### 创建进度条 302 | ``` 303 | createProgress({ 304 | title: '进度条', 305 | async done(report) { 306 | report({ 307 | message: '进度条完成 10%', 308 | increment: 10 309 | }) 310 | setTimeout(() => { 311 | report({ 312 | message: '进度条完成 50', 313 | increment: 50 314 | }) 315 | }) 316 | } 317 | }) 318 | ``` 319 | 320 | ### 创建选择框 321 | ``` 322 | createSelect(['vue','react','svelte','solid']).then((res)=>{}) 323 | ``` 324 | 325 | ### 监听hover元素的事件 326 | ``` 327 | registerHoverProvider('vue', (e) => {}) 328 | ``` 329 | 330 | ### 监听按下option键时控制点击跳转位置 331 | ``` 332 | registerDefinitionProvider('vue', (e) => {}) 333 | ``` 334 | 335 | ### 获取主题相关api 336 | ``` 337 | const { getCurrentTheme, getAllTheme, setTheme, } = useTheme() 338 | ``` 339 | 340 | ### 获取当前激活文本的语言 341 | ``` 342 | const language = getActiveTextEditorLanguageId() // vue 343 | ``` 344 | 345 | ### 重命名文件 346 | ``` 347 | rename('url', 'newUrl') 348 | ``` 349 | 350 | ### nextTick,一些针对文件变化后的操作,需要等待文件变化后再执行 351 | ``` 352 | nextTick(()=>{}) 353 | ``` 354 | 355 | ### 添加样式 356 | ``` 357 | setStyle(createStyle({ 358 | backgroundColor: 'yellow', 359 | border: '1px solid red' 360 | }), createRange([0, 0], [0, 10])) 361 | ``` 362 | ### 创建输入框 363 | ``` 364 | createInput({ 365 | title: '我是输入框', 366 | placeHolder: '请输入内容', 367 | value: '' 368 | }) 369 | ``` 370 | 371 | ### 获取当前激活的编辑器 372 | 373 | ``` 374 | const activeTextEditor = getActiveTextEditor() 375 | ``` 376 | 377 | ### 获取position位置的关键词 378 | 379 | ``` 380 | const keyWords = getKeyWords(position) 381 | ``` 382 | 383 | ### 设置MarkdownString的点击command参数 384 | 385 | ``` 386 | const md = new vscode.MarkdownString() 387 | md.isTrusted = true 388 | md.supportHtml = true 389 | const commandUri = `command:a.b?${setCommandParams(['params1', 'params2'])}` 390 | md.appendMarkdown(`[🦘](${commandUri})`); 391 | ``` 392 | 393 | ### getOffsetFromPosition 394 | ``` 395 | const offset = getOffsetFromPosition(position) // 获取当前文本,位置的offset 396 | const offset = getOffsetFromPosition(position,code) // 获取指定code,位置的offset 397 | ``` 398 | 399 | ## License 400 | 401 | [MIT](./LICENSE) License © 2022 [Simon He](https://github.com/Simon-He95) 402 | 403 | Buy Me A Coffee 404 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | vscode-use/utils 3 |

4 |

English | 简体中文

5 | 6 | 🐰 vscode use has a secondary encapsulation of the vscode api, providing a large number of streamlined and practical functions, and making the function names closer to the actual meaning, just like lodash in vscode. 7 | 8 | ## [📘 Documentation](https://vscode-use-docs.netlify.app/) 9 | 10 | ## 📍 Install 11 | ``` 12 | npm i @vscode-use/utils -d 13 | ``` 14 | 15 | ## Recommended VSCode Starter 16 | - https://github.com/Simon-He95/vitesse-vscode 17 | 18 | ### [Example](https://github.com/Simon-He95/vitesse-vscode) 19 | 20 | ## 📝 Api 21 | 22 | - registerCommand: ***Registration instructions*** 23 | - executeCommand: ***Trigger instructions*** 24 | - getConfiguration: ***get workspace configuration*** 25 | - message {type:'info'|'error',message:string,buttons:['ok']}: ***Pop up message*** 26 | - openFile: ***Open a file.*** 27 | - addEventListener: ***Listen to file switching, terminal, content change, add, delete and other events in vscode*** 28 | - createTerminal: ***Quickly create a terminal*** 29 | - createCompletionItem: ***Generate the prompt content of registerCompletionItemProvider*** 30 | - registerCompletionItemProvider: ***Generate the corresponding prompt according to the input*** 31 | - isDark: ***Determine whether the current vscode theme is dark*** 32 | - getSelection: ***Get the information of the line where the current mouse is located*** 33 | - getActiveTextEditorLanguageId: ***Get a type of the current file javascriptreact | typescriptreact | vue, etc.*** 34 | - createProgress: ***Create an execution progress bar in vscode*** 35 | - registerInlayHintsProvider: ***Give a hint similar to copilot.*** 36 | - getCopyText: ***Read the pasteboard Content.*** 37 | - setCopyText: ***Plug the content into the pasteboard.*** 38 | - updateText: ***Modify the text content*** 39 | - jumpToLine: ***Open a file and jump to a certain line*** 40 | - createBottomBar: ***Create the bottom bar button*** 41 | - nextTick: ***Create the bottom bar button*** 42 | - createSquare: ***Create a square block*** 43 | - watchFiles: ***Monitor changes in file content and deletion*** 44 | - createEvents: ***Tools for subscribing to event communication*** 45 | - getActiveText: ***Get the text content of the current activation tab*** 46 | - fold: ***fold code*** 47 | - unFold: ***unfold code*** 48 | - registerDefinitionProvider: ***It provides option + click to achieve the function of fast jump.*** 49 | - registerHoverProvider: ***Provide a callback for mouse hover*** 50 | - registerCodeActionsProvider ***Registered Code Action Provider*** 51 | - openExternalUrl: ***Open the external url in the browser*** 52 | - getLineText: ***Get the text of a certain line*** 53 | - useTheme: ***Theme Configuration and Operatation*** 54 | - isInPosition: ***Determine whether one area is a sub-area of another*** 55 | - getCurrentFileUrl: ***Get the path of the current activation file*** 56 | - createInput: ***Create an input box*** 57 | - getLocale: ***Get the local language environment*** 58 | - rename: ***Quickly rename files*** 59 | - createDefinitionLocation ***Create jump address data after left-clicking after pressing option*** 60 | - setStyle ***Add style to a certain area*** 61 | - createStyle ***Create Style*** 62 | - getActiveTextEditor ***Get the currently activated editor*** 63 | - getKeyWords ***Get the keywords at the position*** 64 | - setCommandParams ***Set the click command parameter of MarkdownString*** 65 | - getOffsetFromPosition ***Get the offset from position*** 66 | - getRootPath ***Get the root directory path of the project*** 67 | - registerCodeLensProvider ***Register the text button at the head of the text and tie the event.*** 68 | - createCodeLens ***Quickly create items in provideCodeLenses*** 69 | - saveFile ***Save the file*** 70 | - createStyleAnimation ***Add style animation*** 71 | - createStyleAnimations ***Add style animation group*** 72 | - getWordRangeAtPosition ***Get the area of ​​keywords for your location*** 73 | 74 | ## 📖 @vscode-use/utils api description 75 | 76 | ### The registration instruction needs to be declared in package.json. A prompt pops up in the lower right corner. 77 | ``` 78 | registerCommand('vscode-use.hello', () => { 79 | message.info('Hello World!') 80 | }) 81 | ``` 82 | 83 | ### The registration instruction needs to be declared in package.json. An error prompt pops up in the lower right corner. 84 | ``` 85 | registerCommand('vscode-use.error', () => { 86 | message.error('Hello World!') 87 | }) 88 | ``` 89 | 90 | ### Registration instructions need to declare in package.json to open Baidu 91 | ``` 92 | registerCommand('vscode-use.openExternalUrl', () => { 93 | openExternalUrl('http://www.baidu.com') 94 | }) 95 | ``` 96 | 97 | ### Get the current language 98 | ``` 99 | const isZh = getLocale().includes('zh') 100 | message.info(`当前语言:${isZh ? '中文' : '英文'}`) 101 | ``` 102 | 103 | ### Monitor and switch the active text editor 104 | ``` 105 | addEventListener('activeText-change', (e) => {}) 106 | ``` 107 | 108 | ### Monitor login status changes 109 | ``` 110 | addEventListener('auth-change', (e) => {}) 111 | ``` 112 | 113 | ### Monitoring configuration changes (including: plug-in configuration, user configuration, workspace configuration) 114 | ``` 115 | addEventListener('config-change', (e) => {}) 116 | ``` 117 | 118 | ### Monitor editor visibility changes 119 | ``` 120 | addEventListener('editor-visible', (e) => {}) 121 | ``` 122 | 123 | ### Monitor file creation 124 | ``` 125 | addEventListener('file-create', (e) => {}) 126 | ``` 127 | 128 | ### Monitoring file deletion 129 | ``` 130 | addEventListener('file-delete', (e) => {}) 131 | ``` 132 | 133 | ### Monitor folder creation and deletion 134 | ``` 135 | addEventListener('folder-change', (e) => {}) 136 | ``` 137 | 138 | ### Listen to file renaming 139 | ``` 140 | addEventListener('rename', (e) => {}) 141 | ``` 142 | 143 | ### Monitor the changes of selected content 144 | ``` 145 | addEventListener('selection-change', (e) => {}) 146 | ``` 147 | 148 | ### Monitor terminal changes 149 | ``` 150 | addEventListener('terminal-change', (e) => {}) 151 | ``` 152 | 153 | ### Monitoring terminal is closed 154 | ``` 155 | addEventListener('terminal-close', (e) => {}) 156 | ``` 157 | 158 | ### Monitoring terminal creation 159 | ``` 160 | addEventListener('terminal-open', (e) => {}) 161 | ``` 162 | 163 | ### Monitor text modifications 164 | ``` 165 | addEventListener('text-change', (e) => {}) 166 | ``` 167 | 168 | ### Monitor new text 169 | ``` 170 | addEventListener('text-open', (e) => {}) 171 | ``` 172 | 173 | ### Monitor text saving 174 | ``` 175 | addEventListener('text-save', (e) => {}) 176 | ``` 177 | ### Monitor text visibility changes 178 | ``` 179 | addEventListener('text-visible-change', (e) => {}) 180 | ``` 181 | 182 | ### Monitor theme changes 183 | ``` 184 | addEventListener('theme-change', (e) => {}) 185 | ``` 186 | 187 | ### Jump to a certain line of a file 188 | ``` 189 | jumpToLine(10, 'path/Uri') 190 | ``` 191 | 192 | ### Collapse all lines between the start line and the end line 193 | ``` 194 | onFold([ 195 | createRange([1, 0], [5, 0]), 196 | createRange([5, 0], [10, 0]) 197 | ]) 198 | ``` 199 | 200 | ### Expand all lines between the start line and the end line 201 | ``` 202 | unFold([ 203 | createRange([1, 0], [5, 0]), 204 | createRange([5, 0], [10, 0]) 205 | ]) 206 | ``` 207 | 208 | ### Update text 209 | ``` 210 | updateText(edit=>{ 211 | //Insert text in the first line 212 | edit.insert(new vscode.Position(0, 0), 'Hello World!') 213 | 214 | // Delete the first 5 characters of the first line 215 | edit.delete(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 5))) 216 | 217 | // Replace the first 5 characters of the first line with Hello World! 218 | edit.replace(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 5)), 'Hello World!') 219 | }) 220 | ``` 221 | 222 | ### Get the currently active editor text 223 | ``` 224 | const activeText = getActiveText() 225 | ``` 226 | 227 | ### Get the text of a certain line 228 | ``` 229 | const lineText = getLineText(0) 230 | ``` 231 | 232 | ### Read config 233 | ``` 234 | const mode1 = getConfiguration('vscode-use').get('mode') 235 | const mode2 = getConfiguration('vscode-use.mode') 236 | ``` 237 | 238 | ### Update config 239 | ``` 240 | setConfiguration('vscode-use.mode', 'dev') 241 | ``` 242 | 243 | ### Create terminal 244 | ``` 245 | createTerminal('test') 246 | ``` 247 | 248 | ### Create bottom bar 249 | ``` 250 | createBottomBar({ 251 | position: 'left', 252 | text: 'I am the bottom bar', 253 | color: '#fff', 254 | backgroundColor: '#000', 255 | }) 256 | ``` 257 | 258 | ### Get the position based on offset 259 | ``` 260 | const pos = getPosition(100) 261 | ``` 262 | 263 | ### Get the content of the copy 264 | ``` 265 | getCopyText().then(text=>{}) 266 | ``` 267 | 268 | ### Write content to the clipboard 269 | ``` 270 | setCopyText('Hello World!') 271 | ``` 272 | 273 | ### Get the path of the currently active text 274 | ``` 275 | const currentFileUrl = getCurrentFileUrl() 276 | ``` 277 | 278 | ### Set selected content 279 | ``` 280 | setSelection([0, 0], [0, 5]) 281 | ``` 282 | 283 | ### Set multiple selections 284 | ``` 285 | setSelections([{ 286 | start: [0, 0], 287 | end: [0, 5], 288 | position: 'left' // Control cursor position 289 | }, { 290 | start: [1, 0], 291 | end: [1, 5], 292 | position: 'right' 293 | }]) 294 | ``` 295 | 296 | ### Monitor file changes 297 | ``` 298 | watchFiles('filepath', (e) => {}) 299 | ``` 300 | 301 | ### Create a progress bar 302 | ``` 303 | createProgress({ 304 | title: 'Progress Bar', 305 | async done(report) { 306 | report({ 307 | message: 'Progress bar 10% completed', 308 | increment: 10 309 | }) 310 | setTimeout(() => { 311 | report({ 312 | message: 'Progress bar completed 50', 313 | increment: 50 314 | }) 315 | }) 316 | } 317 | }) 318 | ``` 319 | 320 | ### Create a selection box 321 | ``` 322 | createSelect(['vue','react','svelte','solid']).then((res)=>{}) 323 | ``` 324 | 325 | ### Listen to the event of hover element 326 | ``` 327 | registerHoverProvider('vue', (e) => {}) 328 | ``` 329 | 330 | ### Monitor the click jump position when the option key is pressed. 331 | ``` 332 | registerDefinitionProvider('vue', (e) => {}) 333 | ``` 334 | 335 | ### Get topic-related APIs 336 | ``` 337 | const { getCurrentTheme, getAllTheme, setTheme, } = useTheme() 338 | ``` 339 | 340 | ### Get the language of the currently active text 341 | ``` 342 | const language = getActiveTextEditorLanguageId() // vue 343 | ``` 344 | 345 | ### Rename file 346 | ``` 347 | rename('url', 'newUrl') 348 | ``` 349 | 350 | ### nextTick, some operations after file changes need to wait for the file to change before executing 351 | ``` 352 | nextTick(()=>{}) 353 | ``` 354 | 355 | ### Add style 356 | ``` 357 | setStyle(createStyle({ 358 | backgroundColor: 'yellow', 359 | border: '1px solid red' 360 | }), createRange([0, 0], [0, 10])) 361 | ``` 362 | 363 | ### Create input box 364 | 365 | ``` 366 | createInput({ 367 | title: 'I am an input box', 368 | placeHolder: 'Please enter content', 369 | value: '' 370 | }) 371 | ``` 372 | 373 | ### getActiveTextEditor 374 | 375 | ``` 376 | const activeTextEditor = getActiveTextEditor() 377 | ``` 378 | 379 | ### getKeyWords 380 | 381 | ``` 382 | const keyWords = getKeyWords(position) 383 | ``` 384 | 385 | ### Set the click command parameter of MarkdownString 386 | 387 | ``` 388 | const md = new vscode.MarkdownString() 389 | md.isTrusted = true 390 | md.supportHtml = true 391 | const commandUri = `command:a.b?${setCommandParams(['params1', 'params2'])}` 392 | md.appendMarkdown(`[🦘](${commandUri})`); 393 | ``` 394 | 395 | ### getOffsetFromPosition 396 | ``` 397 | const offset = getOffsetFromPosition(position) // Get the offset of the current text and location 398 | const offset = getOffsetFromPosition(position,code) // 获取指定code,位置的offset 399 | ``` 400 | 401 | ## License 402 | 403 | [MIT](./LICENSE) License © 2022 [Simon He](https://github.com/Simon-He95) 404 | 405 | Buy Me A Coffee 406 | --------------------------------------------------------------------------------