VS Code - Selection to multi cursor - visual-studio-code

Does anyone know how to turn an vscode editor selection range into a multi cursor selection?
for instance on this line:
"out of this line I'd like to select this|"
run the key bind
selection would turn into multi cursor like so
"out of this line I'd like to | select this |"

You can use the extension Select By v1.10
Execute the command: SelectBy: Create separate cursors for anchor and active position of the selection(s) , selectby.anchorAndActiveSeparate
It will create new cursors for every anchor and active position of all the current selections. Overlapping cursors are eliminated.

Assuming you are working with only a single selection:
const selection = vscode.window.activeTextEditor.selections[0];
const newSelection1 = new vscode.Selection(selection.start, selection.start);
const newSelection2 = new vscode.Selection(selection.end, selection.end);
vscode.window.activeTextEditor.selections = [newSelection1, newSelection2];
You will get the same result selecting left-to-right as right-to-left.
I made this into an extension: Convert Selection - it works on multiple selections.
Here is the entire code of the extension:
const vscode = require('vscode');
/**
* #param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand('convert-selection.surround', function () {
const editor = vscode.window.activeTextEditor;
const selections = editor.selections;
const newSelections = [];
for (const selection of selections) {
const newSelection1 = new vscode.Selection(selection.start, selection.start);
const newSelection2 = new vscode.Selection(selection.end, selection.end);
newSelections.push(newSelection1, newSelection2);
}
editor.selections = newSelections;
});
context.subscriptions.push(disposable);
}
exports.activate = activate;

Related

how to delete auto closed brackets in VSCode extetnsion Completion?

I register [[ as the completion trigger word, VSCode will auto generate ]] for [[,
My completion want to delete the [[]].
For example:
when user type [[,
user may type some filter text,
the final result will be [xxx](/xxx)
I tried additionalTextEdits to delete [[]], but when user type some filter text, the position will be wrong.
item.insertText = `[${title}](/${relativePath})`;
const start = position.character - 2;
item.additionalTextEdits = [
vscode.TextEdit.delete(
new vscode.Range(position.line, start, position.line, start + 4)
),
];
Solve this by using command, completion can add a command param, which can do something when completion complete.
vscode.commands.registerCommand(
'foam-vscode.delete-wiki-link-end-brackets',
() => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const current = editor.selection.active;
editor.edit(editBuilder => {
editBuilder.delete(
new vscode.Range(
current.line,
current.character,
current.line,
current.character + 2
)
);
});
return;
}
}
);

Open another document in VSCode extension from Hover

I try to open a document from a Hover in a VSCode Extension.
The Hover appears, the link is shown and also the URI, but when I click, nothing happens. There is an output in the Debug Console, that the command is unknown in the Developer Tools Console.
What I am doing wrong? Here is the code, a little bit simplified
context.subscriptions.push(
vscode.languages.registerHoverProvider({pattern: '**/*.{ttp,tts}'}, {
provideHover(document, position, token) {
const linkPosition = new vscode.Position(10, 1);
const range = new vscode.Range(position, position);
const opts: vscode.TextDocumentShowOptions = {
selection: range,
viewColumn: vscode.ViewColumn.Beside
};
const workspace = vscode.workspace.workspaceFolders?.find(e => e.uri.fsPath.endsWith("workspace"));
const uri = vscode.Uri.file(`${workspace?.uri.path}/_global.tt/ercdata/ttc.properties`);
const args = [{ uri: uri , options: opts}];
const stageCommandUri = vscode.Uri.parse(
`command:window.showTextDocument?${encodeURIComponent(JSON.stringify(args))}`
);
let link = new vscode.MarkdownString(`[Open...](${stageCommandUri})`);
link.isTrusted = true;
let hover: vscode.Hover = {
contents: [link]
};
return hover;
let x = properties.getHoverFor(document, position, path.basename(document.uri.fsPath).replace(".tts","").replace(".ttp","").toLowerCase());
return x;
}
}));
Here is how the Hover renders:
Here is the output of the dev console:
You should use a true command like vscode.open as documented in this article, or your own command.
window.showTextDocument alone is an extension API.
Lex Li pointed me into the right direction, thank you.
Wrapping the openTextDocument task into my own command and adressing this command from the Hover solves the problem:
context.subscriptions.push(vscode.commands.registerCommand('estudio.internal.open', (uri: vscode.Uri, options: vscode.TextDocumentShowOptions) => {
logger.info("Opening a document");
vscode.window.showTextDocument(uri, options);
}));
Than composing the Hover use
const stageCommandUri = vscode.Uri.parse(
`command:estudio.internal.open?${encodeURIComponent(JSON.stringify(args))}`
did it.

What is the name of the element that github copilot uses to highlighting text?

I would like to make a control similar to the used by github copilot. I mean highlighting the proposed text. Live share extension uses a very similar approach. What is the name of this control?
Control in live preview extension:
Control in copilot extension:
I guess it could be TextEditorDecorationType? However, I do not know how to style it so that the author is absolutely positioned :/
You can create a similar experience using Text Editor Decorators. These decorators allow you to use custom style patterns for any text in a document (including foreground and background colors).
The text highlighting examples that you have visualized above, are simply adding a a background color to a span of text that has been selected by a user, or suggested by an extension.
As an example: if you wanted to add custom highlighting for console.log:
Then you could use the following:
import * as vscode from 'vscode'
const decorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: 'green',
border: '2px solid white',
})
export function activate(context: vscode.ExtensionContext) {
vscode.workspace.onWillSaveTextDocument(event => {
const openEditor = vscode.window.visibleTextEditors.filter(
editor => editor.document.uri === event.document.uri
)[0]
decorate(openEditor)
})
}
function decorate(editor: vscode.TextEditor) {
let sourceCode = editor.document.getText()
let regex = /(console\.log)/
let decorationsArray: vscode.DecorationOptions[] = []
const sourceCodeArr = sourceCode.split('\n')
for (let line = 0; line < sourceCodeArr.length; line++) {
let match = sourceCodeArr[line].match(regex)
if (match !== null && match.index !== undefined) {
let range = new vscode.Range(
new vscode.Position(line, match.index),
new vscode.Position(line, match.index + match[1].length)
)
let decoration = { range }
decorationsArray.push(decoration)
}
}
editor.setDecorations(decorationType, decorationsArray)
}
Reference Link

Is it possible to set TextDocument as dirty programatically in VSCode?

Is it possible to set a TextDocument as dirty programatically in VSCode? Something like
openedDocument.setDirty()
There isn't a direct way to do it; TextDocument.isDirty is a read-only property.
However, I put together a workaround that sets isDirty by making an edit that has no effect (tested with VSCode 1.37.1):
// Set the dirty bit on 'textEditor'. This is meant to be called as a
// text editor command.
async function setDirty(textEditor: TextEditor, editBuilder: TextEditorEdit)
: Promise<void>
{
// The strategy here is to make a change that has no effect. If the
// document has text in it, we can replace some text with itself
// (simply inserting an empty string does not work). We prefer to
// edit text at the end of the file in order to minimize spurious
// recomputation by analyzers.
// Try to replace the last line.
if (textEditor.document.lineCount >= 2) {
const lineNumber = textEditor.document.lineCount-2;
const lastLineRange = new Range(
new Position(lineNumber, 0),
new Position(lineNumber+1, 0));
const lastLineText = textEditor.document.getText(lastLineRange);
editBuilder.replace(lastLineRange, lastLineText);
return;
}
// Try to replace the first character.
const range = new Range(new Position(0, 0), new Position(0, 1));
const text = textEditor.document.getText(range);
if (text.length > 0) {
editBuilder.replace(range, text);
return;
}
// With an empty file, we first add a character and then remove it.
// This has to be done as two edits, which can cause the cursor to
// visibly move and then return, but we can at least combine them
// into a single undo step.
await textEditor.edit(
(innerEditBuilder: TextEditorEdit) => {
innerEditBuilder.replace(range, " ");
},
{ undoStopBefore: true, undoStopAfter: false });
await textEditor.edit(
(innerEditBuilder: TextEditorEdit) => {
innerEditBuilder.replace(range, "");
},
{ undoStopBefore: false, undoStopAfter: true });
}
In your activate function, hook it up with something like:
context.subscriptions.push(
commands.registerTextEditorCommand("extension.setDirty", setDirty));

Unable to set cursor in Draft.js editor

I am trying to integrate the Draft.js editor in a project.
The way I am thinking of using it, is to create a new EditorState out of my own state on every render call (the reason for this approach are related to my specific context I am not going to detail here).
What I have not succeeded is to set the cursor position in the Editor.
I have created an example on Codepen:
http://codepen.io/nutrina/pen/JKaaOo?editors=0011
In this example any character I type is prepended to the beginning of the text, instead of being inserted at the cursor position.
I have tried setting the cursor by using:
state = EditorState.acceptSelection(state, this.state.selectionState);
state = EditorState.forceSelection(state, this.state.selectionState);
but without much success.
Any help would be appreciated.
Thanks,
Gerald
A easy way to move the cursor around is to use Editor.forceSelection and a key binding function!
This is what your render function would look like once you have it set up
render() {
return (
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
handleKeyCommand={this.handleKeyCommand}
keyBindingFn={this.myKeyBindingFn}
/>
);
}
Once you have your keybinding function, you can do something along the lines of
myKeyBindingFn = (e) => {
// on spacebar
if (e.keyCode == 32) {
const newSelection = selectionState.merge({
anchorOffset: selectionState.getAnchorOffset() + 1,
focusOffset: selectionState.getAnchorOffset() + 1,
});
const newEditorState = EditorState.forceSelection(
editorState,
newSelection,
);
this.setState({ editorState: newEditorState });
return 'space-press';
}
};
Feel free to replace anchorOffset and focusOffset with the position you would like the cursor to be in. Using a keybinding function allows better control over events
Your handleKeyCommand function would look something like this
handleKeyCommand = (command: string): DraftHandleValue => {
if (command === 'space-press') {
return 'handled';
}
return 'not-handled';
};