简体   繁体   English

VSCode 扩展 - 如何更改文件的文本

[英]VSCode extension - how to alter file's text

I have an extension that grabs the open file's text and alters it.我有一个扩展程序可以抓取打开文件的文本并更改它。 Once the text is altered, how do I put it back into the file that is displayed in VSCode?更改文本后,如何将其放回 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 "myExtension" is now active!');
  console.log(process.versions);

  // 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('extension.myExtension', () => {
    // The code you place here will be executed every time your command is executed

    let activeEditor = vscode.window.activeTextEditor;
    if (!activeEditor) {
      return;
    }
    let text = activeEditor.document.getText();

    getAsyncApi(text).then((textToInsertIntoDoc) => {

      let finaldoc = insertTextIntoDoc(text, textToInsertIntoDoc);

      // not what I want - just used to see new text
      vscode.window.showInformationMessage(textToInsertIntoDoc);
    });

  });

  context.subscriptions.push(disposable);
}

This is a revision of the main function in Rebornix's extension sample (included with the set of Microsoft extension samples) that handles the selection issues you raised.这是 Rebornix 扩展示例(包含在一组 Microsoft 扩展示例中)中主要功能的修订版,用于处理您提出的选择问题。 It reverses the content of the selection(s) (leaving the selections) or if a selection is empty it will reverse the word under the cursor at that selection without leaving anything selected.它反转选择的内容(留下选择),或者如果选择为空,它将反转该选择处光标下的单词,而不保留任何选择。 It often makes sense to leave a selection, but you can add code to remove selection.离开选择通常是有意义的,但您可以添加代码来删除选择。

    let disposable = vscode.commands.registerCommand('extension.reverseWord', function () {
        // Get the active text editor
        const editor = vscode.window.activeTextEditor;

        if (editor) {
            const document = editor.document;
            editor.edit(editBuilder => {
                editor.selections.forEach(sel => {
                    const range = sel.isEmpty ? document.getWordRangeAtPosition(sel.start) || sel : sel;
                    let word = document.getText(range);
                    let reversed = word.split('').reverse().join('');
                    editBuilder.replace(range, reversed);
                })
            }) // apply the (accumulated) replacement(s) (if multiple cursors/selections)
        }
    });

Admittedly, while I could remove a single selection by setting .selection to a new empty selection that doesn't seem to work with .selections[i] .诚然,虽然我可以通过将.selection设置为似乎不适用于.selections[i]的新空.selection来删除单个选择。 But you can make multiple changes without having selections in the first place.但是您可以在没有选择的情况下进行多项更改。

What you don't want to do is make a selection through code just to alter text through code.您不想做的是通过代码进行选择只是为了通过代码更改文本。 Users make selections, you don't (unless the end purpose of the function is to make a selection).用户进行选择,而您不进行选择(除非该功能的最终目的是进行选择)。

I came to this question looking for a way to apply a textEdit[] array (which is normally returned by a provideDocumentRangeFormattingEdits callback function).我来到这个问题寻找一种方法来应用textEdit[]数组(通常由provideDocumentRangeFormattingEdits回调函数返回)。 If you build changes in the array you can apply them to your document in your own function:如果您在数组中构建更改,您可以在您自己的函数中将它们应用到您的文档:

        const { activeTextEditor } = vscode.window;

        if (activeTextEditor) {
            const { document } = activeTextEditor;
            if (document) {
                /*
                  build your textEdits similarly to the above with insert, delete, replace 
                  but not within an editBuilder arrow function
                const textEdits: vscode.TextEdit[] = [];
                textEdits.push(vscode.TextEdit.replace(...));
                textEdits.push(vscode.TextEdit.insert(...));
                */

                const workEdits = new vscode.WorkspaceEdit();
                workEdits.set(document.uri, textEdits); // give the edits
                vscode.workspace.applyEdit(workEdits); // apply the edits
            }
        }

So that's another way to apply edits to a document.所以这是将编辑应用到文档的另一种方法。 Even though I got the editBuilder sample to work correctly without selecting text, I have had problems with selections in other cases.即使我在没有选择文本的情况下让 editBuilder 示例正常工作,我在其他情况下也遇到了选择问题。 WorkspaceEdit doesn't select the changes. WorkspaceEdit 不会选择更改。

The API you can use here is TextEditor.edit , whose definition is您可以在此处使用的 API 是TextEditor.edit ,其定义为

edit(callback: (editBuilder: TextEditorEdit) => void, options?: {   undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;

It asks for a callback as the first parameter and in the callback, you can make edits to the document by visiting editBuilder.它要求回调作为第一个参数,在回调中,您可以通过访问 editBuilder 对文档进行编辑。

I put a sample extension in https://github.com/Microsoft/vscode-extension-samples/tree/master/document-editing-sample which reverses the content in current selection, which is basically a simple use TextEditor.edit .我在https://github.com/Microsoft/vscode-extension-samples/tree/master/document-editing-sample 中放置了一个示例扩展,它反转当前选择中的内容,这基本上是一个简单的使用TextEditor.edit

Here is the code snippet that will solve your issue :这是可以解决您的问题的代码片段:

activeEditor.edit((selectedText) => {
    selectedText.replace(activeEditor.selection, newText);
})

Due to the issues I commented about in the above answer, I ended up writing a quick function that does multi-cursor friendly insert, and if the selection was empty, then it does not leave the inserted text selected afterwards (ie it has the same intuitive behavior as if you had pressed CTRL + V , or typed text on the keyboard, etc.)由于我在上面的答案中评论过的问题,我最终编写了一个快速函数来进行多光标友好插入,如果选择为空,那么它不会在之后选择插入的文本(即它具有相同的直观的行为,就像您按下了CTRL + V ,或在键盘上输入文本等)

Invoking it is simple:调用它很简单:

// x is the cursor index, it can be safely ignored if you don't need it.
InsertText(x => 'Hello World'); 

Implementation:执行:

function InsertText(getText: (i:number) => string, i: number = 0, wasEmpty: boolean = false) {

    let activeEditor = vscode.window.activeTextEditor;
    if (!activeEditor) { return; }

    let sels = activeEditor.selections;

    if (i > 0 && wasEmpty)
    {
        sels[i - 1] = new vscode.Selection(sels[i - 1].end, sels[i - 1].end);
        activeEditor.selections = sels; // required or the selection updates will be ignored! 😱
    }

    if (i < 0 || i >= sels.length) { return; }

    let isEmpty = sels[i].isEmpty;
    activeEditor.edit(edit => edit.replace(sels[i], getText(i))).then(x => {

        InsertText(getText, i + 1, isEmpty);
    });
}
let strContent = "hello world";

const edit = new vscode.WorkspaceEdit();
edit.insert(YOUR_URI, new vscode.Position(0, 0), strContent);
let success = await vscode.workspace.applyEdit(edit);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM