VS Code扩展API以撤销非活动文本编辑器上的更改。

huangapple go评论54阅读模式
英文:

VS Code extension API to Undo changes on a non-active text editor

问题

我正在编写一个VS Code扩展,它会在现有文本编辑器旁边打开一个Webview,用于可视化和编辑SCXML状态图表。

Webview中的更改会导致文本文档被重写(完全替换文本)。如果用户犯了一个错误,我希望他们能够撤消更改。如果用户在文本编辑器中单击并调用“撤消”,则一切都按预期运行。但我不希望用户不得不切换到文本编辑器来执行撤消操作。我想保持Webview聚焦。我可以如何:

  • 向特定文本编辑器发送“撤消”命令?
  • 发送命令将特定文本编辑器置于前台?

在Webview处发送vscode.commands.executeCommand('undo')不会影响文本编辑器。

以下是由于下面接受的答案而编写的TypeScript代码。它通过一些方式将焦点放在编辑器上,发送命令,然后重新聚焦Webview。

// 查找编辑器和Webview的标签列,以便可以将它们聚焦而不会在另一列中打开新副本
private findTabs() {
   let edTabCol:  ViewColumn|null = null,
       webTabCol: ViewColumn|null = null;
   for (const tab of window.tabGroups.all.flatMap(group => group.tabs)) {
      if (tab.input instanceof vscode.TabInputText) {
         if (tab.input.uri.fsPath === this.editor.document.uri.fsPath) {
            edTabCol = tab.group.viewColumn;
         }
      } else if (tab.input instanceof vscode.TabInputWebview) {
         // TODO: input.viewType不完全匹配创建Webview时提供的viewType; 为什么?
         if (/scxml$/.test(tab.input.viewType)) {
            webTabCol = tab.group.viewColumn;
         }
      }
   }
   return {edTabCol, webTabCol};
}

// 通过将焦点放在文本编辑器上、发送撤消命令,然后重新聚焦Webview来执行撤消操作
private undo() {
   const {edTabCol, webTabCol} = this.findTabs();
   if (edTabCol) {
      const opts = {preserveFocus: false, preview: false, viewColumn: edTabCol};
      window.showTextDocument(this.editor.document, opts).then(() => {
         vscode.commands.executeCommand('undo').then(() => {
            if (webTabCol) this.panel.reveal(webTabCol, false);
         });
      });
   }
}
英文:

I'm writing a VS Code extension that opens a Webview adjacent to an existing text editor to visualize and edit an SCXML state chart.

VS Code扩展API以撤销非活动文本编辑器上的更改。

Changes in the webview cause the text document to be rewritten (complete text replacement). If the user makes a mistake, I want them to be able to use to undo the change. If the user clicks in the text editor and invokes Undo, all works as expected. But I do not want the user to have to switch to the text editor to undo. I'd like to leave the webview focused. I can

How can I either:

  • Send an Undo command to a specific text editor?
  • Send a command to bring a specific text editor to the foreground?

Sending vscode.commands.executeCommand('undo') with the Webview active does not affect the text editor.


Following is the Typescript code I ended up writing, thanks to the accepted answer below. It jumps through some hoops to focus the editor in place, send the command, and then re-focus the webview.

// Locate the tab columns for the editor and webview, so they can be focused
// without opening a new copy in another column
private findTabs() {
   let edTabCol:  ViewColumn|null = null,
       webTabCol: ViewColumn|null = null;
   for (const tab of window.tabGroups.all.flatMap(group => group.tabs)) {
      if (tab.input instanceof vscode.TabInputText) {
         if (tab.input.uri.fsPath===this.editor.document.uri.fsPath) {
            edTabCol = tab.group.viewColumn;
         }
      } else if (tab.input instanceof vscode.TabInputWebview) {
         // TODO: input.viewType does not exactly match the viewType
         // supplied during creation of the webview; why?
         if (/scxml$/.test(tab.input.viewType)) {
            webTabCol = tab.group.viewColumn;
         }
      }
   }
   return {edTabCol, webTabCol};
}

// Undo by focusing text editor, sending undo, and restoring webview focus
private undo() {
   const {edTabCol, webTabCol} = this.findTabs();
   if (edTabCol) {
      const opts = {preserveFocus:false, preview:false, viewColumn:edTabCol};
      window.showTextDocument(this.editor.document, opts).then(() => {
         vscode.commands.executeCommand('undo').then(() => {
            if (webTabCol) this.panel.reveal(webTabCol, false);
         });
      });
   }
}

答案1

得分: 1

以下是代码部分的翻译:

// as I recall the index is 0-based, note the index is in an array
await vscode.commands.executeCommand('workbench.action.openEditorAtIndex', [sourceIndex]);
const uri = vscode.Uri.file("C:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");

// viewColumn is 1-based, same as which editorGroup
const openOptions = { preserveFocus: false, preview: false, viewColumn: 1 };  

await vscode.commands.executeCommand('vscode.open', uri, openOptions);
const uri = vscode.Uri.file("C:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");
let showOptions = { viewColumn: 1, preserveFocus: false, preview: false };
await vscode.window.showTextDocument(uri, showOptions);
const allTabs = vscode.window.tabGroups.all.flatMap(tabGroup => tabGroup.tabs);
const theDocTab = allTabs.find(tab => tab.input?.uri.fsPath === "c:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");

const uri = vscode.Uri.file("C:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");
let showOptions = { viewColumn: theDocTab.group.viewColumn, preserveFocus: false, preview: false };
await vscode.window.showTextDocument(uri, showOptions);

请注意,这些部分仅是代码的翻译,没有其他内容。

英文:

A couple of things to try to focus another editor (and after the undo you could switch right back to the webView and see if that is very noticeable to the user):

// as I recall the index is 0-based, note the index is in an array
await vscode.commands.executeCommand('workbench.action.openEditorAtIndex', [sourceIndex]);

so for the above you need to know that textDocument's index. There are also a series of commnads like workbench.action.openEditorAtIndex1, workbench.action.openEditorAtIndex2, etc.


const uri = vscode.Uri.file("C:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");

// viewColumn is 1-based, same as which editorGroup
const openOptions = { preserveFocus: false, preview: false, viewColumn: 1 };  

await vscode.commands.executeCommand('vscode.open', uri, openOptions);

if that textDocument is already open this should just focus that one, not open another.


const uri = vscode.Uri.file("C:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");
let showOptions = { viewColumn: 1, preserveFocus: false, preview: false };
await vscode.window.showTextDocument(uri, showOptions);

If you don't know that textDocument's viewColumn/editorGroup or index, you could loop through the TabGroups object and match with its uri, which I presume you do know. And of course a user could change the editorGroup or index, so if you need that code I can come up with an example for that. But in the meantime you can investigate the above methods.

Assuming you know the path of your base textDocument, this code will find it as a Tab which has a group.viewColumn property:

const allTabs = vscode.window.tabGroups.all.flatMap(tabGroup => tabGroup.tabs);
const theDocTab = allTabs.find(tab => tab.input?.uri.fsPath === "c:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");

const uri = vscode.Uri.file("C:\\Users\\Mark\\OneDrive\\Test Bed\\test.css");
let showOptions = { viewColumn: theDocTab.group.viewColumn, preserveFocus: false, preview: false };
await vscode.window.showTextDocument(uri, showOptions);

Note the use of theDocTab.group.viewColumn in the showOptions and the form of tab.input?.uri.fsPath === "c:\\Users\\Mark\\OneDrive\\Test Bed\\test.css" - with a small c drive letter.

huangapple
  • 本文由 发表于 2023年2月24日 08:10:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75551534.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定