VSCode API - 'textInputFocus' for webview or custom undo handling - visual-studio-code

I am working on VSCode extension implementation.
I am using webview for my extension - in result there is something similar to visual editor, when you can select items and edit.
In result I want to implement custom undo/redo handling for webview.
I have following code to handle VSCode's 'undo'/'redo' commands:
let undoCommand: Disposable;
let redoCommand: Disposable;
const registerCommands = () => {
undoCommand = commands.registerCommand('undo', async (args) => {
// Call custom undo handler
triggerCustomUndo(appJsonFilePath, extensionWebView.webview);
// Execute default undo handler
return commands.executeCommand('default:undo', args);
});
redoCommand = commands.registerCommand('redo', async (args) => {
// Call custom redo handler
triggerCustomRedo(appJsonFilePath, extensionWebView.webview);
// Execute default redo handler
return commands.executeCommand('default:redo', args);
});
};
extensionWebView.onDidChangeViewState((action: WebviewPanelOnDidChangeViewStateEvent) => {
if (!action.webviewPanel.visible || !action.webviewPanel.active) {
undoCommand.dispose();
redoCommand.dispose();
} else {
registerCommands();
}
});
registerCommands();
It works for me.
In result my custom undo/redo handler is called when I select 'undo'/'redo' from VSCode's menu:
Problem is that when I am using 'Ctrl+Z'|'Command+Z' shortcut, then 'undo' command is not called for webview.
This happens because of following 'when' clause in default keybindings:
If I remove 'textInputFocus' statement from 'when' clause, then 'undo' command is called for webview when keyboard shortcut is used.
Some information regarding 'when' contexts - https://github.com/microsoft/vscode-docs/blob/master/docs/getstarted/keybindings.md#contexts
Question:
Is there a way how I can set 'textInputFocus' to 'true', when I am using webview?
Alternative way could be:
I can read keybinding attachments
Default - 'vscode://defaultsettings/keybindings.json'
Custom/Overwritten:
Windows - %APPDATA%\Code\User\keybindings.json;
MacOS - $HOME/Library/Application Support/Code/User/keybindings.json;
Linux - $HOME/.config/Code/User/keybindings.json;
Attach to keyboard key down event manually and handle event to detect 'undo'/'redo' key combination;
That should work, but if I could somehow set 'textInputFocus' to 'true' for webview then it would be much easier.
Or maybe there is other simpler solution available?

I found way how to set 'textInputFocus' manually:
vscode.commands.executeCommand('setContext', 'textInputFocus', true);

Related

VSCode Extension API - listen for built-in context menu events

I am building my first VSCode Extension and struggling a little bit.
Is it possible to listen to context menu events, like copy for example?
For example:
When user clicked on "Copy" in the context menu (screenshot of context menu)
I want to get the copied text.
There is an option to add commands to the context menu. But I don't want that, I want to listen to the existing built-in copy command.
I know, I can listen to the keybinding, but that doesn´t trigger the context menu event.
Here is a better version of my previous answer - it just gets the clipboard text in an easier method:
let typeDisposable = vscode.commands.registerCommand('editor.action.clipboardCopyAction', async (arg) => myCopy(typeDisposable) );
async function myCopy(typeDisposable) {
typeDisposable.dispose(); // must dispose to avoid endless loops
// run the built-in copy command
await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
// get the copied text
const clipboardText = await vscode.env.clipboard.readText();
// use your clipboard text here
console.log(clipboardText);
// re-register to continue intercepting copy commands
typeDisposable = vscode.commands.registerCommand('editor.action.clipboardCopyAction', async (arg) => myCopy(typeDisposable) );
context.subscriptions.push(typeDisposable);
}
context.subscriptions.push(typeDisposable);
[Previous version of answer]
This seems to work - but should be thoroughly tested (it is sort of a thought experiment at this point):
let typeDisposable = vscode.commands.registerCommand('editor.action.clipboardCopyAction', async (arg) => myCopy(typeDisposable) );
async function myCopy(typeDisposable) {
typeDisposable.dispose();
// get the selectedText from the editor here
const selectedRange = new vscode.Range(vscode.window.activeTextEditor.selection.start, vscode.window.activeTextEditor.selection.end);
const copiedText = vscode.window.activeTextEditor.document.getText(selectedRange);
// use your copiedText here
await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
typeDisposable = vscode.commands.registerCommand('editor.action.clipboardCopyAction', async (arg) => myCopy(typeDisposable) );
context.subscriptions.push(typeDisposable);
}
context.subscriptions.push(typeDisposable);
You would have to modify this for multiple selections which should be pretty easy.
This will intercept ALL calls to copy, including Ctrl+C. Maybe you are able to limit registering the command to a more limited set of circumstances?

Tinymce 5 dialog urlinput disable/enable broken

Heads up to anyone who is self hosting who also runs across this bug....
In version 5.6.0 silver theme, the dialog urlinput enable/disable works for the input field but not the browse button of the control. The problem is that the enable/disable events are intercepted by the typeaheadBehaviours portion of the internal object so they never make it to the event handlers for the overall field. The fix is to add the onDisabled and onEnabled handlers to the Disabling.config for typeaheadBehaviours and remove the line of code from each handler that addresses the input field.
Original typeaheadBehaviours Disabling.config....
Disabling.config({
disabled: function () {
return spec.disabled || providersBackstage.isDisabled();
}
})
Amended code....
Disabling.config({
disabled: function () {
return spec.disabled || providersBackstage.isDisabled();
},
onDisabled: function (comp) {
memUrlPickerButton.getOpt(comp).each(Disabling.disable);
},
onEnabled: function (comp) {
memUrlPickerButton.getOpt(comp).each(Disabling.enable);
}
})
Haven't been able to figure out how to get those events to bubble up to the the overall control handlers but this seems to make things work as expected.

Maintain screen position always centered on cursor

I'm trying to write an extension for VSCode where the editor screen is always centered on the cursor. There are other extensions that add a command to center the screen onto the cursor, but you have to press the command to activate it.
Currently the only way I've found to implement this is to rewrite the cursorUp, cursorDown, enter, pageUp, pageDown -- any command that moves the cursor up and down basically, and then use the "revealLine" command with the cursor line position and with the "at" attribute as "center".
Is there a better way? Reimplementing the default editor commands seems very inefficient.
Here's what I've got currently:
"use strict";
import * as vscode from "vscode";
export function activate(context: vscode.ExtensionContext) {
let disposable1 = vscode.commands.registerCommand("cursorUp",() => {
centralizar();
vscode.commands.executeCommand("cursorMove", {
to: "up",
});
}
);
let disposable2 = vscode.commands.registerCommand("cursorDown",() => {
centralizar();
vscode.commands.executeCommand("cursorMove", {
to: "down",
});
}
);
context.subscriptions.push(disposable1);
context.subscriptions.push(disposable2);
}
function centralizar() {
let currentLineNumber = vscode.window.activeTextEditor.selection.start.line;
vscode.commands.executeCommand("revealLine", {
lineNumber: currentLineNumber,
at: "center"
});
}
export function deactivate() {}
Perhaps you can utilize the new (v1.38) command editor.cursorSurroundingLines. See scrollOff release notes.
It takes a number, but if you can get the number of visible lines in an editor window, then set editor.cursorSurroundingLines to the appropriate midpoint that may work. It seems you would not have to listen for scroll events. But would have to update the value if the editor window was resized.
The Scrolloff extension implements this functionality when its "alwaysCenter" option is enabled. It works by listening to window.onDidChangeTextEditorSelection, which fires when the cursor moves.

On property change event handler

In a VSCode extension I'm looking for a way to react when the user modify an extension property defined in contributes.configuration section of package.json.
Does it exists an event like onPropertyChange or some other way to register an event handler?
After re-reading vscode documentation I found myself an answer:
workspace.onDidChangeConfiguration callback receive a ConfigurationChangeEvent when a config property is modified.
with the method affectsConfiguration it is then possible to react at the specific property change, for example:
export function activate(context: vscode.ExtensionContext) {
vscode.workspace.onDidChangeConfiguration(event => {
let affected = event.affectsConfiguration("riot.compiler");
if (affected) {
// rebuild cpp project settings
setup();
}
})
...

Change content before preview in TinyMCE 4

In TinyMCE 4, I want to change displayed contents before they are showed on preview popup windows. This change must not affect current contents in editor. Can we do that?
If it can't, I want to catch close event of preview windows. How to do that?
TinyMCE allows us to register callbacks via the property init_instance_callback
By using the BeforeExecCommand event, oddly not in current documentation, you can make changes prior to a command being executed. We can similarly use the ExecCommand event to make changes after the command is executed. The Preview Plugin triggers the mcePreview command. You can view the Editor command Identifiers here.
Putting that together you can add the following when initializing your TinyMCE. This will show "changed content" in the preview without making visible changes to the content within TinyMCE.
var preProssesInnerHtml;
tinymce.init({
//other things...
init_instance_callback: function (editor) {
editor.on('BeforeExecCommand', function (e) {
if (e.command == "mcePreview") {
//store content prior to changing.
preProssesInnerHtml = editor.getContent();
editor.setContent("changed content");
}
});
editor.on("ExecCommand", function (e) {
if (e.command == "mcePreview") {
//Restore initial content.
editor.setContent(preProssesInnerHtml);
}
});
}
}