From 28a672b9827ddc29aa2f9d8419c2dc94c9d14b2c Mon Sep 17 00:00:00 2001 From: Rob O'Leary <3703647+robole@users.noreply.github.com> Date: Tue, 12 Dec 2023 21:45:40 +0300 Subject: [PATCH] v2.0.0 - Upgrade the "active" commands to operate on any file. --- .vscode/settings.json | 3 +- CHANGELOG.md | 17 +- README.md | 24 +- package-lock.json | 14 +- package.json | 6 +- src/duplicateActiveFilePicker.js | 45 ++-- src/fileAction.js | 388 +++++++++++++++++-------------- src/util.js | 35 ++- todo.md | 2 +- 9 files changed, 306 insertions(+), 228 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8bec6b7..71a1f60 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "task.allowAutomaticTasks": "on" + "task.allowAutomaticTasks": "on", + "bogus.keybindings.enabled": true } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c3ed19..41353af 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,15 +5,28 @@ All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/-0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.0] - 2023-12-12 + +## Changed + +- Upgraded **minimum version of VS Code to support extension to 1.84** i.e. the `engines` field in `package.json`. I want to avail of the most recent API to improve the extension. +- Change the commands: `File Bunny: Open Active File in External Default App`, `File Bunny: Move Active File`, `File Bunny: Rename Active File`, `File Bunny: Duplicate Active File`, `File Bunny: Delete Active File`, and `File Bunny: Copy File Name` to be able to operate on any type of file. It was limited to text files. Uses the [`Tabgroup`](https://code.visualstudio.com/api/references/vscode-api#TabGroup) and [`Tab`](https://code.visualstudio.com/api/references/vscode-api#Tab) interfaces. +- Changed `File Bunny: Delete File` to delete the file and not close any open tabs related to that deleted file. +- Organised functions in *fileAction.js* to correspond with README for easier cross-referencing. Added region comments to each major section. + +## Removed + +- Removed "new" image label from `Filebunny: Starting Location Open Folder` in README. + ## [1.10.2] - 2023-12-12 -## Fixed +### Fixed - Fixed spacing in lists in README that affected layout. ## [1.10.1] - 2023-12-12 -## Fixed +### Fixed - Fixed typo in README in commands section. Accidentally deleted `File Bunny: Open File` title from list! Doh! diff --git a/README.md b/README.md index 1a78ae3..1c59e9c 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-
@@ -75,13 +75,15 @@ There are times when you want to do something with a workspace file outside of V
You may want to perform some action on a group of files, so it's probably easier to open that folder in your system file manager and do it there. You can use the `File Bunny: Open Workspace Folder Externally` command, or the `File Bunny: Open Folder Externally` command to open a specific folder.
-You may want to edit a file in an app specific to that file type. I often want to edit SVG images in my default editor (Inkscape). You can use the `File Bunny: Open File in External App` command to do this.
+You may want to edit a file in an app specific to that file type. For example, I often want to edit SVG files in *Inkscape*, my preferred vector graphics editor. You can use the `File Bunny: Open File in External App` command to do this.
## Commands
The following commands can be run from the Command Palette (`Ctrl+Shift+P`). They are categorised below:
-### File actions
+### File Actions
+
+These commands are scoped to the active workspace.
1. `File Bunny: Open File`: Choose a file to open from the current workspace.
1. `File Bunny: Open File to the Right`: Choose a file to open from the current workspace, and split it to the right of the active editor.
@@ -99,22 +101,24 @@ The following commands can be run from the Command Palette (`Ctrl+Shift+P`). The
1. `File Bunny: Open Active File in External Default App`: Open the active file in the system default app.
1. `File Bunny: Move Active File`: Move the active file to another location in the current workspace.
1. `File Bunny: Duplicate Active File`: Copy the active file and place it somewhere in the current workspace.
-1. `File Bunny: Rename Active File`
+1. `File Bunny: Rename Active File`: Change the name of the active file.
1. `File Bunny: Delete Active File`: Delete the active file. The file is put into the trash (recycle bin).
### Folder actions
+These commands are scoped to the active workspace.
+
1. `File Bunny: Open Folder`: Choose a folder to open as the workspace.
-1. `File Bunny: Open Workspace Folder in External Default App`: Open the current workspace folder in the Operating Systems' file explorer.
-1. `File Bunny: Open Folder in External Default App`: Open a folder from the current workspace in the Operating Systems' file explorer.
+1. `File Bunny: Open Workspace Folder in External Default App`: Open the current workspace folder in the system file explorer.
+1. `File Bunny: Open Folder in External Default App`: Open a folder from the current workspace in the system file explorer.
1. `File Bunny: Create New Folder`: Create a new folder in the current workspace.
1. `File Bunny: Duplicate Folder`: Duplicate a folder from the current workspace, and place it somewhere in the current workspace.
1. `File Bunny: Delete Folder`: Delete a folder from the current workspace.
### Quick navigation
-1. `File Bunny: Go to Top of Active File`
-1. `File Bunny: Go to End of Active File`
+1. `File Bunny: Go to Top of Active File`: Takes you to the first line of a file.
+1. `File Bunny: Go to End of Active File`: Takes you to the last line of a file.
### Quick metadata
@@ -125,7 +129,7 @@ The following commands can be run from the Command Palette (`Ctrl+Shift+P`). The
## Settings
- `Filebunny: Excludes`: Configure glob patterns for excluding files and folders from file lists for commands. By default, the *.git* and *node_modules* folders are ignored in your workspace.
-- `Filebunny: Starting Location Open Folder`: The initial location shown in the QuickPick when you run the command `File Bunny: Open Folder`. If this field is empty or the path is invalid, it will default to the system home directory. ![New command](/img/new.png)
+- `Filebunny: Starting Location Open Folder`: The initial location shown in the QuickPick when you run the command `File Bunny: Open Folder`. If this field is empty or the path is invalid, it will default to the system home directory.
## Keybindings
diff --git a/package-lock.json b/package-lock.json
index e115fab..1aa8948 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "file-bunny",
- "version": "1.8.1",
+ "version": "2.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "file-bunny",
- "version": "1.8.1",
+ "version": "2.0.0",
"dependencies": {
"glob": "^7.1.6"
},
@@ -14,7 +14,7 @@
"@types/glob": "^7.1.3",
"@types/mocha": "^8.0.4",
"@types/node": "^12.11.7",
- "@types/vscode": "^1.46.0",
+ "@types/vscode": "^1.84.0",
"@vscode/test-electron": "^2.3.0",
"@vscode/vsce": "^2.22.0",
"chai": "^4.3.4",
@@ -31,7 +31,7 @@
},
"engines": {
"node": ">=12",
- "vscode": "^1.46.0"
+ "vscode": "^1.84.0"
}
},
"node_modules/@babel/code-frame": {
@@ -571,9 +571,9 @@
"dev": true
},
"node_modules/@types/vscode": {
- "version": "1.46.0",
- "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.46.0.tgz",
- "integrity": "sha512-8m9wPEB2mcRqTWNKs9A9Eqs8DrQZt0qNFO8GkxBOnyW6xR//3s77SoMgb/nY1ctzACsZXwZj3YRTDsn4bAoaUw==",
+ "version": "1.85.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.85.0.tgz",
+ "integrity": "sha512-CF/RBon/GXwdfmnjZj0WTUMZN5H6YITOfBCP4iEZlOtVQXuzw6t7Le7+cR+7JzdMrnlm7Mfp49Oj2TuSXIWo3g==",
"dev": true
},
"node_modules/@ungap/promise-all-settled": {
diff --git a/package.json b/package.json
index ab5d22f..6960229 100755
--- a/package.json
+++ b/package.json
@@ -7,9 +7,9 @@
},
"description": "Perform file actions quickly with keyboard-driven file selection. 🐰⌨️",
"icon": "img/logo.png",
- "version": "1.10.2",
+ "version": "2.0.0",
"engines": {
- "vscode": "^1.46.0",
+ "vscode": "^1.84.0",
"node": ">=12"
},
"categories": [
@@ -279,7 +279,7 @@
"@types/glob": "^7.1.3",
"@types/mocha": "^8.0.4",
"@types/node": "^12.11.7",
- "@types/vscode": "^1.46.0",
+ "@types/vscode": "^1.84.0",
"@vscode/test-electron": "^2.3.0",
"@vscode/vsce": "^2.22.0",
"chai": "^4.3.4",
diff --git a/src/duplicateActiveFilePicker.js b/src/duplicateActiveFilePicker.js
index 75bdebd..2272823 100644
--- a/src/duplicateActiveFilePicker.js
+++ b/src/duplicateActiveFilePicker.js
@@ -24,16 +24,27 @@ class DuplicateActiveFilePicker extends MultiStepPicker {
super(steps);
- this.fileName = nodePath.basename(
- vscode.window.activeTextEditor.document.fileName
- );
-
- this.steps[1].value = this.fileName;
-
- if (util.isWorkspaceOpen()) {
+ if (util.isWorkspaceOpen() === false) {
+ this.close();
+ throw new Error(
+ "You cannot duplicate a file if there is no open workspace."
+ );
+ } else {
this.rootFolder = vscode.workspace.workspaceFolders[0].uri.fsPath;
}
+ if (util.hasActiveTab()) {
+ this.activeFileUri = util.getActiveTabUri();
+ if (this.activeFileUri) {
+ this.filename = nodePath.basename(this.activeFileUri.fsPath);
+ }
+ } else {
+ this.close();
+ throw new Error("There is no active file");
+ }
+
+ this.steps[1].value = this.filename;
+
let disposable1 = this.picker.onDidChangeValue(
this.onDidChangeValue.bind(this)
);
@@ -41,15 +52,7 @@ class DuplicateActiveFilePicker extends MultiStepPicker {
}
async run() {
- if (vscode.window.activeTextEditor === undefined) {
- return;
- }
-
- if (this.rootFolder === undefined) {
- vscode.window.showWarningMessage(
- "You cannot duplicate a file if a workspace is not open."
- );
- this.close();
+ if (util.isWorkspaceOpen() === false || util.isWorkspaceOpen() === false) {
return;
}
@@ -86,8 +89,8 @@ class DuplicateActiveFilePicker extends MultiStepPicker {
this.currentStepNum = 2;
this.steps[1].title = `Duplicate Active File - name - '${
- this.fileName
- }' to '${nodePath.join(selection, this.fileName)}'`;
+ this.filename
+ }' to '${nodePath.join(selection, this.filename)}'`;
this.setCurrentStep(this.steps[1]);
} else if (this.currentStepNum === 2) {
this.steps[1].value = currentValue;
@@ -122,7 +125,7 @@ class DuplicateActiveFilePicker extends MultiStepPicker {
}
setTitle(filepath) {
- this.picker.title = `Duplicate Active File - name - '${this.fileName}' to '${filepath}'`;
+ this.picker.title = `Duplicate Active File - name - '${this.filename}' to '${filepath}'`;
}
async duplicateFile() {
@@ -131,14 +134,14 @@ class DuplicateActiveFilePicker extends MultiStepPicker {
this.steps[0].value,
this.steps[1].value
);
- let activeDocUri = vscode.window.activeTextEditor.document.uri;
+
let newUri = vscode.Uri.file(absoluteFilepath);
try {
let exists = await fileSystem.exists(newUri);
if (exists === false) {
- await vscode.workspace.fs.copy(activeDocUri, newUri, {
+ await vscode.workspace.fs.copy(this.activeFileUri, newUri, {
overwrite: false,
});
await vscode.commands.executeCommand("vscode.open", newUri);
diff --git a/src/fileAction.js b/src/fileAction.js
index 159ef86..ae0ed30 100644
--- a/src/fileAction.js
+++ b/src/fileAction.js
@@ -12,21 +12,11 @@ const globPicker = require("./globPicker");
const fileSystem = require("./fileSystem");
const util = require("./util");
-async function createFile() {
- if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
- "You cannot create a file if a workspace is not open."
- );
- return;
- }
-
- let picker = new NewFilePicker();
- await picker.run();
-}
+// #region Workspace file functions
async function openFile() {
if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
+ vscode.window.showErrorMessage(
"You cannot open a file if a workspace is not open."
);
return;
@@ -39,41 +29,9 @@ async function openFile() {
}
}
-async function openFileExternal() {
- if (util.isWorkspaceOpen() === false) {
- return;
- }
-
- let selectedFile = await selectWorkspaceFile(
- "Open File in External Default App"
- );
-
- if (selectedFile !== undefined) {
- try {
- await vscode.env.openExternal(selectedFile);
- } catch (err) {
- vscode.window.showErrorMessage(err);
- }
- }
-}
-
-async function openActiveFileExternal() {
- if (util.hasActiveTextEditor() === false) {
- return;
- }
-
- let activeDocUri = vscode.window.activeTextEditor.document.uri;
-
- try {
- await vscode.env.openExternal(activeDocUri);
- } catch (err) {
- vscode.window.showErrorMessage(err);
- }
-}
-
async function openFileAbove() {
if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
+ vscode.window.showErrorMessage(
"You cannot open a file if a workspace is not open."
);
return;
@@ -92,7 +50,7 @@ async function openFileAbove() {
async function openFileBelow() {
if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
+ vscode.window.showErrorMessage(
"You cannot open a file if a workspace is not open."
);
return;
@@ -111,7 +69,7 @@ async function openFileBelow() {
async function openFileToRight() {
if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
+ vscode.window.showErrorMessage(
"You cannot open a file if a workspace is not open."
);
return;
@@ -130,7 +88,7 @@ async function openFileToRight() {
async function openFileToLeft() {
if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
+ vscode.window.showErrorMessage(
"You cannot open a file if a workspace is not open."
);
return;
@@ -147,51 +105,135 @@ async function openFileToLeft() {
}
}
-async function selectWorkspaceFile(title = "") {
+async function openFileExternal() {
if (util.isWorkspaceOpen() === false) {
- return undefined;
+ return;
}
- let selectedFileUri;
+ let selectedFile = await selectWorkspaceFile(
+ "Open File in External Default App"
+ );
+
+ if (selectedFile !== undefined) {
+ try {
+ await vscode.env.openExternal(selectedFile);
+ } catch (err) {
+ vscode.window.showErrorMessage(err);
+ }
+ }
+}
+
+async function createFile() {
+ if (util.isWorkspaceOpen() === false) {
+ vscode.window.showErrorMessage(
+ "You cannot create a file if a workspace is not open."
+ );
+ return;
+ }
+
+ let picker = new NewFilePicker();
+ await picker.run();
+}
+
+async function moveFile() {
+ if (util.isWorkspaceOpen() === false) {
+ vscode.window.showErrorMessage(
+ "You cannot move a file if a workspace is not open."
+ );
+ return;
+ }
+
+ let picker = new MoveFilePicker();
+ await picker.run();
+}
+
+async function duplicateFile() {
+ if (util.isWorkspaceOpen() === false) {
+ vscode.window.showErrorMessage(
+ "You cannot duplicate a file if a workspace is not open."
+ );
+ return;
+ }
+
+ let picker = new DuplicateFilePicker();
+ await picker.run();
+}
+
+async function deleteFile() {
+ if (util.isWorkspaceOpen() === false) {
+ vscode.window.showErrorMessage(
+ "You cannot delete a file if a workspace is not open."
+ );
+ return;
+ }
let workspaceFolderPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
let absoluteExcludes = configuration.getAbsoluteExcludes(workspaceFolderPath);
- let pickerItems = await globPicker.getFilesRecursivelyAsPickerItems(
+ let allFiles = await globPicker.getFilesRecursivelyAsPickerItems(
workspaceFolderPath,
- { showFiles: true, showFolders: false, excludes: absoluteExcludes }
+ {
+ showFiles: true,
+ showFolders: false,
+ excludes: absoluteExcludes,
+ }
);
- let selectedFile = await vscode.window.showQuickPick(pickerItems, {
+ let selectedFile = await vscode.window.showQuickPick(allFiles, {
ignoreFocusOut: true,
placeHolder: `Pick a file`,
- title,
+ title: `Delete File`,
});
if (selectedFile !== undefined) {
- selectedFileUri = vscode.Uri.file(
+ let selectedFileUri = vscode.Uri.file(
nodePath.join(workspaceFolderPath, selectedFile.name)
);
- }
- return selectedFileUri;
+ try {
+ await vscode.workspace.fs.delete(selectedFileUri, { useTrash: true });
+ } catch (error) {
+ vscode.window.showErrorMessage(
+ `Could not delete file: ${selectedFileUri.path}. ${error}`
+ );
+ }
+ }
}
-async function moveActiveFile() {
- if (util.hasActiveTextEditor() === false) {
+// #endregion
+
+// #region Active file functions
+
+async function openActiveFileExternal() {
+ if (util.hasActiveTab() === false) {
return;
}
- let activeDocUri = vscode.window.activeTextEditor.document.uri;
- let activeDocFileName = nodePath.basename(activeDocUri.path);
+ let uri = util.getActiveTabUri();
+
+ try {
+ await vscode.env.openExternal(uri);
+ } catch (err) {
+ vscode.window.showErrorMessage(
+ `Could not open the file in default external app: ${uri.fsPath}. ${err.message}.`
+ );
+ }
+}
+async function moveActiveFile() {
if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
- "You cannot move an active file if a workspace is not open."
+ vscode.window.showErorMessage(
+ "You cannot move an active file if there is no open workspace."
);
return;
}
+ if (util.hasActiveTab() === false) {
+ return;
+ }
+
+ let uri = util.getActiveTabUri();
+
let startingLocation = vscode.workspace.workspaceFolders[0].uri.fsPath;
let absoluteExcludes = configuration.getAbsoluteExcludes(startingLocation);
let topFolderDescription = "Workspace Root";
@@ -214,21 +256,25 @@ async function moveActiveFile() {
});
if (selectedFolder !== undefined) {
+ let filename = nodePath.basename(uri.path);
let newUri = vscode.Uri.file(
- nodePath.join(startingLocation, selectedFolder.name, activeDocFileName)
+ nodePath.join(startingLocation, selectedFolder.name, filename)
);
let exists = await fileSystem.exists(newUri);
if (exists === false) {
- await vscode.workspace.fs.rename(activeDocUri, newUri, {
- overwrite: false,
- });
-
- // return focus to editor
- await vscode.window.showTextDocument(newUri);
+ try {
+ await vscode.workspace.fs.rename(uri, newUri, {
+ overwrite: false,
+ });
+ } catch (error) {
+ vscode.window.showErrorMessage(
+ `Could not move file: ${uri.path}. ${error}.`
+ );
+ }
} else {
- vscode.window.showErrorMessage(
+ vscode.window.showWarningMessage(
"File exists here already. No action taken."
);
}
@@ -236,30 +282,25 @@ async function moveActiveFile() {
}
async function duplicateActiveFile() {
- if (util.hasActiveTextEditor() === false) {
- return;
+ try {
+ let picker = new DuplicateActiveFilePicker();
+ await picker.run();
+ } catch (error) {
+ vscode.window.showErrorMessage(error.message);
}
-
- let picker = new DuplicateActiveFilePicker();
- await picker.run();
}
async function renameActiveFile() {
- if (util.hasActiveTextEditor() === false) {
+ if (util.hasActiveTab() === false) {
return;
}
- let { uri, fileName } = vscode.window.activeTextEditor.document;
- let name = nodePath.basename(fileName);
- let dir = nodePath.dirname(fileName);
+ let uri = util.getActiveTabUri();
+ let filename = nodePath.basename(uri.fsPath);
let relativePath = getRelativePathOfActiveFile();
- if (relativePath.startsWith("..")) {
- relativePath = uri.fsPath;
- }
-
let newName = await vscode.window.showInputBox({
- value: name,
+ value: filename,
prompt: `Rename Active File - '${relativePath}'`,
});
@@ -269,97 +310,83 @@ async function renameActiveFile() {
newName.endsWith("/") === false &&
newName.endsWith("\\") === false
) {
- let newUri = vscode.Uri.file(nodePath.join(dir, newName));
- await vscode.workspace.fs.rename(uri, newUri);
-
- // return focus to editor
- await vscode.window.showTextDocument(newUri);
+ try {
+ let dirPath = nodePath.dirname(uri.fsPath);
+ let newUri = vscode.Uri.file(nodePath.join(dirPath, newName));
+ await vscode.workspace.fs.rename(uri, newUri);
+ } catch (error) {
+ vscode.window.showErrorMessage(
+ `Could not rename file: ${uri.path}. ${error}.`
+ );
+ }
}
}
async function deleteActiveFile() {
- if (util.hasActiveTextEditor() === false) {
+ if (util.hasActiveTab() === false) {
return;
}
- let { uri } = vscode.window.activeTextEditor.document;
- await vscode.workspace.fs.delete(uri, { useTrash: true });
- await util.closeTextEditor(uri);
+ let uri = util.getActiveTabUri();
- // give focus to next editor
- await vscode.commands.executeCommand("workbench.action.nextEditorInGroup");
+ try {
+ await vscode.workspace.fs.delete(uri, { useTrash: true });
+ await util.closeTab(uri);
+ await util.switchFocusNextTab();
+ } catch (error) {
+ vscode.window.showErrorMessage(
+ `Could not delete file: ${uri.fsPath}. ${error.message}.`
+ );
+ }
}
+// #endregion
-async function duplicateFile() {
- if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
- "You cannot duplicate a file if a workspace is not open."
- );
+// #region Quick navigation functions
+function goToTopActiveFile() {
+ if (util.hasActiveTextEditor() === false) {
return;
}
- let picker = new DuplicateFilePicker();
- await picker.run();
-}
+ let editor = vscode.window.activeTextEditor;
-async function moveFile() {
- if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
- "You cannot move a file if a workspace is not open."
+ if (editor !== undefined) {
+ editor.revealRange(
+ new vscode.Range(0, 0, 0, 0),
+ vscode.TextEditorRevealType.AtTop
);
- return;
- }
- let picker = new MoveFilePicker();
- await picker.run();
+ editor.selection = new vscode.Selection(0, 0, 0, 0);
+ }
}
-async function deleteFile() {
- if (util.isWorkspaceOpen() === false) {
- vscode.window.showWarningMessage(
- "You cannot delete a file if a workspace is not open."
- );
+function goToBottomActiveFile() {
+ if (util.hasActiveTextEditor() === false) {
return;
}
- let workspaceFolderPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
- let absoluteExcludes = configuration.getAbsoluteExcludes(workspaceFolderPath);
-
- let allFiles = await globPicker.getFilesRecursivelyAsPickerItems(
- workspaceFolderPath,
- {
- showFiles: true,
- showFolders: false,
- excludes: absoluteExcludes,
- }
- );
-
- let selectedFile = await vscode.window.showQuickPick(allFiles, {
- ignoreFocusOut: true,
- placeHolder: `Pick a file`,
- title: `Delete File`,
- });
+ let editor = vscode.window.activeTextEditor;
- if (selectedFile !== undefined) {
- let selectedFileUri = vscode.Uri.file(
- nodePath.join(workspaceFolderPath, selectedFile.name)
+ if (editor !== undefined) {
+ let lastLineNum = editor.document.lineCount - 1;
+ editor.revealRange(
+ new vscode.Range(lastLineNum, 0, lastLineNum, 0),
+ vscode.TextEditorRevealType.Default
);
- await vscode.workspace.fs.delete(selectedFileUri, { useTrash: true });
- await util.closeTextEditor(selectedFileUri);
-
- // give focus to next editor
- await vscode.commands.executeCommand("workbench.action.nextEditorInGroup");
+ editor.selection = new vscode.Selection(lastLineNum, 0, lastLineNum, 0);
}
}
+// #endregion
+// #region Quick metadata functions
async function copyFileName() {
- if (util.hasActiveTextEditor() === false) {
+ if (util.hasActiveTab() === false) {
return;
}
- let { fileName } = vscode.window.activeTextEditor.document;
- await vscode.env.clipboard.writeText(nodePath.basename(fileName));
+ let uri = util.getActiveTabUri();
+
+ await vscode.env.clipboard.writeText(nodePath.basename(uri.fsPath));
}
async function copyAbsoluteFilePath() {
@@ -369,60 +396,69 @@ async function copyAbsoluteFilePath() {
async function copyRelativeFilePath() {
await vscode.commands.executeCommand("copyRelativeFilePath");
}
+// #endregion
-function goToTopActiveFile() {
- if (util.hasActiveTextEditor() === false) {
- return;
+async function selectWorkspaceFile(title = "") {
+ if (util.isWorkspaceOpen() === false) {
+ return undefined;
}
- let editor = vscode.window.activeTextEditor;
-
- if (editor !== undefined) {
- editor.revealRange(
- new vscode.Range(0, 0, 0, 0),
- vscode.TextEditorRevealType.AtTop
- );
+ let selectedFileUri;
- editor.selection = new vscode.Selection(0, 0, 0, 0);
- }
-}
+ let workspaceFolderPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
+ let absoluteExcludes = configuration.getAbsoluteExcludes(workspaceFolderPath);
-function goToBottomActiveFile() {
- if (util.hasActiveTextEditor() === false) {
- return;
- }
+ let pickerItems = await globPicker.getFilesRecursivelyAsPickerItems(
+ workspaceFolderPath,
+ { showFiles: true, showFolders: false, excludes: absoluteExcludes }
+ );
- let editor = vscode.window.activeTextEditor;
+ let selectedFile = await vscode.window.showQuickPick(pickerItems, {
+ ignoreFocusOut: true,
+ placeHolder: `Pick a file`,
+ title,
+ });
- if (editor !== undefined) {
- let lastLineNum = editor.document.lineCount - 1;
- editor.revealRange(
- new vscode.Range(lastLineNum, 0, lastLineNum, 0),
- vscode.TextEditorRevealType.Default
+ if (selectedFile !== undefined) {
+ selectedFileUri = vscode.Uri.file(
+ nodePath.join(workspaceFolderPath, selectedFile.name)
);
-
- editor.selection = new vscode.Selection(lastLineNum, 0, lastLineNum, 0);
}
+
+ return selectedFileUri;
}
/**
- * Gets the path of the active file relative to the workspace folder. If no workspace is open, the absolute path is returned.
+ * Gets the path of the active file relative to the workspace folder. If no workspace is open, the absolute path is returned. If the
+ * file is not in the workspace, the absolute path is returned.
* @returns {string}
*/
function getRelativePathOfActiveFile() {
- if (util.hasActiveTextEditor() === false) {
+ if (util.hasActiveTab() === false) {
return undefined;
}
- let { uri } = vscode.window.activeTextEditor.document;
+ let uri;
+ const { activeTab } = vscode.window.tabGroups.activeTabGroup;
+
+ if (activeTab.input) {
+ uri = activeTab.input.uri;
+ }
+
let dirPath = nodePath.dirname(uri.fsPath);
- let fileName = nodePath.basename(uri.fsPath);
+ let filename = nodePath.basename(uri.fsPath);
let relativePath = uri.fsPath;
if (util.isWorkspaceOpen()) {
let workspaceRoot = vscode.workspace.workspaceFolders[0].uri.fsPath;
let relativeDir = nodePath.relative(workspaceRoot, dirPath);
- relativePath = nodePath.join(relativeDir, fileName);
+ relativePath = nodePath.join(relativeDir, filename);
+
+ if (relativePath.startsWith("..")) {
+ relativePath = uri.fsPath;
+ } else {
+ relativePath = `./${relativePath}`;
+ }
}
return relativePath;
diff --git a/src/util.js b/src/util.js
index d192f17..e0c8e36 100644
--- a/src/util.js
+++ b/src/util.js
@@ -11,18 +11,36 @@ function hasActiveTextEditor() {
return !(vscode.window.activeTextEditor === undefined);
}
-async function closeTextEditor(filepath) {
+function hasActiveTab() {
+ return !(vscode.window.tabGroups.activeTabGroup.activeTab === undefined);
+}
+
+function getActiveTabUri() {
+ let uri;
+
+ const { activeTab } = vscode.window.tabGroups.activeTabGroup;
+
+ if (activeTab.input) {
+ uri = activeTab.input.uri;
+ }
+
+ return uri;
+}
+
+async function closeTab(uri) {
const tabs = vscode.window.tabGroups.all.map((tg) => tg.tabs).flat();
- const index = tabs.findIndex(
- (tab) =>
- tab.input instanceof vscode.TabInputText &&
- tab.input.uri.path === filepath.path
- );
+
+ const index = tabs.findIndex((tab) => tab.input.uri.path === uri.path);
+
if (index !== -1) {
await vscode.window.tabGroups.close(tabs[index]);
}
}
+async function switchFocusNextTab() {
+ await vscode.commands.executeCommand("workbench.action.nextEditorInGroup");
+}
+
function isRootFolder(p) {
const parentPath = nodePath.join(p, "../");
if (p === parentPath || parentPath === "./" || /\w:\/$/.test(p)) {
@@ -105,8 +123,11 @@ function createUniqueFileName(fileName, index) {
module.exports = {
isWorkspaceOpen,
isRootFolder,
- closeTextEditor,
+ closeTab,
hasActiveTextEditor,
+ hasActiveTab,
+ getActiveTabUri,
+ switchFocusNextTab,
enableKeyBindings,
disableKeyBindings,
escapePath,
diff --git a/todo.md b/todo.md
index 9c2e121..b75b45b 100644
--- a/todo.md
+++ b/todo.md
@@ -11,6 +11,7 @@
## Further ideas
+1. `File Bunny: Copy Active File as Encoded Data URI` : Similar to https://yoksel.github.io/url-encoder/ . Copy the content of the file as an encoded [data URI](https://en.wikipedia.org/wiki/Data_URI_scheme). This is helpful when you want to use a SVG in CSS. See [StackOverflow Q](https://stackoverflow.com/questions/19255296/is-there-a-way-to-use-svg-as-content-in-a-pseudo-element-before-or-after).
1. Use different fuzzy search algo?
1. broot-like commands available on files. Could use `Terminal.sendText`? See