Browse Source

Switches to eslint from tslint

main
Eric Amodio 5 years ago
parent
commit
7c6b659604
169 changed files with 4032 additions and 2460 deletions
  1. +124
    -0
      .eslintrc.json
  2. +2
    -2
      .vscode/extensions.json
  3. +4
    -1
      .vscode/settings.json
  4. +1
    -1
      .vscode/tasks.json
  5. +1
    -1
      CHANGELOG.md
  6. +1
    -1
      generateEmojiShortcodeMap.js
  7. +1484
    -159
      package-lock.json
  8. +14
    -9
      package.json
  9. +547
    -547
      src/@types/applicationinsights/index.d.ts
  10. +81
    -7
      src/@types/git.d.ts
  11. +5
    -5
      src/annotations/annotationProvider.ts
  12. +38
    -30
      src/annotations/annotations.ts
  13. +13
    -8
      src/annotations/blameAnnotationProvider.ts
  14. +7
    -8
      src/annotations/fileAnnotationController.ts
  15. +16
    -15
      src/annotations/gutterBlameAnnotationProvider.ts
  16. +2
    -2
      src/annotations/heatmapBlameAnnotationProvider.ts
  17. +17
    -10
      src/annotations/lineAnnotationController.ts
  18. +8
    -6
      src/annotations/recentChangesAnnotationProvider.ts
  19. +1
    -1
      src/codelens/codeLensController.ts
  20. +40
    -49
      src/codelens/codeLensProvider.ts
  21. +12
    -10
      src/commands/annotations.ts
  22. +4
    -5
      src/commands/closeUnchangedFiles.ts
  23. +5
    -6
      src/commands/common.ts
  24. +4
    -4
      src/commands/copyMessageToClipboard.ts
  25. +1
    -4
      src/commands/copyRemoteFileUrlToClipboard.ts
  26. +4
    -4
      src/commands/copyShaToClipboard.ts
  27. +3
    -3
      src/commands/diffBranchWithBranch.ts
  28. +3
    -3
      src/commands/diffDirectory.ts
  29. +3
    -3
      src/commands/diffWith.ts
  30. +2
    -2
      src/commands/diffWithBranch.ts
  31. +4
    -4
      src/commands/diffWithNext.ts
  32. +5
    -4
      src/commands/diffWithPrevious.ts
  33. +19
    -17
      src/commands/diffWithRevision.ts
  34. +2
    -2
      src/commands/externalDiff.ts
  35. +8
    -7
      src/commands/openBranchInRemote.ts
  36. +8
    -7
      src/commands/openBranchesInRemote.ts
  37. +3
    -3
      src/commands/openChangedFiles.ts
  38. +6
    -5
      src/commands/openCommitInRemote.ts
  39. +21
    -15
      src/commands/openFileInRemote.ts
  40. +20
    -15
      src/commands/openFileRevision.ts
  41. +1
    -2
      src/commands/openInRemote.ts
  42. +8
    -7
      src/commands/openRepoInRemote.ts
  43. +3
    -3
      src/commands/repositories.ts
  44. +13
    -10
      src/commands/searchCommits.ts
  45. +2
    -2
      src/commands/showLastQuickPick.ts
  46. +4
    -3
      src/commands/showQuickBranchHistory.ts
  47. +6
    -5
      src/commands/showQuickCommitDetails.ts
  48. +12
    -19
      src/commands/showQuickCommitFileDetails.ts
  49. +3
    -2
      src/commands/showQuickCurrentBranchHistory.ts
  50. +18
    -16
      src/commands/showQuickFileHistory.ts
  51. +1
    -1
      src/commands/showQuickRepoStatus.ts
  52. +8
    -9
      src/commands/showQuickStashList.ts
  53. +2
    -2
      src/commands/showView.ts
  54. +13
    -17
      src/commands/stashApply.ts
  55. +4
    -4
      src/commands/stashDelete.ts
  56. +5
    -5
      src/commands/stashSave.ts
  57. +1
    -1
      src/commands/supportGitLens.ts
  58. +2
    -2
      src/commands/toggleLineBlame.ts
  59. +9
    -8
      src/configuration.ts
  60. +10
    -9
      src/container.ts
  61. +0
    -0
      src/emojis.json
  62. +5
    -3
      src/extension.ts
  63. +38
    -36
      src/git/formatters/commitFormatter.ts
  64. +20
    -15
      src/git/formatters/formatter.ts
  65. +20
    -20
      src/git/formatters/statusFormatter.ts
  66. +10
    -9
      src/git/fsProvider.ts
  67. +36
    -30
      src/git/git.ts
  68. +96
    -77
      src/git/gitService.ts
  69. +21
    -15
      src/git/gitUri.ts
  70. +6
    -6
      src/git/locator.ts
  71. +1
    -0
      src/git/models/branch.ts
  72. +1
    -1
      src/git/models/commit.ts
  73. +2
    -2
      src/git/models/log.ts
  74. +12
    -13
      src/git/models/repository.ts
  75. +4
    -0
      src/git/models/stashCommit.ts
  76. +1
    -1
      src/git/models/status.ts
  77. +18
    -10
      src/git/parsers/blameParser.ts
  78. +6
    -6
      src/git/parsers/branchParser.ts
  79. +22
    -26
      src/git/parsers/diffParser.ts
  80. +19
    -10
      src/git/parsers/logParser.ts
  81. +18
    -10
      src/git/parsers/remoteParser.ts
  82. +8
    -5
      src/git/parsers/stashParser.ts
  83. +20
    -9
      src/git/parsers/statusParser.ts
  84. +5
    -5
      src/git/parsers/tagParser.ts
  85. +5
    -4
      src/git/parsers/treeParser.ts
  86. +4
    -1
      src/git/remotes/azure-devops.ts
  87. +4
    -2
      src/git/remotes/bitbucket-server.ts
  88. +4
    -1
      src/git/remotes/bitbucket.ts
  89. +4
    -1
      src/git/remotes/custom.ts
  90. +4
    -1
      src/git/remotes/github.ts
  91. +4
    -1
      src/git/remotes/gitlab.ts
  92. +5
    -5
      src/git/remotes/provider.ts
  93. +22
    -16
      src/git/shell.ts
  94. +12
    -7
      src/hovers/lineHoverController.ts
  95. +5
    -9
      src/keyboard.ts
  96. +25
    -21
      src/logger.ts
  97. +8
    -8
      src/messages.ts
  98. +31
    -39
      src/quickpicks/branchHistoryQuickPick.ts
  99. +7
    -18
      src/quickpicks/branchesAndTagsQuickPick.ts
  100. +68
    -81
      src/quickpicks/commitFileQuickPick.ts

+ 124
- 0
.eslintrc.json View File

@ -0,0 +1,124 @@
{
"env": {
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"prettier",
"prettier/@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true,
"jsx": true
}
},
"plugins": ["import", "prettiest", "@typescript-eslint"],
"rules": {
"arrow-parens": ["off"],
"brace-style": ["off", "stroustrup"],
"consistent-return": "error",
"eol-last": "error",
"linebreak-style": ["error", "unix"],
"new-parens": "error",
"no-console": "off",
"no-constant-condition": ["warn", { "checkLoops": false }],
"no-caller": "error",
"no-dupe-class-members": "off",
"no-duplicate-imports": "error",
"no-else-return": "warn",
"no-empty": ["warn", { "allowEmptyCatch": true }],
"no-empty-function": ["warn", { "allow": ["constructors"] }],
"no-eval": "error",
"no-ex-assign": "warn",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-floating-decimal": "error",
"no-implicit-coercion": "error",
"no-implied-eval": "error",
// Turn off until https://github.com/typescript-eslint/typescript-eslint/issues/239 is fixed
"no-inner-declarations": "off",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-multi-spaces": "error",
"no-return-assign": "error",
"no-return-await": "warn",
"no-self-compare": "error",
"no-sequences": "error",
"no-template-curly-in-string": "warn",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "warn",
"no-unneeded-ternary": "error",
"no-unused-expressions": ["warn", { "allowShortCircuit": true }],
"no-use-before-define": "off",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-with": "error",
"object-shorthand": ["error", "never"],
"one-var": ["error", "never"],
"prefer-arrow-callback": "error",
"prefer-const": "error",
"prefer-numeric-literals": "error",
"prefer-object-spread": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"quotes": ["error", "single", { "avoidEscape": true }],
"require-atomic-updates": "error",
"require-await": "error",
"semi": ["error", "always"],
"semi-style": ["error", "last"],
"sort-imports": [
"error",
{
"ignoreCase": true,
"ignoreDeclarationSort": true,
"ignoreMemberSort": false,
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
}
],
"yoda": "error",
"import/export": "off",
"import/extensions": ["error", "never"],
"import/named": "off",
"import/namespace": "off",
"import/newline-after-import": "warn",
"import/no-cycle": "error",
"import/no-dynamic-require": "error",
"import/no-default-export": "error",
"import/no-duplicates": "error",
"import/no-self-import": "error",
"import/no-unresolved": ["warn", { "ignore": ["vscode"] }],
"import/order": [
"warn",
{
"groups": ["builtin", "external", "internal", ["index", "sibling", "parent"]],
"newlines-between": "never"
}
],
"prettiest/no-block-after-closing": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-parameter-properties": "off",
"@typescript-eslint/no-unused-vars": ["warn", { "args": "none" }],
"@typescript-eslint/no-use-before-define": "off"
}
}

+ 2
- 2
.vscode/extensions.json View File

@ -2,10 +2,10 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint",
"eamodio.tsl-problem-matcher",
"esbenp.prettier-vscode",
"msjsdiag.debugger-for-chrome",
"ms-vscode.typescript-javascript-grammar",
"ms-vscode.vscode-typescript-tslint-plugin"
"ms-vscode.typescript-javascript-grammar"
]
}

+ 4
- 1
.vscode/settings.json View File

@ -1,5 +1,8 @@
{
"editor.insertSpaces": true,
"files.associations": {
".eslintrc.json": "jsonc"
},
"files.trimTrailingWhitespace": true,
"postcssSorting.config": {
"order": ["custom-properties", "dollar-variables", "declarations", "at-rules", "rules"],
@ -7,7 +10,7 @@
"unspecified-properties-position": "bottom"
},
"prettier.requireConfig": true,
"prettier.tslintIntegration": true,
"prettier.eslintIntegration": true,
"search.exclude": {
"**/dist": true
}

+ 1
- 1
.vscode/tasks.json View File

@ -26,7 +26,7 @@
"type": "npm",
"script": "lint",
"group": "build",
"problemMatcher": ["$tslint5"]
"problemMatcher": ["$eslint-stylish"]
},
{
"type": "npm",

+ 1
- 1
CHANGELOG.md View File

@ -21,7 +21,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Adds a `mailto:` link to the author on the _commit details_ hover — closes [#642](https://github.com/eamodio/vscode-gitlens/issues/642)
- Adds support for customizing the layout of the _commit details_ hover
- Adds a `gitlens.hovers.detailsMarkdownFormat` setting to specify the format (in markdown) of the _commit details_ hover
- Adds a `gitlens.hovers.detailsMarkdownFormat` setting to specify the format (in markdown) of the _commit details_ hover
- Adds the author's e-mail to the tooltip of commits in the views — closes [#642](https://github.com/eamodio/vscode-gitlens/issues/642)
- Adds a new author e-mail format token (`${email}`) — closes [#642](https://github.com/eamodio/vscode-gitlens/issues/642)
- Supported in the following settings: `gitlens.blame.format`, `gitlens.currentLine.format`, `gitlens.hovers.detailsMarkdownFormat`, `gitlens.views.commitFormat`, `gitlens.views.commitDescriptionFormat`, `gitlens.views.stashFormat`, `gitlens.views.stashDescriptionFormat`, and `gitlens.statusBar.format`

emoji/shortcodeToEmoji.js → generateEmojiShortcodeMap.js View File

@ -50,7 +50,7 @@ async function generate() {
return m;
}, Object.create(null));
fs.writeFileSync(path.join(process.cwd(), 'emojis.json'), JSON.stringify(map), 'utf8');
fs.writeFileSync(path.join(process.cwd(), 'src/emojis.json'), JSON.stringify(map), 'utf8');
}
function download(url, destination) {

+ 1484
- 159
package-lock.json
File diff suppressed because it is too large
View File


+ 14
- 9
package.json View File

@ -4870,9 +4870,9 @@
"build": "webpack --env.development",
"bundle": "webpack --env.production",
"clean": "git clean -Xdf -e !.cache-images -e !node_modules -e !node_modules/**/*",
"lint": "tslint --project tsconfig.json && tslint --project ui.tsconfig.json",
"lint": "eslint src/**/*.ts --fix",
"pack": "vsce package",
"pretty": "prettier --config .prettierrc --loglevel warn --write \"./**/*.{ts,md,json}\" && tslint --project tsconfig.json --fix && tslint --project ui.tsconfig.json --fix",
"pretty": "prettier --config .prettierrc --loglevel warn --write \"./**/*.{ts,md,json}\" && npm run lint",
"pub": "vsce publish",
"rebuild": "npm run reset && npm run build",
"reset": "npm run clean && npm install --no-save",
@ -4892,27 +4892,32 @@
"devDependencies": {
"@types/lodash-es": "4.17.3",
"@types/node": "10.1.4",
"clean-webpack-plugin": "2.0.0",
"@typescript-eslint/eslint-plugin": "1.4.2",
"@typescript-eslint/parser": "1.4.2",
"clean-webpack-plugin": "2.0.1",
"circular-dependency-plugin": "5.0.2",
"css-loader": "2.1.1",
"eslint": "5.15.2",
"eslint-cli": "1.1.1",
"eslint-config-prettier": "4.1.0",
"eslint-loader": "2.1.2",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-prettiest": "0.0.1",
"html-webpack-inline-source-plugin": "0.0.10",
"html-webpack-plugin": "3.2.0",
"imagemin-webpack-plugin": "2.4.2",
"mini-css-extract-plugin": "0.5.0",
"node-sass": "4.11.0",
"prettier": "1.16.4",
"prettier-tslint": "0.4.2",
"prettier-eslint": "8.8.2",
"sass-loader": "7.1.0",
"terser-webpack-plugin": "1.2.3",
"tslint": "5.13.1",
"tslint-loader": "3.5.4",
"tslint-prettiest": "0.0.1",
"ts-loader": "5.3.3",
"typescript": "3.2.4",
"vsce": "1.57.1",
"vsce": "1.58.0",
"vscode": "1.1.30",
"webpack": "4.29.6",
"webpack-cli": "3.2.3",
"webpack-cli": "3.3.0",
"webpack-bundle-analyzer": "3.1.0"
}
}

+ 547
- 547
src/@types/applicationinsights/index.d.ts
File diff suppressed because it is too large
View File


+ 81
- 7
src/@types/git.d.ts View File

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, SourceControlInputBox, Event, CancellationToken } from 'vscode';
import { Event, Uri } from 'vscode';
export interface Git {
readonly path: string;
@ -41,6 +41,7 @@ export interface Commit {
readonly hash: string;
readonly message: string;
readonly parents: string[];
readonly authorEmail?: string | undefined;
}
export interface Submodule {
@ -56,8 +57,39 @@ export interface Remote {
readonly isReadOnly: boolean;
}
export const enum Status {
INDEX_MODIFIED,
INDEX_ADDED,
INDEX_DELETED,
INDEX_RENAMED,
INDEX_COPIED,
MODIFIED,
DELETED,
UNTRACKED,
IGNORED,
INTENT_TO_ADD,
ADDED_BY_US,
ADDED_BY_THEM,
DELETED_BY_US,
DELETED_BY_THEM,
BOTH_ADDED,
BOTH_DELETED,
BOTH_MODIFIED
}
export interface Change {
// TODO
/**
* Returns either `originalUri` or `renameUri`, depending
* on whether this change is a rename change. When
* in doubt always use `uri` over the other two alternatives.
*/
readonly uri: Uri;
readonly originalUri: Uri;
readonly renameUri: Uri | undefined;
readonly status: Status;
}
export interface RepositoryState {
@ -74,31 +106,57 @@ export interface RepositoryState {
readonly onDidChange: Event<void>;
}
export interface RepositoryUIState {
readonly selected: boolean;
readonly onDidChange: Event<void>;
}
/**
* Log options.
*/
export interface LogOptions {
/** Max number of log entries to retrieve. If not specified, the default is 32. */
readonly maxEntries?: number;
}
export interface Repository {
readonly rootUri: Uri;
readonly inputBox: InputBox;
readonly state: RepositoryState;
readonly ui: RepositoryUIState;
getConfigs(): Promise<{ key: string; value: string; }[]>;
getConfig(key: string): Promise<string>;
setConfig(key: string, value: string): Promise<string>;
getGlobalConfig(key: string): Promise<string>;
getObjectDetails(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }>;
detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }>;
buffer(ref: string, path: string): Promise<Buffer>;
show(ref: string, path: string): Promise<string>;
getCommit(ref: string): Promise<Commit>;
getObjectDetails(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }>;
clean(paths: string[]): Promise<void>;
apply(patch: string, reverse?: boolean): Promise<void>;
diff(cached?: boolean): Promise<string>;
diffWithHEAD(): Promise<Change[]>;
diffWithHEAD(path: string): Promise<string>;
diffWith(ref: string): Promise<Change[]>;
diffWith(ref: string, path: string): Promise<string>;
diffIndexWithHEAD(): Promise<Change[]>;
diffIndexWithHEAD(path: string): Promise<string>;
diffIndexWith(ref: string): Promise<Change[]>;
diffIndexWith(ref: string, path: string): Promise<string>;
diffBlobs(object1: string, object2: string): Promise<string>;
diffBetween(ref1: string, ref2: string): Promise<Change[]>;
diffBetween(ref1: string, ref2: string, path: string): Promise<string>;
hashObject(data: string): Promise<string>;
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
deleteBranch(name: string): Promise<void>;
deleteBranch(name: string, force?: boolean): Promise<void>;
getBranch(name: string): Promise<Branch>;
setBranchUpstream(name: string, upstream: string): Promise<void>;
@ -110,8 +168,12 @@ export interface Repository {
addRemote(name: string, url: string): Promise<void>;
removeRemote(name: string): Promise<void>;
fetch(remote?: string, ref?: string): Promise<void>;
pull(): Promise<void>;
fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
pull(unshallow?: boolean): Promise<void>;
push(remoteName?: string, branchName?: string, setUpstream?: boolean): Promise<void>;
blame(path: string): Promise<string>;
log(options?: LogOptions): Promise<Commit[]>;
}
export interface API {
@ -123,9 +185,16 @@ export interface API {
export interface GitExtension {
readonly enabled: boolean;
readonly onDidChangeEnablement: Event<boolean>;
/**
* Returns a specific API version.
*
* Throws error if git extension is disabled. You can listed to the
* [GitExtension.onDidChangeEnablement](#GitExtension.onDidChangeEnablement) event
* to know when the extension becomes enabled/disabled.
*
* @param version Version number.
* @returns API instance
*/
@ -141,6 +210,7 @@ export const enum GitErrorCodes {
NotAGitRepository = 'NotAGitRepository',
NotAtRepositoryRoot = 'NotAtRepositoryRoot',
Conflict = 'Conflict',
StashConflict = 'StashConflict',
UnmergedChanges = 'UnmergedChanges',
PushRejected = 'PushRejected',
RemoteConnectionError = 'RemoteConnectionError',
@ -161,4 +231,8 @@ export const enum GitErrorCodes {
NoUpstreamBranch = 'NoUpstreamBranch',
IsInSubmodule = 'IsInSubmodule',
WrongCase = 'WrongCase',
}
CantLockRef = 'CantLockRef',
CantRebaseMultipleBranches = 'CantRebaseMultipleBranches',
PatchDoesNotApply = 'PatchDoesNotApply',
NoPathFound = 'NoPathFound'
}

+ 5
- 5
src/annotations/annotationProvider.ts View File

@ -56,10 +56,10 @@ export abstract class AnnotationProviderBase implements Disposable {
this.disposable && this.disposable.dispose();
}
private async onTextEditorSelectionChanged(e: TextEditorSelectionChangeEvent) {
private onTextEditorSelectionChanged(e: TextEditorSelectionChangeEvent) {
if (!TextDocumentComparer.equals(this.document, e.textEditor && e.textEditor.document)) return;
return this.selection(e.selections[0].active.line);
this.selection(e.selections[0].active.line);
}
get editorId(): string {
@ -178,7 +178,7 @@ export abstract class AnnotationProviderBase implements Disposable {
return false;
}
abstract async onProvideAnnotation(shaOrLine?: string | number): Promise<boolean>;
abstract async selection(shaOrLine?: string | number): Promise<void>;
abstract async validate(): Promise<boolean>;
abstract onProvideAnnotation(shaOrLine?: string | number): Promise<boolean>;
abstract selection(shaOrLine?: string | number): Promise<void>;
abstract validate(): Promise<boolean>;
}

+ 38
- 30
src/annotations/annotations.ts View File

@ -2,6 +2,7 @@ import {
DecorationInstanceRenderOptions,
DecorationOptions,
MarkdownString,
ThemableDecorationAttachmentRenderOptions,
ThemableDecorationRenderOptions,
ThemeColor,
workspace
@ -11,13 +12,13 @@ import { FileAnnotationType } from '../configuration';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import {
CommitFormatOptions,
CommitFormatter,
GitCommit,
GitDiffChunkLine,
GitRemote,
GitService,
GitUri,
ICommitFormatOptions
GitUri
} from '../git/gitService';
import { Objects, Strings } from '../system';
import { toRgba } from '../ui/shared/colors';
@ -31,12 +32,15 @@ export interface ComputedHeatmap {
computeAge(date: Date): number;
}
interface IHeatmapConfig {
interface HeatmapConfig {
enabled: boolean;
location?: 'left' | 'right';
}
interface IRenderOptions extends DecorationInstanceRenderOptions, ThemableDecorationRenderOptions {
interface RenderOptions
extends DecorationInstanceRenderOptions,
ThemableDecorationRenderOptions,
ThemableDecorationAttachmentRenderOptions {
height?: string;
uncommittedColor?: string | ThemeColor;
}
@ -50,9 +54,9 @@ let computedHeatmapColor: {
};
export class Annotations {
static applyHeatmap(decoration: DecorationOptions, date: Date, heatmap: ComputedHeatmap) {
static applyHeatmap(decoration: Partial<DecorationOptions>, date: Date, heatmap: ComputedHeatmap) {
const color = this.getHeatmapColor(date, heatmap);
(decoration.renderOptions!.before! as any).borderColor = color;
decoration.renderOptions!.before!.borderColor = color;
}
private static getHeatmapColor(date: Date, heatmap: ComputedHeatmap) {
@ -150,7 +154,7 @@ export class Annotations {
\`\`\``;
}
static async changesHover(commit: GitCommit, line: number, uri: GitUri): Promise<DecorationOptions> {
static async changesHover(commit: GitCommit, line: number, uri: GitUri): Promise<Partial<DecorationOptions>> {
const sha =
!commit.isUncommitted || (uri.sha !== undefined && GitService.isStagedUncommitted(uri.sha))
? commit.previousSha
@ -160,7 +164,7 @@ export class Annotations {
return {
hoverMessage: message
} as DecorationOptions;
};
}
// static detailsHover(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0): DecorationOptions {
@ -173,14 +177,14 @@ export class Annotations {
static gutter(
commit: GitCommit,
format: string,
dateFormatOrFormatOptions: string | null | ICommitFormatOptions,
renderOptions: IRenderOptions
): DecorationOptions {
const decoration = {
dateFormatOrFormatOptions: string | null | CommitFormatOptions,
renderOptions: RenderOptions
): Partial<DecorationOptions> {
const decoration: Partial<DecorationOptions> = {
renderOptions: {
before: { ...renderOptions }
} as DecorationInstanceRenderOptions
} as DecorationOptions;
}
};
if (commit.isUncommitted) {
decoration.renderOptions!.before!.color = renderOptions.uncommittedColor;
@ -194,10 +198,10 @@ export class Annotations {
static gutterRenderOptions(
separateLines: boolean,
heatmap: IHeatmapConfig,
heatmap: HeatmapConfig,
format: string,
options: ICommitFormatOptions
): IRenderOptions {
options: CommitFormatOptions
): RenderOptions {
// Get the character count of all the tokens, assuming there there is a cap (bail if not)
let chars = 0;
for (const token of Objects.values(options.tokenOptions!)) {
@ -247,30 +251,34 @@ export class Annotations {
fontWeight: 'normal',
fontStyle: 'normal',
height: '100%',
margin: `0 26px -1px 0`,
margin: '0 26px -1px 0',
textDecoration: separateLines ? 'overline solid rgba(0, 0, 0, .2)' : 'none',
width: width,
uncommittedColor: new ThemeColor('gitlens.gutterUncommittedForegroundColor')
} as IRenderOptions;
};
}
static heatmap(commit: GitCommit, heatmap: ComputedHeatmap, renderOptions: IRenderOptions): DecorationOptions {
const decoration = {
static heatmap(
commit: GitCommit,
heatmap: ComputedHeatmap,
renderOptions: RenderOptions
): Partial<DecorationOptions> {
const decoration: Partial<DecorationOptions> = {
renderOptions: {
before: { ...renderOptions }
} as DecorationInstanceRenderOptions
} as DecorationOptions;
}
};
Annotations.applyHeatmap(decoration, commit.date, heatmap);
return decoration;
}
static heatmapRenderOptions(): IRenderOptions {
static heatmapRenderOptions(): RenderOptions {
return {
borderStyle: 'solid',
borderWidth: '0 0 0 2px'
} as IRenderOptions;
};
}
// static hover(commit: GitCommit, renderOptions: IRenderOptions, now: number): DecorationOptions {
@ -283,7 +291,7 @@ export class Annotations {
// return decoration;
// }
// static hoverRenderOptions(heatmap: IHeatmapConfig): IRenderOptions {
// static hoverRenderOptions(heatmap: HeatmapConfig): IRenderOptions {
// if (!heatmap.enabled) return { before: undefined };
// return {
@ -301,11 +309,11 @@ export class Annotations {
format: string,
dateFormat: string | null,
scrollable: boolean = true
): DecorationOptions {
): Partial<DecorationOptions> {
const message = CommitFormatter.fromTemplate(format, commit, {
truncateMessageAtNewLine: true,
dateFormat: dateFormat
} as ICommitFormatOptions);
});
return {
renderOptions: {
@ -318,8 +326,8 @@ export class Annotations {
// Pull the decoration out of the document flow if we want to be scrollable
textDecoration: `none;${scrollable ? '' : ' position: absolute;'}`
}
} as DecorationInstanceRenderOptions
} as DecorationOptions;
}
};
}
// static withRange(decoration: DecorationOptions, start?: number, end?: number): DecorationOptions {

+ 13
- 8
src/annotations/blameAnnotationProvider.ts View File

@ -3,7 +3,6 @@ import {
CancellationToken,
Disposable,
Hover,
HoverProvider,
languages,
Position,
Range,
@ -46,7 +45,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
super.clear();
}
async onReset(changes?: {
onReset(changes?: {
decoration: TextEditorDecorationType;
highlightDecoration: TextEditorDecorationType | undefined;
}) {
@ -181,16 +180,22 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
const subscriptions: Disposable[] = [];
if (providers.changes) {
subscriptions.push(
languages.registerHoverProvider({ pattern: this.document.uri.fsPath }, {
provideHover: this.provideChangesHover.bind(this)
} as HoverProvider)
languages.registerHoverProvider(
{ pattern: this.document.uri.fsPath },
{
provideHover: this.provideChangesHover.bind(this)
}
)
);
}
if (providers.details) {
subscriptions.push(
languages.registerHoverProvider({ pattern: this.document.uri.fsPath }, {
provideHover: this.provideDetailsHover.bind(this)
} as HoverProvider)
languages.registerHoverProvider(
{ pattern: this.document.uri.fsPath },
{
provideHover: this.provideDetailsHover.bind(this)
}
)
);
}

+ 7
- 8
src/annotations/fileAnnotationController.ts View File

@ -3,7 +3,6 @@ import * as paths from 'path';
import {
ConfigurationChangeEvent,
DecorationRangeBehavior,
DecorationRenderOptions,
Disposable,
Event,
EventEmitter,
@ -21,7 +20,7 @@ import {
import { AnnotationsToggleMode, configuration, FileAnnotationType, HighlightLocations } from '../configuration';
import { CommandContext, GlyphChars, isTextEditor, setCommandContext } from '../constants';
import { Container } from '../container';
import { KeyboardScope, KeyCommand, Keys } from '../keyboard';
import { KeyboardScope } from '../keyboard';
import { Logger } from '../logger';
import { Functions, Iterables } from '../system';
import {
@ -47,7 +46,7 @@ export const Decorations = {
blameAnnotation: window.createTextEditorDecorationType({
rangeBehavior: DecorationRangeBehavior.ClosedOpen,
textDecoration: 'none'
} as DecorationRenderOptions),
}),
blameHighlight: undefined as TextEditorDecorationType | undefined,
heatmapAnnotation: window.createTextEditorDecorationType({
before: {
@ -55,7 +54,7 @@ export const Decorations = {
height: '100%',
margin: '0 26px -1px 0'
}
} as DecorationRenderOptions),
}),
heatmapHighlight: undefined as TextEditorDecorationType | undefined,
recentChangesAnnotation: undefined as TextEditorDecorationType | undefined,
recentChangesHighlight: undefined as TextEditorDecorationType | undefined
@ -431,14 +430,14 @@ export class FileAnnotationController implements Disposable {
if (this._keyboardScope === undefined) {
this._keyboardScope = await Container.keyboard.beginScope({
escape: {
onDidPressKey: async (key: Keys) => {
onDidPressKey: async () => {
const e = this._editor;
if (e === undefined) return undefined;
await this.clear(e, AnnotationClearReason.User);
return undefined;
}
} as KeyCommand
}
});
}
}
@ -458,7 +457,7 @@ export class FileAnnotationController implements Disposable {
}
if (this._annotationProviders.size === 0) {
Logger.log(`Remove all listener registrations for annotations`);
Logger.log('Remove all listener registrations for annotations');
this._annotationsDisposable && this._annotationsDisposable.dispose();
this._annotationsDisposable = undefined;
@ -543,7 +542,7 @@ export class FileAnnotationController implements Disposable {
}
if (!this._annotationsDisposable && this._annotationProviders.size === 0) {
Logger.log(`Add listener registrations for annotations`);
Logger.log('Add listener registrations for annotations');
this._annotationsDisposable = Disposable.from(
window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveTextEditorChanged, 50), this),

+ 16
- 15
src/annotations/gutterBlameAnnotationProvider.ts View File

@ -1,9 +1,9 @@
'use strict';
import { DecorationOptions, DecorationRenderOptions, Range, TextEditorDecorationType, window } from 'vscode';
import { DecorationOptions, Range, TextEditorDecorationType, window } from 'vscode';
import { FileAnnotationType, GravatarDefaultStyle } from '../configuration';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitBlameCommit, ICommitFormatOptions } from '../git/gitService';
import { CommitFormatOptions, GitBlameCommit } from '../git/gitService';
import { Logger } from '../logger';
import { Objects, Strings } from '../system';
import { Annotations } from './annotations';
@ -21,15 +21,14 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
const cfg = Container.config.blame;
// Precalculate the formatting options so we don't need to do it on each iteration
const tokenOptions = Strings.getTokensFromTemplate(cfg.format).reduce(
(map, token) => {
map[token.key] = token.options as ICommitFormatOptions;
return map;
},
{} as { [token: string]: ICommitFormatOptions }
);
const options: ICommitFormatOptions = {
const tokenOptions = Strings.getTokensFromTemplate(cfg.format).reduce<{
[token: string]: Strings.TokenOptions | undefined;
}>((map, token) => {
map[token.key] = token.options;
return map;
}, Object.create(null));
const options: CommitFormatOptions = {
dateFormat: cfg.dateFormat === null ? Container.config.defaultDateFormat : cfg.dateFormat,
tokenOptions: tokenOptions
};
@ -59,8 +58,10 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
const line = l.line;
if (previousSha === l.sha) {
if (gutter === undefined) continue;
// Use a shallow copy of the previous decoration options
gutter = { ...gutter } as DecorationOptions;
gutter = { ...gutter };
if (cfg.compact && !compacted) {
// Since we are wiping out the contextText make sure to copy the objects
@ -102,7 +103,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
gutter = {
...gutter,
range: new Range(line, 0, line, 0)
} as DecorationOptions;
};
this.decorations.push(gutter);
@ -113,7 +114,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
continue;
}
gutter = Annotations.gutter(commit, cfg.format, options, renderOptions);
gutter = Annotations.gutter(commit, cfg.format, options, renderOptions) as DecorationOptions;
if (computedHeatmap !== undefined) {
Annotations.applyHeatmap(gutter, commit.date, computedHeatmap);
@ -166,7 +167,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
decoration: window.createTextEditorDecorationType({
gutterIconPath: commit.getGravatarUri(gravatarDefault),
gutterIconSize: '16px 16px'
} as DecorationRenderOptions),
}),
ranges: [range]
};
}

+ 2
- 2
src/annotations/heatmapBlameAnnotationProvider.ts View File

@ -35,7 +35,7 @@ export class HeatmapBlameAnnotationProvider extends BlameAnnotationProviderBase
heatmap = {
...heatmap,
range: new Range(line, 0, line, 0)
} as DecorationOptions;
};
this.decorations.push(heatmap);
@ -45,7 +45,7 @@ export class HeatmapBlameAnnotationProvider extends BlameAnnotationProviderBase
commit = blame.commits.get(l.sha);
if (commit === undefined) continue;
heatmap = Annotations.heatmap(commit, computedHeatmap, renderOptions);
heatmap = Annotations.heatmap(commit, computedHeatmap, renderOptions) as DecorationOptions;
heatmap.range = new Range(line, 0, line, 0);
this.decorations.push(heatmap);

+ 17
- 10
src/annotations/lineAnnotationController.ts View File

@ -2,8 +2,8 @@
import {
ConfigurationChangeEvent,
debug,
DecorationOptions,
DecorationRangeBehavior,
DecorationRenderOptions,
Disposable,
Range,
TextEditor,
@ -22,7 +22,7 @@ const annotationDecoration: TextEditorDecorationType = window.createTextEditorDe
textDecoration: 'none'
},
rangeBehavior: DecorationRangeBehavior.ClosedOpen
} as DecorationRenderOptions);
});
export class LineAnnotationController implements Disposable {
private _disposable: Disposable;
@ -153,10 +153,8 @@ export class LineAnnotationController implements Disposable {
await this.refresh(editor);
}
}
else {
if (this.suspend('user')) {
await this.refresh(editor);
}
else if (this.suspend('user')) {
await this.refresh(editor);
}
}
@ -170,7 +168,10 @@ export class LineAnnotationController implements Disposable {
if (editor === undefined && this._editor === undefined) return;
const lines = Container.lineTracker.lines;
if (editor === undefined || lines === undefined || !isTextEditor(editor)) return this.clear(this._editor);
if (editor === undefined || lines === undefined || !isTextEditor(editor)) {
this.clear(this._editor);
return;
}
if (this._editor !== editor) {
// Clear any annotations on the previously active editor
@ -180,10 +181,16 @@ export class LineAnnotationController implements Disposable {
}
const cfg = Container.config.currentLine;
if (this.suspended) return this.clear(editor);
if (this.suspended) {
this.clear(editor);
return;
}
const trackedDocument = await Container.tracker.getOrAdd(editor.document);
if (!trackedDocument.isBlameable && this.suspended) return this.clear(editor);
if (!trackedDocument.isBlameable && this.suspended) {
this.clear(editor);
return;
}
// Make sure the editor hasn't died since the await above and that we are still on the same line(s)
if (editor.document === undefined || !Container.lineTracker.includesAll(lines)) return;
@ -200,7 +207,7 @@ export class LineAnnotationController implements Disposable {
cfg.format,
cfg.dateFormat === null ? Container.config.defaultDateFormat : cfg.dateFormat,
scrollable
);
) as DecorationOptions;
decoration.range = editor.document.validateRange(
new Range(l, Number.MAX_SAFE_INTEGER, l, Number.MAX_SAFE_INTEGER)
);

+ 8
- 6
src/annotations/recentChangesAnnotationProvider.ts View File

@ -1,5 +1,5 @@
'use strict';
import { DecorationOptions, MarkdownString, Position, Range, TextEditor, TextEditorDecorationType } from 'vscode';
import { MarkdownString, Position, Range, TextEditor, TextEditorDecorationType } from 'vscode';
import { FileAnnotationType } from '../configuration';
import { Container } from '../container';
import { GitUri } from '../git/gitService';
@ -65,7 +65,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
this.editor.selection.active.line
),
range: range
} as DecorationOptions);
});
}
if (cfg.hovers.annotations.changes) {
@ -77,7 +77,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
this.decorations.push({
hoverMessage: message,
range: range
} as DecorationOptions);
});
}
}
@ -88,9 +88,11 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
return true;
}
async selection(shaOrLine?: string | number): Promise<void> {}
selection(shaOrLine?: string | number): Promise<void> {
return Promise.resolve(undefined);
}
async validate(): Promise<boolean> {
return true;
validate(): Promise<boolean> {
return Promise.resolve(true);
}
}

+ 1
- 1
src/codelens/codeLensController.ts View File

@ -81,7 +81,7 @@ export class GitCodeLensController implements Disposable {
toggleCodeLens() {
if (!this._canToggle) return;
Logger.log(`toggleCodeLens()`);
Logger.log('toggleCodeLens()');
if (this._provider !== undefined) {
if (this._providerDisposable !== undefined) {
this._providerDisposable.dispose();

+ 40
- 49
src/codelens/codeLensProvider.ts View File

@ -15,8 +15,7 @@ import {
Range,
SymbolInformation,
SymbolKind,
TextDocument,
Uri
TextDocument
} from 'vscode';
import {
Commands,
@ -129,7 +128,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
if (languageScope == null) {
languageScope = {
language: undefined
} as CodeLensLanguageScope;
};
}
if (languageScope.scopes == null) {
languageScope.scopes = cfg.scopes;
@ -170,13 +169,11 @@ export class GitCodeLensProvider implements CodeLensProvider {
if (blame === undefined || blame.lines.length === 0) return lenses;
}
else {
if (languageScope.scopes.length !== 1 || !languageScope.scopes.includes(CodeLensScopes.Document)) {
symbols = (await commands.executeCommand(
BuiltInCommands.ExecuteDocumentSymbolProvider,
document.uri
)) as SymbolInformation[];
}
else if (languageScope.scopes.length !== 1 || !languageScope.scopes.includes(CodeLensScopes.Document)) {
symbols = (await commands.executeCommand(
BuiltInCommands.ExecuteDocumentSymbolProvider,
document.uri
)) as SymbolInformation[];
}
if (token.isCancellationRequested) return lenses;
@ -184,7 +181,9 @@ export class GitCodeLensProvider implements CodeLensProvider {
const documentRangeFn = Functions.once(() => document.validateRange(new Range(0, 1000000, 1000000, 1000000)));
// Since blame information isn't valid when there are unsaved changes -- update the lenses appropriately
const dirtyCommand = dirty ? ({ title: this.getDirtyTitle(cfg) } as Command) : undefined;
const dirtyCommand: Command | undefined = dirty
? { command: undefined!, title: this.getDirtyTitle(cfg) }
: undefined;
if (symbols !== undefined) {
Logger.log('GitCodeLensProvider.provideCodeLenses:', `${symbols.length} symbol(s) found`);
@ -216,7 +215,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
if (dirty || cfg.recentChange.enabled) {
if (!dirty) {
blameForRangeFn = Functions.once(() =>
this._git.getBlameForRangeSync(blame!, gitUri!, blameRange)
this._git.getBlameForRangeSync(blame!, gitUri, blameRange)
);
}
@ -243,7 +242,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
if (!dirty && cfg.authors.enabled) {
if (blameForRangeFn === undefined) {
blameForRangeFn = Functions.once(() =>
this._git.getBlameForRangeSync(blame!, gitUri!, blameRange)
this._git.getBlameForRangeSync(blame!, gitUri, blameRange)
);
}
@ -286,9 +285,9 @@ export class GitCodeLensProvider implements CodeLensProvider {
case SymbolKind.File:
if (
languageScope.scopes.includes(CodeLensScopes.Containers) ||
languageScope.symbolScopes!.includes(symbolName)
languageScope.symbolScopes.includes(symbolName)
) {
valid = !languageScope.symbolScopes!.includes(`!${symbolName}`);
valid = !languageScope.symbolScopes.includes(`!${symbolName}`);
}
if (valid) {
@ -300,9 +299,9 @@ export class GitCodeLensProvider implements CodeLensProvider {
case SymbolKind.Package:
if (
languageScope.scopes.includes(CodeLensScopes.Containers) ||
languageScope.symbolScopes!.includes(symbolName)
languageScope.symbolScopes.includes(symbolName)
) {
valid = !languageScope.symbolScopes!.includes(`!${symbolName}`);
valid = !languageScope.symbolScopes.includes(`!${symbolName}`);
}
if (valid) {
@ -321,11 +320,11 @@ export class GitCodeLensProvider implements CodeLensProvider {
case SymbolKind.Struct:
if (
languageScope.scopes.includes(CodeLensScopes.Containers) ||
languageScope.symbolScopes!.includes(symbolName)
languageScope.symbolScopes.includes(symbolName)
) {
range = getRangeFromSymbol(symbol);
valid =
!languageScope.symbolScopes!.includes(`!${symbolName}`) &&
!languageScope.symbolScopes.includes(`!${symbolName}`) &&
(includeSingleLineSymbols || !range.isSingleLine);
}
break;
@ -337,20 +336,20 @@ export class GitCodeLensProvider implements CodeLensProvider {
case SymbolKind.Property:
if (
languageScope.scopes.includes(CodeLensScopes.Blocks) ||
languageScope.symbolScopes!.includes(symbolName)
languageScope.symbolScopes.includes(symbolName)
) {
range = getRangeFromSymbol(symbol);
valid =
!languageScope.symbolScopes!.includes(`!${symbolName}`) &&
!languageScope.symbolScopes.includes(`!${symbolName}`) &&
(includeSingleLineSymbols || !range.isSingleLine);
}
break;
default:
if (languageScope.symbolScopes!.includes(symbolName)) {
if (languageScope.symbolScopes.includes(symbolName)) {
range = getRangeFromSymbol(symbol);
valid =
!languageScope.symbolScopes!.includes(`!${symbolName}`) &&
!languageScope.symbolScopes.includes(`!${symbolName}`) &&
(includeSingleLineSymbols || !range.isSingleLine);
}
break;
@ -577,15 +576,13 @@ export class GitCodeLensProvider implements CodeLensProvider {
commit = blame.commits.get(blameLine.sha);
}
const commandArgs: DiffWithPreviousCommandArgs = {
commit: commit
};
lens.command = {
title: title,
command: Commands.DiffWithPrevious,
arguments: [
lens.uri!.toFileUri(),
{
commit: commit
} as DiffWithPreviousCommandArgs
]
arguments: [lens.uri!.toFileUri(), commandArgs]
};
return lens;
}
@ -596,16 +593,14 @@ export class GitCodeLensProvider implements CodeLensProvider {
blame: GitBlameLines,
commit?: GitBlameCommit
): T {
const commandArgs: ShowQuickCommitDetailsCommandArgs = {
commit: commit,
sha: commit === undefined ? undefined : commit.sha
};
lens.command = {
title: title,
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitDetails,
arguments: [
lens.uri!.toFileUri(),
{
commit,
sha: commit === undefined ? undefined : commit.sha
} as ShowQuickCommitDetailsCommandArgs
]
arguments: [lens.uri!.toFileUri(), commandArgs]
};
return lens;
}
@ -616,16 +611,14 @@ export class GitCodeLensProvider implements CodeLensProvider {
blame: GitBlameLines,
commit?: GitBlameCommit
): T {
const commandArgs: ShowQuickCommitFileDetailsCommandArgs = {
commit: commit,
sha: commit === undefined ? undefined : commit.sha
};
lens.command = {
title: title,
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitFileDetails,
arguments: [
lens.uri!.toFileUri(),
{
commit,
sha: commit === undefined ? undefined : commit.sha
} as ShowQuickCommitFileDetailsCommandArgs
]
arguments: [lens.uri!.toFileUri(), commandArgs]
};
return lens;
}
@ -650,15 +643,13 @@ export class GitCodeLensProvider implements CodeLensProvider {
blame: GitBlameLines,
commit?: GitBlameCommit
): T {
const commandArgs: ShowQuickFileHistoryCommandArgs = {
range: lens.isFullRange ? undefined : lens.blameRange
};
lens.command = {
title: title,
command: CodeLensCommand.ShowQuickFileHistory,
arguments: [
lens.uri!.toFileUri(),
{
range: lens.isFullRange ? undefined : lens.blameRange
} as ShowQuickFileHistoryCommandArgs
]
arguments: [lens.uri!.toFileUri(), commandArgs]
};
return lens;
}

+ 12
- 10
src/commands/annotations.ts View File

@ -14,7 +14,7 @@ export class ClearFileAnnotationsCommand extends EditorCommand {
super([Commands.ClearFileAnnotations, Commands.ComputingFileAnnotations]);
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri): Promise<any> {
execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri): Promise<any> {
// Handle the case where we are focused on a non-editor editor (output, debug console)
if (editor != null && !isTextEditor(editor)) {
if (uri != null && !UriComparer.equals(uri, editor.document.uri)) {
@ -47,7 +47,7 @@ export class ToggleFileBlameCommand extends ActiveEditorCommand {
super(Commands.ToggleFileBlame);
}
async execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise<any> {
execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Thenable<any> {
// Handle the case where we are focused on a non-editor editor (output, debug console)
if (editor != null && !isTextEditor(editor)) {
if (uri != null && !UriComparer.equals(uri, editor.document.uri)) {
@ -85,11 +85,12 @@ export class ToggleFileHeatmapCommand extends ActiveEditorCommand {
super(Commands.ToggleFileHeatmap);
}
async execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise<any> {
commands.executeCommand(Commands.ToggleFileBlame, uri, {
execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Thenable<any> {
const copyArgs: ToggleFileBlameCommandArgs = {
...args,
type: FileAnnotationType.Heatmap
} as ToggleFileBlameCommandArgs);
};
return commands.executeCommand(Commands.ToggleFileBlame, uri, copyArgs);
}
}
@ -99,11 +100,12 @@ export class ToggleFileRecentChangesCommand extends ActiveEditorCommand {
super(Commands.ToggleFileRecentChanges);
}
async execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise<any> {
commands.executeCommand(Commands.ToggleFileBlame, uri, {
execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Thenable<any> {
const copyArgs: ToggleFileBlameCommandArgs = {
...args,
type: FileAnnotationType.RecentChanges
} as ToggleFileBlameCommandArgs);
};
return commands.executeCommand(Commands.ToggleFileBlame, uri, copyArgs);
}
}
@ -113,14 +115,14 @@ export class ToggleLineBlameCommand extends ActiveEditorCommand {
super(Commands.ToggleLineBlame);
}
async execute(editor: TextEditor, uri?: Uri): Promise<any> {
execute(editor: TextEditor, uri?: Uri): Thenable<any> {
try {
return Container.lineAnnotations.toggle(editor);
}
catch (ex) {
Logger.error(ex, 'ToggleLineBlameCommand');
return window.showErrorMessage(
`Unable to toggle line blame annotations. See output channel for more details`
'Unable to toggle line blame annotations. See output channel for more details'
);
}
}

+ 4
- 5
src/commands/closeUnchangedFiles.ts View File

@ -34,7 +34,7 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
if (!repoPath) return undefined;
const status = await Container.git.getStatusForRepo(repoPath);
if (status === undefined) return window.showWarningMessage(`Unable to close unchanged files`);
if (status === undefined) return window.showWarningMessage('Unable to close unchanged files');
args.uris = status.files.map(f => f.uri);
}
@ -70,10 +70,8 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
count++;
editors.push(editor);
}
else {
if (count !== 0) {
count++;
}
else if (count !== 0) {
count++;
}
editor = await this.nextEditor();
@ -91,6 +89,7 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
editor == null ||
(editor.document !== undefined &&
(editor.document.isDirty ||
// eslint-disable-next-line no-loop-func
args.uris.some(uri =>
UriComparer.equals(uri, editor!.document && editor!.document.uri)
)))

+ 5
- 6
src/commands/common.ts View File

@ -360,7 +360,7 @@ export abstract class Command implements Disposable {
this._disposable && this._disposable.dispose();
}
protected async preExecute(context: CommandContext, ...args: any[]): Promise<any> {
protected preExecute(context: CommandContext, ...args: any[]): Promise<any> {
return this.execute(...args);
}
@ -392,9 +392,8 @@ export abstract class Command implements Disposable {
if (uri !== undefined) {
return [{ command: command, type: 'uri', editor: editor, uri: uri }, rest];
}
else {
args = args.slice(1);
}
args = args.slice(1);
}
if (firstArg instanceof ViewNode) {
@ -442,7 +441,7 @@ export abstract class ActiveEditorCommand extends Command {
super(command);
}
protected async preExecute(context: CommandContext, ...args: any[]): Promise<any> {
protected preExecute(context: CommandContext, ...args: any[]): Promise<any> {
return this.execute(context.editor, context.uri, ...args);
}
@ -557,6 +556,6 @@ export function openWorkspace(uri: Uri, name: string, options: { openInNewWindow
return workspace.updateWorkspaceFolders(
workspace.workspaceFolders !== undefined ? workspace.workspaceFolders.length : 0,
null,
{ uri, name }
{ uri: uri, name: name }
);
}

+ 4
- 4
src/commands/copyMessageToClipboard.ts View File

@ -25,7 +25,7 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
super(Commands.CopyMessageToClipboard);
}
protected async preExecute(context: CommandContext, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: CopyMessageToClipboardCommandArgs = {}) {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.sha = context.node.commit.sha;
@ -35,7 +35,7 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> {
async execute(editor?: TextEditor, uri?: Uri, args: CopyMessageToClipboardCommandArgs = {}) {
uri = getCommandUri(uri, editor);
try {
@ -95,9 +95,9 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
catch (ex) {
if (ex.message.includes("Couldn't find the required `xsel` binary")) {
window.showErrorMessage(
`Unable to copy message, xsel is not installed. Please install it via your package manager, e.g. \`sudo apt install xsel\``
'Unable to copy message, xsel is not installed. Please install it via your package manager, e.g. `sudo apt install xsel`'
);
return;
return undefined;
}
Logger.error(ex, 'CopyMessageToClipboardCommand');

+ 1
- 4
src/commands/copyRemoteFileUrlToClipboard.ts View File

@ -23,10 +23,7 @@ export class CopyRemoteFileUrlToClipboardCommand extends ActiveEditorCommand {
super(Commands.CopyRemoteFileUrlToClipboard);
}
protected async preExecute(
context: CommandContext,
args: CopyRemoteFileUrlToClipboardCommandArgs = { range: true }
): Promise<any> {
protected preExecute(context: CommandContext, args: CopyRemoteFileUrlToClipboardCommandArgs = { range: true }) {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.range = false;

+ 4
- 4
src/commands/copyShaToClipboard.ts View File

@ -24,7 +24,7 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
super(Commands.CopyShaToClipboard);
}
protected async preExecute(context: CommandContext, args: CopyShaToClipboardCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: CopyShaToClipboardCommandArgs = {}) {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.sha = context.node.commit.sha;
@ -34,7 +34,7 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: CopyShaToClipboardCommandArgs = {}): Promise<any> {
async execute(editor?: TextEditor, uri?: Uri, args: CopyShaToClipboardCommandArgs = {}) {
uri = getCommandUri(uri, editor);
try {
@ -76,9 +76,9 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
catch (ex) {
if (ex.message.includes("Couldn't find the required `xsel` binary")) {
window.showErrorMessage(
`Unable to copy commit id, xsel is not installed. Please install it via your package manager, e.g. \`sudo apt install xsel\``
'Unable to copy commit id, xsel is not installed. Please install it via your package manager, e.g. `sudo apt install xsel`'
);
return;
return undefined;
}
Logger.error(ex, 'CopyShaToClipboardCommand');

+ 3
- 3
src/commands/diffBranchWithBranch.ts View File

@ -25,7 +25,7 @@ export class DiffBranchWithBranchCommand extends ActiveEditorCommand {
super([Commands.DiffHeadWithBranch, Commands.DiffWorkingWithBranch]);
}
protected async preExecute(context: CommandContext, args: DiffBranchWithBranchCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: DiffBranchWithBranchCommandArgs = {}) {
switch (context.command) {
case Commands.DiffHeadWithBranch:
args.ref2 = 'HEAD';
@ -39,8 +39,8 @@ export class DiffBranchWithBranchCommand extends ActiveEditorCommand {
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: DiffBranchWithBranchCommandArgs = {}): Promise<any> {
if (args.ref2 === undefined) return;
async execute(editor?: TextEditor, uri?: Uri, args: DiffBranchWithBranchCommandArgs = {}) {
if (args.ref2 === undefined) return undefined;
uri = getCommandUri(uri, editor);

+ 3
- 3
src/commands/diffDirectory.ts View File

@ -32,7 +32,7 @@ export class DiffDirectoryCommand extends ActiveEditorCommand {
]);
}
protected async preExecute(context: CommandContext, args: DiffDirectoryCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: DiffDirectoryCommandArgs = {}) {
switch (context.command) {
case Commands.DiffDirectoryWithHead:
args.ref1 = 'HEAD';
@ -57,7 +57,7 @@ export class DiffDirectoryCommand extends ActiveEditorCommand {
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: DiffDirectoryCommandArgs = {}): Promise<any> {
async execute(editor?: TextEditor, uri?: Uri, args: DiffDirectoryCommandArgs = {}) {
uri = getCommandUri(uri, editor);
try {
@ -90,7 +90,7 @@ export class DiffDirectoryCommand extends ActiveEditorCommand {
const msg = ex && ex.toString();
if (msg === 'No diff tool found') {
const result = await window.showWarningMessage(
`Unable to open directory compare because there is no Git diff tool configured`,
'Unable to open directory compare because there is no Git diff tool configured',
'View Git Docs'
);
if (!result) return undefined;

+ 3
- 3
src/commands/diffWith.ts View File

@ -91,10 +91,10 @@ export class DiffWithCommand extends ActiveEditorCommand {
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithCommandArgs = {}): Promise<any> {
args = {
...args,
lhs: { ...args.lhs },
rhs: { ...args.rhs },
lhs: { ...(args.lhs as DiffWithCommandArgsRevision) },
rhs: { ...(args.rhs as DiffWithCommandArgsRevision) },
showOptions: { ...args.showOptions }
} as DiffWithCommandArgs;
};
if (args.repoPath === undefined || args.lhs === undefined || args.rhs === undefined) return undefined;
try {

+ 2
- 2
src/commands/diffWithBranch.ts View File

@ -23,7 +23,7 @@ export class DiffWithBranchCommand extends ActiveEditorCommand {
super(Commands.DiffWithBranch);
}
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithBranchCommandArgs = {}): Promise<any> {
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithBranchCommandArgs = {}) {
uri = getCommandUri(uri, editor);
if (uri == null) return undefined;
@ -33,7 +33,7 @@ export class DiffWithBranchCommand extends ActiveEditorCommand {
}
const gitUri = await GitUri.fromUri(uri);
if (!gitUri.repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open file compare`);
if (!gitUri.repoPath) return Messages.showNoRepositoryWarningMessage('Unable to open file compare');
const pick = await new BranchesAndTagsQuickPick(gitUri.repoPath).show(
`Compare ${paths.basename(gitUri.fsPath)} with${GlyphChars.Ellipsis}`,

+ 4
- 4
src/commands/diffWithNext.ts View File

@ -22,7 +22,7 @@ export class DiffWithNextCommand extends ActiveEditorCommand {
super(Commands.DiffWithNext);
}
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithNextCommandArgs = {}): Promise<any> {
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithNextCommandArgs = {}) {
uri = getCommandUri(uri, editor);
if (uri == null) return undefined;
@ -36,13 +36,13 @@ export class DiffWithNextCommand extends ActiveEditorCommand {
if (args.commit === undefined || !(args.commit instanceof GitLogCommit) || args.range !== undefined) {
try {
const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
const sha = args.commit === undefined ? gitUri.sha! : args.commit.sha;
if (GitService.isStagedUncommitted(sha!)) {
if (GitService.isStagedUncommitted(sha)) {
const diffArgs: DiffWithCommandArgs = {
repoPath: gitUri.repoPath!,
lhs: {
sha: sha!,
sha: sha,
uri: gitUri
},
rhs: {

+ 5
- 4
src/commands/diffWithPrevious.ts View File

@ -23,7 +23,7 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
super([Commands.DiffWithPrevious, Commands.DiffWithPreviousInDiff]);
}
protected async preExecute(context: CommandContext, args: DiffWithPreviousCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: DiffWithPreviousCommandArgs = {}) {
if (context.command === Commands.DiffWithPreviousInDiff) {
args.inDiffEditor = true;
}
@ -31,7 +31,7 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithPreviousCommandArgs = {}): Promise<any> {
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithPreviousCommandArgs = {}) {
uri = getCommandUri(uri, editor);
if (uri == null) return undefined;
@ -143,10 +143,11 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
}
if (!args.inDiffEditor) {
return commands.executeCommand(Commands.DiffWithWorking, uri, {
const commandArgs: DiffWithWorkingCommandArgs = {
commit: args.commit,
showOptions: args.showOptions
} as DiffWithWorkingCommandArgs);
};
return commands.executeCommand(Commands.DiffWithWorking, uri, commandArgs);
}
}
}

+ 19
- 17
src/commands/diffWithRevision.ts View File

@ -59,29 +59,33 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
let commandArgs: DiffWithRevisionCommandArgs;
if (log.truncated) {
commandArgs = { ...args };
const npc = new CommandQuickPickItem(
{
label: `$(arrow-right) Show Next Commits`,
label: '$(arrow-right) Show Next Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${log.maxCount} newer commits`
},
Commands.DiffWithRevision,
[uri, { ...args class="p">} as DiffWithRevisionCommandArgs]
[uri, commandArgs]
);
const last = Iterables.last(log.commits.values());
if (last != null) {
commandArgs = { ...args, nextPageCommand: npc };
previousPageCommand = new CommandQuickPickItem(
{
label: `$(arrow-left) Show Previous Commits`,
label: '$(arrow-left) Show Previous Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${log.maxCount} older commits`
},
Commands.DiffWithRevision,
[new GitUri(uri, last), { ...argsclass="p">, nextPageCommand: npc } as DiffWithRevisionCommandArgs]
[new GitUri(uri, last), commandArgs]
);
}
}
commandArgs = { ...args };
const currentCommand = new CommandQuickPickItem(
{
label: `go back ${GlyphChars.ArrowBack}`,
@ -98,9 +102,10 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
}`
},
Commands.DiffWithRevision,
[uri, { ...args }]
[uri, commandArgs]
);
commandArgs = { ...args, maxCount: 0 };
const pick = await FileHistoryQuickPick.show(log, gitUri, placeHolder, {
pickerOnly: true,
progressCancellation: progressCancellation,
@ -110,34 +115,31 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
showAllCommand: log.truncated
? new CommandQuickPickItem(
{
label: `$(sync) Show All Commits`,
label: '$(sync) Show All Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} this may take a while`
},
Commands.DiffWithRevision,
[uri, { ...args, class="nx">maxCount: 0 } as DiffWithRevisionCommandArgs]
[uri, commandArgs]
)
: undefined
});
if (pick === undefined) return undefined;
let ref: string;
if (pick instanceof ChooseFromBranchesAndTagsQuickPickItem) {
const branchOrTag = await pick.execute();
if (branchOrTag === undefined) return undefined;
if (branchOrTag instanceof CommandQuickPickItem) return branchOrTag.execute();
return commands class="p">.executeCommand"p">(>="nx">Commands.DiffWithRevision, gitUri, {
commandArgs = {
...args,
branchOrTag: branchOrTag.item,
goBackCommand: currentCommand
} as DiffWithRevisionCommandArgs);
branchOrTag: branchOrTag.item
};
return commands.executeCommand(Commands.DiffWithRevision, gitUri, commandArgs);
}
else {
if (pick instanceof CommandQuickPickItem) return pick.execute();
ref = pick.commit.sha;
}
if (pick instanceof CommandQuickPickItem) return pick.execute();
const ref = pick.commit.sha;
const diffArgs: DiffWithCommandArgs = {
repoPath: gitUri.repoPath,

+ 2
- 2
src/commands/externalDiff.ts View File

@ -65,7 +65,7 @@ export class ExternalDiffCommand extends Command {
super([Commands.ExternalDiff, Commands.ExternalDiffAll]);
}
protected async preExecute(context: CommandContext, args: ExternalDiffCommandArgs = {}): Promise<any> {
protected async preExecute(context: CommandContext, args: ExternalDiffCommandArgs = {}) {
if (isCommandViewContextWithFileCommit(context)) {
args = { ...args };
@ -190,7 +190,7 @@ export class ExternalDiffCommand extends Command {
const tool = await Container.git.getDiffTool(repoPath);
if (tool === undefined) {
const result = await window.showWarningMessage(
`Unable to open changes in diff tool. No Git diff tool is configured`,
'Unable to open changes in diff tool. No Git diff tool is configured',
'View Git Docs'
);
if (!result) return undefined;

+ 8
- 7
src/commands/openBranchInRemote.ts View File

@ -2,7 +2,7 @@
import { commands, TextEditor, Uri, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitService';
import { GitUri, RemoteResourceType } from '../git/gitService';
import { Logger } from '../logger';
import { BranchesAndTagsQuickPick, CommandQuickPickItem } from '../quickpicks';
import {
@ -27,7 +27,7 @@ export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
super(Commands.OpenBranchInRemote);
}
protected async preExecute(context: CommandContext, args: OpenBranchInRemoteCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: OpenBranchInRemoteCommandArgs = {}) {
if (isCommandViewContextWithBranch(context)) {
args = { ...args };
args.branch = context.node.branch.name;
@ -70,19 +70,20 @@ export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
const remotes = await Container.git.getRemotes(repoPath);
return commands.executeCommand(Commands.OpenInRemote, uri, {
const commandArgs: OpenInRemoteCommandArgs = {
resource: {
type: 'branch',
type: RemoteResourceType.Branch,
branch: args.branch || 'HEAD'
},
remote: args.remote,
remotes
} as OpenInRemoteCommandArgs);
remotes: remotes
};
return commands.executeCommand(Commands.OpenInRemote, uri, commandArgs);
}
catch (ex) {
Logger.error(ex, 'OpenBranchInRemoteCommandArgs');
return window.showErrorMessage(
`Unable to open branch on remote provider. See output channel for more details`
'Unable to open branch on remote provider. See output channel for more details'
);
}
}

+ 8
- 7
src/commands/openBranchesInRemote.ts View File

@ -2,7 +2,7 @@
import { commands, TextEditor, Uri, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitService';
import { GitUri, RemoteResourceType } from '../git/gitService';
import { Logger } from '../logger';
import {
ActiveEditorCommand,
@ -25,7 +25,7 @@ export class OpenBranchesInRemoteCommand extends ActiveEditorCommand {
super(Commands.OpenBranchesInRemote);
}
protected async preExecute(context: CommandContext, args: OpenBranchesInRemoteCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: OpenBranchesInRemoteCommandArgs = {}) {
if (isCommandViewContextWithRemote(context)) {
args = { ...args };
args.remote = context.node.remote.name;
@ -49,18 +49,19 @@ export class OpenBranchesInRemoteCommand extends ActiveEditorCommand {
try {
const remotes = await Container.git.getRemotes(repoPath);
return commands.executeCommand(Commands.OpenInRemote, uri, {
const commandArgs: OpenInRemoteCommandArgs = {
resource: {
type: 'branches'
type: RemoteResourceType.Branches
},
remote: args.remote,
remotes
} as OpenInRemoteCommandArgs);
remotes: remotes
};
return commands.executeCommand(Commands.OpenInRemote, uri, commandArgs);
}
catch (ex) {
Logger.error(ex, 'OpenBranchesInRemoteCommand');
return window.showErrorMessage(
`Unable to open branches on remote provider. See output channel for more details`
'Unable to open branches on remote provider. See output channel for more details'
);
}
}

+ 3
- 3
src/commands/openChangedFiles.ts View File

@ -1,5 +1,5 @@
'use strict';
import { TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { TextEditor, Uri, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { Logger } from '../logger';
@ -31,13 +31,13 @@ export class OpenChangedFilesCommand extends ActiveEditorCommand {
if (!repoPath) return undefined;
const status = await Container.git.getStatusForRepo(repoPath);
if (status === undefined) return window.showWarningMessage(`Unable to open changed files`);
if (status === undefined) return window.showWarningMessage('Unable to open changed files');
args.uris = Arrays.filterMap(status.files, f => (f.status !== 'D' ? f.uri : undefined));
}
for (const uri of args.uris) {
await openEditor(uri, { preserveFocus: true, preview: false } as TextDocumentShowOptions);
await openEditor(uri, { preserveFocus: true, preview: false });
}
return undefined;

+ 6
- 5
src/commands/openCommitInRemote.ts View File

@ -31,7 +31,7 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
super(Commands.OpenCommitInRemote);
}
protected async preExecute(context: CommandContext, args: OpenCommitInRemoteCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: OpenCommitInRemoteCommandArgs = {}) {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.sha = context.node.commit.sha;
@ -78,18 +78,19 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
const remotes = await Container.git.getRemotes(gitUri.repoPath);
return commands.executeCommand(Commands.OpenInRemote, uri, {
const commandArgs: OpenInRemoteCommandArgs = {
resource: {
type: RemoteResourceType.Commit,
sha: args.sha
},
remotes
} as OpenInRemoteCommandArgs);
remotes: remotes
};
return commands.executeCommand(Commands.OpenInRemote, uri, commandArgs);
}
catch (ex) {
Logger.error(ex, 'OpenCommitInRemoteCommand');
return window.showErrorMessage(
`Unable to open commit on remote provider. See output channel for more details`
'Unable to open commit on remote provider. See output channel for more details'
);
}
}

+ 21
- 15
src/commands/openFileInRemote.ts View File

@ -29,10 +29,7 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
super(Commands.OpenFileInRemote);
}
protected async preExecute(
context: CommandContext,
args: OpenFileInRemoteCommandArgs = { range: true }
): Promise<any> {
protected preExecute(context: CommandContext, args: OpenFileInRemoteCommandArgs = { range: true }) {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.range = false;
@ -92,22 +89,31 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
: undefined;
const sha = args.sha || gitUri.sha;
return commands.executeCommand(Commands.OpenInRemote, uri, {
resource: {
type: sha === undefined ? RemoteResourceType.File : RemoteResourceType.Revision,
branch: args.branch || 'HEAD',
fileName: gitUri.getRelativePath(),
range: range,
sha: sha
},
remotes,
const commandArgs: OpenInRemoteCommandArgs = {
resource:
sha === undefined
? {
type: RemoteResourceType.File,
branch: args.branch || 'HEAD',
fileName: gitUri.getRelativePath(),
range: range
}
: {
type: RemoteResourceType.Revision,
branch: args.branch || 'HEAD',
fileName: gitUri.getRelativePath(),
range: range,
sha: sha
},
remotes: remotes,
clipboard: args.clipboard
} as OpenInRemoteCommandArgs);
};
return commands.executeCommand(Commands.OpenInRemote, uri, commandArgs);
}
catch (ex) {
Logger.error(ex, 'OpenFileInRemoteCommand');
return window.showErrorMessage(
`Unable to open file on remote provider. See output channel for more details`
'Unable to open file on remote provider. See output channel for more details'
);
}
}

+ 20
- 15
src/commands/openFileRevision.ts View File

@ -60,6 +60,8 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
let progressCancellation: CancellationTokenSource | undefined;
try {
let commandArgs: OpenFileRevisionCommandArgs;
if (args.uri == null) {
uri = getCommandUri(uri, editor);
if (uri == null) return undefined;
@ -90,28 +92,31 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
if (log.truncated) {
commandArgs = { ...args };
const npc = new CommandQuickPickItem(
{
label: `$(arrow-right) Show Next Commits`,
label: '$(arrow-right) Show Next Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${log.maxCount} newer commits`
},
Commands.OpenFileRevision,
[uri, { ...args class="p">} as OpenFileRevisionCommandArgs]
[uri, commandArgs]
);
const last = Iterables.last(log.commits.values());
if (last != null) {
commandArgs = { ...args, nextPageCommand: npc };
previousPageCommand = new CommandQuickPickItem(
{
label: `$(arrow-left) Show Previous Commits`,
label: '$(arrow-left) Show Previous Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${log.maxCount} older commits`
},
Commands.OpenFileRevision,
[new GitUri(uri, last), { ...argsclass="p">, nextPageCommand: npc } as OpenFileRevisionCommandArgs]
[new GitUri(uri, last), commandArgs]
);
}
}
commandArgs = { ...args };
const currentCommand = new CommandQuickPickItem(
{
label: `go back ${GlyphChars.ArrowBack}`,
@ -128,9 +133,10 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
}`
},
Commands.OpenFileRevision,
[uri, { ...args }]
[uri, commandArgs]
);
commandArgs = { ...args, maxCount: 0 };
const pick = await FileHistoryQuickPick.show(log, gitUri, placeHolder, {
pickerOnly: true,
progressCancellation: progressCancellation,
@ -140,11 +146,11 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
showAllCommand: log.truncated
? new CommandQuickPickItem(
{
label: `$(sync) Show All Commits`,
label: '$(sync) Show All Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} this may take a while`
},
Commands.OpenFileRevision,
[uri, { ...args, class="nx">maxCount: 0 } as OpenFileRevisionCommandArgs]
[uri, commandArgs]
)
: undefined
});
@ -155,17 +161,16 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
if (branchOrTag === undefined) return undefined;
if (branchOrTag instanceof CommandQuickPickItem) return branchOrTag.execute();
return commands class="p">.executeCommand"p">(>="nx">Commands.OpenFileRevision, gitUri, {
commandArgs = {
...args,
branchOrTag: branchOrTag.item,
goBackCommand: currentCommand
} as OpenFileRevisionCommandArgs);
branchOrTag: branchOrTag.item
};
return commands.executeCommand(Commands.OpenFileRevision, gitUri, commandArgs);
}
else {
if (pick instanceof CommandQuickPickItem) return pick.execute();
args.uri = GitUri.toRevisionUri(pick.commit.sha, pick.commit.uri.fsPath, pick.commit.repoPath);
}
if (pick instanceof CommandQuickPickItem) return pick.execute();
args.uri = GitUri.toRevisionUri(pick.commit.sha, pick.commit.uri.fsPath, pick.commit.repoPath);
}
if (args.line !== undefined && args.line !== 0) {

+ 1
- 2
src/commands/openInRemote.ts View File

@ -60,8 +60,7 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
break;
case RemoteResourceType.Commit:
const shortSha = GitService.shortenSha(args.resource.sha);
placeHolder = `${verb} commit ${shortSha} ${suffix}`;
placeHolder = `${verb} commit ${GitService.shortenSha(args.resource.sha)} ${suffix}`;
break;
case RemoteResourceType.File:

+ 8
- 7
src/commands/openRepoInRemote.ts View File

@ -2,7 +2,7 @@
import { commands, TextEditor, Uri, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitService';
import { GitUri, RemoteResourceType } from '../git/gitService';
import { Logger } from '../logger';
import {
ActiveEditorCommand,
@ -25,7 +25,7 @@ export class OpenRepoInRemoteCommand extends ActiveEditorCommand {
super(Commands.OpenRepoInRemote);
}
protected async preExecute(context: CommandContext, args: OpenRepoInRemoteCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: OpenRepoInRemoteCommandArgs = {}) {
if (isCommandViewContextWithRemote(context)) {
args = { ...args };
args.remote = context.node.remote.name;
@ -49,18 +49,19 @@ export class OpenRepoInRemoteCommand extends ActiveEditorCommand {
try {
const remotes = await Container.git.getRemotes(repoPath);
return commands.executeCommand(Commands.OpenInRemote, uri, {
const commandArgs: OpenInRemoteCommandArgs = {
resource: {
type: 'repo'
type: RemoteResourceType.Repo
},
remote: args.remote,
remotes
} as OpenInRemoteCommandArgs);
remotes: remotes
};
return commands.executeCommand(Commands.OpenInRemote, uri, commandArgs);
}
catch (ex) {
Logger.error(ex, 'OpenRepoInRemoteCommand');
return window.showErrorMessage(
`Unable to open repository on remote provider. See output channel for more details`
'Unable to open repository on remote provider. See output channel for more details'
);
}
}

+ 3
- 3
src/commands/repositories.ts View File

@ -8,7 +8,7 @@ export class FetchRepositoriesCommand extends Command {
super(Commands.FetchRepositories);
}
async execute() {
execute() {
return Container.git.fetchAll();
}
}
@ -19,7 +19,7 @@ export class PullRepositoriesCommand extends Command {
super(Commands.PullRepositories);
}
async execute() {
execute() {
return Container.git.pullAll();
}
}
@ -30,7 +30,7 @@ export class PushRepositoriesCommand extends Command {
super(Commands.PushRepositories);
}
async execute() {
execute() {
return Container.git.pushAll();
}
}

+ 13
- 10
src/commands/searchCommits.ts View File

@ -54,7 +54,7 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
super([Commands.SearchCommits, Commands.SearchCommitsInView]);
}
protected async preExecute(context: CommandContext, args: SearchCommitsCommandArgs = {}) {
protected preExecute(context: CommandContext, args: SearchCommitsCommandArgs = {}) {
if (context.type === 'viewItem') {
args = { ...args };
args.showInView = true;
@ -102,7 +102,7 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
}
if (!args.search || args.searchBy == null) {
let selection;
let selection: [number, number] | undefined;
if (!args.search) {
if (args.searchBy != null) {
args.search = searchByToSymbolMap.get(args.searchBy);
@ -117,12 +117,14 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
await Container.searchView.show();
}
args.search = await window.showInputBox({
const opts: InputBoxOptions = {
value: args.search,
prompt: `Please enter a search string`,
placeHolder: `Search commits by message, author (@<pattern>), files (:<path/glob>), commit id (#<sha>), changes (=<pattern>), changed lines (~<pattern>)`,
prompt: 'Please enter a search string',
placeHolder:
'Search commits by message, author (@<pattern>), files (:<path/glob>), commit id (#<sha>), changes (=<pattern>), changed lines (~<pattern>)',
valueSelection: selection
} as InputBoxOptions);
};
args.search = await window.showInputBox(opts);
if (args.search === undefined) {
return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
}
@ -179,7 +181,7 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
label: { label: searchLabel! }
});
return;
return undefined;
}
const progressCancellation = CommitsQuickPick.showProgress(searchLabel!);
@ -209,7 +211,7 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
log !== undefined && log.truncated
? new CommandQuickPickItem(
{
label: `$(sync) Show All Commits`,
label: '$(sync) Show All Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} this may take a while`
},
Commands.SearchCommits,
@ -234,7 +236,7 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
commit = Iterables.first(log.commits.values());
}
return commands.executeCommand(Commands.ShowQuickCommitDetails, commit.toGitUri(), {
const commandArgs: ShowQuickCommitDetailsCommandArgs = {
sha: commit.sha,
commit: commit,
goBackCommand:
@ -247,7 +249,8 @@ export class SearchCommitsCommand extends ActiveEditorCachedCommand {
Commands.SearchCommits,
[uri, args]
)
} as ShowQuickCommitDetailsCommandArgs);
};
return commands.executeCommand(Commands.ShowQuickCommitDetails, commit.toGitUri(), commandArgs);
}
catch (ex) {
Logger.error(ex, 'ShowCommitSearchCommand');

+ 2
- 2
src/commands/showLastQuickPick.ts View File

@ -10,9 +10,9 @@ export class ShowLastQuickPickCommand extends Command {
super(Commands.ShowLastQuickPick);
}
async execute() {
execute() {
const command = getLastCommand();
if (command === undefined) return undefined;
if (command === undefined) return Promise.resolve(undefined);
try {
return commands.executeCommand(command.command, ...command.args);

+ 4
- 3
src/commands/showQuickBranchHistory.ts View File

@ -79,7 +79,7 @@ export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
maxCount: args.maxCount,
ref: (gitUri && gitUri.sha) || args.branch
});
if (args.log === undefined) return window.showWarningMessage(`Unable to show branch history`);
if (args.log === undefined) return window.showWarningMessage('Unable to show branch history');
}
if (progressCancellation !== undefined && progressCancellation.token.isCancellationRequested) {
@ -110,12 +110,13 @@ export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
[uri, { ...args }]
);
return commands.executeCommand(Commands.ShowQuickCommitDetails, pick.commit.toGitUri(), {
const commandArgs: ShowQuickCommitDetailsCommandArgs = {
sha: pick.commit.sha,
commit: pick.commit,
repoLog: args.log,
goBackCommand: currentCommand
} as ShowQuickCommitDetailsCommandArgs);
};
return commands.executeCommand(Commands.ShowQuickCommitDetails, pick.commit.toGitUri(), commandArgs);
}
catch (ex) {
Logger.error(ex, 'ShowQuickBranchHistoryCommand');

+ 6
- 5
src/commands/showQuickCommitDetails.ts View File

@ -43,7 +43,7 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
super([Commands.ShowCommitInView, Commands.ShowQuickCommitDetails]);
}
protected async preExecute(context: CommandContext, args: ShowQuickCommitDetailsCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: ShowQuickCommitDetailsCommandArgs = {}) {
if (context.command === Commands.ShowCommitInView) {
args = { ...args };
args.showInView = true;
@ -113,7 +113,7 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
if (args.repoLog === undefined) {
const log = await Container.git.getLog(repoPath!, { maxCount: 2, ref: args.sha });
if (log === undefined) {
return Messages.showCommitNotFoundWarningMessage(`Unable to show commit details`);
return Messages.showCommitNotFoundWarningMessage('Unable to show commit details');
}
args.commit = log.commits.get(args.sha!);
@ -121,7 +121,7 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
}
if (args.commit === undefined) {
return Messages.showCommitNotFoundWarningMessage(`Unable to show commit details`);
return Messages.showCommitNotFoundWarningMessage('Unable to show commit details');
}
if (args.commit.workingFileName === undefined) {
@ -174,11 +174,12 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
if (!(pick instanceof CommitWithFileStatusQuickPickItem)) return pick.execute();
return commands.executeCommand(Commands.ShowQuickCommitFileDetails, pick.commit.toGitUri(), {
const commandArgs: ShowQuickCommitFileDetailsCommandArgs = {
commit: pick.commit,
sha: pick.sha,
goBackCommand: currentCommand
} as ShowQuickCommitFileDetailsCommandArgs);
};
return commands.executeCommand(Commands.ShowQuickCommitFileDetails, pick.commit.toGitUri(), commandArgs);
}
catch (ex) {
Logger.error(ex, 'ShowQuickCommitDetailsCommand');

+ 12
- 19
src/commands/showQuickCommitFileDetails.ts View File

@ -42,10 +42,7 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
super([Commands.ShowQuickCommitFileDetails, Commands.ShowQuickRevisionDetails]);
}
protected async preExecute(
context: CommandContext,
args: ShowQuickCommitFileDetailsCommandArgs = {}
): Promise<any> {
protected async preExecute(context: CommandContext, args: ShowQuickCommitFileDetailsCommandArgs = {}) {
if (context.command === Commands.ShowQuickRevisionDetails && context.editor !== undefined) {
args = { ...args };
@ -99,7 +96,7 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
catch (ex) {
Logger.error(ex, 'ShowQuickCommitFileDetailsCommand', `getBlameForLine(${blameline})`);
return window.showErrorMessage(
`Unable to show commit file details. See output channel for more details`
'Unable to show commit file details. See output channel for more details'
);
}
}
@ -119,19 +116,16 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
}
if (args.fileLog === undefined) {
args.commit = await Container.git.getLogCommitForFile(
args.commit === undefined ? gitUri.repoPath : args.commit.repoPath,
gitUri.fsPath,
{ ref: args.sha }
);
const repoPath = args.commit === undefined ? gitUri.repoPath : args.commit.repoPath;
args.commit = await Container.git.getLogCommitForFile(repoPath, gitUri.fsPath, { ref: args.sha });
if (args.commit === undefined) {
return Messages.showCommitNotFoundWarningMessage(`Unable to show commit file details`);
return Messages.showCommitNotFoundWarningMessage('Unable to show commit file details');
}
}
}
if (args.commit === undefined) {
return Messages.showCommitNotFoundWarningMessage(`Unable to show commit file details`);
return Messages.showCommitNotFoundWarningMessage('Unable to show commit file details');
}
// Attempt to the most recent commit -- so that we can find the real working filename if there was a rename
@ -141,6 +135,11 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
const shortSha = GitService.shortenSha(args.sha!);
if (args.goBackCommand === undefined) {
const commandArgs: ShowQuickCommitDetailsCommandArgs = {
commit: args.commit,
sha: args.sha
};
// Create a command to get back to the commit details
args.goBackCommand = new CommandQuickPickItem(
{
@ -150,13 +149,7 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
}$(git-commit) ${shortSha}`
},
Commands.ShowQuickCommitDetails,
[
args.commit.toGitUri(),
{
commit: args.commit,
sha: args.sha
} as ShowQuickCommitDetailsCommandArgs
]
[args.commit.toGitUri(), commandArgs]
);
}

+ 3
- 2
src/commands/showQuickCurrentBranchHistory.ts View File

@ -32,11 +32,12 @@ export class ShowQuickCurrentBranchHistoryCommand extends ActiveEditorCachedComm
const branch = await Container.git.getBranch(repoPath);
if (branch === undefined) return undefined;
return commands.executeCommand(Commands.ShowQuickBranchHistory, uri, {
const commandArgs: ShowQuickBranchHistoryCommandArgs = {
branch: branch.name,
repoPath: repoPath,
goBackCommand: args.goBackCommand
} as ShowQuickBranchHistoryCommandArgs);
};
return commands.executeCommand(Commands.ShowQuickBranchHistory, uri, commandArgs);
}
catch (ex) {
Logger.error(ex, 'ShowQuickCurrentBranchHistoryCommand');

+ 18
- 16
src/commands/showQuickFileHistory.ts View File

@ -33,7 +33,7 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
super([Commands.ShowFileHistoryInView, Commands.ShowQuickFileHistory]);
}
protected async preExecute(context: CommandContext, args: ShowQuickFileHistoryCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: ShowQuickFileHistoryCommandArgs = {}) {
if (context.command === Commands.ShowFileHistoryInView) {
args = { ...args };
args.showInView = true;
@ -84,29 +84,29 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
if (args.log.truncated) {
let commandArgs: ShowQuickFileHistoryCommandArgs;
commandArgs = { ...args, log: undefined };
const npc = new CommandQuickPickItem(
{
label: `$(arrow-right) Show Next Commits`,
label: '$(arrow-right) Show Next Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${args.log.maxCount} newer commits`
},
Commands.ShowQuickFileHistory,
[gitUri, { ...argsclass="p">, log: undefined } as ShowQuickFileHistoryCommandArgs]
[gitUri, commandArgs]
);
const last = Iterables.last(args.log.commits.values());
if (last != null) {
commandArgs = { ...args, log: undefined, nextPageCommand: npc };
previousPageCommand = new CommandQuickPickItem(
{
label: `$(arrow-left) Show Previous Commits`,
label: '$(arrow-left) Show Previous Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${
args.log.maxCount
} older commits`
},
Commands.ShowQuickFileHistory,
[
new GitUri(uri, last),
{ ...args, log: undefined, nextPageCommand: npc } as ShowQuickFileHistoryCommandArgs
]
[new GitUri(uri, last), commandArgs]
);
}
}
@ -141,7 +141,7 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
args.log !== undefined && args.log.truncated
? new CommandQuickPickItem(
{
label: `$(sync) Show All Commits`,
label: '$(sync) Show All Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} this may take a while`
},
Commands.ShowQuickFileHistory,
@ -163,23 +163,25 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
if (branchOrTag === undefined) return undefined;
if (branchOrTag instanceof CommandQuickPickItem) return branchOrTag.execute();
return commands.executeCommand(Commands.ShowQuickFileHistory, gitUri, {
const commandArgs: ShowQuickFileHistoryCommandArgs = {
...args,
log: undefined,
branchOrTag: branchOrTag.item,
goBackCommand: currentCommand
} as ShowQuickFileHistoryCommandArgs);
}
else {
if (pick instanceof CommandQuickPickItem) return pick.execute();
};
return commands.executeCommand(Commands.ShowQuickFileHistory, gitUri, commandArgs);
}
return commands.executeCommand(Commands.ShowQuickCommitFileDetails, pick.commit.toGitUri(), {
if (pick instanceof CommandQuickPickItem) return pick.execute();
const commandArgs: ShowQuickCommitFileDetailsCommandArgs = {
commit: pick.commit,
fileLog: args.log,
sha: pick.commit.sha,
goBackCommand: currentCommand
} as ShowQuickCommitFileDetailsCommandArgs);
};
return commands.executeCommand(Commands.ShowQuickCommitFileDetails, pick.commit.toGitUri(), commandArgs);
}
catch (ex) {
Logger.error(ex, 'ShowQuickFileHistoryCommand');

+ 1
- 1
src/commands/showQuickRepoStatus.ts View File

@ -29,7 +29,7 @@ export class ShowQuickRepoStatusCommand extends ActiveEditorCachedCommand {
if (!repoPath) return undefined;
const status = await Container.git.getStatusForRepo(repoPath);
if (status === undefined) return window.showWarningMessage(`Unable to show repository status`);
if (status === undefined) return window.showWarningMessage('Unable to show repository status');
const pick = await RepoStatusQuickPick.show(status, args.goBackCommand);
if (pick === undefined) return undefined;

+ 8
- 9
src/commands/showQuickStashList.ts View File

@ -33,23 +33,21 @@ export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
if (!repoPath) return undefined;
const stash = await Container.git.getStashList(repoPath);
if (stash === undefined) return window.showWarningMessage(`Unable to show stashed changes`);
if (stash === undefined) return window.showWarningMessage('Unable to show stashed changes');
if (progressCancellation.token.isCancellationRequested) return undefined;
// Create a command to get back to here
const currentCommandArgs: ShowQuickStashListCommandArgs = {
goBackCommand: args.goBackCommand
};
const currentCommand = new CommandQuickPickItem(
{
label: `go back ${GlyphChars.ArrowBack}`,
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} to stashed changes`
},
Commands.ShowQuickStashList,
[
uri,
{
goBackCommand: args.goBackCommand
} as ShowQuickStashListCommandArgs
]
[uri, currentCommandArgs]
);
const pick = await StashListQuickPick.show(
@ -63,11 +61,12 @@ export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
if (pick instanceof CommandQuickPickItem) return pick.execute();
return commands.executeCommand(Commands.ShowQuickCommitDetails, pick.commit.toGitUri(), {
const commandArgs: ShowQuickCommitDetailsCommandArgs = {
commit: pick.commit,
sha: pick.commit.sha,
goBackCommand: currentCommand
} as ShowQuickCommitDetailsCommandArgs);
};
return commands.executeCommand(Commands.ShowQuickCommitDetails, pick.commit.toGitUri(), commandArgs);
}
catch (ex) {
Logger.error(ex, 'ShowQuickStashListCommand');

+ 2
- 2
src/commands/showView.ts View File

@ -14,7 +14,7 @@ export class ShowViewCommand extends Command {
]);
}
protected async preExecute(context: CommandContext): Promise<any> {
protected preExecute(context: CommandContext) {
return this.execute(context.command as Commands);
}
@ -32,6 +32,6 @@ export class ShowViewCommand extends Command {
return Container.searchView.show();
}
return undefined;
return Promise.resolve(undefined);
}
}

+ 13
- 17
src/commands/stashApply.ts View File

@ -1,5 +1,5 @@
'use strict';
import { MessageItem, window } from 'vscode';
import { window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitStashCommit } from '../git/gitService';
@ -32,10 +32,7 @@ export class StashApplyCommand extends Command {
super(Commands.StashApply);
}
protected async preExecute(
context: CommandContext,
args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }
) {
protected preExecute(context: CommandContext, args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
if (isCommandViewContextWithCommit<GitStashCommit>(context)) {
args = { ...args };
args.stashItem = context.node.commit;
@ -66,7 +63,7 @@ export class StashApplyCommand extends Command {
try {
const stash = await Container.git.getStashList(args.repoPath);
if (stash === undefined) return window.showInformationMessage(`There are no stashed changes`);
if (stash === undefined) return window.showInformationMessage('There are no stashed changes');
if (progressCancellation.token.isCancellationRequested) return undefined;
@ -92,7 +89,7 @@ export class StashApplyCommand extends Command {
}
args.goBackCommand = currentCommand;
args.stashItem = pick.commit as GitStashCommit;
args.stashItem = pick.commit;
}
finally {
progressCancellation.cancel();
@ -107,9 +104,9 @@ export class StashApplyCommand extends Command {
: args.stashItem.message;
const result = await window.showWarningMessage(
`Apply stashed changes '${message}' to your working tree?`,
{ title: 'Yes, delete after applying' } as MessageItem,
{ title: 'Yes' } as MessageItem,
{ title: 'No', isCloseAffordance: true } as MessageItem
{ title: 'Yes, delete after applying' },
{ title: 'Yes' },
{ title: 'No', isCloseAffordance: true }
);
if (result === undefined || result.title === 'No') {
return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
@ -124,17 +121,16 @@ export class StashApplyCommand extends Command {
Logger.error(ex, 'StashApplyCommand');
if (ex.message.includes('Your local changes to the following files would be overwritten by merge')) {
return window.showWarningMessage(
`Unable to apply stash. Your working tree changes would be overwritten.`
'Unable to apply stash. Your working tree changes would be overwritten.'
);
}
else if (ex.message.includes('Auto-merging') && ex.message.includes('CONFLICT')) {
return window.showInformationMessage(`Stash applied with conflicts`);
}
else {
return Messages.showGenericErrorMessage(
`Unable to apply stash \u2014 ${ex.message.trim().replace(/\n+?/g, '; ')}`
);
return window.showInformationMessage('Stash applied with conflicts');
}
return Messages.showGenericErrorMessage(
`Unable to apply stash \u2014 ${ex.message.trim().replace(/\n+?/g, '; ')}`
);
}
}
}

+ 4
- 4
src/commands/stashDelete.ts View File

@ -1,5 +1,5 @@
'use strict';
import { MessageItem, window } from 'vscode';
import { window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitStashCommit } from '../git/gitService';
@ -21,7 +21,7 @@ export class StashDeleteCommand extends Command {
super(Commands.StashDelete);
}
protected async preExecute(context: CommandContext, args: StashDeleteCommandArgs = { confirm: true }) {
protected preExecute(context: CommandContext, args: StashDeleteCommandArgs = { confirm: true }) {
if (isCommandViewContextWithCommit<GitStashCommit>(context)) {
args = { ...args };
args.stashItem = context.node.commit;
@ -53,8 +53,8 @@ export class StashDeleteCommand extends Command {
: args.stashItem.message;
const result = await window.showWarningMessage(
`Delete stashed changes '${message}'?`,
{ title: 'Yes' } as MessageItem,
{ title: 'No', isCloseAffordance: true } as MessageItem
{ title: 'Yes' },
{ title: 'No', isCloseAffordance: true }
);
if (result === undefined || result.title !== 'Yes') {
return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();

+ 5
- 5
src/commands/stashSave.ts View File

@ -1,5 +1,5 @@
'use strict';
import { InputBoxOptions, Uri, window } from 'vscode';
import { Uri, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitUri';
@ -31,7 +31,7 @@ export class StashSaveCommand extends Command {
super([Commands.StashSave, Commands.StashSaveFiles]);
}
protected async preExecute(context: CommandContext, args: StashSaveCommandArgs = {}): Promise<any> {
protected preExecute(context: CommandContext, args: StashSaveCommandArgs = {}) {
if (isCommandViewContextWithFile(context)) {
args = { ...args };
args.uris = [GitUri.fromFile(context.node.file, context.node.file.repoPath || context.node.repoPath)];
@ -75,9 +75,9 @@ export class StashSaveCommand extends Command {
try {
if (args.message == null) {
args.message = await window.showInputBox({
prompt: `Please provide a stash message`,
placeHolder: `Stash message`
} as InputBoxOptions);
prompt: 'Please provide a stash message',
placeHolder: 'Stash message'
});
if (args.message === undefined) {
return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
}

+ 1
- 1
src/commands/supportGitLens.ts View File

@ -8,7 +8,7 @@ export class SupportGitLensCommand extends Command {
super(Commands.SupportGitLens);
}
async execute() {
execute() {
return Messages.showSupportGitLensMessage();
}
}

+ 2
- 2
src/commands/toggleLineBlame.ts View File

@ -10,14 +10,14 @@ export class ToggleLineBlameCommand extends ActiveEditorCommand {
super(Commands.ToggleLineBlame);
}
async execute(editor: TextEditor, uri?: Uri): Promise<any> {
execute(editor: TextEditor, uri?: Uri) {
try {
return Container.lineAnnotations.toggle(editor);
}
catch (ex) {
Logger.error(ex, 'ToggleLineBlameCommand');
return window.showErrorMessage(
`Unable to toggle line blame annotations. See output channel for more details`
'Unable to toggle line blame annotations. See output channel for more details'
);
}
}

+ 9
- 8
src/configuration.ts View File

@ -14,8 +14,9 @@ import { Config } from './config';
import { extensionId } from './constants';
import { Functions } from './system';
const emptyConfig: any = new Proxy<any>({} as Config, {
get(target, propKey, receiver) {
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
const emptyConfig: Config = new Proxy<Config>({} as Config, {
get: function() {
return emptyConfig;
}
});
@ -230,22 +231,22 @@ export class Configuration {
async updateEffective(section: string, value: any, resource: Uri | null = null) {
const inspect = await configuration.inspect(section, resource)!;
if (inspect.workspaceFolderValue !== undefined) {
if (value === inspect.workspaceFolderValue) return;
if (value === inspect.workspaceFolderValue) return undefined;
return await configuration.update(section, value, ConfigurationTarget.WorkspaceFolder, resource);
return void configuration.update(section, value, ConfigurationTarget.WorkspaceFolder, resource);
}
if (inspect.workspaceValue !== undefined) {
if (value === inspect.workspaceValue) return;
if (value === inspect.workspaceValue) return undefined;
return await configuration.update(section, value, ConfigurationTarget.Workspace);
return void configuration.update(section, value, ConfigurationTarget.Workspace);
}
if (inspect.globalValue === value || (inspect.globalValue === undefined && value === inspect.defaultValue)) {
return;
return undefined;
}
return await configuration.update(
return void configuration.update(
section,
value === inspect.defaultValue ? undefined : value,
ConfigurationTarget.Global

+ 10
- 9
src/container.ts View File

@ -6,8 +6,7 @@ import { GitCodeLensController } from './codelens/codeLensController';
import { Commands, ToggleFileBlameCommandArgs } from './commands';
import { AnnotationsToggleMode, Config, configuration, ConfigurationWillChangeEvent } from './configuration';
import { GitFileSystemProvider } from './git/fsProvider';
import { GitService } from './git/gitService';
import { clearGravatarCache } from './git/gitService';
import { clearGravatarCache, GitService } from './git/gitService';
import { LineHoverController } from './hovers/lineHoverController';
import { Keyboard } from './keyboard';
import { Logger, TraceLevel } from './logger';
@ -57,6 +56,7 @@ export class Container {
}
else {
let disposable: Disposable;
// eslint-disable-next-line prefer-const
disposable = configuration.onDidChange(e => {
if (configuration.changed(e, configuration.name('views')('compare')('enabled').value)) {
disposable.dispose();
@ -70,6 +70,7 @@ export class Container {
}
else {
let disposable: Disposable;
// eslint-disable-next-line prefer-const
disposable = configuration.onDidChange(e => {
if (configuration.changed(e, configuration.name('views')('fileHistory')('enabled').value)) {
disposable.dispose();
@ -83,6 +84,7 @@ export class Container {
}
else {
let disposable: Disposable;
// eslint-disable-next-line prefer-const
disposable = configuration.onDidChange(e => {
if (configuration.changed(e, configuration.name('views')('lineHistory')('enabled').value)) {
disposable.dispose();
@ -96,6 +98,7 @@ export class Container {
}
else {
let disposable: Disposable;
// eslint-disable-next-line prefer-const
disposable = configuration.onDidChange(e => {
if (configuration.changed(e, configuration.name('views')('repositories')('enabled').value)) {
disposable.dispose();
@ -109,6 +112,7 @@ export class Container {
}
else {
let disposable: Disposable;
// eslint-disable-next-line prefer-const
disposable = configuration.onDidChange(e => {
if (configuration.changed(e, configuration.name('views')('search')('enabled').value)) {
disposable.dispose();
@ -290,14 +294,11 @@ export class Container {
}
if (command !== undefined) {
const commandArgs: ToggleFileBlameCommandArgs = {
on: true
};
// Make sure to delay the execution by a bit so that the configuration changes get propegated first
setTimeout(
() =>
commands.executeCommand(command!, {
on: true
} as ToggleFileBlameCommandArgs),
50
);
setTimeout(() => commands.executeCommand(command!, commandArgs), 50);
}
}

emoji/emojis.json → src/emojis.json View File


+ 5
- 3
src/extension.ts View File

@ -60,7 +60,7 @@ export async function activate(context: ExtensionContext) {
if (ex.message.includes('Unable to find git')) {
await window.showErrorMessage(
`GitLens was unable to find Git. Please make sure Git is installed. Also ensure that Git is either in the PATH, or that 'git.path' is pointed to its installed location.`
"GitLens was unable to find Git. Please make sure Git is installed. Also ensure that Git is either in the PATH, or that 'git.path' is pointed to its installed location."
);
}
@ -91,7 +91,9 @@ export async function activate(context: ExtensionContext) {
Logger.log(`GitLens(v${gitlensVersion}) activated ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
}
export function deactivate() {}
export function deactivate() {
// nothing to do
}
async function migrateSettings(context: ExtensionContext, previousVersion: string | undefined) {
if (previousVersion === undefined) return;
@ -271,7 +273,7 @@ function notifyOnUnsupportedGitVersion(version: string) {
async function showWelcomePage(version: string, previousVersion: string | undefined) {
if (previousVersion === undefined) {
Logger.log(`GitLens first-time install`);
Logger.log('GitLens first-time install');
if (Container.config.showWhatsNewAfterUpgrades) {
await commands.executeCommand(Commands.ShowWelcomePage);

+ 38
- 36
src/git/formatters/commitFormatter.ts View File

@ -13,16 +13,18 @@ import { Strings } from '../../system';
import { GitUri } from '../gitUri';
import { GitCommit, GitCommitType } from '../models/commit';
import { GitLogCommit, GitRemote } from '../models/models';
import { Formatter, IFormatOptions } from './formatter';
import { FormatOptions, Formatter } from './formatter';
import * as emojis from '../../emojis.json';
const emojiMap: { [key: string]: string } = require('../../../emoji/emojis.json');
const emptyStr = '';
const emojiMap: { [key: string]: string } = emojis;
const emojiRegex = /:([-+_a-z0-9]+):/g;
const escapeMarkdownRegex = /[`\>\#\*\_\-\+\.]/g;
const escapeMarkdownRegex = /[`>#*_\-+.]/g;
// const sampleMarkdown = '## message `not code` *not important* _no underline_ \n> don\'t quote me \n- don\'t list me \n+ don\'t list me \n1. don\'t list me \nnot h1 \n=== \nnot h2 \n---\n***\n---\n___';
const markdownHeaderReplacement = `${GlyphChars.ZeroWidthSpace}===`;
export interface ICommitFormatOptions extends IFormatOptions {
export interface CommitFormatOptions extends FormatOptions {
annotationType?: FileAnnotationType;
dateStyle?: DateStyle;
line?: number;
@ -31,27 +33,27 @@ export interface ICommitFormatOptions extends IFormatOptions {
truncateMessageAtNewLine?: boolean;
tokenOptions?: {
ago?: Strings.ITokenOptions;
agoOrDate?: Strings.ITokenOptions;
author?: Strings.ITokenOptions;
authorAgo?: Strings.ITokenOptions;
authorAgoOrDate?: Strings.ITokenOptions;
changes?: Strings.ITokenOptions;
changesShort?: Strings.ITokenOptions;
date?: Strings.ITokenOptions;
email?: Strings.ITokenOptions;
id?: Strings.ITokenOptions;
message?: Strings.ITokenOptions;
ago?: Strings.TokenOptions;
agoOrDate?: Strings.TokenOptions;
author?: Strings.TokenOptions;
authorAgo?: Strings.TokenOptions;
authorAgoOrDate?: Strings.TokenOptions;
changes?: Strings.TokenOptions;
changesShort?: Strings.TokenOptions;
date?: Strings.TokenOptions;
email?: Strings.TokenOptions;
id?: Strings.TokenOptions;
message?: Strings.TokenOptions;
};
}
export class CommitFormatter extends Formatter<GitCommit, ICommitFormatOptions> {
export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> {
private get _ago() {
return this._item.fromNow();
}
private get _date() {
return this._item.formatDate(this._options.dateFormat!);
return this._item.formatDate(this._options.dateFormat);
}
private get _agoOrDate() {
@ -61,30 +63,30 @@ export class CommitFormatter extends Formatter
}
get ago() {
return this._padOrTruncate(this._ago, this._options.tokenOptions!.ago);
return this._padOrTruncate(this._ago, this._options.tokenOptions.ago);
}
get agoOrDate() {
return this._padOrTruncate(this._agoOrDate, this._options.tokenOptions!.agoOrDate);
return this._padOrTruncate(this._agoOrDate, this._options.tokenOptions.agoOrDate);
}
get author() {
return this._padOrTruncate(this._item.author, this._options.tokenOptions!.author);
return this._padOrTruncate(this._item.author, this._options.tokenOptions.author);
}
get authorAgo() {
const authorAgo = `${this._item.author}, ${this._ago}`;
return this._padOrTruncate(authorAgo, this._options.tokenOptions!.authorAgo);
return this._padOrTruncate(authorAgo, this._options.tokenOptions.authorAgo);
}
get authorAgoOrDate() {
const authorAgo = `${this._item.author}, ${this._agoOrDate}`;
return this._padOrTruncate(authorAgo, this._options.tokenOptions!.authorAgoOrDate);
return this._padOrTruncate(authorAgo, this._options.tokenOptions.authorAgoOrDate);
}
get avatar() {
if (!this._options.markdown || !Container.config.hovers.avatars) {
return '';
return emptyStr;
}
return `![](${this._item.getGravatarUri(Container.config.defaultGravatarsStyle).toString(true)})`;
@ -92,20 +94,20 @@ export class CommitFormatter extends Formatter
get changes() {
if (!(this._item instanceof GitLogCommit) || this._item.type === GitCommitType.File) {
return this._padOrTruncate('', this._options.tokenOptions!.changes);
return this._padOrTruncate(emptyStr, this._options.tokenOptions.changes);
}
return this._padOrTruncate(this._item.getFormattedDiffStatus(), this._options.tokenOptions!.changes);
return this._padOrTruncate(this._item.getFormattedDiffStatus(), this._options.tokenOptions.changes);
}
get changesShort() {
if (!(this._item instanceof GitLogCommit) || this._item.type === GitCommitType.File) {
return this._padOrTruncate('', this._options.tokenOptions!.changesShort);
return this._padOrTruncate(emptyStr, this._options.tokenOptions.changesShort);
}
return this._padOrTruncate(
this._item.getFormattedDiffStatus({ compact: true, separator: '' }),
this._options.tokenOptions!.changesShort
this._item.getFormattedDiffStatus({ compact: true, separator: emptyStr }),
this._options.tokenOptions.changesShort
);
}
@ -113,7 +115,7 @@ export class CommitFormatter extends Formatter
if (this._item.isUncommitted) {
return `\`${
this._item.shortSha === 'Working Tree'
? this._padOrTruncate('00000000', this._options.tokenOptions!.id)
? this._padOrTruncate('00000000', this._options.tokenOptions.id)
: this.id
}\``;
}
@ -156,15 +158,15 @@ export class CommitFormatter extends Formatter
}
get date() {
return this._padOrTruncate(this._date, this._options.tokenOptions!.date);
return this._padOrTruncate(this._date, this._options.tokenOptions.date);
}
get email() {
return this._padOrTruncate(this._item.email || '', this._options.tokenOptions!.email);
return this._padOrTruncate(this._item.email || emptyStr, this._options.tokenOptions.email);
}
get id() {
return this._padOrTruncate(this._item.shortSha || '', this._options.tokenOptions!.id);
return this._padOrTruncate(this._item.shortSha || emptyStr, this._options.tokenOptions.id);
}
get message() {
@ -190,7 +192,7 @@ export class CommitFormatter extends Formatter
message = message.replace(emojiRegex, (s, code) => emojiMap[code] || s);
}
message = this._padOrTruncate(message, this._options.tokenOptions!.message);
message = this._padOrTruncate(message, this._options.tokenOptions.message);
if (!this._options.markdown) {
return message;
@ -225,16 +227,16 @@ export class CommitFormatter extends Formatter
}
static fromTemplate(template: string, commit: GitCommit, dateFormat: string | null): string;
static fromTemplate(template: string, commit: GitCommit, options?: ICommitFormatOptions): string;
static fromTemplate(template: string, commit: GitCommit, options?: CommitFormatOptions): string;
static fromTemplate(
template: string,
commit: GitCommit,
dateFormatOrOptions?: string | null | ICommitFormatOptions
dateFormatOrOptions?: string | null | CommitFormatOptions
): string;
static fromTemplate(
template: string,
commit: GitCommit,
dateFormatOrOptions?: string | null | ICommitFormatOptions
dateFormatOrOptions?: string | null | CommitFormatOptions
): string {
return super.fromTemplateCore(this, template, commit, dateFormatOrOptions);
}

+ 20
- 15
src/git/formatters/formatter.ts View File

@ -1,18 +1,22 @@
'use strict';
import { Strings } from '../../system';
export interface IFormatOptions {
const emptyStr = '';
export interface FormatOptions {
dateFormat?: string | null;
tokenOptions?: { [id: string]: Strings.ITokenOptions | undefined };
tokenOptions?: { [id: string]: Strings.TokenOptions | undefined };
}
type Constructor<T = {}> = new (...args: any[]) => T;
const spaceReplacementRegex = / /g;
export abstract class Formatter<TItem = any, TOptions extends IFormatOptions = IFormatOptions> {
declare type RequiredTokenOptions<TOptions extends FormatOptions> = TOptions & Required<Pick<TOptions, 'tokenOptions'>>;
export abstract class Formatter<TItem = any, TOptions extends FormatOptions = FormatOptions> {
protected _item!: TItem;
protected _options!: TOptions;
protected _options!: RequiredTokenOptions<TOptions>;
constructor(item: TItem, options?: TOptions) {
this.reset(item, options);
@ -24,6 +28,7 @@ export abstract class Formatter
if (options === undefined && this._options !== undefined) return;
if (options === undefined) {
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
options = {} as TOptions;
}
@ -35,12 +40,12 @@ export abstract class Formatter
options.tokenOptions = {};
}
this._options = options;
this._options = options as RequiredTokenOptions<TOptions>;
}
private collapsableWhitespace: number = 0;
protected _padOrTruncate(s: string, options: Strings.ITokenOptions | undefined) {
protected _padOrTruncate(s: string, options: Strings.TokenOptions | undefined) {
if (s == null || s.length === 0) return s;
// NOTE: the collapsable whitespace logic relies on the javascript template evaluation to be left to right
@ -85,7 +90,7 @@ export abstract class Formatter
}
if (options.prefix || options.suffix) {
s = `${options.prefix || ''}${s}${options.suffix || ''}`;
s = `${options.prefix || emptyStr}${s}${options.suffix || emptyStr}`;
}
return s;
@ -96,7 +101,7 @@ export abstract class Formatter
protected static fromTemplateCore<
TFormatter extends Formatter<TItem, TOptions>,
TItem,
TOptions extends IFormatOptions
TOptions extends FormatOptions
>(
formatter: TFormatter | Constructor<TFormatter>,
template: string,
@ -109,6 +114,7 @@ export abstract class Formatter
let options: TOptions | undefined = undefined;
if (dateFormatOrOptions == null || typeof dateFormatOrOptions === 'string') {
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
options = {
dateFormat: dateFormatOrOptions
} as TOptions;
@ -118,13 +124,12 @@ export abstract class Formatter
}
if (options.tokenOptions == null) {
const tokenOptions = Strings.getTokensFromTemplate(template).reduce(
(map, token) => {
map[token.key] = token.options;
return map;
},
{} as { [token: string]: Strings.ITokenOptions | undefined }
);
const tokenOptions = Strings.getTokensFromTemplate(template).reduce<{
[token: string]: Strings.TokenOptions | undefined;
}>((map, token) => {
map[token.key] = token.options;
return map;
}, Object.create(null));
options.tokenOptions = tokenOptions;
}

+ 20
- 20
src/git/formatters/statusFormatter.ts View File

@ -3,52 +3,52 @@ import * as paths from 'path';
import { GlyphChars } from '../../constants';
import { Strings } from '../../system';
import { GitFile, GitFileWithCommit } from '../models/file';
import { Formatter, IFormatOptions } from './formatter';
import { FormatOptions, Formatter } from './formatter';
export interface IStatusFormatOptions extends IFormatOptions {
export interface StatusFormatOptions extends FormatOptions {
relativePath?: string;
tokenOptions?: {
directory?: Strings.ITokenOptions;
file?: Strings.ITokenOptions;
filePath?: Strings.ITokenOptions;
path?: Strings.ITokenOptions;
status?: Strings.ITokenOptions;
working?: Strings.ITokenOptions;
directory?: Strings.TokenOptions;
file?: Strings.TokenOptions;
filePath?: Strings.TokenOptions;
path?: Strings.TokenOptions;
status?: Strings.TokenOptions;
working?: Strings.TokenOptions;
};
}
export class StatusFileFormatter extends Formatter<GitFile, IStatusFormatOptions> {
export class StatusFileFormatter extends Formatter<GitFile, StatusFormatOptions> {
get directory() {
const directory = GitFile.getFormattedDirectory(this._item, false, this._options.relativePath);
return this._padOrTruncate(directory, this._options.tokenOptions!.directory);
return this._padOrTruncate(directory, this._options.tokenOptions.directory);
}
get file() {
const file = paths.basename(this._item.fileName);
return this._padOrTruncate(file, this._options.tokenOptions!.file);
return this._padOrTruncate(file, this._options.tokenOptions.file);
}
get filePath() {
const filePath = GitFile.getFormattedPath(this._item, { relativeTo: this._options.relativePath });
return this._padOrTruncate(filePath, this._options.tokenOptions!.filePath);
return this._padOrTruncate(filePath, this._options.tokenOptions.filePath);
}
get path() {
const directory = GitFile.getRelativePath(this._item, this._options.relativePath);
return this._padOrTruncate(directory, this._options.tokenOptions!.path);
return this._padOrTruncate(directory, this._options.tokenOptions.path);
}
get status() {
const status = GitFile.getStatusText(this._item.status);
return this._padOrTruncate(status, this._options.tokenOptions!.status);
return this._padOrTruncate(status, this._options.tokenOptions.status);
}
get working() {
const commit = (this._item as GitFileWithCommit).commit;
const statusFile = commit === undefined ? this._item : commit.files[0];
let icon = '';
let icon;
if (statusFile.workingTreeStatus !== undefined && statusFile.indexStatus !== undefined) {
icon = `${GlyphChars.Pencil}${GlyphChars.Space}${GlyphChars.SpaceThinnest}${GlyphChars.Check}`;
}
@ -63,20 +63,20 @@ export class StatusFileFormatter extends Formatter
else {
icon = '';
}
return this._padOrTruncate(icon, this._options.tokenOptions!.working);
return this._padOrTruncate(icon, this._options.tokenOptions.working);
}
static fromTemplate(template: string, file: GitFile, dateFormat: string | null): string;
static fromTemplate(template: string, file: GitFile, options?: IStatusFormatOptions): string;
static fromTemplate(template: string, file: GitFile | GitFileWithCommit, dateFormat: string | null): string;
static fromTemplate(template: string, file: GitFile | GitFileWithCommit, options?: StatusFormatOptions): string;
static fromTemplate(
template: string,
file: GitFile,
dateFormatOrOptions?: string | null | IStatusFormatOptions
dateFormatOrOptions?: string | null | StatusFormatOptions
): string;
static fromTemplate(
template: string,
file: GitFile,
dateFormatOrOptions?: string | null | IStatusFormatOptions
dateFormatOrOptions?: string | null | StatusFormatOptions
): string {
return super.fromTemplateCore(this, template, file, dateFormatOrOptions);
}

+ 10
- 9
src/git/fsProvider.ts View File

@ -17,6 +17,8 @@ import { Container } from '../container';
import { GitService, GitTree, GitUri } from '../git/gitService';
import { Iterables, Strings, TernarySearchTree } from '../system';
const emptyArray = new Uint8Array(0);
export function fromGitLensFSUri(uri: Uri): { path: string; ref: string; repoPath: string } {
const gitUri = uri instanceof GitUri ? uri : GitUri.fromRevisionUri(uri);
return { path: gitUri.getRelativePath(), ref: gitUri.sha!, repoPath: gitUri.repoPath! };
@ -26,8 +28,6 @@ export function toGitLensFSUri(ref: string, repoPath: string): Uri {
return GitUri.toRevisionUri(ref, repoPath, repoPath);
}
const emptyArray = new Uint8Array(0);
export class GitFileSystemProvider implements FileSystemProvider, Disposable {
private readonly _disposable: Disposable;
private readonly _searchTreeMap = new Map<string, Promise<TernarySearchTree<GitTree>>>();
@ -64,10 +64,7 @@ export class GitFileSystemProvider implements FileSystemProvider, Disposable {
const { path, ref, repoPath } = fromGitLensFSUri(uri);
const tree = await this.getTree(path, ref, repoPath);
if (tree === undefined) {
debugger;
throw FileSystemError.FileNotFound(uri);
}
if (tree === undefined) throw FileSystemError.FileNotFound(uri);
const items = [
...Iterables.map<GitTree, [string, FileType]>(tree, t => [
@ -141,7 +138,11 @@ export class GitFileSystemProvider implements FileSystemProvider, Disposable {
}
watch(): Disposable {
return { dispose: () => {} };
return {
dispose: () => {
// nothing to dispose
}
};
}
writeFile(): void | Thenable<void> {
@ -153,7 +154,7 @@ export class GitFileSystemProvider implements FileSystemProvider, Disposable {
const trees = await Container.git.getTreeForRevision(repoPath, ref);
// Add a fake root folder so that searches will work
searchTree.set(`~`, { commitSha: '', path: '~', size: 0, type: 'tree' });
searchTree.set('~', { commitSha: '', path: '~', size: 0, type: 'tree' });
for (const item of trees) {
searchTree.set(`~/${item.path}`, item);
}
@ -161,7 +162,7 @@ export class GitFileSystemProvider implements FileSystemProvider, Disposable {
return searchTree;
}
private async getOrCreateSearchTree(ref: string, repoPath: string) {
private getOrCreateSearchTree(ref: string, repoPath: string) {
let searchTree = this._searchTreeMap.get(ref);
if (searchTree === undefined) {
searchTree = this.createSearchTree(ref, repoPath);

+ 36
- 30
src/git/git.ts View File

@ -1,6 +1,7 @@
'use strict';
import * as iconv from 'iconv-lite';
/* eslint-disable @typescript-eslint/camelcase */
import * as paths from 'path';
import * as iconv from 'iconv-lite';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { Logger } from '../logger';
@ -13,6 +14,11 @@ export * from './models/models';
export * from './parsers/parsers';
export * from './remotes/provider';
const emptyArray = (Object.freeze([]) as any) as any[];
const emptyObj = Object.freeze({});
const emptyStr = '';
const slash = '/';
// This is a root sha of all git repo's if using sha1
const rootSha = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
@ -33,7 +39,7 @@ const logFormat = [
`${lb}c${rb}${sp}%ct`, // committed date
`${lb}p${rb}${sp}%P`, // parents
`${lb}s${rb}`,
`%B`, // summary
'%B', // summary
`${lb}${sl}s${rb}`,
`${lb}f${rb}`
].join('%n');
@ -47,7 +53,7 @@ const stashFormat = [
`${lb}c${rb}${sp}%ct`, // committed date
`${lb}l${rb}${sp}%gd`, // reflog-selector
`${lb}s${rb}`,
`%B`, // summary
'%B', // summary
`${lb}${sl}s${rb}`,
`${lb}f${rb}`
].join('%n');
@ -55,7 +61,7 @@ const stashFormat = [
const defaultStashParams = ['stash', 'list', '--name-status', '-M', `--format=${stashFormat}`];
const GitErrors = {
badRevision: /bad revision \'(.*?)\'/i,
badRevision: /bad revision '(.*?)'/i,
notAValidObjectName: /Not a valid object name/i
};
@ -64,16 +70,16 @@ const GitWarnings = {
outsideRepository: /is outside repository/i,
noPath: /no such path/i,
noCommits: /does not have any commits/i,
notFound: /Path \'.*?\' does not exist in/i,
foundButNotInRevision: /Path \'.*?\' exists on disk, but not in/i,
notFound: /Path '.*?' does not exist in/i,
foundButNotInRevision: /Path '.*?' exists on disk, but not in/i,
headNotABranch: /HEAD does not point to a branch/i,
noUpstream: /no upstream configured for branch \'(.*?)\'/i,
unknownRevision: /ambiguous argument \'.*?\': unknown revision or path not in the working tree|not stored as a remote-tracking branch/i,
noUpstream: /no upstream configured for branch '(.*?)'/i,
unknownRevision: /ambiguous argument '.*?': unknown revision or path not in the working tree|not stored as a remote-tracking branch/i,
mustRunInWorkTree: /this operation must be run in a work tree/i,
patchWithConflicts: /Applied patch to \'.*?\' with conflicts/i,
patchWithConflicts: /Applied patch to '.*?' with conflicts/i,
noRemoteRepositorySpecified: /No remote repository specified\./i,
remoteConnectionError: /Could not read from remote repository/i,
notAGitCommand: /\'.+\' is not a git command/i
notAGitCommand: /'.+' is not a git command/i
};
export enum GitErrorHandling {
@ -92,9 +98,6 @@ export interface GitCommandOptions extends RunOptions {
// A map of running git commands -- avoids running duplicate overlaping commands
const pendingCommands: Map<string, Promise<string | Buffer>> = new Map();
const emptyArray: any = [];
const emptyObj = {};
export async function git<TOut extends string | Buffer>(options: GitCommandOptions, ...args: any[]): Promise<TOut> {
if (Container.vsls.isMaybeGuest) {
if (options.local !== true) {
@ -105,7 +108,7 @@ export async function git(options: GitCommandOptio
}
else {
// Since we will have a live share path here, just blank it out
options.cwd = '';
options.cwd = emptyStr;
}
}
@ -114,7 +117,7 @@ export async function git(options: GitCommandOptio
const { configs, correlationKey, errors: errorHandling, ...opts } = options;
const encoding = options.encoding || 'utf8';
const runOpts = {
const runOpts: RunOptions = {
...opts,
encoding: encoding === 'utf8' ? 'utf8' : encoding === 'buffer' ? 'buffer' : 'binary',
// Adds GCM environment variables to avoid any possible credential issues -- from https://github.com/Microsoft/vscode/issues/26573#issuecomment-338686581
@ -126,11 +129,11 @@ export async function git(options: GitCommandOptio
GCM_PRESERVE_CREDS: 'TRUE',
LC_ALL: 'C'
}
} as RunOptions;
};
const gitCommand = `[${runOpts.cwd}] git ${args.join(' ')}`;
const command = `${correlationKey !== undefined ? `${correlationKey}:` : ''}${gitCommand}`;
const command = `${correlationKey !== undefined ? `${correlationKey}:` : emptyStr}${gitCommand}`;
let waiting;
let promise = pendingCommands.get(command);
@ -167,28 +170,31 @@ export async function git(options: GitCommandOptio
switch (errorHandling) {
case GitErrorHandling.Ignore:
exception = undefined;
return '' as TOut;
return emptyStr as TOut;
case GitErrorHandling.Throw:
throw ex;
default:
default: {
const result = defaultExceptionHandler(ex, options, ...args);
exception = undefined;
return result as TOut;
}
}
}
finally {
pendingCommands.delete(command);
const duration = `${Strings.getDurationMilliseconds(start)} ms ${waiting ? '(await) ' : ''}`;
const duration = `${Strings.getDurationMilliseconds(start)} ms ${waiting ? '(await) ' : emptyStr}`;
Logger.log(
`${gitCommand} ${GlyphChars.Dot} ${
exception !== undefined ? `FAILED(${(exception.message || '').trim().split('\n', 1)[0]}) ` : ''
exception !== undefined
? `FAILED(${(exception.message || emptyStr).trim().split('\n', 1)[0]}) `
: emptyStr
}${duration}`
);
Logger.logGitCommand(
`${gitCommand} ${GlyphChars.Dot} ${exception !== undefined ? 'FAILED ' : ''}${duration}`,
`${gitCommand} ${GlyphChars.Dot} ${exception !== undefined ? 'FAILED ' : emptyStr}${duration}`,
exception
);
}
@ -200,7 +206,7 @@ function defaultExceptionHandler(ex: Error, options: GitCommandOptions, ...args:
for (const warning of Objects.values(GitWarnings)) {
if (warning.test(msg)) {
Logger.warn('git', ...args, ` cwd='${options.cwd}'\n\n `, msg.replace(/\r?\n|\r/g, ' '));
return '';
return emptyStr;
}
}
}
@ -210,7 +216,7 @@ function defaultExceptionHandler(ex: Error, options: GitCommandOptions, ...args:
const [, ref] = match;
// Since looking up a ref with ^3 (e.g. looking for untracked files in a stash) can error on some versions of git just ignore it
if (ref != null && ref.endsWith('^3')) return '';
if (ref != null && ref.endsWith('^3')) return emptyStr;
}
Logger.error(ex, 'git', ...args, ` cwd='${options.cwd}'\n\n `);
@ -273,7 +279,7 @@ export class Git {
ref: string,
strings: { stagedUncommitted?: string; uncommitted?: string; working?: string } = {}
) {
strings = { stagedUncommitted: 'Index', uncommitted: 'Working Tree', working: '', ...strings };
strings = { stagedUncommitted: 'Index', uncommitted: 'Working Tree', working: emptyStr, ...strings };
if (ref == null || ref.length === 0) return strings.working;
if (Git.isUncommitted(ref)) {
@ -303,7 +309,7 @@ export class Git {
fileName = Strings.normalizePath(fileName);
repoPath = Strings.normalizePath(repoPath);
const normalizedRepoPath = (repoPath.endsWith('/') ? repoPath : `${repoPath}/`).toLowerCase();
const normalizedRepoPath = (repoPath.endsWith(slash) ? repoPath : `${repoPath}/`).toLowerCase();
if (fileName.toLowerCase().startsWith(normalizedRepoPath)) {
fileName = fileName.substring(normalizedRepoPath.length);
}
@ -330,7 +336,7 @@ export class Git {
static apply(repoPath: string | undefined, patch: string, options: { allowConflicts?: boolean } = {}) {
const params = ['apply', '--whitespace=warn'];
if (options.allowConflicts) {
params.push(`-3`);
params.push('-3');
}
return git<string>({ cwd: repoPath, stdin: patch }, ...params);
}
@ -372,7 +378,7 @@ export class Git {
return git<string>({ cwd: root, stdin: stdin }, ...params, '--', file);
}
static async blame_contents(
static blame_contents(
repoPath: string | undefined,
fileName: string,
contents: string,
@ -478,7 +484,7 @@ export class Git {
static async config_get(key: string, repoPath?: string, options: { local?: boolean } = {}) {
const data = await git<string>(
{ cwd: repoPath || '', errors: GitErrorHandling.Ignore, local: options.local },
{ cwd: repoPath || emptyStr, errors: GitErrorHandling.Ignore, local: options.local },
'config',
'--get',
key
@ -488,7 +494,7 @@ export class Git {
static async config_getRegex(pattern: string, repoPath?: string, options: { local?: boolean } = {}) {
const data = await git<string>(
{ cwd: repoPath || '', errors: GitErrorHandling.Ignore, local: options.local },
{ cwd: repoPath || emptyStr, errors: GitErrorHandling.Ignore, local: options.local },
'config',
'--get-regex',
pattern

+ 96
- 77
src/git/gitService.ts View File

@ -7,7 +7,6 @@ import {
Event,
EventEmitter,
extensions,
MessageItem,
ProgressLocation,
Range,
TextEditor,
@ -18,6 +17,7 @@ import {
WorkspaceFolder,
WorkspaceFoldersChangeEvent
} from 'vscode';
// eslint-disable-next-line import/no-unresolved
import { GitExtension } from '../@types/git';
import { configuration, RemotesConfig } from '../configuration';
import { CommandContext, DocumentSchemes, GlyphChars, setCommandContext } from '../constants';
@ -71,6 +71,9 @@ export * from './formatters/formatters';
export { getNameFromRemoteResource, RemoteProvider, RemoteResource, RemoteResourceType } from './remotes/provider';
export { RemoteProviderFactory } from './remotes/factory';
const emptyStr = '';
const slash = '/';
const RepoSearchWarnings = {
doesNotExist: /no such file or directory/i
};
@ -185,7 +188,7 @@ export class GitService implements Disposable {
e = {
added: workspace.workspaceFolders || [],
removed: []
} as WorkspaceFoldersChangeEvent;
};
Logger.log(`Starting repository search in ${e.added.length} folders`);
}
@ -300,22 +303,21 @@ export class GitService implements Disposable {
})
];
excludes = excludedPaths.reduce(
(accumulator, current) => {
accumulator[current] = true;
return accumulator;
},
Object.create(null) as any
);
excludes = excludedPaths.reduce((accumulator, current) => {
accumulator[current] = true;
return accumulator;
}, Object.create(null));
let repoPaths;
try {
repoPaths = await this.repositorySearchCore(uri.fsPath, depth, excludes);
}
catch (ex) {
if (RepoSearchWarnings.doesNotExist.test(ex.message || '')) {
if (RepoSearchWarnings.doesNotExist.test(ex.message || emptyStr)) {
Logger.log(
`Repository search (depth=${depth}) in '${uri.fsPath}' FAILED${ex.message ? `(${ex.message})` : ''}`
`Repository search (depth=${depth}) in '${uri.fsPath}' FAILED${
ex.message ? `(${ex.message})` : emptyStr
}`
);
}
else {
@ -346,7 +348,7 @@ export class GitService implements Disposable {
return repositories;
}
private async repositorySearchCore(
private repositorySearchCore(
root: string,
depth: number,
excludes: { [key: string]: boolean },
@ -369,7 +371,7 @@ export class GitService implements Disposable {
const promises = files.map(file => {
const path = paths.resolve(root, file);
return new Promise<void>((res, rej) => {
return new Promise<void>((resolve2, reject2) => {
fs.stat(path, (err, stat) => {
if (file === '.git') {
repositories.push(path);
@ -378,7 +380,7 @@ export class GitService implements Disposable {
folders.push(path);
}
res();
resolve2();
});
});
});
@ -460,9 +462,9 @@ export class GitService implements Disposable {
catch (ex) {
if (patch && /patch does not apply/i.test(ex.message)) {
const result = await window.showWarningMessage(
`Unable to apply changes cleanly. Retry and allow conflicts?`,
{ title: 'Yes' } as MessageItem,
{ title: 'No', isCloseAffordance: true } as MessageItem
'Unable to apply changes cleanly. Retry and allow conflicts?',
{ title: 'Yes' },
{ title: 'No', isCloseAffordance: true }
);
if (result === undefined || result.title !== 'Yes') return;
@ -473,13 +475,14 @@ export class GitService implements Disposable {
return;
}
catch (e) {
// eslint-disable-next-line no-ex-assign
ex = e;
}
}
}
Logger.error(ex);
void Messages.showGenericErrorMessage(`Unable to apply changes`);
void Messages.showGenericErrorMessage('Unable to apply changes');
}
}
@ -490,7 +493,7 @@ export class GitService implements Disposable {
@gate()
@log()
async fetch(repoPath: string, remote?: string) {
fetch(repoPath: string, remote?: string) {
return Git.fetch(repoPath, { remote: remote });
}
@ -503,7 +506,7 @@ export class GitService implements Disposable {
await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Fetching repositories`,
title: 'Fetching repositories',
cancellable: true
},
async (progress, token) => {
@ -531,7 +534,7 @@ export class GitService implements Disposable {
await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Pulling repositories`,
title: 'Pulling repositories',
cancellable: true
},
async (progress, token) => {
@ -559,7 +562,7 @@ export class GitService implements Disposable {
await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Pushing repositories`,
title: 'Pushing repositories',
cancellable: true
},
async (progress, token) => {
@ -646,7 +649,7 @@ export class GitService implements Disposable {
return (await this.fileExists(repoPath, fileName, { ensureCase: true }))
? fileName
: await this.findNextFileNameCore(repoPath, fileName, ref);
: this.findNextFileNameCore(repoPath, fileName, ref);
}
private async findNextFileNameCore(repoPath: string, fileName: string, ref?: string): Promise<string | undefined> {
@ -770,9 +773,10 @@ export class GitService implements Disposable {
if (doc.state !== undefined) {
Logger.debug(cc, `Cache add: '${key}'`);
doc.state.set<CachedBlame>(key, {
item: promise
} as CachedBlame);
const value: CachedBlame = {
item: promise as Promise<GitBlame>
};
doc.state.set<CachedBlame>(key, value);
}
return promise;
@ -805,10 +809,11 @@ export class GitService implements Disposable {
const msg = ex && ex.toString();
Logger.debug(cc, `Cache replace (with empty promise): '${key}'`);
document.state.set<CachedBlame>(key, {
item: GitService.emptyPromise,
const value: CachedBlame = {
item: GitService.emptyPromise as Promise<GitBlame>,
errorMessage: msg
} as CachedBlame);
};
document.state.set<CachedBlame>(key, value);
document.setBlameFailure();
@ -851,9 +856,10 @@ export class GitService implements Disposable {
if (doc.state !== undefined) {
Logger.debug(cc, `Cache add: '${key}'`);
doc.state.set<CachedBlame>(key, {
item: promise
} as CachedBlame);
const value: CachedBlame = {
item: promise as Promise<GitBlame>
};
doc.state.set<CachedBlame>(key, value);
}
return promise;
@ -888,10 +894,11 @@ export class GitService implements Disposable {
const msg = ex && ex.toString();
Logger.debug(cc, `Cache replace (with empty promise): '${key}'`);
document.state.set<CachedBlame>(key, {
item: GitService.emptyPromise,
const value: CachedBlame = {
item: GitService.emptyPromise as Promise<GitBlame>,
errorMessage: msg
} as CachedBlame);
};
document.state.set<CachedBlame>(key, value);
document.setBlameFailure();
return GitService.emptyPromise as Promise<GitBlame>;
@ -920,11 +927,12 @@ export class GitService implements Disposable {
const commit = blame.commits.get(blameLine.sha);
if (commit === undefined) return undefined;
const author = blame.authors.get(commit.author)!;
return {
author: { ...blame.authors.get(commit.author), lineCount: commit.lines.length },
author: { ...author, lineCount: commit.lines.length },
commit: commit,
line: blameLine
} as GitBlameLine;
};
}
const lineToBlame = line + 1;
@ -944,7 +952,7 @@ export class GitService implements Disposable {
author: Iterables.first(blame.authors.values()),
commit: Iterables.first(blame.commits.values()),
line: blame.lines[line]
} as GitBlameLine;
};
}
catch {
return undefined;
@ -975,11 +983,12 @@ export class GitService implements Disposable {
const commit = blame.commits.get(blameLine.sha);
if (commit === undefined) return undefined;
const author = blame.authors.get(commit.author)!;
return {
author: { ...blame.authors.get(commit.author), lineCount: commit.lines.length },
author: { ...author, lineCount: commit.lines.length },
commit: commit,
line: blameLine
} as GitBlameLine;
};
}
const lineToBlame = line + 1;
@ -1000,7 +1009,7 @@ export class GitService implements Disposable {
author: Iterables.first(blame.authors.values()),
commit: Iterables.first(blame.commits.values()),
line: blame.lines[line]
} as GitBlameLine;
};
}
catch {
return undefined;
@ -1053,11 +1062,12 @@ export class GitService implements Disposable {
const sortedAuthors = new Map([...authors.entries()].sort((a, b) => b[1].lineCount - a[1].lineCount));
return {
repoPath: uri.repoPath!,
authors: sortedAuthors,
commits: commits,
lines: lines,
allLines: blame.lines
} as GitBlameLines;
};
}
@log()
@ -1102,8 +1112,8 @@ export class GitService implements Disposable {
}
@log()
async getConfig(key: string, repoPath?: string): Promise<string | undefined> {
return await Git.config_get(key, repoPath);
getConfig(key: string, repoPath?: string): Promise<string | undefined> {
return Git.config_get(key, repoPath);
}
@log()
@ -1122,13 +1132,16 @@ export class GitService implements Disposable {
user = { name: undefined, email: undefined };
let key: string;
let value: string;
let match: RegExpExecArray | null = null;
do {
match = userConfigRegex.exec(data);
if (match == null) break;
[, key, value] = match;
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
user[match[1] as 'name' | 'email'] = (' ' + match[2]).substr(1);
user[key as 'name' | 'email'] = ` ${value}`.substr(1);
} while (match != null);
const author = `${user.name} <${user.email}>`;
@ -1192,9 +1205,10 @@ export class GitService implements Disposable {
if (doc.state !== undefined) {
Logger.debug(cc, `Cache add: '${key}'`);
doc.state.set<CachedDiff>(key, {
item: promise
} as CachedDiff);
const value: CachedDiff = {
item: promise as Promise<GitDiff>
};
doc.state.set<CachedDiff>(key, value);
}
return promise;
@ -1223,10 +1237,11 @@ export class GitService implements Disposable {
const msg = ex && ex.toString();
Logger.debug(cc, `Cache replace (with empty promise): '${key}'`);
document.state.set<CachedDiff>(key, {
item: GitService.emptyPromise,
const value: CachedDiff = {
item: GitService.emptyPromise as Promise<GitDiff>,
errorMessage: msg
} as CachedDiff);
};
document.state.set<CachedDiff>(key, value);
return GitService.emptyPromise as Promise<GitDiff>;
}
@ -1287,13 +1302,13 @@ export class GitService implements Disposable {
}
@log()
async getRecentLogCommitForFile(repoPath: string | undefined, fileName: string): Promise<GitLogCommit | undefined> {
getRecentLogCommitForFile(repoPath: string | undefined, fileName: string): Promise<GitLogCommit | undefined> {
return this.getLogCommitForFile(repoPath, fileName, undefined);
}
@log()
async getRecentShaForFile(repoPath: string, fileName: string) {
return await Git.log_recent(repoPath, fileName);
getRecentShaForFile(repoPath: string, fileName: string) {
return Git.log_recent(repoPath, fileName);
}
@log()
@ -1385,7 +1400,7 @@ export class GitService implements Disposable {
searchArgs = ['-M', '--all', '--full-history', '-E', '-i', '--pickaxe-regex', `-S${search}`];
break;
case GitRepoSearchBy.Files:
searchArgs = ['-M', '--all', '--full-history', '-E', '-i', `--`, `${search}`];
searchArgs = ['-M', '--all', '--full-history', '-E', '-i', '--', `${search}`];
break;
case GitRepoSearchBy.Message:
searchArgs = ['-m', '-M', '--all', '--full-history', '-E', '-i'];
@ -1394,7 +1409,7 @@ export class GitService implements Disposable {
}
break;
case GitRepoSearchBy.Sha:
searchArgs = [`-m`, '-M', search];
searchArgs = ['-m', '-M', search];
maxCount = 1;
break;
}
@ -1452,10 +1467,10 @@ export class GitService implements Disposable {
key += `:n${options.maxCount}`;
}
if (options.renames) {
key += `:follow`;
key += ':follow';
}
if (options.reverse) {
key += `:reverse`;
key += ':reverse';
}
const doc = await Container.tracker.getOrAdd(GitUri.fromFile(fileName, repoPath!, options.ref));
@ -1470,7 +1485,7 @@ export class GitService implements Disposable {
if (options.ref !== undefined || options.maxCount !== undefined) {
// Since we are looking for partial log, see if we have the log of the whole file
const cachedLog = doc.state.get<CachedLog>(
`log${options.renames ? ':follow' : ''}${options.reverse ? ':reverse' : ''}`
`log${options.renames ? ':follow' : emptyStr}${options.reverse ? ':reverse' : emptyStr}`
);
if (cachedLog !== undefined) {
if (options.ref === undefined) {
@ -1536,9 +1551,10 @@ export class GitService implements Disposable {
if (doc.state !== undefined && options.range === undefined) {
Logger.debug(cc, `Cache add: '${key}'`);
doc.state.set<CachedLog>(key, {
item: promise
} as CachedLog);
const value: CachedLog = {
item: promise as Promise<GitLog>
};
doc.state.set<CachedLog>(key, value);
}
return promise;
@ -1560,7 +1576,7 @@ export class GitService implements Disposable {
const [file, root] = Git.splitPath(fileName, repoPath, false);
try {
// tslint:disable-next-line:prefer-const
// eslint-disable-next-line prefer-const
let { range, ...opts } = options;
if (range !== undefined && range.start.line > range.end.line) {
range = new Range(range.end, range.start);
@ -1600,10 +1616,11 @@ export class GitService implements Disposable {
const msg = ex && ex.toString();
Logger.debug(cc, `Cache replace (with empty promise): '${key}'`);
document.state.set<CachedLog>(key, {
item: GitService.emptyPromise,
const value: CachedLog = {
item: GitService.emptyPromise as Promise<GitLog>,
errorMessage: msg
} as CachedLog);
};
document.state.set<CachedLog>(key, value);
return GitService.emptyPromise as Promise<GitLog>;
}
@ -1719,7 +1736,7 @@ export class GitService implements Disposable {
else {
folder = workspace.getWorkspaceFolder(GitUri.file(rp, isVslsScheme));
if (folder === undefined) {
const parts = rp.split('/');
const parts = rp.split(slash);
folder = {
uri: GitUri.file(rp, isVslsScheme),
name: parts[parts.length - 1],
@ -1852,7 +1869,7 @@ export class GitService implements Disposable {
if (repo === undefined && isVslsScheme !== false && Container.vsls.isMaybeGuest) {
if (!vslsUriPrefixRegex.test(path)) {
path = Strings.normalizePath(path);
const vslsPath = `/~0${path[0] === '/' ? path : `/${path}`}`;
const vslsPath = `/~0${path[0] === slash ? path : `/${path}`}`;
repo = repositoryTree.findSubstr(vslsPath);
}
}
@ -2028,7 +2045,7 @@ export class GitService implements Disposable {
return tracked;
}
tracked = this.isTrackedCore(fileName, repoPath === undefined ? '' : repoPath, ref);
tracked = this.isTrackedCore(fileName, repoPath === undefined ? emptyStr : repoPath, ref);
if (options.skipCacheUpdate) {
tracked = await tracked;
@ -2047,13 +2064,15 @@ export class GitService implements Disposable {
try {
// Even if we have a ref, check first to see if the file exists (that way the cache will be better reused)
let tracked = Boolean(await Git.ls_files(repoPath === undefined ? '' : repoPath, fileName));
let tracked = Boolean(await Git.ls_files(repoPath === undefined ? emptyStr : repoPath, fileName));
if (!tracked && ref !== undefined) {
tracked = Boolean(await Git.ls_files(repoPath === undefined ? '' : repoPath, fileName, { ref: ref }));
tracked = Boolean(
await Git.ls_files(repoPath === undefined ? emptyStr : repoPath, fileName, { ref: ref })
);
// If we still haven't found this file, make sure it wasn't deleted in that ref (i.e. check the previous)
if (!tracked) {
tracked = Boolean(
await Git.ls_files(repoPath === undefined ? '' : repoPath, fileName, {
await Git.ls_files(repoPath === undefined ? emptyStr : repoPath, fileName, {
ref: `${ref}^`
})
);
@ -2071,7 +2090,7 @@ export class GitService implements Disposable {
async getDiffTool(repoPath?: string) {
return (
(await Git.config_get('diff.guitool', repoPath, { local: true })) ||
(await Git.config_get('diff.tool', repoPath, { local: true }))
Git.config_get('diff.tool', repoPath, { local: true })
);
}
@ -2124,8 +2143,8 @@ export class GitService implements Disposable {
}
@log()
async validateReference(repoPath: string, ref: string) {
return await Git.cat_validate(repoPath, ref);
validateReference(repoPath: string, ref: string) {
return Git.cat_validate(repoPath, ref);
}
stageFile(repoPath: string, fileName: string): Promise<string>;
@ -2239,7 +2258,7 @@ export class GitService implements Disposable {
) {
if (ref === undefined) return undefined;
strings = { deletedOrMissing: '(deleted)', working: '', ...strings };
strings = { deletedOrMissing: '(deleted)', working: emptyStr, ...strings };
if (ref == null || ref.length === 0) return strings.working;
if (ref === GitService.deletedOrMissingSha) return strings.deletedOrMissing;
@ -2247,7 +2266,7 @@ export class GitService implements Disposable {
return Git.isShaLike(ref) || Git.isStagedUncommitted(ref) ? Git.shortenSha(ref, strings) : ref;
}
static compareGitVersion(version: string, throwIfLessThan?: Error) {
static compareGitVersion(version: string) {
return Versions.compare(Versions.fromString(this.getGitVersion()), Versions.fromString(version));
}

+ 21
- 15
src/git/gitUri.ts View File

@ -1,4 +1,5 @@
'use strict';
/* eslint-disable constructor-super */
import * as paths from 'path';
import { Uri } from 'vscode';
import { UriComparer } from '../comparers';
@ -8,7 +9,7 @@ import { GitCommit, GitFile, GitService } from '../git/gitService';
import { Logger } from '../logger';
import { debug, Strings } from '../system';
const empty = '';
const emptyStr = '';
const slash = '/';
export interface GitCommitish {
@ -44,13 +45,13 @@ export class GitUri extends ((Uri as any) as UriEx) {
constructor(uri: Uri, repoPath: string | undefined);
constructor(uri?: Uri, commitOrRepoPath?: GitCommitish | string) {
if (uri == null) {
super('unknown', '', '', '', '');
super('unknown', emptyStr, emptyStr, emptyStr, emptyStr);
return;
}
if (uri.scheme === DocumentSchemes.GitLens) {
const data = JSON.parse(uri.query) as IUriRevisionData;
const data = JSON.parse(uri.query) as UriRevisionData;
// When Uri's come from the FileSystemProvider, the uri.query only contains the root repo info (not the actual file path), so fix that here
const index = uri.path.indexOf(data.path);
@ -156,10 +157,14 @@ export class GitUri extends ((Uri as any) as UriEx) {
}
getFormattedPath(options: { relativeTo?: string; separator?: string; suffix?: string } = {}): string {
const { relativeTo = this.repoPath, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = empty } = options;
const {
relativeTo = this.repoPath,
separator = Strings.pad(GlyphChars.Dot, 2, 2),
suffix = emptyStr
} = options;
const directory = GitUri.getDirectory(this.fsPath, relativeTo);
return `${paths.basename(this.fsPath)}${suffix}${directory ? `${separator}${directory}` : empty}`;
return `${paths.basename(this.fsPath)}${suffix}${directory ? `${separator}${directory}` : emptyStr}`;
}
getRelativePath(relativeTo?: string): string {
@ -250,7 +255,7 @@ export class GitUri extends ((Uri as any) as UriEx) {
let ref;
switch (data.ref) {
case empty:
case emptyStr:
case '~':
ref = GitService.stagedUncommittedSha;
break;
@ -264,11 +269,12 @@ export class GitUri extends ((Uri as any) as UriEx) {
break;
}
return new GitUri(uri, {
const commitish: GitCommitish = {
fileName: data.path,
repoPath: repoPath,
repoPath: repoPath!,
sha: ref
} as GitCommitish);
};
return new GitUri(uri, commitish);
}
return new GitUri(uri, await Container.git.getRepoPath(uri));
@ -280,14 +286,14 @@ export class GitUri extends ((Uri as any) as UriEx) {
directory = paths.relative(relativeTo, directory);
}
directory = Strings.normalizePath(directory);
return !directory || directory === '.' ? empty : directory;
return !directory || directory === '.' ? emptyStr : directory;
}
static getFormattedPath(
fileNameOrUri: string | Uri,
options: { relativeTo?: string; separator?: string; suffix?: string } = {}
): string {
const { relativeTo, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = empty } = options;
const { relativeTo, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = emptyStr } = options;
let fileName: string;
if (fileNameOrUri instanceof Uri) {
@ -327,7 +333,7 @@ export class GitUri extends ((Uri as any) as UriEx) {
const path = GitUri.resolve(fileName, repoPath);
return Uri.parse(
// Change encoded / back to / otherwise uri parsing won't work properly
`git:${encodeURIComponent(path).replace(/%2F/g, '/')}?${encodeURIComponent(
`git:${encodeURIComponent(path).replace(/%2F/g, slash)}?${encodeURIComponent(
JSON.stringify({
// Ensure we use the fsPath here, otherwise the url won't open properly
path: Uri.file(path).fsPath,
@ -391,7 +397,7 @@ export class GitUri extends ((Uri as any) as UriEx) {
}
const filePath = Strings.normalizePath(fileName, { addLeadingSlash: true });
const data: IUriRevisionData = {
const data: UriRevisionData = {
path: filePath,
ref: ref,
repoPath: Strings.normalizePath(repoPath!)
@ -401,14 +407,14 @@ export class GitUri extends ((Uri as any) as UriEx) {
// Replace / in the authority with a similar unicode characters otherwise parsing will be wrong
`${DocumentSchemes.GitLens}://${encodeURIComponent(shortSha!.replace(/\//g, '\u200A\u2215\u200A'))}${
// Change encoded / back to / otherwise uri parsing won't work properly
filePath === slash ? empty : encodeURIComponent(filePath).replace(/%2F/g, '/')
filePath === slash ? emptyStr : encodeURIComponent(filePath).replace(/%2F/g, slash)
}?${encodeURIComponent(JSON.stringify(data))}`
);
return uri;
}
}
interface IUriRevisionData {
interface UriRevisionData {
path: string;
ref?: string;
repoPath: string;

+ 6
- 6
src/git/locator.ts View File

@ -19,7 +19,7 @@ async function findSpecificGit(path: string): Promise {
}
return {
path,
path: path,
version: parseVersion(version.trim())
};
}
@ -49,15 +49,15 @@ async function findGitDarwin(): Promise {
}
}
function findSystemGitWin32(basePath: string): Promise<GitLocation> {
if (!basePath) return Promise.reject(new Error('Unable to find git'));
function findSystemGitWin32(basePath: string | null | undefined): Promise<GitLocation> {
if (basePath == null || basePath.length === 0) return Promise.reject(new Error('Unable to find git'));
return findSpecificGit(paths.join(basePath, 'Git', 'cmd', 'git.exe'));
}
function findGitWin32(): Promise<GitLocation> {
return findSystemGitWin32(process.env['ProgramW6432']!)
.then(null, () => findSystemGitWin32(process.env['ProgramFiles(x86)']!))
.then(null, () => findSystemGitWin32(process.env['ProgramFiles']!))
return findSystemGitWin32(process.env['ProgramW6432'])
.then(null, () => findSystemGitWin32(process.env['ProgramFiles(x86)']))
.then(null, () => findSystemGitWin32(process.env['ProgramFiles']))
.then(null, () => findSpecificGit('git'));
}

+ 1
- 0
src/git/models/branch.ts View File

@ -116,6 +116,7 @@ export class GitBranch {
starred![this.id] = true;
}
else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [this.id]: _, ...rest } = starred!;
starred = rest;
}

+ 1
- 1
src/git/models/commit.ts View File

@ -155,7 +155,7 @@ export abstract class GitCommit {
return this.workingFileName ? GitUri.resolveToUri(this.workingFileName, this.repoPath) : this.uri;
}
private _dateFormatter?: Dates.IDateFormatter;
private _dateFormatter?: Dates.DateFormatter;
formatDate(format?: string | null) {
if (format == null) {

+ 2
- 2
src/git/models/log.ts View File

@ -11,8 +11,8 @@ export interface GitLog {
readonly sha: string | undefined;
readonly count: number;
readonly maxCount: number | undefined;
readonly range: Range;
readonly range: Range | undefined;
readonly truncated: boolean;
query(maxCount: number | undefined): Promise<GitLog | undefined>;
query?(maxCount: number | undefined): Promise<GitLog | undefined>;
}

+ 12
- 13
src/git/models/repository.ts View File

@ -35,9 +35,7 @@ export enum RepositoryChange {
export class RepositoryChangeEvent {
readonly changes: RepositoryChange[] = [];
constructor(
public readonly repository?: Repository
) {}
constructor(public readonly repository?: Repository) {}
changed(change: RepositoryChange, solely: boolean = false) {
if (solely) return this.changes.length === 1 && this.changes[0] === change;
@ -243,18 +241,18 @@ export class Repository implements Disposable {
const { progress, ...opts } = { progress: true, ...options };
if (!progress) return this.fetchCore(opts);
await window.withProgress(
return void (await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Fetching ${opts.remote ? `${opts.remote} of ` : ''}${this.formattedName}...`,
cancellable: false
},
() => this.fetchCore(opts)
);
));
}
private async fetchCore(options: { remote?: string } = {}) {
await Container.git.fetch(this.path, options.remote);
void (await Container.git.fetch(this.path, options.remote));
this.fireChange(RepositoryChange.Repository);
}
@ -327,18 +325,18 @@ export class Repository implements Disposable {
const { progress } = { progress: true, ...options };
if (!progress) return this.pullCore();
await window.withProgress(
return void (await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Pulling ${this.formattedName}...`,
cancellable: false
},
() => this.pullCore()
);
));
}
private async pullCore() {
await commands.executeCommand('git.pull', this.path);
void (await commands.executeCommand('git.pull', this.path));
this.fireChange(RepositoryChange.Repository);
}
@ -349,18 +347,18 @@ export class Repository implements Disposable {
const { force, progress } = { progress: true, ...options };
if (!progress) return this.pushCore(force);
await window.withProgress(
return void (await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Pushing ${this.formattedName}...`,
cancellable: false
},
() => this.pushCore(force)
);
));
}
private async pushCore(force: boolean = false) {
await commands.executeCommand(force ? 'git.pushForce' : 'git.push', this.path);
void (await commands.executeCommand(force ? 'git.pushForce' : 'git.push', this.path));
this.fireChange(RepositoryChange.Repository);
}
@ -404,6 +402,7 @@ export class Repository implements Disposable {
starred![this.id] = true;
}
else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [this.id]: _, ...rest } = starred!;
starred = rest;
}
@ -416,7 +415,7 @@ export class Repository implements Disposable {
// TODO: createFileSystemWatcher doesn't work unless the folder is part of the workspaceFolders
// https://github.com/Microsoft/vscode/issues/3025
const watcher = workspace.createFileSystemWatcher(new RelativePattern(this.folder, `**`));
const watcher = workspace.createFileSystemWatcher(new RelativePattern(this.folder, '**'));
this._fsWatcherDisposable = Disposable.from(
watcher,
watcher.onDidChange(this.onFileSystemChanged, this),

+ 4
- 0
src/git/models/stashCommit.ts View File

@ -4,6 +4,10 @@ import { GitFile, GitFileStatus } from './file';
import { GitLogCommit } from './logCommit';
export class GitStashCommit extends GitLogCommit {
static is(commit: GitLogCommit): commit is GitStashCommit {
return commit.isStash;
}
constructor(
type: GitCommitType,
public readonly stashName: string,

+ 1
- 1
src/git/models/status.ts View File

@ -177,7 +177,7 @@ export class GitStatusFile implements GitFile {
return GitFile.getStatusOcticon(this.status);
}
getStatusText(file: GitFile): string {
getStatusText(): string {
return GitFile.getStatusText(this.status);
}

+ 18
- 10
src/git/parsers/blameParser.ts View File

@ -1,7 +1,10 @@
'use strict';
import * as paths from 'path';
import { Strings } from '../../system';
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitCommitLine } from './../git';
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitCommitLine } from '../git';
const emptyStr = '';
const slash = '/';
interface BlameEntry {
sha: string;
@ -50,11 +53,12 @@ export class GitBlameParser {
if (entry === undefined) {
entry = {
author: undefined!,
sha: lineParts[0],
originalLine: parseInt(lineParts[1], 10) - 1,
line: parseInt(lineParts[2], 10) - 1,
lineCount: parseInt(lineParts[3], 10)
} as BlameEntry;
};
continue;
}
@ -72,7 +76,7 @@ export class GitBlameParser {
}
break;
case 'author-mail':
case 'author-mail': {
if (Git.isUncommitted(entry.sha)) {
entry.authorEmail = currentUser !== undefined ? currentUser.email : undefined;
continue;
@ -94,7 +98,7 @@ export class GitBlameParser {
}
break;
}
case 'author-time':
entry.authorDate = lineParts[1];
break;
@ -121,7 +125,10 @@ export class GitBlameParser {
if (first && repoPath === undefined) {
// Try to get the repoPath from the most recent commit
repoPath = Strings.normalizePath(
fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName!, '')
fileName.replace(
fileName.startsWith(slash) ? `/${entry.fileName}` : entry.fileName!,
emptyStr
)
);
relativeFileName = Strings.normalizePath(paths.relative(repoPath, fileName));
}
@ -141,22 +148,23 @@ export class GitBlameParser {
}
for (const [, c] of commits) {
if (c.author === undefined) return;
if (c.author === undefined) return undefined;
const author = authors.get(c.author);
if (author === undefined) return;
if (author === undefined) return undefined;
author.lineCount += c.lines.length;
}
const sortedAuthors = new Map([...authors.entries()].sort((a, b) => b[1].lineCount - a[1].lineCount));
return {
repoPath: repoPath,
const blame: GitBlame = {
repoPath: repoPath!,
authors: sortedAuthors,
commits: commits,
lines: lines
} as GitBlame;
};
return blame;
}
private static parseEntry(

+ 6
- 6
src/git/parsers/branchParser.ts View File

@ -1,7 +1,7 @@
'use strict';
import { GitBranch } from './../git';
import { GitBranch } from '../git';
const branchWithTrackingRegex = /^(\*?)\s+(.+?)\s+([0-9,a-f]+)\s+(?:\[(.*?\/.*?)(?:\:\s(.*)\]|\]))?/gm;
const branchWithTrackingRegex = /^(\*?)\s+(.+?)\s+([0-9,a-f]+)\s+(?:\[(.*?\/.*?)(?::\s(.*)\]|\]))?/gm;
const branchWithTrackingStateRegex = /^(?:ahead\s([0-9]+))?[,\s]*(?:behind\s([0-9]+))?/;
export class GitBranchParser {
@ -10,6 +10,7 @@ export class GitBranchParser {
const branches: GitBranch[] = [];
let match: RegExpExecArray | null;
let ahead;
let behind;
let current;
@ -17,7 +18,6 @@ export class GitBranchParser {
let sha;
let state;
let tracking;
let match: RegExpExecArray | null = null;
do {
match = branchWithTrackingRegex.exec(data);
if (match == null) break;
@ -28,12 +28,12 @@ export class GitBranchParser {
new GitBranch(
repoPath,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + name).substr(1),
` ${name}`.substr(1),
current === '*',
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
sha === undefined ? undefined : (' ' + sha).substr(1),
sha === undefined ? undefined : ` ${sha}`.substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
tracking === undefined ? undefined : (' ' + tracking).substr(1),
tracking === undefined ? undefined : ` ${tracking}`.substr(1),
ahead,
behind
)

+ 22
- 26
src/git/parsers/diffParser.ts View File

@ -1,14 +1,6 @@
'use strict';
import { Iterables, Strings } from '../../system';
import {
GitDiff,
GitDiffChunk,
GitDiffChunkLine,
GitDiffLine,
GitDiffShortStat,
GitFile,
GitFileStatus
} from './../git';
import { GitDiff, GitDiffChunk, GitDiffChunkLine, GitDiffLine, GitDiffShortStat, GitFile, GitFileStatus } from '../git';
const nameStatusDiffRegex = /^(.*?)\t(.*?)(?:\t(.*?))?$/gm;
const shortStatDiffRegex = /^\s*(\d+)\sfiles? changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/;
@ -20,18 +12,17 @@ export class GitDiffParser {
const chunks: GitDiffChunk[] = [];
let match: RegExpExecArray | null = null;
let chunk: string;
let currentStart: number;
let previousStart: number;
let match: RegExpExecArray | null;
let chunk;
let currentStart;
let previousStart;
do {
match = unifiedDiffRegex.exec(`${data}\n@@`);
if (match == null) break;
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
chunk = (' ' + match[5]).substr(1);
chunk = ` ${match[5]}`.substr(1);
currentStart = parseInt(match[3], 10);
previousStart = parseInt(match[1], 10);
@ -52,10 +43,10 @@ export class GitDiffParser {
if (!chunks.length) return undefined;
const diff = {
const diff: GitDiff = {
diff: debug ? data : undefined,
chunks: chunks
} as GitDiff;
};
return diff;
}
@ -142,22 +133,27 @@ export class GitDiffParser {
const files: GitFile[] = [];
let rawStatus: string;
let fileName: string;
let originalFileName: string;
let match: RegExpExecArray | null = null;
do {
match = nameStatusDiffRegex.exec(data);
if (match == null) break;
[, rawStatus, fileName, originalFileName] = match;
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
const status = (' ' + match[1]).substr(1);
const status = ` ${rawStatus}`.substr(1);
files.push({
repoPath,
repoPath: repoPath,
status: (status[0] !== '.' ? status[0].trim() : '?') as GitFileStatus,
indexStatus: undefined,
workingTreeStatus: undefined,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
fileName: (' ' + match[2]).substr(1),
fileName: ` ${fileName}`.substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
originalFileName: match[3] === undefined ? undefined : (' ' + match[3]).substr(1)
originalFileName: originalFileName === undefined ? undefined : ` ${originalFileName}`.substr(1)
});
} while (match != null);
@ -172,13 +168,13 @@ export class GitDiffParser {
const match = shortStatDiffRegex.exec(data);
if (match == null) return undefined;
const files = match[1];
const insertions = match[2];
const deletions = match[3];
return {
const [, files, insertions, deletions] = match;
const diffShortStat: GitDiffShortStat = {
files: files == null ? 0 : parseInt(files, 10),
insertions: insertions == null ? 0 : parseInt(insertions, 10),
deletions: deletions == null ? 0 : parseInt(deletions, 10)
} as GitDiffShortStat;
};
return diffShortStat;
}
}

+ 19
- 10
src/git/parsers/logParser.ts View File

@ -2,7 +2,10 @@
import * as paths from 'path';
import { Range } from 'vscode';
import { Arrays, Strings } from '../../system';
import { Git, GitAuthor, GitCommitType, GitFile, GitFileStatus, GitLog, GitLogCommit } from './../git';
import { Git, GitAuthor, GitCommitType, GitFile, GitFileStatus, GitLog, GitLogCommit } from '../git';
const emptyStr = '';
const slash = '/';
interface LogEntry {
ref?: string;
@ -50,7 +53,7 @@ export class GitLogParser {
let i = 0;
let first = true;
const lines = Strings.lines(data + '</f>');
const lines = Strings.lines(`${data}</f>`);
// Skip the first line since it will always be </f>
let next = lines.next();
if (next.done) return undefined;
@ -130,7 +133,8 @@ export class GitLogParser {
}
break;
case 102: // 'f': // files
case 102: {
// 'f': // files
// Skip the blank line git adds before the files
next = lines.next();
if (next.done || next.value === '</f>') break;
@ -162,8 +166,8 @@ export class GitLogParser {
else if (line.startsWith('diff')) {
const matches = diffRegex.exec(line);
if (matches != null) {
entry.fileName = matches[1];
const originalFileName = matches[2];
let originalFileName;
[, entry.fileName, originalFileName] = matches;
if (entry.fileName !== originalFileName) {
entry.originalFileName = originalFileName;
entry.status = 'R';
@ -195,7 +199,10 @@ export class GitLogParser {
if (first && repoPath === undefined && type === GitCommitType.File && fileName !== undefined) {
// Try to get the repoPath from the most recent commit
repoPath = Strings.normalizePath(
fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName!, '')
fileName.replace(
fileName.startsWith(slash) ? `/${entry.fileName}` : entry.fileName!,
emptyStr
)
);
relativeFileName = Strings.normalizePath(paths.relative(repoPath, fileName));
}
@ -226,11 +233,12 @@ export class GitLogParser {
);
break;
}
}
}
return {
repoPath: repoPath,
const log: GitLog = {
repoPath: repoPath!,
authors: authors,
commits: commits,
sha: sha,
@ -238,7 +246,8 @@ export class GitLogParser {
maxCount: maxCount,
range: range,
truncated: Boolean(truncationCount && i >= truncationCount && truncationCount !== 1)
} as GitLog;
};
return log;
}
private static parseEntry(
@ -295,7 +304,7 @@ export class GitLogParser {
entry.email,
new Date((entry.date! as any) * 1000),
new Date((entry.committedDate! as any) * 1000),
entry.summary === undefined ? '' : entry.summary,
entry.summary === undefined ? emptyStr : entry.summary,
relativeFileName,
entry.files || [],
entry.status,

+ 18
- 10
src/git/parsers/remoteParser.ts View File

@ -1,7 +1,9 @@
'use strict';
import { GitRemoteType } from '../models/remote';
import { RemoteProvider } from '../remotes/factory';
import { GitRemote } from './../git';
import { GitRemote } from '../git';
const emptyStr = '';
const remoteRegex = /^(.*)\t(.*)\s\((.*)\)$/gm;
const urlRegex = /^(?:(git:\/\/)(.*?)\/|(https?:\/\/)(?:.*?@)?(.*?)\/|git@(.*):|(ssh:\/\/)(?:.*@)?(.*?)(?::.*?)?(?:\/|(?=~))|(?:.*?@)(.*?):)(.*)$/;
@ -55,18 +57,24 @@ export class GitRemoteParser {
const remotes: GitRemote[] = [];
const groups = Object.create(null);
let url: string;
let scheme: string;
let domain: string;
let path: string;
let uniqueness: string;
let remote: GitRemote | undefined;
let match: RegExpExecArray | null = null;
do {
match = remoteRegex.exec(data);
if (match == null) break;
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
const url = (' ' + match[2]).substr(1);
url = ` ${match[2]}`.substr(1);
const [scheme, domain, path] = this.parseGitUrl(url);
[scheme, domain, path] = this.parseGitUrl(url);
const uniqueness = `${domain}/${path}`;
let remote: GitRemote | undefined = groups[uniqueness];
uniqueness = `${domain}/${path}`;
remote = groups[uniqueness];
if (remote === undefined) {
const provider = providerFactory(domain, path);
@ -74,20 +82,20 @@ export class GitRemoteParser {
repoPath,
uniqueness,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + match[1]).substr(1),
` ${match[1]}`.substr(1),
scheme,
provider !== undefined ? provider.domain : domain,
provider !== undefined ? provider.path : path,
provider,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
[{ url: url, type: (' ' + match[3]).substr(1) as GitRemoteType }]
[{ url: url, type: ` ${match[3]}`.substr(1) as GitRemoteType }]
);
remotes.push(remote);
groups[uniqueness] = remote;
}
else {
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
remote.types.push({ url: url, type: (' ' + match[3]).substr(1) as GitRemoteType });
remote.types.push({ url: url, type: ` ${match[3]}`.substr(1) as GitRemoteType });
}
} while (match != null);
@ -98,12 +106,12 @@ export class GitRemoteParser {
static parseGitUrl(url: string): [string, string, string] {
const match = urlRegex.exec(url);
if (match == null) return ['', '', ''];
if (match == null) return [emptyStr, emptyStr, emptyStr];
return [
match[1] || match[3] || match[6],
match[2] || match[4] || match[5] || match[7] || match[8],
match[9].replace(/\.git\/?$/, '')
match[9].replace(/\.git\/?$/, emptyStr)
];
}
}

+ 8
- 5
src/git/parsers/stashParser.ts View File

@ -1,8 +1,10 @@
'use strict';
import { Arrays, Strings } from '../../system';
import { GitCommitType, GitFile, GitFileStatus, GitLogParser, GitStash, GitStashCommit } from './../git';
import { GitCommitType, GitFile, GitFileStatus, GitLogParser, GitStash, GitStashCommit } from '../git';
// import { Logger } from './logger';
const emptyStr = '';
interface StashEntry {
ref?: string;
date?: string;
@ -19,7 +21,7 @@ export class GitStashParser {
static parse(data: string, repoPath: string): GitStash | undefined {
if (!data) return undefined;
const lines = Strings.lines(data + '</f>');
const lines = Strings.lines(`${data}</f>`);
// Skip the first line since it will always be </f>
let next = lines.next();
if (next.done) return undefined;
@ -124,10 +126,11 @@ export class GitStashParser {
}
}
return {
const stash: GitStash = {
repoPath: repoPath,
commits: commits
} as GitStash;
};
return stash;
}
private static parseEntry(entry: StashEntry, repoPath: string, commits: Map<string, GitStashCommit>) {
@ -140,7 +143,7 @@ export class GitStashParser {
entry.ref!,
new Date((entry.date! as any) * 1000),
new Date((entry.committedDate! as any) * 1000),
entry.summary === undefined ? '' : entry.summary,
entry.summary === undefined ? emptyStr : entry.summary,
entry.fileNames!,
entry.files || []
);

+ 20
- 9
src/git/parsers/statusParser.ts View File

@ -1,6 +1,8 @@
'use strict';
import { Strings } from '../../system';
import { GitFileStatus, GitStatus, GitStatusFile } from './../git';
import { GitFileStatus, GitStatus, GitStatusFile } from '../git';
const emptyStr = '';
const aheadStatusV1Regex = /(?:ahead ([0-9]+))/;
const behindStatusV1Regex = /(?:behind ([0-9]+))/;
@ -37,17 +39,17 @@ export class GitStatusParser {
const upstreamStatus = lineParts.slice(2).join(' ');
const aheadStatus = aheadStatusV1Regex.exec(upstreamStatus);
state.ahead = aheadStatus == null ? 0 : +aheadStatus[1] || 0;
state.ahead = aheadStatus == null ? 0 : Number(aheadStatus[1]) || 0;
const behindStatus = behindStatusV1Regex.exec(upstreamStatus);
state.behind = behindStatus == null ? 0 : +behindStatus[1] || 0;
state.behind = behindStatus == null ? 0 : Number(behindStatus[1]) || 0;
}
}
else {
const rawStatus = line.substring(0, 2);
const fileName = line.substring(3);
if (rawStatus[0] === 'R') {
const [file1, file2] = fileName.replace(/\"/g, '').split('->');
const [file1, file2] = fileName.replace(/"/g, emptyStr).split('->');
files.push(this.parseStatusFile(repoPath, rawStatus, file2.trim(), file1.trim()));
}
else {
@ -56,7 +58,7 @@ export class GitStatusParser {
}
}
return new GitStatus(Strings.normalizePath(repoPath), branch || '', '', files, state, upstream);
return new GitStatus(Strings.normalizePath(repoPath), branch || emptyStr, emptyStr, files, state, upstream);
}
private static parseV2(lines: string[], repoPath: string): GitStatus {
@ -86,8 +88,8 @@ export class GitStatusParser {
upstream = lineParts[2];
break;
case 'branch.ab':
state.ahead = +lineParts[2].substring(1);
state.behind = +lineParts[3].substring(1);
state.ahead = Number(lineParts[2].substring(1));
state.behind = Number(lineParts[3].substring(1));
break;
}
}
@ -97,13 +99,15 @@ export class GitStatusParser {
case '1': // normal
files.push(this.parseStatusFile(repoPath, lineParts[1], lineParts.slice(8).join(' ')));
break;
case '2': // rename
case '2': {
// rename
const file = lineParts
.slice(9)
.join(' ')
.split('\t');
files.push(this.parseStatusFile(repoPath, lineParts[1], file[0], file[1]));
break;
}
case 'u': // unmerged
files.push(this.parseStatusFile(repoPath, lineParts[1], lineParts.slice(10).join(' ')));
break;
@ -114,7 +118,14 @@ export class GitStatusParser {
}
}
return new GitStatus(Strings.normalizePath(repoPath), branch || '', sha || '', files, state, upstream);
return new GitStatus(
Strings.normalizePath(repoPath),
branch || emptyStr,
sha || emptyStr,
files,
state,
upstream
);
}
static parseStatusFile(

+ 5
- 5
src/git/parsers/tagParser.ts View File

@ -1,5 +1,5 @@
'use strict';
import { GitTag } from './../git';
import { GitTag } from '../git';
const tagWithRefRegex = /([0-9,a-f]+)\srefs\/tags\/(.*)/gm;
const tagWithAnnotationRegex = /^(.+?)(?:$|(?:\s+)(.*)$)/gm;
@ -22,10 +22,10 @@ export class GitTagParser {
new GitTag(
repoPath,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + name).substr(1),
` ${name}`.substr(1),
undefined,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
annotation === undefined ? undefined : (' ' + annotation).substr(1)
annotation === undefined ? undefined : ` ${annotation}`.substr(1)
)
);
} while (match != null);
@ -52,9 +52,9 @@ export class GitTagParser {
new GitTag(
repoPath,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + name).substr(1),
` ${name}`.substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + sha).substr(1)
` ${sha}`.substr(1)
)
);
} while (match != null);

+ 5
- 4
src/git/parsers/treeParser.ts View File

@ -1,6 +1,7 @@
'use strict';
import { GitTree } from './../git';
import { GitTree } from '../git';
const emptyStr = '';
const treeRegex = /(?:.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+)/gm;
export class GitTreeParser {
@ -17,11 +18,11 @@ export class GitTreeParser {
const [, type, commitSha, size, filePath] = match;
trees.push({
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
commitSha: commitSha === undefined ? '' : (' ' + commitSha).substr(1),
path: filePath === undefined ? '' : filePath,
commitSha: commitSha === undefined ? emptyStr : ` ${commitSha}`.substr(1),
path: filePath === undefined ? emptyStr : filePath,
size: size === '-' ? 0 : Number(size || 0),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
type: (type === undefined ? '' : (' ' + type).substr(1)) as 'blob' | 'tree'
type: (type === undefined ? emptyStr : ` ${type}`.substr(1)) as 'blob' | 'tree'
});
} while (match != null);

+ 4
- 1
src/git/remotes/azure-devops.ts View File

@ -71,7 +71,7 @@ export class AzureDevOpsRemote extends RemoteProvider {
}
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
let line = '';
let line;
if (range) {
if (range.start.line === range.end.line) {
line = `&line=${range.start.line}`;
@ -80,6 +80,9 @@ export class AzureDevOpsRemote extends RemoteProvider {
line = `&line=${range.start.line}&lineEnd=${range.end.line}`;
}
}
else {
line = '';
}
if (sha) return `${this.baseUrl}/commit/${sha}/?_a=contents&path=%2F${fileName}${line}`;
if (branch) return `${this.baseUrl}/?path=%2F${fileName}&version=GB${branch}&_a=contents${line}`;

+ 4
- 2
src/git/remotes/bitbucket-server.ts View File

@ -46,7 +46,7 @@ export class BitbucketServerRemote extends RemoteProvider {
}
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
let line = '';
let line;
if (range) {
if (range.start.line === range.end.line) {
line = `#${range.start.line}`;
@ -55,7 +55,9 @@ export class BitbucketServerRemote extends RemoteProvider {
line = `#${range.start.line}-${range.end.line}`;
}
}
else {
line = '';
}
if (sha) return `${this.baseUrl}/browse/${fileName}?at=${sha}${line}`;
if (branch) return `${this.baseUrl}/browse/${fileName}?at=${branch}${line}`;
return `${this.baseUrl}/browse/${fileName}${line}`;

+ 4
- 1
src/git/remotes/bitbucket.ts View File

@ -41,7 +41,7 @@ export class BitbucketRemote extends RemoteProvider {
}
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
let line = '';
let line;
if (range) {
if (range.start.line === range.end.line) {
line = `#${fileName}-${range.start.line}`;
@ -50,6 +50,9 @@ export class BitbucketRemote extends RemoteProvider {
line = `#${fileName}-${range.start.line}:${range.end.line}`;
}
}
else {
line = '';
}
if (sha) return `${this.baseUrl}/src/${sha}/${fileName}${line}`;
if (branch) return `${this.baseUrl}/src/${branch}/${fileName}${line}`;

+ 4
- 1
src/git/remotes/custom.ts View File

@ -33,7 +33,7 @@ export class CustomRemote extends RemoteProvider {
}
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
let line = '';
let line;
if (range) {
if (range.start.line === range.end.line) {
line = Strings.interpolate(this.urls.fileLine, { line: range.start.line });
@ -42,6 +42,9 @@ export class CustomRemote extends RemoteProvider {
line = Strings.interpolate(this.urls.fileRange, { start: range.start.line, end: range.end.line });
}
}
else {
line = '';
}
if (sha) {
return Strings.interpolate(

+ 4
- 1
src/git/remotes/github.ts View File

@ -44,7 +44,7 @@ export class GitHubRemote extends RemoteProvider {
}
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
let line = '';
let line;
if (range) {
if (range.start.line === range.end.line) {
line = `#L${range.start.line}`;
@ -53,6 +53,9 @@ export class GitHubRemote extends RemoteProvider {
line = `#L${range.start.line}-L${range.end.line}`;
}
}
else {
line = '';
}
if (sha) return `${this.baseUrl}/blob/${sha}/${fileName}${line}`;
if (branch) return `${this.baseUrl}/blob/${branch}/${fileName}${line}`;

+ 4
- 1
src/git/remotes/gitlab.ts View File

@ -35,7 +35,7 @@ export class GitLabRemote extends RemoteProvider {
}
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
let line = '';
let line;
if (range) {
if (range.start.line === range.end.line) {
line = `#L${range.start.line}`;
@ -44,6 +44,9 @@ export class GitLabRemote extends RemoteProvider {
line = `#L${range.start.line}-${range.end.line}`;
}
}
else {
line = '';
}
if (sha) return `${this.baseUrl}/blob/${sha}/${fileName}${line}`;
if (branch) return `${this.baseUrl}/blob/${branch}/${fileName}${line}`;

+ 5
- 5
src/git/remotes/provider.ts View File

@ -112,8 +112,8 @@ export abstract class RemoteProvider {
protected abstract getUrlForCommit(sha: string): string;
protected abstract getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string;
private async openUrl(url?: string): Promise<{} | undefined> {
if (url === undefined) return undefined;
private openUrl(url?: string): Thenable<{} | undefined> {
if (url === undefined) return Promise.resolve(undefined);
return commands.executeCommand(BuiltInCommands.Open, Uri.parse(url));
}
@ -130,9 +130,9 @@ export abstract class RemoteProvider {
catch (ex) {
if (ex.message.includes("Couldn't find the required `xsel` binary")) {
window.showErrorMessage(
`Unable to copy remote url, xsel is not installed. Please install it via your package manager, e.g. \`sudo apt install xsel\``
'Unable to copy remote url, xsel is not installed. Please install it via your package manager, e.g. `sudo apt install xsel`'
);
return;
return undefined;
}
Logger.error(ex, 'CopyRemoteUrlToClipboardCommand');
@ -140,7 +140,7 @@ export abstract class RemoteProvider {
}
}
open(resource: RemoteResource): Promise<{} | undefined> {
open(resource: RemoteResource): Thenable<{} | undefined> {
return this.openUrl(this.url(resource));
}

+ 22
- 16
src/git/shell.ts View File

@ -1,8 +1,8 @@
'use strict';
import { execFile } from 'child_process';
import * as fs from 'fs';
import * as iconv from 'iconv-lite';
import * as paths from 'path';
import * as iconv from 'iconv-lite';
import { Logger } from '../logger';
const isWindows = process.platform === 'win32';
@ -21,7 +21,7 @@ function runDownPath(exe: string): string {
// Posix does
// Files with any directory path don't get this applied
if (exe.match(/[\\\/]/)) return exe;
if (exe.match(/[\\/]/)) return exe;
const target = paths.join('.', exe);
try {
@ -29,13 +29,16 @@ function runDownPath(exe: string): string {
}
catch {}
const haystack = process.env.PATH!.split(isWindows ? ';' : ':');
for (const p of haystack) {
const needle = paths.join(p, exe);
try {
if (fs.statSync(needle)) return needle;
const path = process.env.PATH;
if (path != null && path.length !== 0) {
const haystack = path.split(isWindows ? ';' : ':');
for (const p of haystack) {
const needle = paths.join(p, exe);
try {
if (fs.statSync(needle)) return needle;
}
catch {}
}
catch {}
}
return exe;
@ -67,14 +70,20 @@ export function findExecutable(exe: string, args: string[]): { cmd: string; args
}
if (exe.match(/\.ps1$/i)) {
const cmd = paths.join(process.env.SYSTEMROOT!, 'System32', 'WindowsPowerShell', 'v1.0', 'PowerShell.exe');
const cmd = paths.join(
process.env.SYSTEMROOT || 'C:\\WINDOWS',
'System32',
'WindowsPowerShell',
'v1.0',
'PowerShell.exe'
);
const psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];
return { cmd: cmd, args: psargs.concat(args) };
}
if (exe.match(/\.(bat|cmd)$/i)) {
const cmd = paths.join(process.env.SYSTEMROOT!, 'System32', 'cmd.exe');
const cmd = paths.join(process.env.SYSTEMROOT || 'C:\\WINDOWS', 'System32', 'cmd.exe');
const cmdArgs = ['/C', exe, ...args];
return { cmd: cmd, args: cmdArgs };
@ -91,10 +100,7 @@ export function findExecutable(exe: string, args: string[]): { cmd: string; args
}
export class RunError extends Error {
constructor(
public readonly exitCode: number,
...args: any[]
) {
constructor(public readonly exitCode: number, ...args: any[]) {
super(...args);
Error.captureStackTrace(this, RunError);
@ -103,7 +109,7 @@ export class RunError extends Error {
export interface RunOptions {
cwd?: string;
readonly env?: Object;
readonly env?: Record<string, any>;
readonly encoding?: BufferEncoding | 'buffer';
/**
* The size the output buffer to allocate to the spawned process. Set this
@ -132,7 +138,7 @@ export function run(
encoding: BufferEncoding | 'buffer',
options: RunOptions = {}
): Promise<TOut> {
const { stdin, stdinEncoding, ...opts } = { maxBuffer: 100 * 1024 * 1024, ...options } as RunOptions;
const { stdin, stdinEncoding, ...opts }: RunOptions = { maxBuffer: 100 * 1024 * 1024, ...options };
return new Promise<TOut>((resolve, reject) => {
const proc = execFile(

+ 12
- 7
src/hovers/lineHoverController.ts View File

@ -5,7 +5,6 @@ import {
debug,
Disposable,
Hover,
HoverProvider,
languages,
Position,
Range,
@ -191,16 +190,22 @@ export class LineHoverController implements Disposable {
const subscriptions = [];
if (cfg.currentLine.changes) {
subscriptions.push(
languages.registerHoverProvider({ pattern: editor.document.uri.fsPath }, {
provideHover: this.provideChangesHover.bind(this)
} as HoverProvider)
languages.registerHoverProvider(
{ pattern: editor.document.uri.fsPath },
{
provideHover: this.provideChangesHover.bind(this)
}
)
);
}
if (cfg.currentLine.details) {
subscriptions.push(
languages.registerHoverProvider({ pattern: editor.document.uri.fsPath }, {
provideHover: this.provideDetailsHover.bind(this)
} as HoverProvider)
languages.registerHoverProvider(
{ pattern: editor.document.uri.fsPath },
{
provideHover: this.provideDetailsHover.bind(this)
}
)
);
}

+ 5
- 9
src/keyboard.ts View File

@ -4,7 +4,7 @@ import { CommandContext, extensionId, setCommandContext } from './constants';
import { Logger } from './logger';
export declare interface KeyCommand {
onDidPressKey?(key: Keys): Promise<{} | undefined>;
onDidPressKey?(key: Keys): Thenable<{} | undefined>;
}
const keyNoopCommand = Object.create(null) as KeyCommand;
@ -14,15 +14,13 @@ export declare type Keys = 'left' | 'right' | ',' | '.' | 'escape';
export const keys: Keys[] = ['left', 'right', ',', '.', 'escape'];
export declare interface KeyMapping {
[id: string]: KeyCommand | (() => Promise<KeyCommand>) | undefined;
[id: string]: KeyCommand | (() => Thenable<KeyCommand>) | undefined;
}
const mappings: KeyMapping[] = [];
export class KeyboardScope implements Disposable {
constructor(
private readonly mapping: KeyMapping
) {
constructor(private readonly mapping: KeyMapping) {
for (const key in mapping) {
mapping[key] = mapping[key] || keyNoopCommand;
}
@ -93,11 +91,9 @@ export class Keyboard implements Disposable {
this._disposable && this._disposable.dispose();
}
async beginScope(mapping?: KeyMapping): Promise<KeyboardScope> {
beginScope(mapping?: KeyMapping): Promise<KeyboardScope> {
Logger.log('Keyboard.beginScope', mappings.length);
return await new KeyboardScope(
mapping ? Object.assign(Object.create(null), mapping) : Object.create(null)
).begin();
return new KeyboardScope(mapping ? Object.assign(Object.create(null), mapping) : Object.create(null)).begin();
}
async execute(key: Keys): Promise<{} | undefined> {

+ 25
- 21
src/logger.ts View File

@ -4,6 +4,8 @@ import { extensionOutputChannelName } from './constants';
import { getCorrelationContext } from './system';
// import { Telemetry } from './telemetry';
const emptyStr = '';
export enum TraceLevel {
Silent = 'silent',
Errors = 'errors',
@ -61,16 +63,16 @@ export class Logger {
message = params.shift();
if (contextOrMessage !== undefined) {
message = `${contextOrMessage.prefix} ${message || ''}`;
message = `${contextOrMessage.prefix} ${message || emptyStr}`;
}
}
if (Logger.isDebugging) {
console.log(this.timestamp, ConsolePrefix, message || '', ...params);
console.log(this.timestamp, ConsolePrefix, message || emptyStr, ...params);
}
if (this.output !== undefined && this.level === TraceLevel.Debug) {
this.output.appendLine(`${this.timestamp} ${message || ''}${this.toLoggableParams(true, params)}`);
this.output.appendLine(`${this.timestamp} ${message || emptyStr}${this.toLoggableParams(true, params)}`);
}
}
@ -87,7 +89,7 @@ export class Logger {
message = params.shift();
if (contextOrMessage !== undefined) {
message = `${contextOrMessage.prefix} ${message || ''}`;
message = `${contextOrMessage.prefix} ${message || emptyStr}`;
}
}
@ -102,11 +104,13 @@ export class Logger {
}
if (Logger.isDebugging) {
console.error(this.timestamp, ConsolePrefix, message || '', ...params, ex);
console.error(this.timestamp, ConsolePrefix, message || emptyStr, ...params, ex);
}
if (this.output !== undefined && this.level !== TraceLevel.Silent) {
this.output.appendLine(`${this.timestamp} ${message || ''}${this.toLoggableParams(false, params)}\n${ex}`);
this.output.appendLine(
`${this.timestamp} ${message || emptyStr}${this.toLoggableParams(false, params)}\n${ex}`
);
}
// Telemetry.trackException(ex);
@ -131,16 +135,16 @@ export class Logger {
message = params.shift();
if (contextOrMessage !== undefined) {
message = `${contextOrMessage.prefix} ${message || ''}`;
message = `${contextOrMessage.prefix} ${message || emptyStr}`;
}
}
if (Logger.isDebugging) {
console.log(this.timestamp, ConsolePrefix, message || '', ...params);
console.log(this.timestamp, ConsolePrefix, message || emptyStr, ...params);
}
if (this.output !== undefined && (this.level === TraceLevel.Verbose || this.level === TraceLevel.Debug)) {
this.output.appendLine(`${this.timestamp} ${message || ''}${this.toLoggableParams(false, params)}`);
this.output.appendLine(`${this.timestamp} ${message || emptyStr}${this.toLoggableParams(false, params)}`);
}
}
@ -159,16 +163,16 @@ export class Logger {
message = params.shift();
if (contextOrMessage !== undefined) {
message = `${contextOrMessage.prefix} ${message || ''}`;
message = `${contextOrMessage.prefix} ${message || emptyStr}`;
}
}
if (Logger.isDebugging) {
console.log(this.timestamp, ConsolePrefix, message || '', ...params);
console.log(this.timestamp, ConsolePrefix, message || emptyStr, ...params);
}
if (this.output !== undefined && (this.level === TraceLevel.Verbose || this.level === TraceLevel.Debug)) {
this.output.appendLine(`${this.timestamp} ${message || ''}${this.toLoggableParams(true, params)}`);
this.output.appendLine(`${this.timestamp} ${message || emptyStr}${this.toLoggableParams(true, params)}`);
}
}
@ -185,16 +189,16 @@ export class Logger {
message = params.shift();
if (contextOrMessage !== undefined) {
message = `${contextOrMessage.prefix} ${message || ''}`;
message = `${contextOrMessage.prefix} ${message || emptyStr}`;
}
}
if (Logger.isDebugging) {
console.warn(this.timestamp, ConsolePrefix, message || '', ...params);
console.warn(this.timestamp, ConsolePrefix, message || emptyStr, ...params);
}
if (this.output !== undefined && this.level !== TraceLevel.Silent) {
this.output.appendLine(`${this.timestamp} ${message || ''}${this.toLoggableParams(false, params)}`);
this.output.appendLine(`${this.timestamp} ${message || emptyStr}${this.toLoggableParams(false, params)}`);
}
}
@ -216,7 +220,7 @@ export class Logger {
return JSON.stringify(p, sanitize);
}
catch {
return `<error>`;
return '<error>';
}
}
@ -230,7 +234,7 @@ export class Logger {
name = instance.prototype.constructor.name;
}
else {
name = instance.constructor != null ? instance.constructor.name : '';
name = instance.constructor != null ? instance.constructor.name : emptyStr;
}
// Strip webpack module name (since I never name classes with an _)
@ -243,16 +247,16 @@ export class Logger {
return `[${now
.toISOString()
.replace(/T/, ' ')
.replace(/\..+/, '')}:${('00' + now.getUTCMilliseconds()).slice(-3)}]`;
.replace(/\..+/, emptyStr)}:${`00${now.getUTCMilliseconds()}`.slice(-3)}]`;
}
private static toLoggableParams(debugOnly: boolean, params: any[]) {
if (params.length === 0 || (debugOnly && this.level !== TraceLevel.Debug && !Logger.isDebugging)) {
return '';
return emptyStr;
}
const loggableParams = params.map(p => this.toLoggable(p)).join(', ');
return ` \u2014 ${loggableParams}` || '';
return ` \u2014 ${loggableParams}` || emptyStr;
}
private static _isDebugging: boolean | undefined;
@ -274,6 +278,6 @@ export class Logger {
if (this.gitOutput === undefined) {
this.gitOutput = window.createOutputChannel(`${extensionOutputChannelName} (Git)`);
}
this.gitOutput.appendLine(`${this.timestamp} ${command}${ex != null ? `\n\n${ex.toString()}` : ''}`);
this.gitOutput.appendLine(`${this.timestamp} ${command}${ex != null ? `\n\n${ex.toString()}` : emptyStr}`);
}
}

+ 8
- 8
src/messages.ts View File

@ -22,7 +22,7 @@ export class Messages {
if (commit === undefined) {
return Messages.showMessage(
'info',
`Commit has no previous commit.`,
'Commit has no previous commit.',
SuppressedMessages.CommitHasNoPreviousCommitWarning
);
}
@ -68,7 +68,7 @@ export class Messages {
static showGitDisabledErrorMessage() {
return Messages.showMessage(
'error',
`GitLens requires Git to be enabled. Please re-enable Git \u2014 set \`git.enabled\` to true and reload`,
'GitLens requires Git to be enabled. Please re-enable Git \u2014 set `git.enabled` to true and reload',
SuppressedMessages.GitDisabledWarning
);
}
@ -106,7 +106,7 @@ export class Messages {
const result = await Messages.showMessage(
'info',
`While GitLens is offered to everyone for free, if you find it useful, please consider [supporting](https://gitlens.amod.io/#support-gitlens) it. Thank you! ❤`,
'While GitLens is offered to everyone for free, if you find it useful, please consider [supporting](https://gitlens.amod.io/#support-gitlens) it. Thank you! ❤',
undefined,
null,
...actions
@ -162,13 +162,13 @@ export class Messages {
}
}
private static async showMessage<T extends MessageItem>(
private static async showMessage(
type: 'info' | 'warn' | 'error',
message: string,
suppressionKey?: SuppressedMessages,
dontShowAgain: T | null = { title: "Don't Show Again" } as T,
...actions: T[]
): Promise<T | undefined> {
dontShowAgain: MessageItem | null = { title: "Don't Show Again" },
...actions: MessageItem[]
): Promise<MessageItem | undefined> {
Logger.log(`ShowMessage(${type}, '${message}', ${suppressionKey}, ${dontShowAgain})`);
if (
@ -183,7 +183,7 @@ export class Messages {
actions.push(dontShowAgain);
}
let result: T | undefined = undefined;
let result: MessageItem | undefined = undefined;
switch (type) {
case 'info':
result = await window.showInformationMessage(message, ...actions);

+ 31
- 39
src/quickpicks/branchHistoryQuickPick.ts View File

@ -1,5 +1,5 @@
'use strict';
import { CancellationTokenSource, QuickPickOptions, window } from 'vscode';
import { CancellationTokenSource, window } from 'vscode';
import { Commands, ShowQuickBranchHistoryCommandArgs } from '../commands';
import { GlyphChars } from '../constants';
import { Container } from '../container';
@ -38,6 +38,12 @@ export class BranchHistoryQuickPick {
| CommitQuickPickItem
| CommandQuickPickItem)[];
const currentCommandArgs: ShowQuickBranchHistoryCommandArgs = {
branch: branch,
log: log,
maxCount: log.maxCount,
goBackCommand: goBackCommand
};
const currentCommand = new CommandQuickPickItem(
{
label: `go back ${GlyphChars.ArrowBack}`,
@ -46,15 +52,7 @@ export class BranchHistoryQuickPick {
}$(git-branch) ${branch} history`
},
Commands.ShowQuickBranchHistory,
[
uri,
{
branch,
log,
maxCount: log.maxCount,
goBackCommand
} as ShowQuickBranchHistoryCommandArgs
]
[uri, currentCommandArgs]
);
const remotes = await Container.git.getRemotes((uri && uri.repoPath) || log.repoPath);
@ -77,23 +75,21 @@ export class BranchHistoryQuickPick {
if (log.truncated || log.sha) {
if (log.truncated) {
const commandArgs: ShowQuickBranchHistoryCommandArgs = {
branch: branch,
maxCount: 0,
goBackCommand: goBackCommand
};
items.splice(
0,
0,
new CommandQuickPickItem(
{
label: `$(sync) Show All Commits`,
label: '$(sync) Show All Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} this may take a while`
},
Commands.ShowQuickBranchHistory,
[
GitUri.fromRepoPath(log.repoPath),
{
branch,
maxCount: 0,
goBackCommand
} as ShowQuickBranchHistoryCommandArgs
]
[GitUri.fromRepoPath(log.repoPath), commandArgs]
)
);
}
@ -103,39 +99,35 @@ export class BranchHistoryQuickPick {
}
if (log.truncated) {
const commandArgs: ShowQuickBranchHistoryCommandArgs = {
branch: branch,
maxCount: log.maxCount,
nextPageCommand: nextPageCommand
};
const npc = new CommandQuickPickItem(
{
label: `$(arrow-right) Show Next Commits`,
label: '$(arrow-right) Show Next Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${log.maxCount} newer commits`
},
Commands.ShowQuickBranchHistory,
[
uri,
{
branch,
maxCount: log.maxCount,
nextPageCommand
} as ShowQuickBranchHistoryCommandArgs
]
[uri, commandArgs]
);
const last = Iterables.last(log.commits.values());
if (last != null) {
const commandArgs: ShowQuickBranchHistoryCommandArgs = {
branch: branch,
maxCount: log.maxCount,
goBackCommand: goBackCommand,
nextPageCommand: npc
};
previousPageCommand = new CommandQuickPickItem(
{
label: `$(arrow-left) Show Previous Commits`,
label: '$(arrow-left) Show Previous Commits',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows ${log.maxCount} older commits`
},
Commands.ShowQuickBranchHistory,
[
new GitUri(uri ? uri : last.uri, last),
{
branch,
maxCount: log.maxCount,
goBackCommand,
nextPageCommand: npc
} as ShowQuickBranchHistoryCommandArgs
]
[new GitUri(uri ? uri : last.uri, last), commandArgs]
);
items.splice(0, 0, previousPageCommand);
@ -165,7 +157,7 @@ export class BranchHistoryQuickPick {
// onDidSelectItem: (item: QuickPickItem) => {
// scope.setKeyCommand('right', item);
// }
} as QuickPickOptions);
});
await scope.dispose();

+ 7
- 18
src/quickpicks/branchesAndTagsQuickPick.ts View File

@ -1,5 +1,5 @@
'use strict';
import { CancellationToken, CancellationTokenSource, QuickPickItem, QuickPickOptions, window } from 'vscode';
import { CancellationToken, CancellationTokenSource, QuickPickItem, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitBranch, GitService, GitTag } from '../git/gitService';
@ -11,10 +11,7 @@ export class RefQuickPickItem implements QuickPickItem {
description: string;
detail: string | undefined;
constructor(
public readonly ref: string,
checked?: boolean
) {
constructor(public readonly ref: string, checked?: boolean) {
this.label = `${checked ? `$(check)${GlyphChars.Space}` : GlyphChars.Space.repeat(4)} ${GitService.shortenSha(
ref
)}`;
@ -39,10 +36,7 @@ export class BranchQuickPickItem implements QuickPickItem {
description: string;
detail: string | undefined;
constructor(
public readonly branch: GitBranch,
checked?: boolean
) {
constructor(public readonly branch: GitBranch, checked?: boolean) {
checked = checked || (checked === undefined && branch.current);
this.label = `${checked ? `$(check)${GlyphChars.Space}` : GlyphChars.Space.repeat(4)} ${branch.name}`;
this.description = branch.remote
@ -74,10 +68,7 @@ export class TagQuickPickItem implements QuickPickItem {
description: string;
detail: string | undefined;
constructor(
public readonly tag: GitBranch | GitTag,
checked?: boolean
) {
constructor(public readonly tag: GitBranch | GitTag, checked?: boolean) {
this.label = `${checked ? `$(check)${GlyphChars.Space}` : GlyphChars.Space.repeat(4)} ${tag.name}`;
this.description = `${GlyphChars.Space.repeat(2)} tag`;
}
@ -114,9 +105,7 @@ export interface BranchesAndTagsQuickPickOptions {
}
export class BranchesAndTagsQuickPick {
constructor(
public readonly repoPath: string | undefined
) {}
constructor(public readonly repoPath: string | undefined) {}
async show(
placeHolder: string,
@ -164,7 +153,7 @@ export class BranchesAndTagsQuickPick {
quickpick.onDidChangeValue(value => {
quickpick.title =
value && value.startsWith('#')
? `Please enter a commit id (Press 'Enter' to confirm or 'Escape' to cancel)`
? "Please enter a commit id (Press 'Enter' to confirm or 'Escape' to cancel)"
: undefined;
});
quickpick.onDidAccept(async () => {
@ -206,7 +195,7 @@ export class BranchesAndTagsQuickPick {
{
placeHolder: placeHolder,
ignoreFocusOut: getQuickPickIgnoreFocusOut()
} as QuickPickOptions,
},
cancellation.token
);
}

+ 68
- 81
src/quickpicks/commitFileQuickPick.ts View File

@ -1,6 +1,6 @@
'use strict';
import * as paths from 'path';
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { QuickPickItem, Uri, window } from 'vscode';
import {
Commands,
CopyMessageToClipboardCommandArgs,
@ -26,13 +26,10 @@ import {
import { OpenRemotesCommandQuickPickItem } from './remotesQuickPick';
export class ApplyCommitFileChangesCommandQuickPickItem extends CommandQuickPickItem {
constructor(
private readonly commit: GitLogCommit,
item?: QuickPickItem
) {
constructor(private readonly commit: GitLogCommit, item?: QuickPickItem) {
super(
item || {
label: `$(git-pull-request) Apply Changes`,
label: '$(git-pull-request) Apply Changes',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} $(file-text) ${paths.basename(
commit.fileName
)} in ${GlyphChars.Space}$(git-commit) ${commit.shortSha}`
@ -58,7 +55,7 @@ export class OpenCommitFileCommandQuickPickItem extends OpenFileCommandQuickPick
super(
uri,
item || {
label: `$(file-symlink-file) Open File`,
label: '$(file-symlink-file) Open File',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} ${paths.basename(commit.fileName)}`
}
);
@ -84,7 +81,7 @@ export class OpenCommitFileRevisionCommandQuickPickItem extends OpenFileCommandQ
super(
uri,
item || {
label: `$(file-symlink-file) Open Revision`,
label: '$(file-symlink-file) Open Revision',
description: description
}
);
@ -122,41 +119,37 @@ export class CommitFileQuickPick {
}
if (commit.previousFileShortSha) {
const commandArgs: DiffWithPreviousCommandArgs = {
commit: commit
};
items.push(
new CommandQuickPickItem(
{
label: `$(git-compare) Open Changes`,
label: '$(git-compare) Open Changes',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} $(git-commit) ${
commit.previousFileShortSha
} ${GlyphChars.Space} $(git-compare) ${GlyphChars.Space} $(git-commit) ${commit.shortSha}`
},
Commands.DiffWithPrevious,
[
commit.uri,
{
commit
} as DiffWithPreviousCommandArgs
]
[commit.uri, commandArgs]
)
);
}
if (commit.workingFileName) {
const commandArgs: DiffWithWorkingCommandArgs = {
commit: commit
};
items.push(
new CommandQuickPickItem(
{
label: `$(git-compare) Open Changes with Working File`,
label: '$(git-compare) Open Changes with Working File',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} $(git-commit) ${commit.shortSha} ${
GlyphChars.Space
} $(git-compare) ${GlyphChars.Space} $(file-text) ${workingName}`
},
Commands.DiffWithWorking,
[
GitUri.resolveToUri(commit.workingFileName, commit.repoPath),
{
commit
} as DiffWithWorkingCommandArgs
]
[GitUri.resolveToUri(commit.workingFileName, commit.repoPath), commandArgs]
)
);
}
@ -203,60 +196,57 @@ export class CommitFileQuickPick {
if (!stash) {
items.push(new ApplyCommitFileChangesCommandQuickPickItem(commit));
const copyShaCommandArgs: CopyShaToClipboardCommandArgs = {
sha: commit.sha
};
items.push(
new CommandQuickPickItem(
{
label: `$(clippy) Copy Commit ID to Clipboard`,
label: '$(clippy) Copy Commit ID to Clipboard',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} ${commit.shortSha}`
},
Commands.CopyShaToClipboard,
[
uri,
{
sha: commit.sha
} as CopyShaToClipboardCommandArgs
]
[uri, copyShaCommandArgs]
)
);
const copyMessageCommandArgs: CopyMessageToClipboardCommandArgs = {
message: commit.message,
sha: commit.sha
};
items.push(
new CommandQuickPickItem(
{
label: `$(clippy) Copy Commit Message to Clipboard`,
label: '$(clippy) Copy Commit Message to Clipboard',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} ${commit.getShortMessage()}`
},
Commands.CopyMessageToClipboard,
[
uri,
{
message: commit.message,
sha: commit.sha
} as CopyMessageToClipboardCommandArgs
]
[uri, copyMessageCommandArgs]
)
);
}
if (commit.workingFileName) {
const commandArgs: ShowQuickFileHistoryCommandArgs = {
log: fileLog,
goBackCommand: currentCommand
};
items.push(
new CommandQuickPickItem(
{
label: `$(history) Show File History`,
label: '$(history) Show File History',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} of ${paths.basename(commit.fileName)}`
},
Commands.ShowQuickFileHistory,
[
GitUri.resolveToUri(commit.workingFileName, commit.repoPath),
{
fileLog,
goBackCommand: currentCommand
} as ShowQuickFileHistoryCommandArgs
]
[GitUri.resolveToUri(commit.workingFileName, commit.repoPath), commandArgs]
)
);
}
if (!stash) {
const fileHistoryCommandArgs: ShowQuickFileHistoryCommandArgs = {
goBackCommand: currentCommand
};
items.push(
new CommandQuickPickItem(
{
@ -268,30 +258,23 @@ export class CommitFileQuickPick {
}`
},
Commands.ShowQuickFileHistory,
[
commit.toGitUri(),
{
goBackCommand: currentCommand
} as ShowQuickFileHistoryCommandArgs
]
[commit.toGitUri(), fileHistoryCommandArgs]
)
);
const commitDetailsCommandArgs: ShowQuickCommitDetailsCommandArgs = {
commit: commit,
sha: commit.sha,
goBackCommand: currentCommand
};
items.push(
new CommandQuickPickItem(
{
label: `$(git-commit) Show Commit Details`,
label: '$(git-commit) Show Commit Details',
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} $(git-commit) ${commit.shortSha}`
},
Commands.ShowQuickCommitDetails,
[
commit.toGitUri(),
{
commit,
sha: commit.sha,
goBackCommand: currentCommand
} as ShowQuickCommitDetailsCommandArgs
]
[commit.toGitUri(), commitDetailsCommandArgs]
)
);
}
@ -305,28 +288,30 @@ export class CommitFileQuickPick {
if (!stash) {
// If we have the full history, we are good
if (fileLog !== undefined && !fileLog.truncated && fileLog.sha === undefined) {
const previousCommandArgs: ShowQuickCommitFileDetailsCommandArgs = {
fileLog: fileLog,
sha: commit.previousSha,
goBackCommand: goBackCommand
};
previousCommand =
commit.previousSha === undefined
? undefined
: new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
commit.previousUri,
{
fileLog,
sha: commit.previousSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
previousCommandArgs
]);
const nextCommandArgs: ShowQuickCommitFileDetailsCommandArgs = {
fileLog: fileLog,
sha: commit.nextSha,
goBackCommand: goBackCommand
};
nextCommand =
commit.nextSha === undefined
? undefined
: new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
commit.nextUri,
{
fileLog,
sha: commit.nextSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
nextCommandArgs
]);
}
else {
@ -358,13 +343,14 @@ export class CommitFileQuickPick {
if (c === undefined || c.previousSha === undefined) return KeyNoopCommand;
const previousCommandArgs: ShowQuickCommitFileDetailsCommandArgs = {
fileLog: log,
sha: c.previousSha,
goBackCommand: goBackCommand
};
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
c.previousUri,
{
fileLog: log,
sha: c.previousSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
previousCommandArgs
]);
};
@ -388,13 +374,14 @@ export class CommitFileQuickPick {
if (c === undefined || c.nextSha === undefined) return KeyNoopCommand;
const nextCommandArgs: ShowQuickCommitFileDetailsCommandArgs = {
fileLog: log,
sha: c.nextSha,
goBackCommand: goBackCommand
};
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
c.nextUri,
{
fileLog: log,
sha: c.nextSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
nextCommandArgs
]);
};
}
@ -417,7 +404,7 @@ export class CommitFileQuickPick {
onDidSelectItem: (item: QuickPickItem) => {
void scope.setKeyCommand('right', item as KeyCommand);
}
} as QuickPickOptions);
});
await scope.dispose();

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save