I am trying to run a function when the "pick" object from CodeMirror's show hints pick function is triggered.
I have tried (among a lot of other options):
CodeMirror.commands.pick = function (cm) {
console.log(cm)
}
CodeMirror.on("pick", function (cm) { console.log(cm) } );
var completion = cm.state.completionActive;
console.log('handling the completion object:', completion);
var pick = completion.pick;
completion.pick = function (data, i) {
var completion = data.list[i];
console.log('picked', data, completion);
pick.apply(this, arguments);
}
In the documentation on codemirror it is described as:
"pick" (completion)
Fired when a completion is picked. Passed the completion value (string or object).
and I can see in the code for the show hints that this is triggered:
CodeMirror.signal(data, "pick", completion);
But how do I monitor that signal and react to it.
Related
I've tried so many variations of this from code I found on github using the provideInlineCompletionItems function but cannot seem to get it to work. Is there something I am doing wrong?
const vscode = require('vscode');
function activate(context) {
const provider = {
provideInlineCompletionItems: async (document, position, context, token) => {
const txt = 'hi'
return [
{
text: txt,
insertText: txt,
range:new vscode.Range(position.translate(0, txt.length), position)
}
]
},
};
vscode.languages.registerInlineCompletionItemProvider({pattern: "**"}, provider);
}
exports.activate = activate;
function deactivate() {}
module.exports = {
activate,
deactivate
};
Even with https://github.com/microsoft/vscode/issues/125663 and "editor.inlineSuggest.enabled": true, set to true it doesn't work. I know inline suggestions works since I have github copilot, I just can't seem to get it to work. Copilot is also disabled so they don't interfere
I rollbacked a version of VSCode and it works now. this is the debug code I used.
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
/**
* #param {vscode.ExtensionContext} context
*/
function activate(context) {
// 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 "seven" is now active!');
// 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('seven.helloWorld', function () {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World from seven!');
});
const provider = {
provideInlineCompletionItems: async (document, position, context, token) => {
const line = document.lineAt(position.line);
console.log("420")
if (line.text.startsWith('if')) {
console.log("421")
let range = line.range;
if (line.text.indexOf(";") !== -1) {
console.log("423")
range = new vscode.Range(range.start, range.end.with(undefined, line.text.indexOf(";") + 1));
}
console.log("424")
return [{ text: 'if (hello) {\n};', insertText: "if (hello)", range }];
}
}
};
vscode.languages.registerInlineCompletionItemProvider({ pattern: '**' }, provider);
context.subscriptions.push(disposable);
}
// This method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate
}
I have a Gjs app that will need to save files. I can open the file chooser dialog just fine from my menu, and I have added a "save" and "cancel" button, but I can't get the "save" button to trigger anything.
I know I'm supposed to pass it a response_id, but I'm not sure what that's supposed to look like nor what I'm supposed to do with it afterwards.
I read that part here:
https://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/Gtk.FileChooserDialog.html#expand
let actionSaveAs = new Gio.SimpleAction ({ name: 'saveAs' });
actionSaveAs.connect('activate', () => {
const saver = new Gtk.FileChooserDialog({title:'Select a destination'});
saver.set_action(Gtk.FileChooserAction.SAVE);
saver.add_button('save', 'GTK_RESPONSE_ACCEPT');
saver.add_button('cancel', 'GTK_RESPONSE_CANCEL');
const res = saver.run();
if (res) {
print(res);
const filename = saver.get_filename();
print(filename);
}
saver.destroy();
});
APP.add_action(actionSaveAs);
I can catch res and fire the associated little logging action when I close the dialog, but both the "save" and "cancel" buttons just close the dialog without doing or saying anything.
My question is, what are GTK_RESPONSE_ACCEPT and GTK_RESPONSE_CANCEL supposed to be (look like) in GJS and how do I use them?
In GJS enums like GTK_RESPONSE_* are numbers and effectively look like this:
// imagine this is the Gtk import
const Gtk = {
ResponseType: {
NONE: -1,
REJECT: -2,
ACCEPT: -3,
DELETE_EVENT: -4,
...
}
};
// access like so
let response_id = -3;
if (response_id === Gtk.ResponseType.ACCEPT) {
log(true);
}
There's a bit more information here about that.
let saver = new Gtk.FileChooserDialog({
title:'Select a destination',
// you had the enum usage correct here
action: Gtk.FileChooserAction.SAVE
});
// Really the response code doesn't matter much, since you're
// deciding what to do with it. You could pass number literals
// like 1, 2 or 3. Probably this was not working because you were
// passing a string as a response id.
saver.add_button('Cancel', Gtk.ResponseType.CANCEL);
saver.add_button('Save', Gtk.ResponseType.OK);
// run() is handy, but be aware that it will block the current (only)
// thread until it returns, so I usually prefer to connect to the
// GtkDialog::response signal and use GtkWidget.show()
saver.connect('response', (dialog, response_id) => {
if (response_id === Gtk.ResponseType.OK) {
// outputs "-5"
print(response_id);
// NOTE: we're using #dialog instead of 'saver' in the callback to
// avoid a possible cyclic reference which could prevent the dialog
// from being garbage collected.
let filename = dialog.get_filename();
// here's where you do your stuff with the filename. You might consider
// wrapping this whole thing in a re-usable Promise. Then you could call
// `resolve(filename)` or maybe `resolve(null)` if the response_id
// was not Gtk.ResponseType.OK. You could then `await` the result to get
// the same functionality as run() but allow other code to execute while
// you wait for the user.
print(filename);
// Also note, you actually have to do the writing yourself, such as
// with a GFile. GtkFileChooserDialog is really just for getting a
// file path from the user
let file = Gio.File.new_for_path(filename);
file.replace_contents_bytes_async(
// of course you actually need bytes to write, since GActions
// have no way to return a value, unless you're passing all the
// data through as a parameter, it might not be the best option
new GLib.Bytes('file contents to write to disk'),
null,
false,
Gio.FileCreateFlags.REPLACE_DESTINATION,
null,
// "shadowing" variable with the same name is another way
// to prevent cyclic references in callbacks.
(file, res) => {
try {
file.replace_contents_finish(res);
} catch (e) {
logError(e);
}
}
);
}
// destroy the dialog regardless of the response when we're done.
dialog.destroy();
});
// for bonus points, here's how you'd implement a simple preview widget ;)
saver.preview_widget = new Gtk.Image();
saver.preview_widget_active = false;
this.connect('update-preview', (dialog) => {
try {
// you'll have to import GdkPixbuf to use this
let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
dialog.get_preview_filename(),
dialog.get_scale_factor() * 128,
-1
);
dialog.preview_widget.pixbuf = pixbuf;
dialog.preview_widget.visible = true;
dialog.preview_widget_active = true;
// if there's some kind of error or the file isn't an image
// we'll just hide the preview widget
} catch (e) {
dialog.preview_widget.visible = false;
dialog.preview_widget_active = false;
}
});
// this is how we'll show the dialog to the user
saver.show();
I have an extension that grabs the open file's text and alters it. Once the text is altered, how do I put it back into the file that is displayed in 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);
}
The API you can use here is TextEditor.edit, whose definition is
edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
It asks for a callback as the first parameter and in the callback, you can make edits to the document by visiting editBuilder.
I put a sample extension in https://github.com/Microsoft/vscode-extension-samples/tree/master/document-editing-sample which reverses the content in current selection, which is basically a simple use TextEditor.edit.
This is a revision of the main function in Rebornix's extension sample (included with the set of Microsoft extension samples) that handles the selection issues you raised. It reverses the content of the selection(s) (leaving the selections) or if a selection is empty it will reverse the word under the cursor at that selection without leaving anything selected. It often makes sense to leave a selection, but you can add code to remove selection.
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)
}
});
Admittedly, while I could remove a single selection by setting .selection to a new empty selection that doesn't seem to work with .selections[i]. But you can make multiple changes without having selections in the first place.
What you don't want to do is make a selection through code just to alter text through code. Users make selections, you don't (unless the end purpose of the function is to make a selection).
I came to this question looking for a way to apply a textEdit[] array (which is normally returned by a provideDocumentRangeFormattingEdits callback function). If you build changes in the array you can apply them to your document in your own function:
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
}
}
So that's another way to apply edits to a document. Even though I got the editBuilder sample to work correctly without selecting text, I have had problems with selections in other cases. WorkspaceEdit doesn't select the changes.
Here is the code snippet that will solve your issue :
activeEditor.edit((selectedText) => {
selectedText.replace(activeEditor.selection, newText);
})
Due to the issues I commented about in the above answer, I ended up writing a quick function that does multi-cursor friendly insert, and if the selection was empty, then it does not leave the inserted text selected afterwards (i.e. it has the same intuitive behavior as if you had pressed CTRL + V, or typed text on the keyboard, etc.)
Invoking it is simple:
// x is the cursor index, it can be safely ignored if you don't need it.
InsertText(x => 'Hello World');
Implementation:
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);
});
}
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);
I have code like this:
element(by.model("roleSelection.role")).element(by.cssContainingText('option', newRole)).click();//.then(function() {console.log('role click')})//;
where the options is loaded via a call to the server.
I can wait for the first element by doing this
browser.wait(function() {
return browser.isElementPresent(by.model("roleSelection.role")).then(function(present){
return present;
});}, 8000);
and it seems to work. But how can I wait until the "sub-element" is clickable.
I have tried this
browser.wait(function() {
return browser.isElementPresent(by.model("roleSelection.role")).then(function(present){
if (present) {
var elm = element(by.model("roleSelection.role"));
return elm.isElementPresent(by.cssContainingText('option', newRole)).then(function(subpresent) {
return subpresent;
});
}
}); }, 8000);
Have you tried clickable? Something along these lines
var EC = protractor.ExpectedConditions;
var select = element(by.model("roleSelection.role"))
var isClickable = EC.elementToBeClickable(select);
browser.wait(isClickable,5000); //now options should have been loaded by now
Well, try to this: https://angular.github.io/protractor/#/api?view=ExpectedConditions.prototype.elementToBeClickable
But, Please keep in mind, Protractor is suitable for angular webpages and interactions, and animations. For example ng-animate. So, it is not sure to working for example jquery, or other animates.
In this way:
onPrepare: function () {
// disable animations when testing to speed things up
var disableNgAnimate = function () {
angular.module('disableNgAnimate', []).run(function ($animate) {
$animate.enabled(false);
});
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
}
Or you can switch in script way in browser.executeScript().
Please see this link. It works only jquery animations.
If you not have animate problems. Use setTimeout() JS function.
I'm trying to create new observable based on two others. I have:
var mouseClickObservable = Rx.Observable.fromEvent(this.canvas, "click");
var mouseMoveObservable = Rx.Observable.fromEvent(this.canvas, "mousemove");
function findObject(x, y) {/* logic for finding object under cursor here. */}
var objectUnderCursor = this.mouseMoveObservable.select(function (ev) {
return findObject(ev.clientX, clientY);
});
I want to create objectClicked observable, that should produce values when user clicks on an object. I could just call findObject again, like this:
var objectClicked = this.mouseClickObservable.select(function (ev) {
return findObject(ev.clientX, clientY);
});
but it's very time-consuming function.
Another way, which I currently use, is to store last hovered object in a variable, but I assume, there should be pure functional way of doing this. I tryed to use Observable.join like this:
var objectClicked = this.objectUnderCursor.join(
mouseClickObservable,
function (obj) { return this.objectUnderCursor },
function (ev) { return Rx.Observable.empty() },
function (obj, ev) { return obj })
but it produces multiple values for one click
I don't see any code where you actually subscribe to any of these observables you have defined, so it is hard to provide a good answer. Do you actually need to call findObject on every mouse move? Are you needing to provide some sort of hover effect as the mouse moves? Or do you just need to know the object that was clicked, in which case you only need to call findObject once when clicked?
Assuming you only need to know what object was clicked, you don't even worry about mouse moves and just do something like:
var objectClicked = mouseClickObservable
.select(function (ev) { return findObject(ev.clientX, ev.clientY); });
objectClicked.subscribe(function(o) { ... });
If you indeed need to know what object the mouse is hovering over, but want to avoid calling your expensive hit test also on a click, then indeed you need to store the intermediate value (which you are needing to store anyway to do your hovering effects). You can use a BehaviorSubject for this purpose:
this.objectUnderCursor = new Rx.BehaviorSubject();
mouseMoveObservable
.select(function (ev) { return findObject(ev.clientX, ev.clientY); })
.subscribe(this.objectUnderCursor);
this.objectUnderCursor.subscribe(function (o) { do your hover effects here });
mouseClickObservable
.selectMany(function () { return this.objectUnderCursor; })
.subscribe(function (o) { do your click effect });