Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,22 @@ export function activate(context: vscode.ExtensionContext): ExtensionApi {
vscode.commands.registerCommand('workspace-file-bookmarks.goToBookmark', () =>
goToBookmark(store),
),
vscode.commands.registerCommand(
'workspace-file-bookmarks.copyBookmarkPath',
(item: BookmarkTreeItem) => copyBookmarkPath(item.bookmark),
),
vscode.commands.registerCommand(
'workspace-file-bookmarks.copyBookmarkRelativePath',
(item: BookmarkTreeItem) => copyBookmarkRelativePath(item.bookmark),
),
vscode.commands.registerCommand(
'workspace-file-bookmarks.revealBookmarkInExplorer',
(item: BookmarkTreeItem) => revealBookmarkInExplorer(item.bookmark),
),
vscode.commands.registerCommand(
'workspace-file-bookmarks.revealBookmarkInFileManager',
(item: BookmarkTreeItem) => revealBookmarkInFileManager(item.bookmark),
),
);

return { store, provider };
Expand Down Expand Up @@ -903,6 +919,26 @@ export async function removeBrokenBookmarks(store: BookmarkStore): Promise<void>
vscode.window.showInformationMessage(`Removed ${broken.length} broken bookmark(s).`);
}

/** Copies the bookmarked file's absolute path to the clipboard. */
export async function copyBookmarkPath(bookmark: Bookmark): Promise<void> {
await vscode.env.clipboard.writeText(vscode.Uri.parse(bookmark.uri).fsPath);
}

/** Copies the bookmarked file's workspace-relative path to the clipboard. */
export async function copyBookmarkRelativePath(bookmark: Bookmark): Promise<void> {
await vscode.env.clipboard.writeText(bookmark.relativePath);
}

/** Reveals the bookmarked file in VS Code's Explorer view. */
export async function revealBookmarkInExplorer(bookmark: Bookmark): Promise<void> {
await vscode.commands.executeCommand('revealInExplorer', vscode.Uri.parse(bookmark.uri));
}

/** Reveals the bookmarked file in the OS file manager. */
export async function revealBookmarkInFileManager(bookmark: Bookmark): Promise<void> {
await vscode.commands.executeCommand('revealFileInOS', vscode.Uri.parse(bookmark.uri));
}

export async function openAllInFolder(store: BookmarkStore, item: FolderGroupItem) {
if (item.bookmarks.length === 0) {
vscode.window.showInformationMessage(`"${item.folder.name}" has no bookmarks.`);
Expand Down
40 changes: 40 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,26 @@
"title": "Go to Bookmark...",
"category": "Workspace File Bookmarks",
"icon": "$(go-to-file)"
},
{
"command": "workspace-file-bookmarks.copyBookmarkPath",
"title": "Copy Path",
"category": "Workspace File Bookmarks"
},
{
"command": "workspace-file-bookmarks.copyBookmarkRelativePath",
"title": "Copy Relative Path",
"category": "Workspace File Bookmarks"
},
{
"command": "workspace-file-bookmarks.revealBookmarkInExplorer",
"title": "Reveal in Explorer",
"category": "Workspace File Bookmarks"
},
{
"command": "workspace-file-bookmarks.revealBookmarkInFileManager",
"title": "Reveal in File Manager",
"category": "Workspace File Bookmarks"
}
],
"menus": {
Expand Down Expand Up @@ -286,6 +306,26 @@
"when": "view == workspace-file-bookmarks-view && viewItem == bookmarkItem",
"group": "1_modification"
},
{
"command": "workspace-file-bookmarks.revealBookmarkInExplorer",
"when": "view == workspace-file-bookmarks-view && viewItem == bookmarkItem",
"group": "2_reveal@1"
},
{
"command": "workspace-file-bookmarks.revealBookmarkInFileManager",
"when": "view == workspace-file-bookmarks-view && viewItem == bookmarkItem",
"group": "2_reveal@2"
},
{
"command": "workspace-file-bookmarks.copyBookmarkPath",
"when": "view == workspace-file-bookmarks-view && viewItem == bookmarkItem",
"group": "3_copy@1"
},
{
"command": "workspace-file-bookmarks.copyBookmarkRelativePath",
"when": "view == workspace-file-bookmarks-view && viewItem == bookmarkItem",
"group": "3_copy@2"
},
{
"command": "workspace-file-bookmarks.openAllInFolder",
"when": "view == workspace-file-bookmarks-view && viewItem == bookmarkFolder",
Expand Down
11 changes: 8 additions & 3 deletions test/activate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ describe('activate', () => {
'workspace-file-bookmarks-view',
expect.objectContaining({ canSelectMany: true }),
);
expect(commands.registerCommand).toHaveBeenCalledTimes(25);
expect((context as any).subscriptions).toHaveLength(26); // tree view + 25 commands
expect(commands.registerCommand).toHaveBeenCalledTimes(29);
expect((context as any).subscriptions).toHaveLength(30); // tree view + 29 commands
});

it('exercises every registered command handler at least once', async () => {
Expand Down Expand Up @@ -78,8 +78,13 @@ describe('activate', () => {
await handlers.get('workspace-file-bookmarks.importBookmarks')?.();
window.showQuickPick.mockResolvedValue(undefined);
await handlers.get('workspace-file-bookmarks.goToBookmark')?.();
await handlers.get('workspace-file-bookmarks.copyBookmarkPath')?.({ bookmark });
await handlers.get('workspace-file-bookmarks.copyBookmarkRelativePath')?.({ bookmark });
await handlers.get('workspace-file-bookmarks.revealBookmarkInExplorer')?.({ bookmark });
await handlers.get('workspace-file-bookmarks.revealBookmarkInFileManager')?.({ bookmark });

expect(handlers.size).toBe(25);
expect(commands.registerCommand).toHaveBeenCalledTimes(29);
expect((context as any).subscriptions).toHaveLength(30); // tree view + 29 commands
});
});

Expand Down
38 changes: 37 additions & 1 deletion test/commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
addActiveSelectionBookmark,
addBookmarksForUris,
addBookmarksToFolder,
copyBookmarkPath,
copyBookmarkRelativePath,
createFolder,
createSubfolder,
deleteFolder,
Expand All @@ -24,11 +26,13 @@ import {
removeBrokenBookmarks,
renameFolder,
resolveBookmarkTargets,
revealBookmarkInExplorer,
revealBookmarkInFileManager,
type Bookmark,
type BookmarkFolder,
} from '../extension';
import { createFakeContext } from './fakeContext';
import { Position, Selection, Uri, window, workspace } from './vscode-mock';
import { Position, Selection, Uri, commands, env, window, workspace } from './vscode-mock';
import type { InputBox } from './vscode-mock';

function newStore() {
Expand Down Expand Up @@ -1097,3 +1101,35 @@ describe('removeBrokenBookmarks', () => {
expect(window.showWarningMessage).not.toHaveBeenCalled();
});
});

describe('copy path / reveal actions', () => {
it('copies the absolute path of the bookmarked file', async () => {
await copyBookmarkPath(makeBookmark({ uri: 'file:///repo/src/a.ts' }));

expect(env.clipboard.writeText).toHaveBeenCalledWith('/repo/src/a.ts');
});

it('copies the workspace-relative path of the bookmarked file', async () => {
await copyBookmarkRelativePath(makeBookmark({ relativePath: 'src/a.ts' }));

expect(env.clipboard.writeText).toHaveBeenCalledWith('src/a.ts');
});

it("reveals the bookmarked file in VS Code's Explorer", async () => {
await revealBookmarkInExplorer(makeBookmark({ uri: 'file:///repo/src/a.ts' }));

expect(commands.executeCommand).toHaveBeenCalledWith(
'revealInExplorer',
expect.objectContaining({ fsPath: '/repo/src/a.ts' }),
);
});

it('reveals the bookmarked file in the OS file manager', async () => {
await revealBookmarkInFileManager(makeBookmark({ uri: 'file:///repo/src/a.ts' }));

expect(commands.executeCommand).toHaveBeenCalledWith(
'revealFileInOS',
expect.objectContaining({ fsPath: '/repo/src/a.ts' }),
);
});
});
28 changes: 28 additions & 0 deletions test/e2e/extension.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ describe('Workspace File Bookmarks (e2e)', () => {
'workspace-file-bookmarks.exportBookmarks',
'workspace-file-bookmarks.importBookmarks',
'workspace-file-bookmarks.goToBookmark',
'workspace-file-bookmarks.copyBookmarkPath',
'workspace-file-bookmarks.copyBookmarkRelativePath',
'workspace-file-bookmarks.revealBookmarkInExplorer',
'workspace-file-bookmarks.revealBookmarkInFileManager',
]) {
assert.ok(commands.includes(id), `expected command "${id}" to be registered`);
}
Expand Down Expand Up @@ -373,4 +377,28 @@ describe('Workspace File Bookmarks (e2e)', () => {
);
assert.equal(store.getAllBookmarks().length, 0);
});

it('copies the absolute and relative path of a bookmark to the clipboard', async () => {
const { store } = await getApi();
const document = await vscode.workspace.openTextDocument(fixtureUri('src/sample-a.ts'));
await vscode.window.showTextDocument(document);
await vscode.commands.executeCommand('workspace-file-bookmarks.addBookmark');
const item = { bookmark: store.getAllBookmarks()[0] };

await vscode.commands.executeCommand('workspace-file-bookmarks.copyBookmarkPath', item);
assert.equal(await vscode.env.clipboard.readText(), document.uri.fsPath);

await vscode.commands.executeCommand('workspace-file-bookmarks.copyBookmarkRelativePath', item);
assert.equal(await vscode.env.clipboard.readText(), 'src/sample-a.ts');
});

it("reveals a bookmark in VS Code's Explorer without error", async () => {
const { store } = await getApi();
const document = await vscode.workspace.openTextDocument(fixtureUri('src/sample-a.ts'));
await vscode.window.showTextDocument(document);
await vscode.commands.executeCommand('workspace-file-bookmarks.addBookmark');
const item = { bookmark: store.getAllBookmarks()[0] };

await vscode.commands.executeCommand('workspace-file-bookmarks.revealBookmarkInExplorer', item);
});
});
6 changes: 6 additions & 0 deletions test/vscode-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,9 @@ export const commands = {
registerCommand: vi.fn(() => ({ dispose: () => {} })),
executeCommand: vi.fn(),
};

export const env = {
clipboard: {
writeText: vi.fn(() => Promise.resolve()),
},
};
Loading