vscode插件开发笔记——大模型应用之AI编程助手

系列文章目录

文章目录


前言

最近在开发vscode插件相关的项目,网上很少有关于大模型作为AI 编程助手这方面的教程。因此,借此机会把最近写的几个demo分享记录一下。

一、代码补全

思路:

  1. 读取vscode插件上鼠标光标的上下文信息。
  2. 将提示词和上下文代码作为输入,通过modelfusion调用大模型得到输出。
  3. 将输出内容插入到光标所在位置,通过Declaration在vscode页面进行显示。
  4. 设置快捷键,如果代码补全正确,按下快捷键后自动插入代码。反之光标移动,代码自动消失。

下面直接上代码。

extension.ts 文件:

typescript 复制代码
import * as vscode from 'vscode';
import {
    BaseUrlApiConfiguration,
    openaicompatible,
	streamText,
  } from 'modelfusion';
import{ previewInsertion, getBeforeText, getAfterText }from '../src/main'

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 "dytest" is now active!');

   let globalText:string|undefined ; 
   let globalindex: vscode.Position | undefined;
	// 如何删除字符
	const editor = vscode.window.activeTextEditor;


	// 代码补全命令
	const disposable = vscode.commands.registerCommand('dytest.helloWorld', async () => {
	if (!editor) {
		return;
	}
	// 代码所在位置
	const code =editor.document.getText();

	//光标所在位置
	const offset =editor.document.offsetAt(editor.selection.active);
	const index = editor.document.positionAt(offset);
	
	
	const position = editor.selection.active;
	const document = editor.document;

	const beforeText = getBeforeText(document, position);
	const afterText = getAfterText(document, position);

	// 调用大模型
	const code_prompt='提示词';
	const code_instruction='{{{prefix}}}[BLANK]{{{suffix}}}';
	const code_instruction_2=code_instruction.replace("{{{prefix}}}", beforeText).replace("{{{suffix}}}",afterText)
	 console.log(code_instruction_2)
const text2 = await streamText({
    model: openaicompatible
      .ChatTextGenerator({
        // 这里使用的是自己部署的大模型,url和openai的一样。但是模型不是用的openai系列的。如果要改,可以换成openai的。
        api: new BaseUrlApiConfiguration({
          baseUrl: "模型的url",
          headers: {
            Authorization: `模型的api`,
          },
        }),
        provider: "openaicompatible-fireworksai", // optional, only needed for logging and custom configs
        model: "自己的模型",
      })
      .withInstructionPrompt(),
      prompt: {
                system:
                code_prompt,
                instruction:
                code_instruction_2
              },
  });
  
 
  let responseUntilNow = "";
  for await (const textPart of text2) {
    // process.stdout.write(textPart);
    responseUntilNow += textPart;
  }
  console.log(responseUntilNow)
	  // 进行代码补全的提示
	  const previewinsertion =previewInsertion(editor,index,responseUntilNow);
	  globalText=responseUntilNow;
	  globalindex=index

		vscode.window.showInformationMessage('Hello World from dy_test!');
	});

	
	
	context.subscriptions.push(disposable);

	const disposable2 = vscode.commands.registerCommand('extension.myCommand', async () => {

		editor?.edit((editBuilder => {
			if (!globalindex || !globalText){
				return;
			}
			const lines = globalText.split(/\r\n|\n/); // 分割文本
			editBuilder.insert(globalindex, lines[0])
			globalindex=undefined;
			globalText=undefined;
		}));
		vscode.window.showInformationMessage('Hello World from myextension!');
	  });
	
	  let timeout: NodeJS.Timeout | undefined;
	  context.subscriptions.push(disposable2);

	  // 注册事件监听器以在特定条件下调用命令
	  context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => {
		if (editor) {
            // 延迟调用命令
            if (timeout) {
                clearTimeout(timeout);
            }
            timeout = setTimeout(() => {
                vscode.commands.executeCommand('dytest.helloWorld');
            }, 200); // 延迟
        }
    }));

    context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection(event => {
		if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(() => {
            vscode.commands.executeCommand('dytest.helloWorld');
        }, 200); // 延迟
    }));
}
export function deactivate() {}

main.ts文件:

typescript 复制代码
import {parse}from '@babel/parser'
import traverse from '@babel/traverse'
import * as vscode from 'vscode';

// 代码补全插入
export function previewInsertion(editor: vscode.TextEditor, position: vscode.Position, text: string, ) {
  const range = new vscode.Range(position, position.translate({characterDelta: text.length}));
  let currentDecoration: vscode.DecorationOptions[] | undefined = undefined;
  let decorationType: vscode.TextEditorDecorationType | undefined = undefined;
 

const lines = text.split(/\r\n|\n/); // 分割文本
let lineCount = 0;
let totalCharacterCount = 0;

// 计算总行数和总字符数
for (const line of lines) {
    lineCount++;
    totalCharacterCount += line.length;
}
totalCharacterCount--;
console.log(lineCount); // 输出非空行数


if (!decorationType) {
    decorationType = vscode.window.createTextEditorDecorationType({
     light: { // Light theme settings
         after: {
             contentText: lines[0],
             fontStyle: 'italic',
             color: '#7f8c8d', // 灰色
             backgroundColor: 'transparent',
            //  textDecoration: 'none',
              margin: '0 0 0 0',
         },
     },
     dark: { // Dark theme settings
         after: {
             contentText: lines[0],
             fontStyle: 'italic',
             color: '#95a5a6', // 灰色,适合深色主题
             backgroundColor: 'transparent',
            //  textDecoration: 'none',
             margin: '0 0 0 0',
         }, 
 }
});
}

const endPosition=position.translate({lineDelta:lineCount-1,characterDelta:totalCharacterCount })
console.log("position:",position)
console.log("endPosition:",endPosition)
 // 创建装饰器选项
 
 currentDecoration = [{
    range: new vscode.Range(position, position),
    hoverMessage: new vscode.MarkdownString('按"tab"键确认'),
}];


// 应用装饰器
editor.setDecorations(decorationType, currentDecoration);



// 监听鼠标移动事件,移除装饰
const mouseMoveDisposable = vscode.window.onDidChangeTextEditorSelection(
        (event) => {
            if (event.textEditor === editor) {
                editor.setDecorations(decorationType, []);
                currentDecoration = undefined;
              
            }
        },
        null,
    );


  

   
}
  // 获取文本上下文信息
export function getBeforeText(document: vscode.TextDocument, position: vscode.Position): string {
    const range = new vscode.Range(new vscode.Position(0, 0), position);
    return document.getText(range);
}
export function getAfterText(document: vscode.TextDocument, position: vscode.Position): string {
    const lastLine = document.lineCount - 1;
    const lastLineLength = document.lineAt(lastLine).text.length;
    const range = new vscode.Range(position, new vscode.Position(lastLine, lastLineLength));
    return document.getText(range);
}

package.json

添加两个命令

typescript 复制代码
"commands": [
  {
    "command": "dytest.helloWorld",
    "title": "Hello World"
  },
  {  "command": "extension.myCommand",
     "title": "My Command"
      }
]

快捷键

typescript 复制代码
   "keybindings": [
    {
      "command": "extension.myCommand",
      "key": "ctrl+shift",
      "when": "editorTextFocus"
    }
  ]

实现效果:

代码补全(2)

相关推荐
郭庆汝15 小时前
(七)自然语言处理笔记——Ai医生
人工智能·笔记·自然语言处理
czhc114007566315 小时前
Winform笔记1129 checkbox listbox combabox checkedlistbox datapacker
笔记
心随雨下15 小时前
TypeScript泛型开发常见错误解析
java·开发语言·typescript
('-')15 小时前
《从根上理解MySQL是怎样运行的》第十二章学习笔记
笔记·学习·mysql
回忆彡美好17 小时前
OpenGL的3D编程个人笔记之材质贴图
笔记·3d·材质·opengl
一个平凡而乐于分享的小比特17 小时前
UCOSIII内核 VS FreeRTOS内核
笔记·freertos·ucosiii
云起SAAS17 小时前
1V1七彩测评抖音快手微信小程序看广告流量主开源
微信小程序·小程序·ai编程·看广告变现轻·1v1七彩测评
小兵张健17 小时前
AI 如何再工程化项目中提效?
ai编程
mixboot17 小时前
Visual Studio Code 中使用 Claude Code
vscode·glm·claude code
星轨初途18 小时前
C++入门(算法竞赛类)
c++·经验分享·笔记·算法