How to get the name of selected files in source control via VSCode extension API? - visual-studio-code

I can manage to get one file name of source control with following code. The file name is from the line 'await vscode.commands.executeCommand('copyFilePath');' I can get the file name by reading the clipboard text. But when I select multiple files, still the first file name is available. Is it possible to get all files' name?
let copySelectedFileName = vscode.commands.registerCommand('folder-operations.copySelectedFileName', async (folder) => {
let newUri = folder; // folder will be undefined when triggered by keybinding
console.log('folder'+folder);
if (!folder) { // so triggered by a keybinding
await vscode.commands.executeCommand('copyFilePath');
}
console.log(newUri);
});
I try another way: add one command to SCM as below shown.
I use parameter in command to retrieve the selected files' name. But the size of the array is 1 even if I choose more than 2 files.
let copySelectedFileNameSCM = vscode.commands.registerCommand('testSource.copySelectedFileNameSCM', async (...file) => {
console.log('file:'+file);
});

Add your command to this context menu in your package.json:
"contributes": {
"menus": {
"scm/resourceState/context": [
{
"command": "testSource.copySelectedFileNameSCM"
}
]
}
}
It looks like you were adding it to the wrong menu. That may be the only menu that will return selected files.
Then in your command:
let copySelectedFileNameSCM = vscode.commands.registerCommand('testSource.copySelectedFileNameSCM', async (...file) => {
console.log('file:'+file);
});
file will be an array of all selected items in the scm view when you trigger a context menu on one or more selected files.

Related

Insert default text into newly created files using vscod extension api

I'm trying to create a simple vscode extension that will insert some default text into a newly created file. What I want is for the vscode.workspace.createFileSystemWatcher to call a function that gets the activeTextEditor and writes to the new file. Here is what I've tried:
import * as vscode from "vscode";
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand(
"default-text-generator.generate",
() => {
function _watcherChangeApplied(editor?: vscode.TextEditor) {
if (editor) {
editor.edit((editBuilder) => {
editBuilder.insert(editor.selection.active, "Hello World");
});
}
}
const editor = vscode.window.activeTextEditor;
let uri: vscode.Uri | undefined = editor?.document.uri;
if (uri) {
let watcher = vscode.workspace.createFileSystemWatcher(
new vscode.RelativePattern(
vscode.workspace.getWorkspaceFolder(uri)!,
"**/*.ts"
),
false,
false,
false
);
watcher.onDidCreate(() => _watcherChangeApplied(editor));
}
}
);
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate(): void {
//deactivate
}
Here's what's happening. The editor seems to insert the text, then immediately gets overwritten back to a blank page. I can't seem to figure out why.
The problem happens because the editor you are referring to is not what you think to be. It is not the newly created editor but instead, the editor that you are focused/active when the new .ts file is created.
The FileSystemWatcher.onDidCreate event provides you a Uri to the newly created file inside your workspace, but not necessarily opened in VS Code. Try creating a file via terminal and you will see what I mean. The file is created, the event is fired, but no editor is opened in VS Code.
So, you won't be able to use the editor.edit API to manipulate the file. Instead, you should edit the file using RAW/Node functions. But, in this case, maybe/probably you will clash with the external tool that is creating the .ts file (which may not be VS Code, if you use the FileWatcher). If only files created via VS Code must be detected, you should change to the workspace.onDidCreateFiles event instead. But yet, it also only provides you the Uri, not the Editor.
Hope this helps
This works:
let disposable2 = vscode.commands.registerCommand('yourCommand.here', async (...file) => {
async function _watcherChangeApplied(uri) {
if (uri) {
const editor = await vscode.window.showTextDocument(uri);
editor.edit((editBuilder) => {
editBuilder.insert(editor.selection.active, "Hello World");
});
await editor.document.save();
}
}
const editor = vscode.window.activeTextEditor;
let uri = editor?.document.uri;
if (uri) {
let watcher = vscode.workspace.createFileSystemWatcher(
new vscode.RelativePattern(
vscode.workspace.getWorkspaceFolder(uri),
"**/*.ts"
),
false,
false,
false
);
// watcher.onDidCreate(() => _watcherChangeApplied(editor));
watcher.onDidCreate((uri) => _watcherChangeApplied(uri));
}
}
The key point is that watcher.onDidCreate() will return the uri of the newly created file. You can pass that to your _watcherChangeApplied(uri) function.
In _watcherChangeApplied(uri) you can show the created file via await vscode.window.showTextDocument(uri) and that function returns an editor that you can use with its edit functions.
The code works whether you create the file within vscode (like the New File... icon button at the top of the explorer) or via the terminal (like touch test.ts).
If you want to enable creating new files through the terminal, for example, and NOT open them, try this _watcherChangeApplied(uri):
async function _watcherChangeApplied(uri) {
if (uri) {
const document = await vscode.workspace.openTextDocument(uri);
const strToAdd = "Hello World";
const wse = new vscode.WorkspaceEdit();
wse.insert(uri, new vscode.Position(0,0), strToAdd);
await vscode.workspace.applyEdit(wse);
await document.save();
}
}

VSCode Extension: How to open a file if no workspace folders are available?

I've been working on an extension that allows adding files with pre-defined content and modifying them using a custom web editor.
The custom command "Add new XXX file" looks like the following:
let disposable = vscode.commands.registerCommand('myextension.add-new-file', () => {
if(vscode.workspace.workspaceFolders?.length){
const rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath ;
let counter = 0;
let filePath = '';
do{
counter++;
filePath = path.join(rootPath, `NewFile${counter}.my-ext`);
}while(fs.existsSync(filePath));
fs.writeFileSync(filePath, JSON.stringify(newFileContent), 'utf8');
const openPath = vscode.Uri.file(filePath);
vscode.commands.executeCommand('vscode.openWith', openPath, 'myextension.custom-designer');
}
});
It works OK if a folder is opened in VS Code. However, if no folder is opened, the rootPath can't be resolved. What's the solution for such a scenario? Does the 'vscode.openWith' accept the file content instead of the path to open?
You can accomplish your goal using the untitled scheme:
vscode.commands.executeCommand(
'vscode.openWith',
vscode.Uri.parse("untitled:FooBar"),
'myextension.custom-designer',
);
You can change your custom editor so that it detects when empty document gets passed to it and replaces the empty document with newFileContent.

Is there a vscode startup complete event or folder open event?

Can extension code be set to run when startup of vscode has completed? Or when a folder has been opened?
How to write an extension that opens a folder in a new vscode window, and then opens a text file in that folder?
I have the open the folder part working. And I am using global state to store the name of the file to open.
// store in name of file to open in global state.
context.globalState.update('fileToOpen', './src/index.html');
// open folder in a new vscode instance.
const uri_path = `file:///c:/web/tester/parcel`;
const uri = vscode.Uri.parse(uri_path);
await vscode.commands.executeCommand('vscode.openFolder', uri, true);
Then, when my extension is activated in the new vscode instance, I want to read the file name from global state, wait for vscode to open the folder, then run openTextDocument to open the file.
Since v1.46 there's a onStartupFinished activation event. So your package.json would have it:
...
"activationEvents": [
"onStartupFinished"
]
...
Then proceed to check the state upon activation
export function activate(context: vscode.ExtensionContext) {
const fileToOpen = context.globalState.get('fileToOpen')
if (fileToOpen) {
// open file
let document = await vscode.workspace.openTextDocument(fileToOpen);
await vscode.window.showTextDocument(document);
// reset state
context.globalState.update('fileToOpen', undefined);
} else {
// store in name of file to open in global state.
context.globalState.update('fileToOpen', './src/index.html');
// open folder in a new vscode instance.
const uri_path = `file:///c:/web/tester/parcel`;
const uri = vscode.Uri.parse(uri_path);
await vscode.commands.executeCommand('vscode.openFolder', uri, true);
}
...
}

Create duplicate tab of an already open file [duplicate]

We can use the "split editor" option to make two views into one file.
I'm looking for an option to open the same file in separated tabs like I can do in Sublime Text (open new view of file). Is that possible?
Note: I want to do this without splitting the view, so there should be two tabs for the same file within the same view container.
I couldn't find anything built-in that lets you do this, nor an existing extension in the marketplace. I thought it should be quite trivial to implement a "Duplicate Tab" command yourself in a custom extension, but it turns out VSCode only allows the same resource to be opened once within the same view column.
It's still possible to do this on Windows or macOS, but only by abusing this bug:
Issues with not case/fragment-normalizing file paths (macOS, Windows) #12448
Here's what the code for the extension looks like:
'use strict';
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand("duplicateTab", () => {
var activeEditor = vscode.window.activeTextEditor;
if (activeEditor == null) {
return;
}
// HACK!
const sameFileNameButDifferent = activeEditor.document.fileName.toUpperCase();
vscode.workspace.openTextDocument(sameFileNameButDifferent).then(document => {
vscode.window.showTextDocument(document, {preview: false});
});
});
}
In package.json:
"contributes": {
"commands": [
{
"title": "Duplicate Tab",
"command": "duplicateTab"
}
]
},

How to create a custom dialog in VSCode?

I'm developing an extension for VSCode, and I want to display a custom dialog to help the user configure an ini file.
Is it possible to create a custom dialog with labels and inputs?
You cannot create new UI elements, but if you want to get inputs from the user you can use code like below:
let options: InputBoxOptions = {
prompt: "Label: ",
placeHolder: "(placeholder)"
}
window.showInputBox(options).then(value => {
if (!value) return;
answer1 = value;
// show the next dialog, etc.
});
This will use the same UI as the command palette (when you press Ctrl+P, or any of the other commands that open the input box at the top).