I've been working on a custom extension for Visual Studio Code recently and am trying to show a link to the user when hovering over a specific phrase but it hasn't been working. The hover shows up but the link isn't "actionable".
My extension is registering a HoverProvider and is returning a new Hover object which contains a string with a link inside of it like so:
return new vscode.Hover({language: 'markdown', value: '[test-link](https://www.google.com)'});
I've tried switching the language between "markdown" and "HTML", but in either case, although the link was in the correct format, it was never actionable. I suspect this is because the value being fed in as a parameter to the Hover constructor is a MarkdownString which has the following note:
Note that markdown strings will be sanitized - that means html will be
escaped.
I could've sworn I've seen this feature elsewhere in VS Code like in a package.json file where a link to a repository was shown when hovering over a dependency name, but I can't seem to find a working example.
Here's an example of what the hover looks like:
Is there any way to get this feature working?
This is working for me:
let disposable1 = vscode.languages.registerHoverProvider('javascript', {
provideHover(document, position, token) {
const word = document.getText(document.getWordRangeAtPosition(position));
const searchOptions = {
query: word
};
const contents = new vscode.MarkdownString(`[test-link](https://www.google.com)`);
contents.isTrusted = true;
return new vscode.Hover(contents);
}
});
Note that new Hover() has this signature:
new Hover(contents: MarkdownString | MarkedString | Array<MarkdownString | MarkedString>, range?: Range): Hover
See Hover api reference.
You were trying to give it an object (with a language key).
With vscode v1.61 this will also work within the provider:
const contents = new vscode.MarkdownString(`[test-link](https://www.google.com)`);
contents.appendMarkdown("<a href='https://www.google.com'>test-link2</a>");
contents.supportHtml = true;
contents.isTrusted = true;
return new vscode.Hover(contents);
See https://stackoverflow.com/a/67954180/836330 for more on newly supported html tags.
Related
I'm curious if it is possible to append to a generated Word document that I've created with Js and docx module. Currently I can generate the document and format it. Yet, I'm not seeing anything in their documentation about appending or adding a paragraph to an existing document (there is a section on exporting, but it always creates a new file, even if its the same name). Is this a limitation in JavaScript? I'm assuming that since I'd want to look for the document in the system files, that this creates a security issue (JS from a browser looking for a file in a end user's system) and hence why docx doesn't do it. Any guidance on this is greatly appreciated. Also, if it's not then would using Word APIs solve this?
P.S. I can share the code that generates the document, but that part is running fine, I just need to know if what I want is possible or if I'm wasting time.
This is a function I've tried and found from stackoverflow, but it was for a web app, this is a chrome extension. I've looked around and can't find anything else to try. Idally I'd like to write to the doc generated and add to it.
// pretty sure I cann't utilize a function like this unfornately
// all code is functional before this is call
function writeToDocument(doc, text){
let paragraph = new docx.Paragraph();
// invalid code
// paragraph.addRun(new docx.TextRun(text));
// doc.addParagraph(paragraph);
let packer = new docx.Packer();
docx.packer.toBuffer(doc).then((buffer) =>{
fs.writeFileSync(docName + ".docx",buffer);
});
}
It looks this is limitation of library. There is addSection() but it is private. Also, there are no methods to open a previously generated file.
Only way is: first create content, and later create doc and save it:
let paragraphs = [];
//any way to add element to array, eg
paragraphs[paragraphs.length] = new Paragraph({
children: [
new TextRun("Hello World"),
new TextRun({
text: "Foo Bar",
bold: true,
}),
new TextRun({
text: "\tGithub is the best",
bold: true,
}),
],
});
//paragraphs[paragraphs.length] = addAnotherParagraph()
//create document
const doc = new Document({
sections: [
{
properties: {},
children: paragraphs,
},
],
});
//and save it in fauvorite way
Packer.toBuffer(doc).then((buffer) => {
//why in `docx` documentation uses sync versioin?... You should avoid it
fs.writeFileSync("My Document.docx", buffer);
});
I am trying to develop a custom button in vscode hover function. Meaning if I click the shortcut button, it will go to search sidebar and have a specific query search. Refer to the two images which is uploaded.
In vscode command form, the extension code will look like this. (This works well except it requires to run from command pallete)
let disposable = vscode.commands.registerCommand('test-hover.helloWorldSearch', () => {
var word = "i_want_to_search";
const searchOptions = {
query: word,
};
vscode.commands.executeCommand('workbench.action.findInFiles', searchOptions);
});
context.subscriptions.push(disposable);
After that I convert into hover by using vscode.languages.registerHoverProvider, and the code look like this:
let disposable1 = vscode.languages.registerHoverProvider('javascript', {
provideHover(document, position, token) {
var word = "i_want_to_search";
const searchOptions = {
query: word,
};
const commentCommandUri = vscode.Uri.parse(`command:workbench.action.findInFiles`);
const contents = new vscode.MarkdownString(`[Search String](${commentCommandUri})`);
contents.isTrusted = true;
return new vscode.Hover(contents);
}
});
context.subscriptions.push(disposable1);
This code is able to navigate the sidebar to search In file BUT without any query seacrh.
The problem is, I can't pass "searchOptions" to the command if I am using "vscode.Uri.parse". Is there any other way to do the same action as the above code but able to pass the searchOption? I have tried to search many different examples in the internet but most only come out to run command without searchOption.
The arguments to your command have to be appended as an encoded string, as shown in command-uris.
const searchCommandUri = vscode.Uri.parse(
`command:workbench.action.findInFiles?${encodeURIComponent(JSON.stringify(searchOptions))}`
);
const contents = new vscode.MarkdownString(`[Search String](${searchCommandUri})`);
If you wanted to get the word that you are hovering over, try this code:
const word = document.getText(document.getWordRangeAtPosition(position));
Now your "Search String" hover button will search the word that is being hovered over.
Then change the text: "Search String" to the actual word you will be searching for:
const contents = new vscode.MarkdownString(`[Search: ${word}](${searchCommandUri})`);
I've been working with Liferay 7 for a while and needed to create a feedback form with prefilled values. I created a feedback form and a page, where it's shown and where I could add Javascript.
The user clicks on a link ("Did you find this helpful? Yes/No") and it takes you to the feedback page with the page and answer as URL parameters.
URL: {feedback-page-url/} ?pageUrl=/services&answer=Yes
Now here's where the problems began. Liferay updates it's values very confusingly and while generic document.getElementsByName(...) etc. seemed to work at first, they updated back when clicking the page. The difficult thing is to update the right values in right elements, so they won't be overrun by Liferay.
I provided an answer to my question below. Feel free to ask me anything, I'll try to help :)
Full code block in the end!
So I found out a solution to this problem. Liferay creates an instance (_com_liferay...) and uses it's values to be up to date, so we need to get a hold of it and update it's values. You can do it manually by inspecting and finding your instance, but I have an automatic code that should get it for you.
The id we are searching for is for DDMFormPortlet and the String we get this way is close to perfect. The String that document.querySelector() finds begins with p_p_id_com..., so we can use .substring to remove the unnecessary part and then add +"form" in the end to make it complete. If you find a better way to find this, please share it :)
// _com_liferay_dynamic_data_mapping_form_web_portlet_DDMFormPortlet_INSTANCE_randomkey_form
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
Now that we have the correct String text, we'll find the element, that corresponds to it:
const formFieldArray = window[idFinder()];
Now if you try it just by itself, it most likely won't find anything, because it's loads slowly. I put all of this into try-catch with setTimeout() to make sure everything works as intended. Now all we need to do is collect the information from our URL and set it to the correct places.
const params = new URLSearchParams(location.search);
const formAutoFiller = function (params) {
try {
const formFieldArray = window[idFinder()];
// make sure you have the numbers according to your form!
formFieldArray.pages[0].rows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldArray.pages[0].rows[1].columns[0].fields[0].value=params.get('answer');
// ...
}
}
And finally, as the changed values update to the form after clicking an input field, we'll move the selection focus to one of the input fields after the other code is ran:
document.getElementsByClassName("ddm-field-text")[1].focus();
A bit cleanup for myself and we're done! Full Javascript here:
const params = new URLSearchParams(location.search);
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
const formAutoFiller = function (params) {
try {
const formFieldRows = window[idFinder()].pages[0].rows;
formFieldRows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldRows[1].columns[0].fields[0].value=params.get('answer');
document.getElementsByClassName("ddm-field-text")[1].focus();
} catch (e) {
setTimeout(formAutoFiller, 500, params);
}
}
formAutoFiller(params);
I'm making a vscode extension to provide syntax highlighting and suggestions for a custom language that extends the HTML lang. I'm using the CompletionItemProvider API.
In this language we got commands wrapped in $%-$ like $%FOR (...)$ or $%IF (...)$, so I want to show a suggestion of the available commands when I type $%.
But for some reason, it doesn't work when the cursor is on the % character.
Here is a simplified version of the code. I basically based on the completion sample (https://github.com/Microsoft/vscode-extension-samples/blob/master/completions-sample/src/extension.ts):
const completionProvider = vscode.languages.registerCompletionItemProvider(
'*',
{
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
let linePrefix = document.lineAt(position).text.substr(0, position.character);
if (!linePrefix.endsWith("$%")) {
return undefined;
}
console.log("should show suggestions");
return [
new vscode.CompletionItem('IF', vscode.CompletionItemKind.Method),
new vscode.CompletionItem('FOR', vscode.CompletionItemKind.Method)
];
}
}
);
context.subscriptions.push(completionProvider);
The function takes the text typed on the editor and checks if the user has just typed $%, if so then shows the list of suggestions
The result is a pop up whit a "No suggestions" message:
But if I check for another trigger string that ends with another char different from '%', changing the line
if (!linePrefix.endsWith("$%")) {
to this
if (!linePrefix.endsWith("$%$")) {
or this
if (!linePrefix.endsWith("$%.")) {
it works!
Can someone explain what am I doing wrong?
I was facing the same issue. I reset the setting of VS code, now it's working.
Warning: All the installed extensions will be removed.
After searching through the API docs, I can't figure out how to access and manipulate specific toolbar elements. I need to remove several nav tools, like 'Pan' or 'FirstPersonTool'.
Even using trusty 'ole JQuery remove() doesn't work.
$('#toolbar-orbitTools').remove(); //"Fails"
Here is my initializer code:
var token = gon.token;
var urn = gon.urn;
function getToken() {
return token;
}
var viewerApp;
var options = {
env: 'AutodeskProduction',
accessToken: getToken(),
refreshToken: getToken(),
};
var documentId = 'urn:' + urn;
var callback = function() {
viewerApp = new Autodesk.A360ViewingApplication('viewer');
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D);
viewerApp.loadDocumentWithItemAndObject(documentId);
};
Autodesk.Viewing.Initializer(options, callback);
I know of a way to remove the toolbar tools that you don't need through the use of an extension. The simplest way will be to go over the code of the extension located here. http://viewer.autodesk.io/node/gallery/#/viewer?id=57cb8d7cf818a81c0c8502fb
See attached image so you have a better reference of the Extension named Control Selector to remove the toolbar options you will not like.
Now if you would like to start your viewer without any toolbar options and add custom buttons to use the functionality of the ones you want, that can be done as well. Change this line
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D);
change it to the following:
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Viewer3D);