Browse Source

Adds new context menu for editor gutter

main
Eric Amodio 1 year ago
parent
commit
a4a30d94f5
11 changed files with 301 additions and 81 deletions
  1. +3
    -0
      CHANGELOG.md
  2. +123
    -3
      package.json
  3. +25
    -0
      src/commands/base.ts
  4. +9
    -0
      src/commands/diffLineWithPrevious.ts
  5. +9
    -0
      src/commands/diffLineWithWorking.ts
  6. +8
    -3
      src/commands/openCommitOnRemote.ts
  7. +21
    -10
      src/commands/openFileOnRemote.ts
  8. +35
    -65
      src/commands/showQuickCommitFile.ts
  9. +7
    -0
      src/config.ts
  10. +1
    -0
      src/constants.ts
  11. +60
    -0
      src/webviews/apps/settings/partials/menus.html

+ 3
- 0
CHANGELOG.md View File

@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Adds new _Commit Graph_ features and improvements
- Unlocks columns in the _Commit Graph_ that were previously locked, including the Branch/Tag column, the Graph column, and the Commit Message column, allowing all columns to be rearranged
- Column headers now show icons instead of text when their width is sufficiently small
- Adds _Share_, _Open Changes_, and _Open on Remote (Web)_ submenus to the new editor line numbers (gutter) context menu
- Adds an _Open Line Commit Details_ command to the _Open Changes_ submenus on editor context menus
### Changed
@ -26,6 +28,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Consolidates existing file history commands into a _File History_ submenu
- Consolidates existing "Open on Remote" commands into _Open on Remote (Web)_ submenu
- Renames the _Commit Changes_ submenu to _Open Changes_
- Renames _Show Commit_ command to _Quick Show Commit_ and _Show Line Commit_ command to _Quick Show Line Commit_ for better clarity as it opens a quick pick menu
- Renames _Delete Stash..._ command to _Drop Stash..._ in the _Stashes_ view
- Removes the commit icon when hiding avatars in the _Commits_ view to allow for a more compact layout
- Limits Git CodeLens on docker files — closes [#2153](https://github.com/gitkraken/vscode-gitlens/issues/2153)

+ 123
- 3
package.json View File

@ -2827,6 +2827,29 @@
}
]
},
"editorGutter": {
"anyOf": [
{
"enum": [
false
]
},
{
"type": "object",
"properties": {
"compare": {
"type": "boolean"
},
"remote": {
"type": "boolean"
},
"share": {
"type": "boolean"
}
}
}
]
},
"editorTab": {
"anyOf": [
{
@ -3058,6 +3081,11 @@
"blame": true,
"compare": true
},
"editorGutter": {
"compare": true,
"remote": true,
"share": true
},
"editorTab": {
"clipboard": true,
"compare": true,
@ -4840,6 +4868,12 @@
"icon": "$(eye)"
},
{
"command": "gitlens.showLineCommitInView",
"title": "Open Line Commit Details",
"category": "GitLens",
"icon": "$(eye)"
},
{
"command": "gitlens.showInDetailsView",
"title": "Open Details",
"category": "GitLens",
@ -4867,12 +4901,12 @@
},
{
"command": "gitlens.showQuickCommitDetails",
"title": "Show Commit",
"title": "Quick Show Commit",
"category": "GitLens"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"title": "Show Line Commit",
"title": "Quick Show Line Commit",
"category": "GitLens"
},
{
@ -7737,6 +7771,10 @@
"when": "false"
},
{
"command": "gitlens.showLineCommitInView",
"when": "gitlens:activeFileStatus =~ /blameable/"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"when": "gitlens:activeFileStatus =~ /blameable/"
},
@ -9328,6 +9366,23 @@
"group": "3_gitlens@2"
}
],
"editor/lineNumber/context": [
{
"submenu": "gitlens/editor/lineNumber/context/share",
"when": "gitlens:hasRemotes && config.gitlens.menus.editorGutter.share && resourceScheme != output",
"group": "2_gitlens@2"
},
{
"submenu": "gitlens/editor/lineNumber/context/changes",
"when": "config.gitlens.menus.editorGutter.compare && resourceScheme != output",
"group": "3_gitlens@1"
},
{
"submenu": "gitlens/editor/lineNumber/context/openOn",
"when": "gitlens:hasRemotes && config.gitlens.menus.editorGutter.remote && resourceScheme != output",
"group": "3_gitlens@2"
}
],
"editor/title": [
{
"command": "gitlens.diffWithWorking",
@ -12428,10 +12483,14 @@
"group": "2_gitlens@4"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"command": "gitlens.showLineCommitInView",
"group": "3_gitlens@1"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"group": "3_gitlens@2"
},
{
"command": "gitlens.showQuickRevisionDetails",
"when": "gitlens:activeFileStatus =~ /revision/ && !isInDiffEditor",
"group": "3_gitlens@2"
@ -12509,6 +12568,55 @@
"alt": "gitlens.copyRemoteFileUrlFrom"
}
],
"gitlens/editor/lineNumber/context/changes": [
{
"command": "gitlens.diffLineWithPrevious",
"group": "1_gitlens@1"
},
{
"command": "gitlens.diffLineWithWorking",
"group": "1_gitlens@2"
},
{
"command": "gitlens.showLineCommitInView",
"group": "3_gitlens@1"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"group": "3_gitlens@2"
}
],
"gitlens/editor/lineNumber/context/openOn": [
{
"command": "gitlens.openFileOnRemote",
"group": "1_gitlens@2",
"alt": "gitlens.copyRemoteFileUrlToClipboard"
},
{
"command": "gitlens.openFileOnRemoteFrom",
"group": "1_gitlens@3",
"alt": "gitlens.copyRemoteFileUrlFrom"
},
{
"command": "gitlens.openCommitOnRemote",
"group": "1_gitlens_commit@1",
"alt": "gitlens.copyRemoteCommitUrl"
}
],
"gitlens/editor/lineNumber/context/share": [
{
"command": "gitlens.copyRemoteFileUrlToClipboard",
"group": "1_gitlens@2"
},
{
"command": "gitlens.copyRemoteFileUrlFrom",
"group": "1_gitlens@3"
},
{
"command": "gitlens.copyRemoteCommitUrl",
"group": "1_gitlens_commit@1"
}
],
"gitlens/explorer/changes": [
{
"command": "gitlens.diffWithPrevious",
@ -12830,6 +12938,18 @@
"label": "Open on Remote (Web)"
},
{
"id": "gitlens/editor/lineNumber/context/changes",
"label": "Open Changes"
},
{
"id": "gitlens/editor/lineNumber/context/openOn",
"label": "Open on Remote (Web)"
},
{
"id": "gitlens/editor/lineNumber/context/share",
"label": "Share"
},
{
"id": "gitlens/explorer/changes",
"label": "Open Changes"
},

+ 25
- 0
src/commands/base.ts View File

@ -40,6 +40,12 @@ export interface CommandBaseContext {
uri?: Uri;
}
export interface CommandEditorLineContext extends CommandBaseContext {
readonly type: 'editorLine';
readonly line: number;
readonly uri: Uri;
}
export interface CommandGitTimelineItemContext extends CommandBaseContext {
readonly type: 'timeline-item:git';
readonly item: GitTimelineItem;
@ -89,6 +95,10 @@ export interface CommandViewNodesContext extends CommandBaseContext {
readonly nodes: ViewNode[];
}
export function isCommandContextEditorLine(context: CommandContext): context is CommandEditorLineContext {
return context.type === 'editorLine';
}
export function isCommandContextGitTimelineItem(context: CommandContext): context is CommandGitTimelineItemContext {
return context.type === 'timeline-item:git';
}
@ -188,6 +198,7 @@ export function isCommandContextViewNodeHasTag(
}
export type CommandContext =
| CommandEditorLineContext
| CommandGitTimelineItemContext
| CommandScmContext
| CommandScmGroupsContext
@ -333,6 +344,20 @@ export function parseCommandContext(
args = args.slice(1);
} else if (editor == null) {
if (firstArg != null && typeof firstArg === 'object' && 'lineNumber' in firstArg && 'uri' in firstArg) {
const [, ...rest] = args;
return [
{
command: command,
type: 'editorLine',
editor: undefined,
line: firstArg.lineNumber - 1, // convert to zero-based
uri: firstArg.uri,
},
rest,
];
}
// If we are expecting an editor and we have no uri, then pass the active editor
editor = window.activeTextEditor;
}

+ 9
- 0
src/commands/diffLineWithPrevious.ts View File

@ -6,6 +6,7 @@ import type { GitCommit } from '../git/models/commit';
import { showCommitHasNoPreviousCommitWarningMessage, showGenericErrorMessage } from '../messages';
import { command, executeCommand } from '../system/command';
import { Logger } from '../system/logger';
import type { CommandContext } from './base';
import { ActiveEditorCommand, getCommandUri } from './base';
import type { DiffWithCommandArgs } from './diffWith';
@ -22,6 +23,14 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
super(Commands.DiffLineWithPrevious);
}
protected override preExecute(context: CommandContext, args?: DiffLineWithPreviousCommandArgs): Promise<any> {
if (context.type === 'editorLine') {
args = { ...args, line: context.line };
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args?: DiffLineWithPreviousCommandArgs): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri == null) return;

+ 9
- 0
src/commands/diffLineWithWorking.ts View File

@ -8,6 +8,7 @@ import { uncommittedStaged } from '../git/models/constants';
import { showFileNotUnderSourceControlWarningMessage, showGenericErrorMessage } from '../messages';
import { command, executeCommand } from '../system/command';
import { Logger } from '../system/logger';
import type { CommandContext } from './base';
import { ActiveEditorCommand, getCommandUri } from './base';
import type { DiffWithCommandArgs } from './diffWith';
@ -24,6 +25,14 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
super(Commands.DiffLineWithWorking);
}
protected override preExecute(context: CommandContext, args?: DiffLineWithWorkingCommandArgs): Promise<any> {
if (context.type === 'editorLine') {
args = { ...args, line: context.line };
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args?: DiffLineWithWorkingCommandArgs): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri == null) return;

+ 8
- 3
src/commands/openCommitOnRemote.ts View File

@ -19,6 +19,7 @@ import type { OpenOnRemoteCommandArgs } from './openOnRemote';
export interface OpenCommitOnRemoteCommandArgs {
clipboard?: boolean;
line?: number;
sha?: string;
}
@ -38,6 +39,10 @@ export class OpenCommitOnRemoteCommand extends ActiveEditorCommand {
protected override preExecute(context: CommandContext, args?: OpenCommitOnRemoteCommandArgs) {
let uri = context.uri;
if (context.type === 'editorLine') {
args = { ...args, line: context.line };
}
if (isCommandContextViewNodeHasCommit(context)) {
if (context.node.commit.isUncommitted) return Promise.resolve(undefined);
@ -79,10 +84,10 @@ export class OpenCommitOnRemoteCommand extends ActiveEditorCommand {
try {
if (args.sha == null) {
const blameline = editor == null ? 0 : editor.selection.active.line;
if (blameline < 0) return;
const blameLine = args.line ?? editor?.selection.active.line;
if (blameLine == null) return;
const blame = await this.container.git.getBlameForLine(gitUri, blameline, editor?.document);
const blame = await this.container.git.getBlameForLine(gitUri, blameLine, editor?.document);
if (blame == null) {
void showFileNotUnderSourceControlWarningMessage('Unable to open commit on remote provider');

+ 21
- 10
src/commands/openFileOnRemote.ts View File

@ -26,6 +26,7 @@ import type { OpenOnRemoteCommandArgs } from './openOnRemote';
export interface OpenFileOnRemoteCommandArgs {
branchOrTag?: string;
clipboard?: boolean;
line?: number;
range?: boolean;
sha?: string;
pickBranchOrTag?: boolean;
@ -47,6 +48,10 @@ export class OpenFileOnRemoteCommand extends ActiveEditorCommand {
protected override async preExecute(context: CommandContext, args?: OpenFileOnRemoteCommandArgs) {
let uri = context.uri;
if (context.type === 'editorLine') {
args = { ...args, line: context.line, range: true };
}
if (context.command === Commands.CopyRemoteFileUrlWithoutRange) {
args = { ...args, range: false };
}
@ -100,7 +105,7 @@ export class OpenFileOnRemoteCommand extends ActiveEditorCommand {
}
if (context.command === Commands.OpenFileOnRemoteFrom || context.command === Commands.CopyRemoteFileUrlFrom) {
args = { ...args, pickBranchOrTag: true, range: false };
args = { ...args, pickBranchOrTag: true, range: false }; // Override range since it can be wrong at a different commit
}
return this.execute(context.editor, uri, args);
@ -117,15 +122,21 @@ export class OpenFileOnRemoteCommand extends ActiveEditorCommand {
try {
let remotes = await this.container.git.getRemotesWithProviders(gitUri.repoPath);
const range =
args.range && editor != null && UriComparer.equals(editor.document.uri, uri)
? new Range(
editor.selection.start.with({ line: editor.selection.start.line + 1 }),
editor.selection.end.with({
line: editor.selection.end.line + (editor.selection.end.character === 0 ? 0 : 1),
}),
)
: undefined;
let range: Range | undefined;
if (args.range) {
if (editor != null && UriComparer.equals(editor.document.uri, uri)) {
range = new Range(
editor.selection.start.with({ line: editor.selection.start.line + 1 }),
editor.selection.end.with({
line: editor.selection.end.line + (editor.selection.end.character === 0 ? 0 : 1),
}),
);
} else if (args.line != null) {
range = new Range(args.line + 1, 0, args.line + 1, 0);
}
}
let sha = args.sha ?? gitUri.sha;
if (args.branchOrTag == null && sha != null && !isSha(sha) && remotes.length !== 0) {

+ 35
- 65
src/commands/showQuickCommitFile.ts View File

@ -13,16 +13,20 @@ import {
showGenericErrorMessage,
showLineUncommittedWarningMessage,
} from '../messages';
import { command } from '../system/command';
import { command, executeCommand } from '../system/command';
import { Logger } from '../system/logger';
import type { CommandContext } from './base';
import { ActiveEditorCachedCommand, getCommandUri, isCommandContextViewNodeHasCommit } from './base';
import type { ShowCommitsInViewCommandArgs } from './showCommitsInView';
export interface ShowQuickCommitFileCommandArgs {
sha?: string;
commit?: GitCommit | GitStashCommit;
line?: number;
fileLog?: GitLog;
revisionUri?: string;
sha?: string;
inView?: boolean;
}
@command()
@ -37,20 +41,27 @@ export class ShowQuickCommitFileCommand extends ActiveEditorCachedCommand {
Commands.ShowQuickCommitRevision,
Commands.ShowQuickCommitRevisionInDiffLeft,
Commands.ShowQuickCommitRevisionInDiffRight,
Commands.ShowLineCommitInView,
]);
}
protected override async preExecute(context: CommandContext, args?: ShowQuickCommitFileCommandArgs) {
if (context.editor != null && context.command.startsWith(Commands.ShowQuickCommitRevision)) {
args = { ...args };
if (context.type === 'editorLine') {
args = { ...args, line: context.line };
}
if (context.command === Commands.ShowLineCommitInView) {
args = { ...args, inView: true };
}
if (context.editor != null && context.command.startsWith(Commands.ShowQuickCommitRevision)) {
const gitUri = await GitUri.fromUri(context.editor.document.uri);
args.sha = gitUri.sha;
args = { ...args, sha: gitUri.sha };
}
if (context.type === 'viewItem') {
args = { ...args };
args.sha = context.node.uri.sha;
args = { ...args, sha: context.node.uri.sha };
if (isCommandContextViewNodeHasCommit(context)) {
args.commit = context.node.commit;
@ -75,10 +86,8 @@ export class ShowQuickCommitFileCommand extends ActiveEditorCachedCommand {
}
if (args.sha == null) {
if (editor == null) return;
const blameLine = editor.selection.active.line;
if (blameLine < 0) return;
const blameLine = args.line ?? editor?.selection.active.line;
if (blameLine == null) return;
try {
const blame = await this.container.git.getBlameForLine(gitUri, blameLine);
@ -142,60 +151,21 @@ export class ShowQuickCommitFileCommand extends ActiveEditorCachedCommand {
}
}
// const shortSha = shorten(args.sha);
// if (args.commit instanceof GitBlameCommit) {
// args.commit = (await this.container.git.getCommit(args.commit.repoPath, args.commit.ref))!;
// }
await executeGitCommand({
command: 'show',
state: {
repo: args.commit.repoPath,
reference: args.commit,
fileName: path,
},
});
// if (args.goBackCommand === undefined) {
// const commandArgs: ShowQuickCommitCommandArgs = {
// commit: args.commit,
// sha: args.sha,
// };
// // Create a command to get back to the commit details
// args.goBackCommand = new CommandQuickPickItem(
// {
// label: `go back ${GlyphChars.ArrowBack}`,
// description: `to details of ${GlyphChars.Space}$(git-commit) ${shortSha}`,
// },
// Commands.ShowQuickCommit,
// [args.commit.toGitUri(), commandArgs],
// );
// }
// // Create a command to get back to where we are right now
// const currentCommand = new CommandQuickPickItem(
// {
// label: `go back ${GlyphChars.ArrowBack}`,
// description: `to details of ${args.commit.getFormattedPath()} from ${
// GlyphChars.Space
// }$(git-commit) ${shortSha}`,
// },
// Commands.ShowQuickCommitFile,
// [args.commit.toGitUri(), args],
// );
// const pick = await CommitFileQuickPick.show(args.commit as GitCommit, uri, {
// goBackCommand: args.goBackCommand,
// currentCommand: currentCommand,
// fileLog: args.fileLog,
// });
// if (pick === undefined) return undefined;
// if (pick instanceof CommandQuickPickItem) return pick.execute();
// return undefined;
if (args.inView) {
await executeCommand<ShowCommitsInViewCommandArgs>(Commands.ShowCommitsInView, {
refs: [args.commit.sha],
repoPath: args.commit.repoPath,
});
} else {
await executeGitCommand({
command: 'show',
state: {
repo: args.commit.repoPath,
reference: args.commit,
fileName: path,
},
});
}
} catch (ex) {
Logger.error(ex, 'ShowQuickCommitFileDetailsCommand');
void showGenericErrorMessage('Unable to show commit file details');

+ 7
- 0
src/config.ts View File

@ -482,6 +482,13 @@ export interface MenuConfig {
blame: boolean;
compare: boolean;
};
editorGutter:
| false
| {
compare: boolean;
remote: boolean;
share: boolean;
};
editorTab:
| false
| {

+ 1
- 0
src/constants.ts View File

@ -242,6 +242,7 @@ export const enum Commands {
ShowInCommitGraph = 'gitlens.showInCommitGraph',
ShowInDetailsView = 'gitlens.showInDetailsView',
ShowLastQuickPick = 'gitlens.showLastQuickPick',
ShowLineCommitInView = 'gitlens.showLineCommitInView',
ShowLineHistoryView = 'gitlens.showLineHistoryView',
ShowQuickBranchHistory = 'gitlens.showQuickBranchHistory',
ShowQuickCommit = 'gitlens.showQuickCommitDetails',

+ 60
- 0
src/webviews/apps/settings/partials/menus.html View File

@ -103,6 +103,66 @@
<div class="setting__input">
<div class="setting__expander"></div>
<input
id="menus.editorGutter"
name="menus.editorGutter"
type="checkbox"
value="undefined"
data-setting
data-setting-type="object"
disabled
/>
<label for="menus.editorGutter">Add to the editor's line number (gutter) context menu</label>
</div>
</div>
<div class="settings ml-4">
<div class="setting" data-enablement="menus.editorGutter">
<div class="setting__input">
<input
id="menus.editorGutter.share"
name="menus.editorGutter.share"
type="checkbox"
data-setting
data-setting-type="object"
disabled
/>
<label for="menus.editorGutter.share">Add a <i>Share</i> submenu</label>
</div>
</div>
<div class="setting" data-enablement="menus.editorGutter">
<div class="setting__input">
<input
id="menus.editorGutter.compare"
name="menus.editorGutter.compare"
type="checkbox"
data-setting
data-setting-type="object"
disabled
/>
<label for="menus.editorGutter.compare">Add an <i>Open Changes</i> submenu</label>
</div>
</div>
<div class="setting" data-enablement="menus.editorGutter">
<div class="setting__input">
<input
id="menus.editorGutter.remote"
name="menus.editorGutter.remote"
type="checkbox"
data-setting
data-setting-type="object"
disabled
/>
<label for="menus.editorGutter.remote">Add an <i>Open on Remote (Web)</i> submenu</label>
</div>
</div>
</div>
<div class="setting setting--expandable" data-enablement="menus">
<div class="setting__input">
<div class="setting__expander"></div>
<input
id="menus.editorTab"
name="menus.editorTab"
type="checkbox"

Loading…
Cancel
Save