16 Commits

Author SHA1 Message Date
Eric Amodio
c0d5f55baa Preps v3.6.0-beta 2017-05-27 04:33:27 -04:00
Eric Amodio
68f6ae8f3a Updates dependencies 2017-05-27 04:32:42 -04:00
Eric Amodio
53c691898f Changes behavior of diffWithWorking to always does what it says
Compares the current file with the working tree -- if the current file *is* the working file, it will show a `File matches the working tree` message
2017-05-27 04:26:51 -04:00
Eric Amodio
365af9c54b Changes behavior of diffWithPrevious to always does what it says
Compares the current file with the previous commit to that file
2017-05-27 04:26:12 -04:00
Eric Amodio
55b1a66ec0 Adds 'gitlens.diffWithWorking' status bar command option
Changes 'gitlens.diffWithPrevious' status bar command option behavior
2017-05-27 04:25:12 -04:00
Eric Amodio
522e5a49a2 Renames 'Compare with *' in quick pick menus
Renames 'Compare File with Previous Commit' command
Renames 'Compare Line with Previous Commit' command
Renames 'Compare Line with Working Tree' command
2017-05-27 04:20:25 -04:00
Eric Amodio
e99febb52d Adds diff info to active line hover always 2017-05-27 02:39:10 -04:00
Eric Amodio
2036c8abaf Preps v3.5.1 2017-05-25 01:39:16 -04:00
Eric Amodio
021a5b833a Fixes #71 - blame invalid on external edit 2017-05-25 01:31:24 -04:00
Eric Amodio
f1042de9c7 Stops some code lens actions when uncommitted 2017-05-25 01:30:28 -04:00
Eric Amodio
efd3d40aa8 Switches to use GitUris in more places 2017-05-25 01:05:18 -04:00
Eric Amodio
9c7062020e Fixes issue with blame on versioned files
Stops falling back to the cached blame of the working file
Handles git scheme urls properly
2017-05-25 00:49:36 -04:00
Eric Amodio
9da80c121b Debounces other active line events 2017-05-25 00:35:12 -04:00
Eric Amodio
5380724323 Preps v3.5.0 2017-05-24 23:01:28 -04:00
Eric Amodio
77651701aa Removes insiders flag from stash commands 2017-05-24 22:59:41 -04:00
Eric Amodio
bb834f2e0a Removes insiders flag from remotes 2017-05-24 22:58:54 -04:00
20 changed files with 223 additions and 143 deletions

View File

@@ -4,26 +4,51 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
## [3.5.0-beta.2] - 2017-05-23
### Fixed
- Fixes [#40](https://github.com/eamodio/vscode-gitlens/issues/40) - Encoding issues
- Given the limitations of the vscode api, I'm unable to fix all the encoding issues, but many of them should now be squashed
- `files.encoding` is now honored for the cases where the encoding cannot currently be gleaned
## [3.6.0-beta] - 2017-05-27
### Added
- Adds diff information (the line's previous version) into the active line hover
- Adds a `gitlens.diffWithWorking` status bar command option - compares the current line commit with the working tree
## [3.5.0-beta] - 2017-05-23
### Changed
- Changes the behavior of the `Compare File with Working Tree` command (`gitlens.diffWithWorking`) - always does what it says :)
- Compares the current file with the working tree -- if the current file *is* the working file, it will show a `File matches the working tree` message
- Changes the behavior of the `Compare File with Previous` command (`gitlens.diffWithPrevious`) - always does what it says :)
- Compares the current file with the previous commit to that file
- Changes the behavior of the `gitlens.diffWithPrevious` status bar command option - compares the current line commit with the previous
- Renames `Compare File with Previous Commit` command to `Compare File with Previous`
- Renames `Compare Line with Previous Commit` command to `Compare Line Commit with Previous`
- Renames `Compare Line with Working Tree` command to `Compare Line Commit with Working Tree`
- Renames `Compare with Previous Commit` in quick pick menus to `Compare File with Previous`
- Renames `Compare with Working Tree` in quick pick menus to `Compare File with Working Tree`
## [3.5.1] - 2017-05-25
### Changed
- Changes certain code lens actions to be unavailable (unclickable) when the commit referenced is uncommitted - avoids unwanted error messages
- Debounces more events when tracking the active line to further reduce lag
### Fixed
- Fixes [#71](https://github.com/eamodio/vscode-gitlens/issues/71) - Blame information is invalid when a file has changed outside of vscode
- Fixes issue with showing the incorrect blame for versioned files (i.e. files on the left of a diff, etc)
## [3.5.0] - 2017-05-24
### Added
- Improves performance
- Reduces the number of git calls on known "untrackables"
- Caches many more git commands to reduce git command roundtrips and parsing
- Increases the debounce (delay) on cursor movement to reduce lag when navigating around a file
- Adds diff information (previous line's code) into the active line hover when the current line is uncommitted
- Adds diff information (the line's previous version) into the active line hover when the current line is uncommitted
- Adds `gitlens.statusBar.alignment` settings to control the alignment of the status bar -- thanks to [PR #72](https://github.com/eamodio/vscode-gitlens/pull/72) by Zack Schuster ([@zackschuster](https://github.com/zackschuster))!
- Adds `Open Branch in Remote` command (`gitlens.openBranchInRemote`) - opens the current branch commits in the supported remote service
- Adds `Open Repository in Remote` command (`gitlens.openRepoInRemote`) - opens the repository in the supported remote service
- Adds `Stash Changes` option to stashed changes quick pick menu -- no longer hidden behind the `"gitlens.insiders": true` setting
- Adds `Stash Unstaged Changes` option to stashed changes quick pick menu -- no longer hidden behind the `"gitlens.insiders": true` setting
- Adds `Apply Stashed Changes` command (`gitlens.stashApply`) to apply the selected stashed changes to the working tree -- no longer hidden behind the `"gitlens.insiders": true` setting
- Adds `Stash Changes` command (`gitlens.stashSave`) to stash any working tree changes -- no longer hidden behind the `"gitlens.insiders": true` setting
- Adds support to the `Search commits` command (`gitlens.showCommitSearch`) to work without any active editor
- Adds commit search pre-population -- if there is an active editor it will use the commit sha of the current line commit, otherwise it will use the current clipboard
### Changed
- Changes `Open File in Remote` and `Open Line Commit in Remote` commands to actually work for everyone (part of their implementation was still behind the `gitlens.insiders` setting)
- Changes the active line hover to only show at the beginning and end of a line if `gitlens.blame.annotation.activeLine` is `both`
- Changes `alt+f` shortcut to `alt+/` for the `Search commits` command (`gitlens.showCommitSearch`)
- Changes `alt+right` on commit details quick pick menu to execute the `Compare File with Previous Commit` command (`gitlens.diffWithPrevious`) when a file is selected
@@ -32,6 +57,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Fixed
- Fixes [#73](https://github.com/eamodio/vscode-gitlens/issues/73) - GitLens doesn't work with Chinese filenames
- Fixes [#40](https://github.com/eamodio/vscode-gitlens/issues/40) - Encoding issues
- Given the limitations of the vscode api, I'm unable to fix all the encoding issues, but many of them should now be squashed
- `files.encoding` is now honored for the cases where the encoding cannot currently be gleaned
- Fixes incorrect file selection from the commit details quick pick menu
- Fixes incorrect command execution when using `"gitlens.statusBar.command": "gitlens.showQuickRepoHistory"`
- Fixes a bunch of issues that were revealed by enabling Typescript `strict` mode

View File

@@ -20,7 +20,7 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
#### Git Blame Annotations
- Adds a **blame annotation** to the end of the selected line showing the commit id and message, with more details in a hover popup ([optional](#extension-settings), on by default)
- Adds a **blame annotation** to the end of the selected line showing the commit id and message, with more details (including the line's previous version) in a hover popup ([optional](#extension-settings), on by default)
- Adds a `Toggle Blame Annotations` command (`gitlens.toggleBlame`) with a shortcut of `alt+b` to toggle **inline Git blame annotations** for a whole file with multiple styles — compact, expanded, and trailing
- Also adds a `Show Blame Annotations` command (`gitlens.showBlame`)
@@ -68,13 +68,13 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
- Adds a `Compare File with Next Commit` command (`gitlens.diffWithNext`) with a shortcut of `alt+.` to compare the active file/diff with the next commit revision
- Adds a `Compare File with Previous Commit` command (`gitlens.diffWithPrevious`) with a shortcut of `alt+,` to compare the active file/diff with the previous commit revision
- Adds a `Compare File with Previous` command (`gitlens.diffWithPrevious`) with a shortcut of `alt+,` to compare the active file/diff with the previous commit revision
- Adds a `Compare Line with Previous Commit` command (`gitlens.diffLineWithPrevious`) with a shortcut of `shift+alt+,` to compare the active file/diff with the previous line commit revision
- Adds a `Compare Line Commit with Previous` command (`gitlens.diffLineWithPrevious`) with a shortcut of `shift+alt+,` to compare the active file/diff with the previous line commit revision
- Adds a `Compare File with Working Tree` command (`gitlens.diffWithWorking`) with a shortcut of `shift+alt+w` to compare the most recent commit revision of the active file/diff with the working tree
- Adds a `Compare Line with Working Tree` command (`gitlens.diffLineWithWorking`) with a shortcut of `alt+w` to compare the commit revision of the active line with the working tree
- Adds a `Compare Line Commit with Working Tree` command (`gitlens.diffLineWithWorking`) with a shortcut of `alt+w` to compare the commit revision of the active line with the working tree
#### Navigate and Explore
@@ -120,7 +120,7 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
![Line Commit Details Quick Pick Menu](https://raw.githubusercontent.com/eamodio/vscode-git-codelens/master/images/screenshot-commit-file-details.png)
- Provides entries to `Show Commit Details`, `Show File History`, `Compare with...`, `Copy to Clipboard`, `Open File`, `Open File in <remote-service>` when available, and more
- Provides entries to `Show Commit Details`, `Show File History`, `Compare File with...`, `Copy to Clipboard`, `Open File`, `Open File in <remote-service>` when available, and more
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
- Use the `alt+right arrow` shortcut on an entry to execute it without closing the quick pick menu, if possible — commands that open windows outside of VS Code will still close the quick pick menu unless [`"gitlens.advanced.quickPick.closeOnFocusOut": false`](#extension-settings) is set
@@ -141,7 +141,7 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
![Stashed Changes Quick Pick Menu](https://raw.githubusercontent.com/eamodio/vscode-git-codelens/master/images/screenshot-stash-list.png)
- [Insiders only](#insiders) — Provides entries to `Stash Changes`
- Provides entries to `Stash Changes`
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
- Chosing a stash entry shows a **stash details quick pick menu** which is very similar to the **commit details quick pick menu** above
@@ -150,7 +150,7 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
- Quickly see the set of files changed in the stash, complete with status indicators for adds, changes, renames, and deletes
- Provides entries to `Copy Message to Clipboard`, `Directory Compare`, and `Open Changed Files`
- [Insiders only](#insiders) — Provides entries to `Apply Stashed Changes` and `Delete Stashed Changes` — both require a confirmation
- Provides entries to `Apply Stashed Changes` and `Delete Stashed Changes` — both require a confirmation
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
- Use the `alt+right arrow` shortcut on an entry to execute it without closing the quick pick menu, if possible — commands that open windows outside of VS Code will still close the quick pick menu unless [`"gitlens.advanced.quickPick.closeOnFocusOut": false`](#extension-settings) is set
- Use the `alt+right arrow` shortcut on a file entry in the `Changed Files` section to preview the current revision of the while leaving the quick pick menu open
@@ -174,9 +174,9 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
- Adds a `Close Unchanged Files` command (`gitlens.closeUnchangedFiles`) to close any files without working tree changes
- [Insiders only](#insiders) — Adds a `Apply Stashed Changes` command (`gitlens.stashApply`) to chose a stash entry to apply to the working tree from a quick pick menu
- Adds a `Apply Stashed Changes` command (`gitlens.stashApply`) to chose a stash entry to apply to the working tree from a quick pick menu
- [Insiders only](#insiders) — Adds a `Stash Changes` command (`gitlens.stashSave`) to save any working tree changes to the stash — can optionally provide a stash message
- Adds a `Stash Changes` command (`gitlens.stashSave`) to save any working tree changes to the stash — can optionally provide a stash message
## Insiders
@@ -211,7 +211,7 @@ GitLens is highly customizable and provides many configuration settings to allow
|`gitlens.menus.diff.enabled`|Specifies whether diff commands will be added to the context menus
|`gitlens.statusBar.enabled`|Specifies whether blame information is shown in the status bar
|`gitlens.statusBar.alignment`|Specifies the blame alignment in the status bar. `left` - align to the left, `right` - align to the right
|`gitlens.statusBar.command`|"Specifies the command executed when the blame status bar item is clicked. `gitlens.toggleBlame` - toggles blame annotations. `gitlens.showBlameHistory` - opens the blame history explorer. `gitlens.showFileHistory` - opens the file history explorer. `gitlens.diffWithPrevious` - compares the current committed file with the previous commit. `gitlens.toggleCodeLens` - toggles Git code lens. `gitlens.showQuickCommitDetails` - shows a commit details quick pick. `gitlens.showQuickCommitFileDetails` - shows a commit file details quick pick. `gitlens.showQuickFileHistory` - shows a file history quick pick. `gitlens.showQuickRepoHistory` - shows a branch history quick pick
|`gitlens.statusBar.command`|Specifies the command executed when the blame status bar item is clicked. `gitlens.toggleBlame` - toggles blame annotations. `gitlens.showBlameHistory` - opens the blame history explorer. `gitlens.showFileHistory` - opens the file history explorer. `gitlens.diffWithPrevious` - compares the current line commit with the previous. `gitlens.diffWithWorking` - compares the current line commit with the working tree. `gitlens.toggleCodeLens` - toggles Git code lens. `gitlens.showQuickCommitDetails` - shows a commit details quick pick. `gitlens.showQuickCommitFileDetails` - shows a commit file details quick pick. `gitlens.showQuickFileHistory` - shows a file history quick pick. `gitlens.showQuickRepoHistory` - shows a branch history quick pick
|`gitlens.statusBar.date`|Specifies whether and how the commit date will be shown in the blame status bar. `off` - no date. `relative` - relative date (e.g. 1 day ago). `absolute` - date format specified by `gitlens.statusBar.dateFormat`
|`gitlens.statusBar.dateFormat`|Specifies the date format of how absolute dates will be shown in the blame status bar. See https://momentjs.com/docs/#/displaying/format/ for valid formats

View File

@@ -1,6 +1,6 @@
{
"name": "gitlens",
"version": "3.5.0-beta.2",
"version": "3.6.0-beta",
"author": {
"name": "Eric Amodio",
"email": "eamodio@gmail.com"
@@ -308,13 +308,14 @@
"gitlens.showBlameHistory",
"gitlens.showFileHistory",
"gitlens.diffWithPrevious",
"gitlens.diffWithWorking",
"gitlens.toggleCodeLens",
"gitlens.showQuickCommitDetails",
"gitlens.showQuickCommitFileDetails",
"gitlens.showQuickFileHistory",
"gitlens.showQuickRepoHistory"
],
"description": "Specifies the command executed when the blame status bar item is clicked. `gitlens.toggleBlame` - toggles blame annotations. `gitlens.showBlameHistory` - opens the blame history explorer. `gitlens.showFileHistory` - opens the file history explorer. `gitlens.diffWithPrevious` - compares the current committed file with the previous commit. `gitlens.toggleCodeLens` - toggles Git code lens. `gitlens.showQuickCommitDetails` - shows a commit details quick pick. `gitlens.showQuickCommitFileDetails` - shows a commit file details quick pick. `gitlens.showQuickFileHistory` - shows a file history quick pick. `gitlens.showQuickRepoHistory` - shows a branch history quick pick"
"description": "Specifies the command executed when the blame status bar item is clicked. `gitlens.toggleBlame` - toggles blame annotations. `gitlens.showBlameHistory` - opens the blame history explorer. `gitlens.showFileHistory` - opens the file history explorer. `gitlens.diffWithPrevious` - compares the current line commit with the previous. `gitlens.diffWithWorking` - compares the current line commit with the working tree. `gitlens.toggleCodeLens` - toggles Git code lens. `gitlens.showQuickCommitDetails` - shows a commit details quick pick. `gitlens.showQuickCommitFileDetails` - shows a commit file details quick pick. `gitlens.showQuickFileHistory` - shows a file history quick pick. `gitlens.showQuickRepoHistory` - shows a branch history quick pick"
},
"gitlens.statusBar.date": {
"type": "string",
@@ -386,12 +387,12 @@
},
{
"command": "gitlens.diffWithPrevious",
"title": "Compare File with Previous Commit",
"title": "Compare File with Previous",
"category": "GitLens"
},
{
"command": "gitlens.diffLineWithPrevious",
"title": "Compare Line with Previous Commit",
"title": "Compare Line Commit with Previous",
"category": "GitLens"
},
{
@@ -401,7 +402,7 @@
},
{
"command": "gitlens.diffLineWithWorking",
"title": "Compare Line with Working Tree",
"title": "Compare Line Commit with Working Tree",
"category": "GitLens"
},
{
@@ -645,11 +646,11 @@
},
{
"command": "gitlens.stashApply",
"when": "gitlens:enabled && config.gitlens.insiders"
"when": "gitlens:enabled"
},
{
"command": "gitlens.stashSave",
"when": "gitlens:enabled && config.gitlens.insiders"
"when": "gitlens:enabled"
}
],
"explorer/context": [
@@ -900,7 +901,7 @@
"vscode:prepublish": "npm install && npm run compile"
},
"dependencies": {
"applicationinsights": "0.20.0",
"applicationinsights": "0.20.1",
"copy-paste": "1.3.0",
"iconv-lite": "0.4.17",
"ignore": "3.3.3",

View File

@@ -3,6 +3,7 @@ import { Functions, Objects } from './system';
import { DecorationInstanceRenderOptions, DecorationOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
import { BlameAnnotationController } from './blameAnnotationController';
import { BlameAnnotationFormat, BlameAnnotationFormatter } from './blameAnnotationFormatter';
import { Commands } from './commands';
import { TextEditorComparer } from './comparers';
import { IBlameConfig, IConfig, StatusBarCommand } from './configuration';
import { DocumentSchemes, ExtensionKey } from './constants';
@@ -140,7 +141,7 @@ export class BlameActiveLineController extends Disposable {
this.git.getBlameForFile(this._uri);
}
this._updateBlame(editor.selection.active.line, editor);
this._updateBlameDebounced(editor.selection.active.line, editor);
}
private _onBlameabilityChanged(e: BlameabilityChangeEvent) {
@@ -153,7 +154,7 @@ export class BlameActiveLineController extends Disposable {
// Make sure this is for the editor we are tracking
if (!TextEditorComparer.equals(this._editor, e.editor)) return;
this._updateBlame(this._editor.selection.active.line, this._editor);
this._updateBlameDebounced(this._editor.selection.active.line, this._editor);
}
private _onBlameAnnotationToggled() {
@@ -244,7 +245,12 @@ export class BlameActiveLineController extends Disposable {
this._statusBarItem.tooltip = 'Open File History Explorer';
break;
case StatusBarCommand.DiffWithPrevious:
this._statusBarItem.tooltip = 'Compare with Previous Commit';
this._statusBarItem.command = Commands.DiffLineWithPrevious;
this._statusBarItem.tooltip = 'Compare File with Previous';
break;
case StatusBarCommand.DiffWithWorking:
this._statusBarItem.command = Commands.DiffLineWithWorking;
this._statusBarItem.tooltip = 'Compare File with Working Tree';
break;
case StatusBarCommand.ToggleCodeLens:
this._statusBarItem.tooltip = 'Toggle Git CodeLens';
@@ -298,30 +304,25 @@ export class BlameActiveLineController extends Disposable {
if (!commit.isUncommitted && (!possibleDuplicate || !this.annotationController.isAnnotating(editor))) {
hoverMessage = BlameAnnotationFormatter.getAnnotationHover(cfg, blameLine, logCommit || commit);
// if (commit.previousSha !== undefined) {
// const changes = await this.git.getDiffForLine(this._uri.repoPath, this._uri.fsPath, blameLine.line + offset, commit.previousSha);
// if (changes !== undefined) {
// const previous = changes[0];
// if (previous !== undefined) {
// hoverMessage += `\n\n\`Before ${commit.shortSha}\`\n\`\`\`\n${previous.trim().replace(/\n/g, '\`\n>\n> \`')}\n\`\`\``;
// }
// else {
// hoverMessage += `\n\n\`Added in ${commit.shortSha}\``;
// }
// }
// }
if (commit.previousSha !== undefined) {
const changes = await this.git.getDiffForLine(this._uri, blameLine.line + offset, commit.previousSha);
if (changes !== undefined) {
let previous = changes[0];
if (previous !== undefined) {
previous = previous.replace(/\n/g, '\`\n>\n> \`').trim();
hoverMessage += `\n\n---\n\`\`\`\n${previous}\n\`\`\``;
}
}
}
}
else if (commit.isUncommitted) {
const changes = await this.git.getDiffForLine(this._uri.repoPath, this._uri.fsPath, blameLine.line + offset);
const changes = await this.git.getDiffForLine(this._uri, blameLine.line + offset);
if (changes !== undefined) {
let original = changes[0];
if (original !== undefined) {
original = original.replace(/\n/g, '\`\n>\n> \`').trim();
hoverMessage = `\`${'0'.repeat(8)}\` &nbsp; __Uncommitted change__\n\n\---\n\`\`\`\n${original}\n\`\`\``;
let previous = changes[0];
if (previous !== undefined) {
previous = previous.replace(/\n/g, '\`\n>\n> \`').trim();
hoverMessage = `\`${'0'.repeat(8)}\` &nbsp; __Uncommitted change__\n\n---\n\`\`\`\n${previous}\n\`\`\``;
}
// else {
// hoverMessage = `\`${'0'.repeat(8)}\` &nbsp; __Uncommitted change__\n\n\`Added\``;
// }
}
}
}

View File

@@ -1,6 +1,6 @@
'use strict';
import { Functions } from './system';
import { DecorationRenderOptions, Disposable, Event, EventEmitter, ExtensionContext, OverviewRulerLane, TextDocument, TextEditor, TextEditorDecorationType, TextEditorViewColumnChangeEvent, window, workspace } from 'vscode';
import { DecorationRenderOptions, Disposable, Event, EventEmitter, ExtensionContext, OverviewRulerLane, TextDocument, TextDocumentChangeEvent, TextEditor, TextEditorDecorationType, TextEditorViewColumnChangeEvent, window, workspace } from 'vscode';
import { BlameAnnotationProvider } from './blameAnnotationProvider';
import { TextDocumentComparer, TextEditorComparer } from './comparers';
import { IBlameConfig } from './configuration';
@@ -176,6 +176,7 @@ export class BlameAnnotationController extends Disposable {
subscriptions.push(window.onDidChangeVisibleTextEditors(Functions.debounce(this._onVisibleTextEditorsChanged, 100), this));
subscriptions.push(window.onDidChangeTextEditorViewColumn(this._onTextEditorViewColumnChanged, this));
subscriptions.push(workspace.onDidChangeTextDocument(this._onTextDocumentChanged, this));
subscriptions.push(workspace.onDidCloseTextDocument(this._onTextDocumentClosed, this));
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
@@ -217,6 +218,23 @@ export class BlameAnnotationController extends Disposable {
}
}
private _onTextDocumentChanged(e: TextDocumentChangeEvent) {
for (const [key, p] of this._annotationProviders) {
if (!TextDocumentComparer.equals(p.document, e.document)) continue;
// We have to defer because isDirty is not reliable inside this event
setTimeout(() => {
// If the document is dirty all is fine, just kick out since the GitContextTracker will handle it
if (e.document.isDirty) return;
// If the document isn't dirty, it is very likely this event was triggered by an outside edit of this document
// Which means the document has been reloaded and the blame annotations have been removed, so we need to update (clear) our state tracking
Logger.log('TextDocumentChanged:', `Clear blame annotations for column ${key}`);
this.clear(key);
}, 1);
}
}
private _onTextDocumentClosed(e: TextDocument) {
for (const [key, p] of this._annotationProviders) {
if (!TextDocumentComparer.equals(p.document, e)) continue;

View File

@@ -32,17 +32,15 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
const gitUri = await GitUri.fromUri(uri, this.git);
try {
// If the sha is missing or the file is uncommitted, treat it as a DiffWithWorking
if (gitUri.sha === undefined && await this.git.isFileUncommitted(gitUri)) {
return commands.executeCommand(Commands.DiffWithWorking, uri, { showOptions: args.showOptions } as DiffWithWorkingCommandArgs);
}
const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, args.range!);
if (log === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
// If the sha is missing, treat it as a DiffWithWorking
if (gitUri.sha === undefined) return commands.executeCommand(Commands.DiffWithWorking, uri, { commit: args.commit, showOptions: args.showOptions } as DiffWithWorkingCommandArgs);
}
catch (ex) {
Logger.error(ex, 'DiffWithPreviousCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`);

View File

@@ -26,6 +26,8 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
const gitUri = await GitUri.fromUri(uri, this.git);
// If the sha is missing, just let the user know the file matches
if (gitUri.sha === undefined) return window.showInformationMessage(`File matches the working tree`);
try {
args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });

View File

@@ -21,7 +21,6 @@ export class StashApplyCommand extends Command {
}
async execute(args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
if (!this.git.config.insiders) return undefined;
if (!this.git.repoPath) return undefined;
if (args.stashItem === undefined || args.stashItem.stashName === undefined) {

View File

@@ -19,7 +19,6 @@ export class StashDeleteCommand extends Command {
}
async execute(args: StashDeleteCommandArgs = { confirm: true }) {
if (!this.git.config.insiders) return undefined;
if (!this.git.repoPath) return undefined;
if (args.stashItem === undefined || args.stashItem.stashName === undefined) return undefined;

View File

@@ -19,7 +19,6 @@ export class StashSaveCommand extends Command {
}
async execute(args: StashSaveCommandArgs = { unstagedOnly : false }) {
if (!this.git.config.insiders) return undefined;
if (!this.git.repoPath) return undefined;
if (args.unstagedOnly === undefined) {

View File

@@ -73,12 +73,13 @@ export interface ICodeLensesConfig {
authors: ICodeLensConfig;
}
export type StatusBarCommand = 'gitlens.toggleBlame' | 'gitlens.showBlameHistory' | 'gitlens.showFileHistory' | 'gitlens.toggleCodeLens' | 'gitlens.diffWithPrevious' | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory';
export type StatusBarCommand = 'gitlens.toggleBlame' | 'gitlens.showBlameHistory' | 'gitlens.showFileHistory' | 'gitlens.toggleCodeLens' | 'gitlens.diffWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory';
export const StatusBarCommand = {
BlameAnnotate: Commands.ToggleBlame as StatusBarCommand,
ShowBlameHistory: Commands.ShowBlameHistory as StatusBarCommand,
ShowFileHistory: Commands.ShowFileHistory as CodeLensCommand,
DiffWithPrevious: Commands.DiffWithPrevious as StatusBarCommand,
DiffWithWorking: Commands.DiffWithWorking as StatusBarCommand,
ToggleCodeLens: Commands.ToggleCodeLens as StatusBarCommand,
ShowQuickCommitDetails: Commands.ShowQuickCommitDetails as StatusBarCommand,
ShowQuickCommitFileDetails: Commands.ShowQuickCommitFileDetails as StatusBarCommand,

View File

@@ -62,8 +62,8 @@ export class GitContextTracker extends Disposable {
}
private _onBlameFailed(key: string) {
const fileName = this._editor && this._editor.document && this._editor.document.fileName;
if (!fileName || key !== this.git.getCacheEntryKey(fileName)) return;
if (this._editor === undefined || this._editor.document === undefined || this._editor.document.uri === undefined) return;
if (key !== this.git.getCacheEntryKey(this._editor.document.uri)) return;
this._updateBlameability(false);
}

View File

@@ -83,15 +83,15 @@ export class GitUri extends Uri {
if (!git.isTrackable(uri)) return new GitUri(uri, git.repoPath);
const gitUri = git.getGitUriForFile(uri.fsPath);
if (gitUri) return gitUri;
// If this is a git uri, assume it is showing the most recent commit
if (uri.scheme === DocumentSchemes.Git && uri.query === '~') {
if (uri.scheme === DocumentSchemes.Git) {
const commit = await git.getLogCommit(undefined, uri.fsPath);
if (commit) return new GitUri(uri, commit);
if (commit !== undefined) return new GitUri(uri, commit);
}
const gitUri = git.getGitUriForFile(uri);
if (gitUri) return gitUri;
return new GitUri(uri, (await git.getRepoPathFromFile(uri.fsPath)) || git.repoPath);
}

View File

@@ -1,18 +1,19 @@
'use strict';
export interface IGitDiffChunk {
current: (string | undefined)[];
currentStart: number;
currentEnd: number;
previous: (string | undefined)[];
previousStart: number;
previousEnd: number;
chunk?: string;
original: (string | undefined)[];
originalStart: number;
originalEnd: number;
changes: (string | undefined)[];
changesStart: number;
changesEnd: number;
}
export interface IGitDiff {
diff?: string;
chunks: IGitDiffChunk[];
diff?: string;
}

View File

@@ -15,22 +15,41 @@ export class GitDiffParser {
match = unifiedDiffRegex.exec(`${data}\n@@`);
if (match == null) break;
const originalStart = +match[1];
const changedStart = +match[3];
const previousStart = +match[1];
const currentStart = +match[3];
const chunk = match[5];
const lines = chunk.split('\n').slice(1);
const original = lines.filter(l => l[0] !== '+').map(l => (l[0] === '-') ? l.substring(1) : undefined);
const changed = lines.filter(l => l[0] !== '-').map(l => (l[0] === '+') ? l.substring(1) : undefined);
const current = [];
const previous = [];
for (const l of lines) {
switch (l[0]) {
case '+':
current.push(` ${l.substring(1)}`);
previous.push(undefined);
break;
case '-':
current.push(undefined);
previous.push(` ${l.substring(1)}`);
break;
default:
current.push(l);
previous.push(l);
break;
}
}
chunks.push({
chunk: debug ? chunk : undefined,
original: original,
originalStart: originalStart,
originalEnd: originalStart + +match[2],
changes: changed,
changesStart: changedStart,
changesEnd: changedStart + +match[4]
current: current,
currentStart: currentStart,
currentEnd: currentStart + +match[4],
previous: previous,
previousStart: previousStart,
previousEnd: previousStart + +match[2]
});
} while (match != null);

View File

@@ -360,7 +360,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
}
_applyDiffWithPreviousCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
if (!commit) {
if (commit === undefined) {
const blameLine = blame.allLines[lens.range.start.line];
commit = blame.commits.get(blameLine.sha);
}
@@ -382,7 +382,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
_applyShowQuickCommitDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
lens.command = {
title: title,
command: CodeLensCommand.ShowQuickCommitDetails,
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitDetails,
arguments: [
Uri.file(lens.uri.fsPath),
{
@@ -396,7 +396,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
_applyShowQuickCommitFileDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
lens.command = {
title: title,
command: CodeLensCommand.ShowQuickCommitFileDetails,
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitFileDetails,
arguments: [
Uri.file(lens.uri.fsPath),
{

View File

@@ -1,6 +1,6 @@
'use strict';
import { Iterables, Objects } from './system';
import { Disposable, Event, EventEmitter, ExtensionContext, FileSystemWatcher, languages, Location, Position, Range, TextDocument, TextEditor, Uri, workspace } from 'vscode';
import { Disposable, Event, EventEmitter, ExtensionContext, FileSystemWatcher, languages, Location, Position, Range, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, workspace } from 'vscode';
import { CommandContext, setCommandContext } from './commands';
import { CodeLensVisibility, IConfig } from './configuration';
import { DocumentSchemes, ExtensionKey } from './constants';
@@ -166,6 +166,7 @@ export class GitService extends Disposable {
const disposables: Disposable[] = [];
disposables.push(workspace.onDidCloseTextDocument(d => this._removeCachedEntry(d, RemoveCacheReason.DocumentClosed)));
disposables.push(workspace.onDidChangeTextDocument(this._onTextDocumentChanged, this));
disposables.push(workspace.onDidSaveTextDocument(d => this._removeCachedEntry(d, RemoveCacheReason.DocumentSaved)));
disposables.push(this._fsWatcher.onDidChange(this._onGitChanged, this));
@@ -208,6 +209,21 @@ export class GitService extends Disposable {
this.config = cfg;
}
private _onTextDocumentChanged(e: TextDocumentChangeEvent) {
if (!this.UseCaching) return;
if (e.document.uri.scheme !== DocumentSchemes.File) return;
// We have to defer because isDirty is not reliable inside this event
setTimeout(() => {
// If the document is dirty all is fine, we'll just wait for the save before clearing our cache
if (e.document.isDirty) return;
// If the document isn't dirty, it is very likely this event was triggered by an outside edit of this document
// Which means the document has been reloaded and we should clear our cache for it
this._removeCachedEntry(e.document, RemoveCacheReason.DocumentSaved);
}, 1);
}
private _onGitChanged() {
this._gitCache.clear();
@@ -219,7 +235,7 @@ export class GitService extends Disposable {
if (!this.UseCaching) return;
if (document.uri.scheme !== DocumentSchemes.File) return;
const cacheKey = this.getCacheEntryKey(document.fileName);
const cacheKey = this.getCacheEntryKey(document.uri);
if (reason === RemoveCacheReason.DocumentSaved) {
// Don't remove broken blame on save (since otherwise we'll have to run the broken blame again)
@@ -313,7 +329,7 @@ export class GitService extends Disposable {
public async getBlameability(uri: GitUri): Promise<boolean> {
if (!this.UseCaching) return await this.isTracked(uri);
const cacheKey = this.getCacheEntryKey(uri.fsPath);
const cacheKey = this.getCacheEntryKey(uri);
const entry = this._gitCache.get(cacheKey);
if (entry === undefined) return await this.isTracked(uri);
@@ -326,11 +342,9 @@ export class GitService extends Disposable {
key += `:${uri.sha}`;
}
const fileName = uri.fsPath;
let entry: GitCacheEntry | undefined;
if (this.UseCaching) {
const cacheKey = this.getCacheEntryKey(fileName);
const cacheKey = this.getCacheEntryKey(uri);
entry = this._gitCache.get(cacheKey);
if (entry !== undefined) {
@@ -339,19 +353,6 @@ export class GitService extends Disposable {
Logger.log(`Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
return cachedBlame.item;
}
if (key !== 'blame') {
// Since we are looking for partial blame, see if we have the blame of the whole file
const cachedBlame = entry.get<ICachedBlame>('blame');
if (cachedBlame !== undefined) {
Logger.log(`? Cache(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
const blame = await cachedBlame.item;
if (blame !== undefined && blame.commits.has(uri.sha!)) {
Logger.log(`Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
return cachedBlame.item;
}
}
}
}
Logger.log(`Not Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
@@ -365,7 +366,7 @@ export class GitService extends Disposable {
Logger.log(`getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
}
const promise = this._getBlameForFile(uri, fileName, entry, key);
const promise = this._getBlameForFile(uri, entry, key);
if (entry) {
Logger.log(`Add blame cache for '${entry.key}:${key}'`);
@@ -378,12 +379,12 @@ export class GitService extends Disposable {
return promise;
}
private async _getBlameForFile(uri: GitUri, fileName: string, entry: GitCacheEntry | undefined, key: string): Promise<IGitBlame | undefined> {
const [file, root] = Git.splitPath(fileName, uri.repoPath, false);
private async _getBlameForFile(uri: GitUri, entry: GitCacheEntry | undefined, key: string): Promise<IGitBlame | undefined> {
const [file, root] = Git.splitPath(uri.fsPath, uri.repoPath, false);
const ignore = await this._gitignore;
if (ignore && !ignore.filter([file]).length) {
Logger.log(`Skipping blame; '${fileName}' is gitignored`);
Logger.log(`Skipping blame; '${uri.fsPath}' is gitignored`);
if (entry && entry.key) {
this._onDidBlameFail.fire(entry.key);
}
@@ -550,8 +551,10 @@ export class GitService extends Disposable {
return branches;
}
getCacheEntryKey(fileName: string) {
return Git.normalizePath(fileName).toLowerCase();
getCacheEntryKey(fileName: string): string;
getCacheEntryKey(uri: Uri): string;
getCacheEntryKey(fileNameOrUri: string | Uri): string {
return Git.normalizePath(typeof fileNameOrUri === 'string' ? fileNameOrUri : fileNameOrUri.fsPath).toLowerCase();
}
async getConfig(key: string, repoPath?: string): Promise<string> {
@@ -560,13 +563,17 @@ export class GitService extends Disposable {
return await Git.config_get(key, repoPath);
}
getGitUriForFile(fileName: string) {
const cacheKey = this.getCacheEntryKey(fileName);
getGitUriForFile(uri: Uri) {
const cacheKey = this.getCacheEntryKey(uri);
const entry = this._uriCache.get(cacheKey);
return entry && entry.uri;
}
async getDiffForFile(repoPath: string | undefined, fileName: string, sha1?: string, sha2?: string): Promise<IGitDiff | undefined> {
async getDiffForFile(uri: GitUri, sha1?: string, sha2?: string): Promise<IGitDiff | undefined> {
if (sha1 !== undefined && sha2 === undefined && uri.sha !== undefined) {
sha2 = uri.sha;
}
let key = 'diff';
if (sha1 !== undefined) {
key += `:${sha1}`;
@@ -577,18 +584,18 @@ export class GitService extends Disposable {
let entry: GitCacheEntry | undefined;
if (this.UseCaching) {
const cacheKey = this.getCacheEntryKey(fileName);
const cacheKey = this.getCacheEntryKey(uri);
entry = this._gitCache.get(cacheKey);
if (entry !== undefined) {
const cachedDiff = entry.get<ICachedDiff>(key);
if (cachedDiff !== undefined) {
Logger.log(`Cached(${key}): getDiffForFile('${repoPath}', '${fileName}', ${sha1}, ${sha2})`);
Logger.log(`Cached(${key}): getDiffForFile('${uri.repoPath}', '${uri.fsPath}', ${sha1}, ${sha2})`);
return cachedDiff.item;
}
}
Logger.log(`Not Cached(${key}): getDiffForFile('${repoPath}', '${fileName}', ${sha1}, ${sha2})`);
Logger.log(`Not Cached(${key}): getDiffForFile('${uri.repoPath}', '${uri.fsPath}', ${sha1}, ${sha2})`);
if (entry === undefined) {
entry = new GitCacheEntry(cacheKey);
@@ -596,10 +603,10 @@ export class GitService extends Disposable {
}
}
else {
Logger.log(`getDiffForFile('${repoPath}', '${fileName}', ${sha1}, ${sha2})`);
Logger.log(`getDiffForFile('${uri.repoPath}', '${uri.fsPath}', ${sha1}, ${sha2})`);
}
const promise = this._getDiffForFile(repoPath, fileName, sha1, sha2, entry, key);
const promise = this._getDiffForFile(uri.repoPath, uri.fsPath, sha1, sha2, entry, key);
if (entry) {
Logger.log(`Add log cache for '${entry.key}:${key}'`);
@@ -617,7 +624,7 @@ export class GitService extends Disposable {
try {
const data = await Git.diff(root, file, sha1, sha2);
return GitDiffParser.parse(data, this.config.debug);
return GitDiffParser.parse(data);
}
catch (ex) {
// Trap and cache expected diff errors
@@ -637,17 +644,34 @@ export class GitService extends Disposable {
}
}
async getDiffForLine(repoPath: string | undefined, fileName: string, line: number, sha1?: string, sha2?: string): Promise<[string | undefined, string | undefined] | undefined> {
async getDiffForLine(uri: GitUri, line: number, sha1?: string, sha2?: string): Promise<[string | undefined, string | undefined] | undefined> {
try {
const diff = await this.getDiffForFile(repoPath, fileName, sha1, sha2);
const diff = await this.getDiffForFile(uri, sha1, sha2);
if (diff === undefined) return undefined;
const chunk = diff.chunks.find(_ => Math.min(_.originalStart, _.changesStart) <= line && Math.max(_.originalEnd, _.changesEnd) >= line);
const chunk = diff.chunks.find(_ => _.currentStart <= line && _.currentEnd >= line);
if (chunk === undefined) return undefined;
// Search for the line (skipping deleted lines -- since they don't currently exist in the editor)
// Keep track of the deleted lines for the original version
line = line - chunk.currentStart + 1;
let count = 0;
let deleted = 0;
for (const l of chunk.current) {
if (l === undefined) {
deleted++;
if (count === line) break;
continue;
}
if (count === line) break;
count++;
}
return [
chunk.original[line - chunk.originalStart + 1],
chunk.changes[line - chunk.changesStart + 1]
chunk.previous[line + deleted - 1],
chunk.current[line + deleted]
];
}
catch (ex) {
@@ -845,7 +869,6 @@ export class GitService extends Disposable {
}
async getRemotes(repoPath: string): Promise<GitRemote[]> {
if (!this.config.insiders) return [];
if (!repoPath) return [];
Logger.log(`getRemotes('${repoPath}')`);
@@ -927,19 +950,10 @@ export class GitService extends Disposable {
return Git.show(repoPath, fileName, sha);
}
hasGitUriForFile(editor: TextEditor): boolean;
hasGitUriForFile(fileName: string): boolean;
hasGitUriForFile(fileNameOrEditor: string | TextEditor): boolean {
let fileName: string;
if (typeof fileNameOrEditor === 'string') {
fileName = fileNameOrEditor;
}
else {
if (!fileNameOrEditor || !fileNameOrEditor.document || !fileNameOrEditor.document.uri) return false;
fileName = fileNameOrEditor.document.uri.fsPath;
}
hasGitUriForFile(editor: TextEditor): boolean {
if (editor === undefined || editor.document === undefined || editor.document.uri === undefined) return false;
const cacheKey = this.getCacheEntryKey(fileName);
const cacheKey = this.getCacheEntryKey(editor.document.uri);
return this._uriCache.has(cacheKey);
}

View File

@@ -110,7 +110,7 @@ export class CommitDetailsQuickPick {
let index = 0;
if (stash && git.config.insiders) {
if (stash) {
items.splice(index++, 0, new CommandQuickPickItem({
label: `$(git-pull-request) Apply Stashed Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`

View File

@@ -72,7 +72,7 @@ export class CommitFileDetailsQuickPick {
if (commit.previousSha) {
items.push(new CommandQuickPickItem({
label: `$(git-compare) Compare with Previous Commit`,
label: `$(git-compare) Compare File with Previous`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}`
}, Commands.DiffWithPrevious, [
commit.uri,
@@ -85,7 +85,7 @@ export class CommitFileDetailsQuickPick {
if (commit.workingFileName) {
items.push(new CommandQuickPickItem({
label: `$(git-compare) Compare with Working Tree`,
label: `$(git-compare) Compare File with Working Tree`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-text) ${workingName}`
}, Commands.DiffWithWorking, [
Uri.file(path.resolve(commit.repoPath, commit.workingFileName)),

View File

@@ -10,7 +10,7 @@ export class StashListQuickPick {
static async show(git: GitService, stash: IGitStash, mode: 'list' | 'apply', goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
const items = ((stash && Array.from(Iterables.map(stash.commits.values(), c => new CommitQuickPickItem(c)))) || []) as (CommitQuickPickItem | CommandQuickPickItem)[];
if (mode === 'list' && git.config.insiders) {
if (mode === 'list') {
items.splice(0, 0, new CommandQuickPickItem({
label: `$(repo-push) Stash Unstaged Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 stashes only unstaged changes`