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

相关推荐
JohnYan3 天前
工作笔记 - WSL端口映射
后端·网络协议·visual studio code
有一只柴犬7 天前
科学休息,我用AI写了个vscode养鱼插件:DevFish发布
程序员·visual studio code
ol木子李lo8 天前
Doxygen入门指南:从注释到自动文档
c语言·c++·windows·编辑器·visual studio code·visual studio·doxygen
散峰而望10 天前
基本魔法语言数组 (一) (C语言)
c语言·开发语言·编辑器·github·visual studio code·visual studio
AmazingKO11 天前
推送报错403怎么办?vscode推送项目到github
chatgpt·github·visual studio code·竹相左边
Axizs16 天前
我用AI摸鱼写了个VSCode摸鱼插件
ai编程·visual studio code
飞哥数智坊17 天前
分享一个 VS Code 插件:一键把 Markdown 网络图片存本地
markdown·visual studio code
Wind哥17 天前
VS Code搭建C/C++开发调试环境-Windows
c语言·开发语言·c++·visual studio code
歪歪10018 天前
在C#中详细介绍一下Visual Studio中如何使用数据可视化工具
开发语言·前端·c#·visual studio code·visual studio·1024程序员节
JohnYan24 天前
工作笔记 - VSCode ssh远程开发
javascript·ssh·visual studio code