From 915b40d5d5c8044deb0648ebfdd149c4bdc79165 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. --- 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 ++- 7 files changed, 303 insertions(+), 226 deletions(-) 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,