VS Code 插件开发——Console、Region快捷插件

自己平时使用了一些插件,有些地方感觉不顺手,索性按自己需求写一个VS Code插件,同时练练手。 大体功能就是快速打印Console,Region任意折叠代码块。

官网文档: code.visualstudio.com/api/get-sta...

快速开始

  1. 安装开发脚手架
shell 复制代码
npm install -g yo generator-code
  1. 运行创建yo code
shell 复制代码
# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? HelloWorld
### Press <Enter> to choose default for all options below ###

# ? What's the identifier of your extension? helloworld
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm

# ? Do you want to open the new folder with Visual Studio Code? Open with `code`

Console快速打印

获取选中的文本

  • 原始代码,运行右下角弹出Hello World from loghuu!
typescript 复制代码
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	console.log('Congratulations, your extension "loghuu" is now active!');

	// The command has been defined in the package.json file
	// Now provide the implementation of the command with registerCommand
	// The commandId parameter must match the command field in package.json
	let disposable = vscode.commands.registerCommand('loghuu.helloWorld', () => {
		// The code you place here will be executed every time your command is executed
		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World from loghuu!');
	});

	context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
export function deactivate() { }
  • 修改代码,获取选中文本
typescript 复制代码
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	console.log('Congratulations, your extension "loghuu" is now active!');


	let disposable = vscode.commands.registerCommand('loghuu.helloWorld', () => {
		// 获取当前活动的编辑器
		const editor = vscode.window.activeTextEditor;

		if (editor) {
			// 获取当前选中的文本
			const selectedText = editor.document.getText(editor.selection);
			vscode.window.showInformationMessage(`Selected text: ${selectedText}`);
		} else {
			vscode.window.showInformationMessage('No active editor.');
		}
	});


	context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
export function deactivate() { }
  • 效果

将获取到的文本插入到下一行

将刚才的代码改为:

typescript 复制代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
	console.log('Congratulations, your extension "loghuu" is now active!');

	let disposable = vscode.commands.registerCommand('loghuu.helloWorld', () => {
		// 获取当前活动的编辑器
		const editor = vscode.window.activeTextEditor;

		if (editor) {
			// 获取当前选中的文本
			const selectedText = editor.document.getText(editor.selection);

			if (selectedText) {
				// 获取选中文本的结束位置
				const selectionEnd = editor.selection.end;

				// 计算下一行的位置
				const nextLine = new vscode.Position(selectionEnd.line + 1, 0);

				// 插入新行并输出文本
				editor.edit(editBuilder => {
					editBuilder.insert(nextLine, selectedText + '\n');
				});

				vscode.window.showInformationMessage('Inserted text below selected text.');
			} else {
				vscode.window.showInformationMessage('No text selected.');
			}
		} else {
			vscode.window.showInformationMessage('No active editor.');
		}
	});


	context.subscriptions.push(disposable);
}

export function deactivate() { }

绑定快捷键

  • 完善修改代码
typescript 复制代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
	console.log('Congratulations, your extension "loghuu" is now active!');

	let disposable = vscode.commands.registerCommand('loghuu.consoleLog', () => {
		// 获取当前活动的编辑器
		const editor = vscode.window.activeTextEditor;

		if (editor) {
			// 获取当前选中的文本
			const selectedText = editor.document.getText(editor.selection);

			// 获取当前行的行号
			const currentLineNumber = editor.selection.active.line;

			// 获取当前行的文本
			const currentLineText = editor.document.lineAt(currentLineNumber).text;

			// 构造要插入的 console.log 语句
			const consoleStatement = selectedText ? `console.log(${selectedText});\n` : `console.log('${currentLineText}');\n`;

			// 获取当前光标位置
			const currentPosition = editor.selection.active;

			// 插入 console.log 语句
			editor.edit(editBuilder => {
				if (selectedText) {
					// 如果有选中文本,则插入到下一行
					editBuilder.insert(new vscode.Position(currentLineNumber + 1, 0), consoleStatement);
				} else {
					// 如果没有选中文本,则插入到当前行
					editBuilder.insert(currentPosition, consoleStatement);
				}
			});

			vscode.window.showInformationMessage('Inserted console.log statement.');
		}
	});

	context.subscriptions.push(disposable);
}

export function deactivate() { }
  • 打开package.json,绑定快捷键CTRL + L
json 复制代码
  "contributes": {
    "commands": [
      {
        "command": "loghuu.consoleLog",
        "title": "Loghuu"
      }
    ],
    "keybindings": [
      {
        "command": "loghuu.consoleLog",
        "key": "ctrl+l",
        "mac": "cmd+l",
        "when": "editorTextFocus"
      }
    ]
  }

光标定位

输出新的一行之后,把光标定位过去,方便后续操作

typescript 复制代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  console.log('Congratulations, your extension "loghuu" is now active!');

  let disposable = vscode.commands.registerCommand('loghuu.consoleLog', async () => {
  	// 获取当前活动的编辑器
  	const editor = vscode.window.activeTextEditor;

  	if (editor) {
  		// 获取当前选中的文本
  		const selectedText = editor.document.getText(editor.selection);

  		// 获取当前行的行号
  		const currentLineNumber = editor.selection.active.line;

  		// 获取当前行的文本
  		const currentLineText = editor.document.lineAt(currentLineNumber).text;

  		// 构造要插入的 console.log 语句
  		const consoleStatement = selectedText ? `\nconsole.log(${selectedText});` : `console.log('${currentLineText}');`;

  		// 获取当前光标位置
  		const currentPosition = editor.selection.active;

  		// 插入 console.log 语句
  		await editor.edit(async editBuilder => {
  			if (selectedText) {
  				// 如果有选中文本,则插入到下一行
  				await editBuilder.insert(new vscode.Position(currentLineNumber + 1, 0), consoleStatement);
  				// 获取括号内的位置
  				const openBracketPosition = new vscode.Position(currentLineNumber + 1, consoleStatement.indexOf('('));
  				const closeBracketPosition = new vscode.Position(currentLineNumber + 1, consoleStatement.indexOf(')') - 1);
  				// 将光标定位到括号内并选中括号内的内容
  				editor.selection = new vscode.Selection(openBracketPosition, closeBracketPosition);
  			} else {
  				// 如果没有选中文本,则插入到当前行
  				await editBuilder.insert(currentPosition, consoleStatement);
  				// 获取括号内的位置
  				const openBracketPosition = new vscode.Position(currentPosition.line, consoleStatement.indexOf('(') + 2);
  				const closeBracketPosition = new vscode.Position(currentPosition.line, consoleStatement.indexOf(')') - 1);
  				// 将光标定位到括号内并选中括号内的内容
  				editor.selection = new vscode.Selection(openBracketPosition, closeBracketPosition);
  			}
  		});

  		vscode.window.showInformationMessage('Inserted console.log statement.');
  	}
  });

  context.subscriptions.push(disposable);
}

export function deactivate() { }

快速console的核心功能到这里就都实现了,下面优化一下使用体验

优化体验,随机文字颜色

console是支持修改打印样式的

生成随机颜色

typescript 复制代码
/**
* 生成随机颜色
*
* @return {*}  {string}
*/
function getRandomColor(): string {
  const letters = '0123456789ABCDEF';
  let color = '#';
  for (let i = 0; i < 6; i++) {
  	color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
}

由于控制台可能是亮色或者暗色的,导致文字不可见或者模糊,需要针对这种情况作出处理:

生成随机颜色,亮度处理

typescript 复制代码
/**
 * 生成亮色随机颜色
 *
 * @param {number} [maxAttempts=10]
 * @return {*}  {string}
 */
function getRandomColor(maxAttempts: number = 10): string {

	const isLightColor = (color: string): boolean => {
		// 解析颜色
		const rgb = parseInt(color.substring(1), 16);
		const r = (rgb >> 16) & 0xff;
		const g = (rgb >> 8) & 0xff;
		const b = (rgb >> 0) & 0xff;

		// 计算亮度
		const brightness = (r * 299 + g * 587 + b * 114) / 1000;

		// 判断亮度,可调整阈值
		return brightness > 128;
	};

	let color: string;

	for (let attempt = 0; attempt < maxAttempts; attempt++) {
		// 生成随机颜色
		color = '#' + Math.floor(Math.random() * 16777215).toString(16);

		// 如果是亮色,返回颜色
		if (isLightColor(color)) {
			return color;
		}
	}

	// 如果尝试次数超过限制,返回默认颜色
	return '#5662f6';
}

调整光标位置

typescript 复制代码
// 插入 console.log 语句
			await editor.edit(async editBuilder => {
				if (selectedText) {
					// 如果有选中文本,则插入到下一行
					await editBuilder.insert(new vscode.Position(currentLineNumber + 1, 0), consoleStatement);

					const secondCommaIndex = consoleStatement.indexOf(',', consoleStatement.indexOf(',') + 1);
					const openBracketPosition = new vscode.Position(currentLineNumber + 1, secondCommaIndex + 1);

					const closeBracketPosition = new vscode.Position(currentLineNumber + 1, consoleStatement.indexOf(')') - 1);
					editor.selection = new vscode.Selection(openBracketPosition, closeBracketPosition);
				} else {
					// 如果没有选中文本,则插入到当前行
					await editBuilder.insert(currentPosition, consoleStatement);

					const firstPosition = new vscode.Position(currentPosition.line, consoleStatement.indexOf('[') + 1);

					const secondCommaIndex = consoleStatement.indexOf(',', consoleStatement.indexOf(',') + 1);
					const openBracketPosition = new vscode.Position(currentPosition.line, secondCommaIndex + 1);

					editor.selections = [
						new vscode.Selection(openBracketPosition, openBracketPosition),
						new vscode.Selection(firstPosition, firstPosition),
					];
				}
			});
                        

继续升级,根据选中文字自动打印错误

写代码的时候经常需要trycatch错误并打印输出展示,但是打包的时候我们想清除所有console.log单保留错误的输出,这时候可以对错误使用console.error:

typescript 复制代码
// 构造要插入的 console 语句
			let consoleStatement: string;
			if (selectedText && (selectedText.toLowerCase() === 'error' || selectedText.toLowerCase() === 'err')) {
				consoleStatement = `\nconsole.error('%c[${selectedText}]-${currentLineNumber}:', 'color: ${randomColor}', ${selectedText});`;
			} else {
				consoleStatement = selectedText
					? `\nconsole.log('%c[${selectedText}]-${currentLineNumber}:', 'color: ${randomColor}', ${selectedText});`
					: `console.log(' %c[]-${currentLineNumber}:', 'color: ${randomColor}',);`;
			}

拆分代码,优化结构

由于后面会添加别的功能,对代码进行拆分,优化结构,方便后面的升级优化

typescript 复制代码
// commands/loghuu.consoleLog.ts
import * as vscode from 'vscode';
import { getRandomColor } from '../utils/getRandomColor';

export async function insertConsoleStatement(editor: vscode.TextEditor) {
    if (editor) {
        // 获取当前选中的文本
        const selectedText = editor.document.getText(editor.selection);
        // 获取当前行的行号
        const currentLineNumber = editor.selection.active.line;

        // 生成随机颜色,最多尝试10次
        const randomColor = getRandomColor(10);

        // 构造要插入的 console 语句
        let consoleStatement: string;
        if (selectedText && (selectedText.toLowerCase() === 'error' || selectedText.toLowerCase() === 'err')) {
            consoleStatement = `\nconsole.error('%c[${selectedText}]-${currentLineNumber}:', 'color: ${randomColor}', ${selectedText});`;
        } else {
            consoleStatement = selectedText
                ? `\nconsole.log('%c[${selectedText}]-${currentLineNumber}:', 'color: ${randomColor}', ${selectedText});`
                : `console.log(' %c[]-${currentLineNumber}:', 'color: ${randomColor}',);`;
        }

        // 获取当前光标位置
        const currentPosition = editor.selection.active;

        // 插入 console 语句
        await editor.edit(async editBuilder => {
            if (selectedText) {
                // 如果有选中文本,则插入到下一行
                await editBuilder.insert(new vscode.Position(currentLineNumber + 1, 0), consoleStatement);

                const secondCommaIndex = consoleStatement.indexOf(',', consoleStatement.indexOf(',') + 1);
                const openBracketPosition = new vscode.Position(currentLineNumber + 1, secondCommaIndex + 1);

                const closeBracketPosition = new vscode.Position(currentLineNumber + 1, consoleStatement.indexOf(')') - 1);
                editor.selection = new vscode.Selection(openBracketPosition, closeBracketPosition);
            } else {
                // 如果没有选中文本,则插入到当前行
                await editBuilder.insert(currentPosition, consoleStatement);

                const firstPosition = new vscode.Position(currentPosition.line, consoleStatement.indexOf('[') + 1);

                const secondCommaIndex = consoleStatement.indexOf(',', consoleStatement.indexOf(',') + 1);
                const openBracketPosition = new vscode.Position(currentPosition.line, secondCommaIndex + 1);

                editor.selections = [
                    new vscode.Selection(openBracketPosition, openBracketPosition),
                    new vscode.Selection(firstPosition, firstPosition),
                ];
            }
        });

    }
}
typescript 复制代码
// extension.ts
import * as vscode from 'vscode';
import { insertConsoleStatement } from './commands/consoleLog';

export function activate(context: vscode.ExtensionContext) {
	let disposable = vscode.commands.registerCommand('loghuu.consoleLog', async () => {
		const editor = vscode.window.activeTextEditor;

		editor && insertConsoleStatement(editor);

	});

	context.subscriptions.push(disposable);
}

export function deactivate() { }

Region快速折叠代码

vs code支持region折叠代码,写个指令快速在代码块前后自动加入region

typescript 复制代码
import * as vscode from 'vscode';

export function addRegionToSelection(): vscode.Disposable {
    const disposable = vscode.commands.registerCommand('loghuu.addRegionToSelection', () => {
        const editor = vscode.window.activeTextEditor;

        if (editor && editor.selections.length > 0) {
            editor.edit(editBuilder => {
                const [firstSelection] = editor.selections;
                const lastSelection = editor.selections.at(-1);

                // 在第一个选中文本的前面和最后一个选中文本的后面插入 regionText
                editBuilder.insert(firstSelection.start, '// #region\n');
                editBuilder.insert(lastSelection!.end, '\n// #endregion');
            });
        }
    });

    return disposable;
}
typescript 复制代码
import * as vscode from 'vscode';
import { insertConsoleStatement } from './commands/consoleLog';
import { addRegionToSelection } from './commands/addRegionToSelection';

export function activate(context: vscode.ExtensionContext) {
	const addRegion = addRegionToSelection();
	const insertConsole = insertConsoleStatement();

	context.subscriptions.push(addRegion);
	context.subscriptions.push(insertConsole);
}

export function deactivate() { }

插件: https://marketplace.visualstudio.com/items?itemName=sharebravery.loghuu

  • ctrl + l 快速打印
  • ctrl + shift + r 快速Region

我后续迭代了不少版本,文章里没有说到,代码也迁移用了antfu大佬的模板:

此插件完整代码在: https://github.com/sharebravery/vscode-loghuu

antfu插件模板:https://github.com/antfu/starter-vscode?tab=readme-ov-file

END

相关推荐
Eric_见嘉31 分钟前
真的能无限试(白)用(嫖)cursor 吗?
前端·visual studio code
heilai42 天前
workerman的安装与使用
c++·websocket·http·php·phpstorm·visual studio code
移民找老国8 天前
加拿大移民新风向
java-ee·maven·phpstorm·visual studio code·nio
闪亮Girl10 天前
vs2015安装插件QtPackage.vsix等vsix文件类型
visual studio code
SuperYing11 天前
💯What?维护新老项目频繁切换node版本太恼火?开发一个vscode插件自动切换版本,从此告别烦恼
前端·visual studio code
羊小猪~~12 天前
数据结构C语言描述1(图文结合)--顺序表讲解,实现,表达式求值应用,考研可看
java·c语言·数据结构·c++·链表·visual studio code·visual studio
羊小猪~~12 天前
C/C++语言基础--C++模板与元编程系列三(变量模板、constexpr、萃取等…………)
java·c语言·开发语言·c++·visual studio code·visual studio
羊小猪~~15 天前
C/C++语言基础--C++模板与元编程系列二类模板、全特化、偏特化、编译模型简介、实现简单Vetctor等…………)
java·c语言·开发语言·c++·visual studio code·visual studio
编程老船长21 天前
用PlantUML让状态图“动”起来 —— 快速绘制老师申报课程流程
uml·visual studio code
风雪中的兔子24 天前
vscode插件开发入门:小试牛刀
前端·visual studio code