Zoom
Zoom

Reputation: 464

VSCode API: Anticipate or combine document text changes

Let's say I want to make an extension that listens for document changes and always applies them twice. If the user types 'w' it will turn out as 'ww', if the user backspaces once, it should actually backspace twice. If the user pastes something, it should be pasted twice. (My real use case is more complicated, but it is similar to this)

I could listen for document changes using

vscode.workspace.onDidChangeTextDocument(event => {
    // Do something
});

and use event.contentChanges to see what changes were made and then use

activeEditor.edit((editBuilder: vscode.TextEditorEdit) => {
    // Do something
});

to make the same edit to the document again.

The problem is that this effectively makes two changes to the document so the user will need to ctrl+z twice to undo what is seen as a single action from the user's perspective.

What would be great is if I could anticipate text changes (and then just append more changes) through some method like vscode.workspace.onWillChangeTextDocument but this does not exist (vscode issue #74381, #44771). I also described my problem there.

I see that some people override the 'type' command in vscode to execute before any edit is made (example). But this does not give me access to the edit I want to alter, nor does it capture backspaces or copy/paste commands.

I also tried uding a formatter but this will seemingly override other formatters and users will need to enable "formatting on type" (manually?) for it to update as often as I want. That will also mess with unnecessary user settings/workflows/extensions.

Any idea of how I can achieve this?

Upvotes: 0

Views: 657

Answers (1)

Zoom
Zoom

Reputation: 464

The undesired behavior with undo/redo can be mitigated by passing an options object to activeEditor.edit that prevents an "undo stop" to be added before my 2nd edit/change/action. Like this:

activeEditor.edit((editBuilder: vscode.TextEditorEdit) => {
    // Do something
}, {undoStopBefore: false, undoStopAfter: false});

undoStopAfter seems like it could be either true or false, producing identical behavior for now.

Upvotes: 1

Related Questions