How do I get all the tabs in a Visual Studio Code window as an array of filenames? - visual-studio-code

I am currently looking to find the call that will allow me to see all the tabs in a Visual Studio Code editor (1.txt, 2.txt, 3.txt) being returned back in an array for example.

const tabArray = vscode.window.tabGroups.all;
will return an array of editor groups. And then within each editor group (or "tabGroup") you can get an array of its tabs with:
const firstGroupOfTabs = tabArray[0].tabs;
const firstTabName = firstGroupOfTabs[0].label;
or
const firstTabUri = firstGroupOfTabs[0].input.uri; // gives you a uri if you need the full path - for most, but not all, editor types
So you will have to do a loop through the tabGroups.all to get all the fileNames. One example of doing so:
const tabArray = tabGroupArray.flatMap(group => group.tabs.map(tab => tab.label));

Related

how to make snippets auto complete in my custom vs code extension?

im korean beginner developer... help... T^T
i want to make auto complete like snippets in my custom vs code extension.
now my code,
const snippetBase = `axios.({
url: "${service.url}",
method: "${service.description}",
`
const editor = vscode.window.activeTextEditor
const selection: any = editor?.selection
editor?.edit(builder => {
builder.replace(
selection,
snippetBase + snippetHeaders(snippetRes.data.header) + snippetBody(snippetRes.data.body)
)
})
then, my extension auto complete image
I want to focus my cursor automatically inside the format after the snippet is shown.
Just like picture below.
snippets image
help me plz!!
It sounds from your comment that you want the edit to act as a snippet. Then you need to make a SnippetString and use the editor.insertSnippet() command which can take that SnippetString as an argument. This should work for you:
const editor = vscode.window.activeTextEditor
const selection = editor?.selection
const axiosSnippet = new vscode.SnippetString("axios.({\n")
axiosSnippet.appendText("\turl: \"")
axiosSnippet.appendPlaceholder(service.url)
axiosSnippet.appendText("\",\n")
axiosSnippet.appendText("\tmethod: \"")
axiosSnippet.appendPlaceholder(service.description)
axiosSnippet.appendText("\",\n")
editor.insertSnippet(axiosSnippet, selection)
axiosSnippet.appendPlaceholder(service.url); is the key to this, as it will select that placeholder first and then allow you to tab to the next placeholder axiosSnippet.appendPlaceholder(service.description).
[I don't know the structure of the rest of your snippet,e.g., snippetHeaders(snippetRes.data.header). If it is just text than you can use the appendText method with \n for newlines.

Can I show an image in a HoverProvider?

I am new to vscode extension development so not sure best places to look for help. I want to hover over a word, and if that word matches the name in our icon directory, show a hover with that image. My first try was to use markdown to show the svg image from the web, but I believe that is not allowed for security that code could be executed. Can I show an svg in the markdown in a vscode.Hover? I can either include the svgs in the extension, or expect that the developer has already installed the npm package with the files into the workspace.
There is actually quite rich support for content and styling in MarkdownString in hovers.
You can use svg's directly this way:
const icon = new vscode.MarkdownString('<img src="icon.svg"/>');
icon.baseUri = vscode.Uri.file(path.join(context.extensionPath, 'images', path.sep));
The baseUri property is crucial. Here it gets the svgs from an images folder.
In the below I added the png images to an extension images folder. You can detect what word is hovered and load the corresponding icon.
Below is testing in a plaintext file:
// with this require/import
const path = require('path');
// ...
let disposable4 = vscode.languages.registerHoverProvider('plaintext', {
provideHover(document, position) {
// one way to find the current hovered word
// note that what is a 'word' is languaged-defined and typically does not include hyphens
// const word = document.getText(document.getWordRangeAtPosition(position));
// first check if there is an icon for the hovered word, if not return undefined
// glob the images folder and find 'icon'.svg
// const icon = new vscode.MarkdownString(`<img src="${word}.svg"/>`);
// dimensions not necessary if you aren't changing them
const content = new vscode.MarkdownString(`<img src="favicon144.png" width=144 height=144/>`);
content.appendMarkdown(`$(zap)`); // notice the little "zap" icon in the hover
content.supportHtml = true;
content.isTrusted = true;
content.supportThemeIcons = true; // to supports codicons
// baseUri was necessary, full path in the img src did not work
// with your icons stroed in the 'images' directory
content.baseUri = vscode.Uri.file(path.join(context.extensionPath, 'images', path.sep));
return new vscode.Hover(content, new vscode.Range(position, position));
}
});
There's only very limited Markdown support in hover items and images are not supported there at all, as far as I know.

How to search for and highlight a substring in Codemirror 6?

I'm building a simple code editor to help children learn HTML. One feature I'm trying to add is that when users mouseover their rendered code (in an iframe), the corresponding HTML code in the editor is highlighted. So, for example, if a user mouses-over an image of kittens, the actual code, , would be highlighted in the editor.
Mousing-over the iframe to get the html source for that element is the easy part, which I've done (using document.elementFromPoint(e.clientX, e.clientY in the iframe itself, and posting that up to the parent) - so that's not the part I need help with. The part I can't figure out is how to search for and highlight that string of selected code in the code editor.
I'm using Codemirror 6 for this project, as it seems as it will give me the most flexibility to create such a feature. However, as a Codemirror 6 novice, I'm struggling with the documentation to find out where I should start. It seems like the steps I need to complete to accomplish this are:
Search for a range in the editor's text that matches a string (ie.'<img src="kittens.gif"').
Highlight that range in the editor.
Can anyone out there give me some advice as to where in the Codemirror 6 API I should look to start implementing this? It seems like it should be easy, but my unfamiliarity with the Codemirror API and the terse documentation is making this difficult.
1. Search for a range in the editor's text that matches a string (ie.'<img src="kittens.gif"').
You can use SearchCursor class (iterator) to get the character's range where is located the DOM element in your editor.
// the import for SearchCursor class
import {SearchCursor} from "#codemirror/search"
// your editor's view
let main_view = new EditorView({ /* your code */ });
// will create a cursor based on the doc content and the DOM element as a string (outerHTML)
let cursor = new SearchCursor(main_view.state.doc, element.outerHTML);
// will search the first match of the string element.outerHTML in the editor view main_view.state.doc
cursor.next()
// display the range where is located your DOM element in your editor
console.log(cursor.value);
2. Highlight that range in the editor.
As described in the migration documentation here, marked text is replace by decoration. To highlight a range in the editor with codemirror 6, you need to create one decoration and apply it in a dispatch on your view. This decoration need to be provide by an extension that you add in the extensions of your editor view.
// the import for the 3 new classes
import {StateEffect, StateField} from "#codemirror/state"
import {Decoration} from "#codemirror/view"
// code mirror effect that you will use to define the effect you want (the decoration)
const highlight_effect = StateEffect.define();
// define a new field that will be attached to your view state as an extension, update will be called at each editor's change
const highlight_extension = StateField.define({
create() { return Decoration.none },
update(value, transaction) {
value = value.map(transaction.changes)
for (let effect of transaction.effects) {
if (effect.is(highlight_effect)) value = value.update({add: effect.value, sort: true})
}
return value
},
provide: f => EditorView.decorations.from(f)
});
// this is your decoration where you can define the change you want : a css class or directly css attributes
const highlight_decoration = Decoration.mark({
// attributes: {style: "background-color: red"}
class: 'red_back'
});
// your editor's view
let main_view = new EditorView({
extensions: [highlight_extension]
});
// this is where the change takes effect by the dispatch. The of method instanciate the effect. You need to put this code where you want the change to take place
main_view.dispatch({
effects: highlight_effect.of([highlight_decoration.range(cursor.value.from, cursor.value.to)])
});
Hope it will help you to implement what you want ;)
Have a look at #codemirror/search.
Specifically, the source code implementation of Selection Matching may be of use for you to adapt.
It uses Decoration.mark over a range of text.
You can use SearchCursor to iterate over ranges that match your pattern (or RegExpCursor)
Use getSearchCursor, something like this:
var cursor = cmEditor.getSearchCursor(keyword , CodeMirror.Pos(cmEditor.firstLine(), 0), {caseFold: true, multiline: true});
if(cursor.find(false)){ //move to that position.
cmEditor.setSelection(cursor.from(), cursor.to());
cmEditor.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
}
Programmatically search and select a keyword
Take a look at getSearchCursor source code it it give some glow about how it works and its usage.
So use getSearchCursor for finding text and optionally use markText for highlighting text because you can mark text with setSelection method of editor.
Selection Marking Demo
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
styleSelectedText: true
});
editor.markText({line: 6, ch: 26}, {line: 6, ch: 42}, {className: "styled-background"});
And it seem this is what you are looking for:
codemirror: search and highlight multipule words without dialog
RegExpCursor is another option that you can use:
new RegExpCursor(
text: Text,
query: string,
options⁠?: {ignoreCase⁠?: boolean},
from⁠?: number = 0,
to⁠?: number = text.length
)
Sample usage at:
Replacing text between dollar signs for Mathml expression.

VSCode: How can I determine the cursor's column position within an editor?

I'm looking for a simple method to determine the column position of a VSCode editor's text insertion cursor/caret, either prior to selecting an area of text to copy or immediately the mouse is used to start the selection. The column number would then be stored in the clipboard before performing further clipboard manipulation.
I have tried searching for AutoHotkey methods to achieve this, but the only solution I'm able to find involves using ImageSearch, which is not suitable for my purpose.
Edit: I found this API reference, could I possibly use this to determine the cursor position preferably using windows cmd/powershell?
You can make a vscode extension and bind the command to a keyboard shortcut.
How to get line and column(character) of cursor:
const activeEditor = vscode.window.activeTextEditor
if (activeEditor) {
console.log(activeEditor.selection.active.line)
console.log(activeEditor.selection.active.character) //column
}
api: https://code.visualstudio.com/api/references/vscode-api#details-159
activeEditor.selection gives you an object with 4 objects
start:Object
line:4
character:8
end:Object
line:6
character:8
active:Object
line:4
character:8
anchor:Object
line:6
character:8
activeEditor.selection.active is your cursor.
activeEditor.selection.anchor is
The position at which the selection starts. This position might be before or after active.
anchor-active may be reversed, but start-end will always be up-down.
note: I found the api AFTER I found out how to get current line from here:
VScode API why can't I get the current line?
EDIT: for columnNum (see Eric's comment):
const activeEditor = vscode.window.activeTextEditor
if (activeEditor) {
const lineOffset = activeEditor.selection.active.line
const charOffset = activeEditor.selection.active.character
console.log(`line: ${lineOffset + 1}`)
console.log(`character: ${charOffset + 1}`)
console.log(`column: ${getColumn(activeEditor.document.lineAt(lineOffset).text,charOffset) + 1}`) //column
function getColumn(str, sumCharacter) {
const arr = [...str]
let whichCharacter = 0
for (let whichColumn = 0; whichColumn < arr.length; whichColumn++) {
if (whichCharacter===sumCharacter) {
return whichColumn
}
whichCharacter+=arr[whichColumn].length
}
return arr.length
}
}

Get tab status using pyforms

I'm working with pyforms to create a tab widget and I want to get and set the current active tab. Consider this example:
self.formset = [{
'Person A': ['_firstname', '_lastname'],
'Person B': ['_firstname', '_lastname'] }]
so we get 2 tabs Person A and Person B. If I switch between them I would like to be informed with something similar to PyQt function currentIndex(). So far I havn't been able to find a method in the pyforms documentation, is there a way to accomplish this just using pyforms?
The main issue in getting or setting the current index of your tab widget is to get access to the QTabWidget created by pyforms when the layout is generated. Once you have access to it, you simply call the setCurrentIndex(int)/currentIndex() of the widget.
A (dirty) quick fix to this is to modify the BaseWidget.py located in the pyforms module files which can be <VIRTUALENV_DIR>/lib/python3.6/site-packages/pyforms/gui when using virtualenv.
def generate_tabs(self, formsetdict):
"""
Generate QTabWidget for the module form
#param formset: Tab form configuration
#type formset: dict
"""
tabs = QTabWidget(self)
for key, item in sorted(formsetdict.items()):
ctrl = self.generate_panel(item)
tabs.addTab(ctrl, key[key.find(':') + 1:])
self.tabs = tabs
return tabs
Note the additional :
self.tabs = tabs
Then in the code of your widget/app (subclass of BasicWidget) :
>>> _t = self.tabs
>>> _t.setCurrentIndex(3) # activate the 4th tab
>>> print(_t.currentIndex())
3