Skip to content

Commit

Permalink
Added commands to open the links directly in the browser.
Browse files Browse the repository at this point in the history
  • Loading branch information
reduckted committed Jan 28, 2021
1 parent b614a65 commit 0d256ff
Show file tree
Hide file tree
Showing 16 changed files with 525 additions and 97 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@typescript-eslint/no-confusing-non-null-assertion": "error",
"@typescript-eslint/prefer-readonly": "warn",
"@typescript-eslint/promise-function-async": "warn",
"@typescript-eslint/restrict-template-expressions": "off",
"import/no-deprecated": "error",
"import/no-duplicates": "error",
"import/newline-after-import": "warn",
Expand Down
51 changes: 43 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,27 +92,37 @@
"commands": [
{
"command": "gitweblinks.copyFile",
"title": "Copy Web Link to File",
"title": "Copy Link to File",
"category": "Git Web Links"
},
{
"command": "gitweblinks.copySelection",
"title": "Copy Web Link to Selection",
"title": "Copy Link to Selection",
"category": "Git Web Links"
},
{
"command": "gitweblinks.copySelectionToDefaultBranch",
"title": "Copy Web Link to Selection (on default branch)",
"title": "Copy Link to Selection (on default branch)",
"category": "Git Web Links"
},
{
"command": "gitweblinks.copySelectionToBranch",
"title": "Copy Web Link to Selection (on current branch)",
"title": "Copy Link to Selection (on current branch)",
"category": "Git Web Links"
},
{
"command": "gitweblinks.copySelectionToCommit",
"title": "Copy Web Link to Selection (at current commit)",
"title": "Copy Link to Selection (at current commit)",
"category": "Git Web Links"
},
{
"command": "gitweblinks.openFile",
"title": "Open Link to File",
"category": "Git Web Links"
},
{
"command": "gitweblinks.openSelection",
"title": "Open Link to Selection",
"category": "Git Web Links"
}
],
Expand All @@ -121,21 +131,36 @@
{
"command": "gitweblinks.copySelection",
"group": "gitweblinks@1",
"when": "gitweblinks:canCopy"
"when": "gitweblinks:hasRepositories && gitweblinks:canCopy"
},
{
"command": "gitweblinks.openSelection",
"group": "gitweblinks@2",
"when": "gitweblinks:hasRepositories && gitweblinks:canOpen"
}
],
"editor/title/context": [
{
"command": "gitweblinks.copyFile",
"group": "gitweblinks@1",
"when": "gitweblinks:canCopy"
"when": "gitweblinks:hasRepositories && gitweblinks:canCopy"
},
{
"command": "gitweblinks.openFile",
"group": "gitweblinks@2",
"when": "gitweblinks:hasRepositories && gitweblinks:canOpen"
}
],
"explorer/context": [
{
"command": "gitweblinks.copyFile",
"group": "gitweblinks@1",
"when": "gitweblinks:canCopy"
"when": "gitweblinks:hasRepositories && gitweblinks:canCopy"
},
{
"command": "gitweblinks.openFile",
"group": "gitweblinks@2",
"when": "gitweblinks:hasRepositories && gitweblinks:canOpen"
}
]
},
Expand Down Expand Up @@ -240,6 +265,16 @@
],
"additionalProperties": false
}
},
"gitweblinks.showCopy": {
"type": "boolean",
"description": "Controls the visibility of the 'Copy Link' menu item.",
"default": true
},
"gitweblinks.showOpen": {
"type": "boolean",
"description": "Controls the visibility of the 'Open Link' menu item.",
"default": false
}
}
}
Expand Down
82 changes: 64 additions & 18 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ export class Command {
* @param handlerSelector The link handler selector to use for selecing the handler for a file.
* @param linkType The type of links to generate. A value of `undefined` means the settings will be used to determine the type.
* @param includeSelection Indicates whether the current selected range should be included in the links.
* @param action The action that the command should perform with the link.
*/
constructor(
private readonly repositoryFinder: RepositoryFinder,
private readonly handlerSelector: LinkHandlerSelector,
private readonly linkType: LinkType | undefined,
private readonly includeSelection: boolean
private readonly includeSelection: boolean,
private readonly action: CommandAction
) {}

/**
Expand Down Expand Up @@ -78,17 +80,26 @@ export class Command {
});

log('Web link created: %s', link);
await env.clipboard.writeText(link);

void window
.showInformationMessage<ActionMessageItem>(
STRINGS.command.linkCopied(file.handler.name),
{
title: STRINGS.command.openInBrowser,
action: 'open'
}
)
.then((x) => this.onNotificationItemClick(x, link));

switch (this.action) {
case 'copy':
await env.clipboard.writeText(link);

void window
.showInformationMessage<ActionMessageItem>(
STRINGS.command.linkCopied(file.handler.name),
{
title: STRINGS.command.openInBrowser,
action: 'open'
}
)
.then((x) => this.onNotificationItemClick(x, link));

break;

case 'open':
void env.openExternal(Uri.parse(link));
}
} catch (ex) {
log('Error while generating a link: %o', ex);
void window.showErrorMessage(STRINGS.command.error);
Expand Down Expand Up @@ -169,6 +180,7 @@ export class Command {
if (link) {
void env.openExternal(Uri.parse(link));
}
break;
}
}
}
Expand All @@ -190,14 +202,34 @@ export function registerCommands(
subscriptions.push(
register(COMMANDS.copyFile, repositoryFinder, handlerSelector, {
linkType: undefined,
includeSelection: false
includeSelection: false,
action: 'copy'
})
);

subscriptions.push(
register(COMMANDS.copySelection, repositoryFinder, handlerSelector, {
linkType: undefined,
includeSelection: true
includeSelection: true,
action: 'copy'
})
);

// Add the two commands that appear in the menus to
// open a link to the file and open a link to the selection.
subscriptions.push(
register(COMMANDS.openFile, repositoryFinder, handlerSelector, {
linkType: undefined,
includeSelection: false,
action: 'open'
})
);

subscriptions.push(
register(COMMANDS.openSelection, repositoryFinder, handlerSelector, {
linkType: undefined,
includeSelection: true,
action: 'open'
})
);

Expand All @@ -207,21 +239,24 @@ export function registerCommands(
subscriptions.push(
register(COMMANDS.copySelectionToBranch, repositoryFinder, handlerSelector, {
linkType: 'branch',
includeSelection: true
includeSelection: true,
action: 'copy'
})
);

subscriptions.push(
register(COMMANDS.copySelectionToCommit, repositoryFinder, handlerSelector, {
linkType: 'commit',
includeSelection: true
includeSelection: true,
action: 'copy'
})
);

subscriptions.push(
register(COMMANDS.copySelectionToDefaultBranch, repositoryFinder, handlerSelector, {
linkType: 'defaultBranch',
includeSelection: true
includeSelection: true,
action: 'copy'
})
);
}
Expand All @@ -247,12 +282,18 @@ export function register(
repositoryFinder,
handlerSelector,
options.linkType,
options.includeSelection
options.includeSelection,
options.action
);

return commands.registerCommand(identifier, async (resource) => command.execute(resource));
}

/**
* Indicates whether a command should copy the link or open the link.
*/
type CommandAction = 'copy' | 'open';

/**
* Options for registering a command.
*/
Expand All @@ -268,6 +309,11 @@ interface CommandOptions {
* from the file in the link that is generated.
*/
includeSelection: boolean;

/**
* The action the command should perform.
*/
action: CommandAction;
}

/**
Expand Down
12 changes: 9 additions & 3 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@ export const EXTENSION = {
export const CONFIGURATION = {
section: EXTENSION.id,
linkType: 'linkType',
defaultBranch: 'defaultBranch'
defaultBranch: 'defaultBranch',
showCopy: 'showCopy',
showOpen: 'showOpen'
};

export const CONTEXT = {
canCopy: `${EXTENSION.id}:canCopy`
hasRepositories: `${EXTENSION.id}:hasRepositories`,
canCopy: `${EXTENSION.id}:canCopy`,
canOpen: `${EXTENSION.id}:canOpen`
};

export const COMMANDS = {
copyFile: `${EXTENSION.id}.copyFile`,
copySelection: `${EXTENSION.id}.copySelection`,
copySelectionToDefaultBranch: `${EXTENSION.id}.copySelectionToDefaultBranch`,
copySelectionToBranch: `${EXTENSION.id}.copySelectionToBranch`,
copySelectionToCommit: `${EXTENSION.id}.copySelectionToCommit`
copySelectionToCommit: `${EXTENSION.id}.copySelectionToCommit`,
openFile: `${EXTENSION.id}.openFile`,
openSelection: `${EXTENSION.id}.openSelection`
};
81 changes: 81 additions & 0 deletions src/context-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { commands, Disposable, workspace } from 'vscode';

import { CONFIGURATION, CONTEXT } from './constants';
import { log } from './log';
import { Settings } from './settings';
import { WorkspaceInfo, WorkspaceTracker } from './workspace-tracker';

/**
* Manages the context for commands.
*/
export class ContextManager extends Disposable {
private readonly disposable: Disposable;

/**
* @constructor
* @param workspaceTracker The workspace tracker to observe.
*/
constructor(workspaceTracker: WorkspaceTracker) {
super(() => {
this.disposable.dispose();
});

this.disposable = Disposable.from(
// When the workspaces change, update the context that
// indicates whether any workspaces have a repository.
workspaceTracker.onWorkspacesChanged((workspaces) => {
this.sethasRepositoriesContext(workspaces);
}),
// When the configuration changes, re-apply the menu item visibility.
workspace.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration(CONFIGURATION.section)) {
log('Configuration has changed.');
this.applyMenuItemVisibility();
}
})
);

this.setContext(
CONTEXT.hasRepositories,
workspaceTracker.workspaces.some((x) => x.hasRepositories)
);

// Set the current values.
// this.sethasRepositoriesContext(workspaceTracker.workspaces);
this.applyMenuItemVisibility();
}

/**
* Sets the "hasRepositories" context value.
*
* @param workspaces The current workspaces.
*/
private sethasRepositoriesContext(workspaces: readonly WorkspaceInfo[]): void {
this.setContext(
CONTEXT.hasRepositories,
workspaces.some((x) => x.hasRepositories)
);
}

/**
* Sets the context that is used to control the visibility of menu items.
*/
private applyMenuItemVisibility(): void {
let settings: Settings;

settings = new Settings();

void commands.executeCommand('setContext', CONTEXT.canCopy, settings.getShowCopy());
void commands.executeCommand('setContext', CONTEXT.canOpen, settings.getShowOpen());
}

/**
* Sets the value of the specified context.
*
* @param name The name of the context.
* @param value The value of the context.
*/
private setContext(name: string, value: unknown): void {
void commands.executeCommand('setContext', name, value);
}
}
Loading

0 comments on commit 0d256ff

Please sign in to comment.