【问题标题】:VSCode extension - how to alter file's textVSCode 扩展 - 如何更改文件的文本
【发布时间】:2019-05-04 06:34:27
【问题描述】:

我有一个扩展程序可以抓取打开文件的文本并对其进行更改。文本更改后,如何将其放回 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);
}

【问题讨论】:

    标签: visual-studio-code vscode-extensions


    【解决方案1】:

    这里可以使用的API是TextEditor.edit,其定义是

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

    它要求回调作为第一个参数,在回调中,您可以通过访问 editBuilder 对文档进行编辑。

    我在https://github.com/Microsoft/vscode-extension-samples/tree/master/document-editing-sample中放了一个示例扩展,它反转当前选择的内容,这基本上是一个简单的使用TextEditor.edit

    【讨论】:

    • 这仅适用于单个光标(甚至示例中的代码)。使用 for 循环遍历每个 editor.selections 实例对我来说也不起作用,此外它还有其他怪癖,比如它如何在之后选择文本,所以你会不小心输入插入的文本等等——所有这使我得出结论,这不是插入文本的最佳方式。 -- 我在下面添加了一个可以解决这些问题的答案。
    • @BrainSlugs83,这里的校长是正确的。要修改示例,您只需迭代 editor.selections 以应用于每个示例。我不确定为什么,但迭代需要在编辑生成器中。如果使用选择调用命令,则离开选择是有意义的。否则,您可以通过代码消除选择,甚至不需要使用 getWordRangeAtPosition() 进行选择。
    【解决方案2】:

    这是 Rebornix 扩展示例(包含在 Microsoft 扩展示例集中)中主要功能的修订版,用于处理您提出的选择问题。它反转选择的内容(保留选择),或者如果选择为空,它将反转该选择处光标下的单词而不留下任何选择。保留选择通常是有意义的,但您可以添加代码来删除选择。

        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)
            }
        });
    
    

    诚然,虽然我可以通过将.selection 设置为似乎不适用于.selections[i] 的新空选择来删除单个选择。但是您可以在没有选择的情况下进行多项更改。

    您不想做的是通过代码进行选择,只是为了通过代码更改文本。用户进行选择,而您不需要(除非函数的最终目的是进行选择)。

    我来这个问题是为了寻找一种方法来应用 textEdit[] 数组(通常由 provideDocumentRangeFormattingEdits 回调函数返回)。如果您在数组中构建更改,您可以在您自己的函数中将它们应用到您的文档:

            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
                }
            }
    

    这是对文档应用编辑的另一种方式。即使我在没有选择文本的情况下让 editBuilder 示例正常工作,但在其他情况下我也遇到了选择问题。 WorkspaceEdit 不会选择更改。

    【讨论】:

    • 非常好,比处理连续的承诺要简单得多。
    【解决方案3】:

    这是解决您问题的代码 sn-p :

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

    【讨论】:

      【解决方案4】:

      由于我在上面的答案中评论过的问题,我最终编写了一个快速函数,可以进行多光标友好插入,如果选择为空,那么它不会在之后选择插入的文本(即具有与按下 CTRL + V 或在键盘上键入文本等相同的直观行为)

      调用它很简单:

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

      实施:

      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);
          });
      }
      

      【讨论】:

      • 似乎这段代码不适用于 theia 或 gitpod 云实例,但适用于 vscode 本身。很有趣。
      【解决方案5】:
      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);
      

      【讨论】:

        猜你喜欢
        • 2019-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多