mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-12 11:08:34 -05:00
Compare commits
19 Commits
v3.5.0-bet
...
v3.6.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0d5f55baa | ||
|
|
68f6ae8f3a | ||
|
|
53c691898f | ||
|
|
365af9c54b | ||
|
|
55b1a66ec0 | ||
|
|
522e5a49a2 | ||
|
|
e99febb52d | ||
|
|
2036c8abaf | ||
|
|
021a5b833a | ||
|
|
f1042de9c7 | ||
|
|
efd3d40aa8 | ||
|
|
9c7062020e | ||
|
|
9da80c121b | ||
|
|
5380724323 | ||
|
|
77651701aa | ||
|
|
bb834f2e0a | ||
|
|
535e627048 | ||
|
|
8a74950708 | ||
|
|
3502bdf6c7 |
21
.vscode/tasks.json
vendored
21
.vscode/tasks.json
vendored
@@ -9,24 +9,33 @@
|
|||||||
// A task runner that calls a custom npm script that compiles the extension.
|
// A task runner that calls a custom npm script that compiles the extension.
|
||||||
{
|
{
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"showOutput": "always",
|
"showOutput": "silent",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"taskName": "compile",
|
"taskName": "compile",
|
||||||
"command": "npm run compile",
|
"command": "npm run compile --silent",
|
||||||
"isBuildCommand": true,
|
"isBuildCommand": true,
|
||||||
"isShellCommand": true,
|
"isShellCommand": true,
|
||||||
"problemMatcher": [ "$tsc", "$tslint5" ]
|
"problemMatcher": [
|
||||||
|
"$tsc",
|
||||||
|
{
|
||||||
|
"base": "$tslint5",
|
||||||
|
"fileLocation": "relative"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskName": "lint",
|
"taskName": "lint",
|
||||||
"command": "npm run lint",
|
"command": "npm run lint --silent",
|
||||||
"isShellCommand": true,
|
"isShellCommand": true,
|
||||||
"problemMatcher": "$tslint5"
|
"problemMatcher": {
|
||||||
|
"base": "$tslint5",
|
||||||
|
"fileLocation": "relative"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskName": "watch",
|
"taskName": "watch",
|
||||||
"command": "npm run watch",
|
"command": "npm run watch --silent",
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"isShellCommand": true,
|
"isShellCommand": true,
|
||||||
"problemMatcher": "$tsc-watch"
|
"problemMatcher": "$tsc-watch"
|
||||||
|
|||||||
40
CHANGELOG.md
40
CHANGELOG.md
@@ -4,20 +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/).
|
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] - 2017-05-23
|
## [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
|
||||||
|
|
||||||
|
### 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
|
### Added
|
||||||
- Improves performance
|
- Improves performance
|
||||||
- Reduces the number of git calls on known "untrackables"
|
- Reduces the number of git calls on known "untrackables"
|
||||||
- Caches many more git commands to reduce git command roundtrips and parsing
|
- 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
|
- 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 Zack Schuster (@zackschuster)!
|
- 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 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 `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 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
|
- 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
|
### 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 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+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
|
- 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
|
||||||
@@ -26,6 +57,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixes [#73](https://github.com/eamodio/vscode-gitlens/issues/73) - GitLens doesn't work with Chinese filenames
|
- 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 file selection from the commit details quick pick menu
|
||||||
- Fixes incorrect command execution when using `"gitlens.statusBar.command": "gitlens.showQuickRepoHistory"`
|
- Fixes incorrect command execution when using `"gitlens.statusBar.command": "gitlens.showQuickRepoHistory"`
|
||||||
- Fixes a bunch of issues that were revealed by enabling Typescript `strict` mode
|
- Fixes a bunch of issues that were revealed by enabling Typescript `strict` mode
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -20,7 +20,7 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
|
|||||||
|
|
||||||
#### Git Blame Annotations
|
#### 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
|
- 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`)
|
- 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 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 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
|
#### Navigate and Explore
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ GitLens provides an unobtrusive blame annotation at the end of the selected line
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
- 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
|
- 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 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
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
- [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
|
- 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
|
- 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
|
- 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`
|
- 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
|
- 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 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
|
- 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
|
- 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
|
## 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.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.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.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.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
|
|`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
|
||||||
|
|
||||||
@@ -219,3 +219,10 @@ GitLens is highly customizable and provides many configuration settings to allow
|
|||||||
|
|
||||||
- If the `Copy to * clipboard` commands don't work on Linux -- `xclip` needs to be installed. You can install it via `sudo apt-get install xclip`
|
- If the `Copy to * clipboard` commands don't work on Linux -- `xclip` needs to be installed. You can install it via `sudo apt-get install xclip`
|
||||||
- Visible whitespace causes issues ([vscode issue #11485](https://github.com/Microsoft/vscode/issues/11485)) with the `expanded` and `compact` blame annotation styles when using a non-monospace font -- set `"gitlens.advanced.toggleWhitespace.enabled": true` if you are using a non-monospace font
|
- Visible whitespace causes issues ([vscode issue #11485](https://github.com/Microsoft/vscode/issues/11485)) with the `expanded` and `compact` blame annotation styles when using a non-monospace font -- set `"gitlens.advanced.toggleWhitespace.enabled": true` if you are using a non-monospace font
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
A big thanks to the people that have contributed to this project:
|
||||||
|
|
||||||
|
- Aurelio Ogliari ([@nobitagit](https://github.com/nobitagit)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=nobitagit)
|
||||||
|
- Zack Schuster ([@zackschuster](https://github.com/zackschuster)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=zackschuster)
|
||||||
|
|||||||
25
package.json
25
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitlens",
|
"name": "gitlens",
|
||||||
"version": "3.5.0-beta",
|
"version": "3.6.0-beta",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Eric Amodio",
|
"name": "Eric Amodio",
|
||||||
"email": "eamodio@gmail.com"
|
"email": "eamodio@gmail.com"
|
||||||
@@ -308,13 +308,14 @@
|
|||||||
"gitlens.showBlameHistory",
|
"gitlens.showBlameHistory",
|
||||||
"gitlens.showFileHistory",
|
"gitlens.showFileHistory",
|
||||||
"gitlens.diffWithPrevious",
|
"gitlens.diffWithPrevious",
|
||||||
|
"gitlens.diffWithWorking",
|
||||||
"gitlens.toggleCodeLens",
|
"gitlens.toggleCodeLens",
|
||||||
"gitlens.showQuickCommitDetails",
|
"gitlens.showQuickCommitDetails",
|
||||||
"gitlens.showQuickCommitFileDetails",
|
"gitlens.showQuickCommitFileDetails",
|
||||||
"gitlens.showQuickFileHistory",
|
"gitlens.showQuickFileHistory",
|
||||||
"gitlens.showQuickRepoHistory"
|
"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": {
|
"gitlens.statusBar.date": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -386,12 +387,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffWithPrevious",
|
"command": "gitlens.diffWithPrevious",
|
||||||
"title": "Compare File with Previous Commit",
|
"title": "Compare File with Previous",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffLineWithPrevious",
|
"command": "gitlens.diffLineWithPrevious",
|
||||||
"title": "Compare Line with Previous Commit",
|
"title": "Compare Line Commit with Previous",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -401,7 +402,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffLineWithWorking",
|
"command": "gitlens.diffLineWithWorking",
|
||||||
"title": "Compare Line with Working Tree",
|
"title": "Compare Line Commit with Working Tree",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -645,11 +646,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.stashApply",
|
"command": "gitlens.stashApply",
|
||||||
"when": "gitlens:enabled && config.gitlens.insiders"
|
"when": "gitlens:enabled"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.stashSave",
|
"command": "gitlens.stashSave",
|
||||||
"when": "gitlens:enabled && config.gitlens.insiders"
|
"when": "gitlens:enabled"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"explorer/context": [
|
"explorer/context": [
|
||||||
@@ -900,25 +901,27 @@
|
|||||||
"vscode:prepublish": "npm install && npm run compile"
|
"vscode:prepublish": "npm install && npm run compile"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"applicationinsights": "0.20.0",
|
"applicationinsights": "0.20.1",
|
||||||
"copy-paste": "1.3.0",
|
"copy-paste": "1.3.0",
|
||||||
|
"iconv-lite": "0.4.17",
|
||||||
"ignore": "3.3.3",
|
"ignore": "3.3.3",
|
||||||
"lodash.debounce": "4.0.8",
|
"lodash.debounce": "4.0.8",
|
||||||
"lodash.escaperegexp": "4.1.2",
|
"lodash.escaperegexp": "4.1.2",
|
||||||
"lodash.isequal": "4.5.0",
|
"lodash.isequal": "4.5.0",
|
||||||
"lodash.once": "4.1.1",
|
"lodash.once": "4.1.1",
|
||||||
"moment": "2.18.1",
|
"moment": "2.18.1",
|
||||||
"spawn-rx": "2.0.10",
|
"spawn-rx": "2.0.11",
|
||||||
"tmp": "0.0.31"
|
"tmp": "0.0.31"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/applicationinsights": "0.15.33",
|
"@types/applicationinsights": "0.15.33",
|
||||||
"@types/copy-paste": "1.1.30",
|
"@types/copy-paste": "1.1.30",
|
||||||
|
"@types/iconv-lite": "0.0.1",
|
||||||
"@types/mocha": "2.2.41",
|
"@types/mocha": "2.2.41",
|
||||||
"@types/node": "7.0.22",
|
"@types/node": "7.0.22",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"mocha": "3.4.1",
|
"mocha": "3.4.2",
|
||||||
"tslint": "5.3.0",
|
"tslint": "5.3.2",
|
||||||
"typescript": "2.3.3",
|
"typescript": "2.3.3",
|
||||||
"vscode": "1.1.0"
|
"vscode": "1.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,5 +56,4 @@ export class ActiveEditorTracker extends Disposable {
|
|||||||
this._resolver = undefined;
|
this._resolver = undefined;
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Functions, Objects } from './system';
|
import { Functions, Objects } from './system';
|
||||||
import { DecorationOptions, DecorationInstanceRenderOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
|
import { DecorationInstanceRenderOptions, DecorationOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
|
||||||
import { BlameAnnotationController } from './blameAnnotationController';
|
import { BlameAnnotationController } from './blameAnnotationController';
|
||||||
import { BlameAnnotationFormat, BlameAnnotationFormatter } from './blameAnnotationFormatter';
|
import { BlameAnnotationFormat, BlameAnnotationFormatter } from './blameAnnotationFormatter';
|
||||||
|
import { Commands } from './commands';
|
||||||
import { TextEditorComparer } from './comparers';
|
import { TextEditorComparer } from './comparers';
|
||||||
import { IBlameConfig, IConfig, StatusBarCommand } from './configuration';
|
import { IBlameConfig, IConfig, StatusBarCommand } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey } from './constants';
|
import { DocumentSchemes, ExtensionKey } from './constants';
|
||||||
@@ -54,7 +55,7 @@ export class BlameActiveLineController extends Disposable {
|
|||||||
private _onConfigurationChanged() {
|
private _onConfigurationChanged() {
|
||||||
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
||||||
|
|
||||||
let changed: boolean = false;
|
let changed = false;
|
||||||
|
|
||||||
if (!Objects.areEquivalent(cfg.statusBar, this._config && this._config.statusBar)) {
|
if (!Objects.areEquivalent(cfg.statusBar, this._config && this._config.statusBar)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
@@ -89,7 +90,7 @@ export class BlameActiveLineController extends Disposable {
|
|||||||
|
|
||||||
if (!changed) return;
|
if (!changed) return;
|
||||||
|
|
||||||
let trackActiveLine = cfg.statusBar.enabled || cfg.blame.annotation.activeLine !== 'off';
|
const trackActiveLine = cfg.statusBar.enabled || cfg.blame.annotation.activeLine !== 'off';
|
||||||
if (trackActiveLine && !this._activeEditorLineDisposable) {
|
if (trackActiveLine && !this._activeEditorLineDisposable) {
|
||||||
const subscriptions: Disposable[] = [];
|
const subscriptions: Disposable[] = [];
|
||||||
|
|
||||||
@@ -140,7 +141,7 @@ export class BlameActiveLineController extends Disposable {
|
|||||||
this.git.getBlameForFile(this._uri);
|
this.git.getBlameForFile(this._uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateBlame(editor.selection.active.line, editor);
|
this._updateBlameDebounced(editor.selection.active.line, editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onBlameabilityChanged(e: BlameabilityChangeEvent) {
|
private _onBlameabilityChanged(e: BlameabilityChangeEvent) {
|
||||||
@@ -153,7 +154,7 @@ export class BlameActiveLineController extends Disposable {
|
|||||||
// Make sure this is for the editor we are tracking
|
// Make sure this is for the editor we are tracking
|
||||||
if (!TextEditorComparer.equals(this._editor, e.editor)) return;
|
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() {
|
private _onBlameAnnotationToggled() {
|
||||||
@@ -244,7 +245,12 @@ export class BlameActiveLineController extends Disposable {
|
|||||||
this._statusBarItem.tooltip = 'Open File History Explorer';
|
this._statusBarItem.tooltip = 'Open File History Explorer';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.DiffWithPrevious:
|
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;
|
break;
|
||||||
case StatusBarCommand.ToggleCodeLens:
|
case StatusBarCommand.ToggleCodeLens:
|
||||||
this._statusBarItem.tooltip = 'Toggle Git CodeLens';
|
this._statusBarItem.tooltip = 'Toggle Git CodeLens';
|
||||||
@@ -298,30 +304,25 @@ export class BlameActiveLineController extends Disposable {
|
|||||||
if (!commit.isUncommitted && (!possibleDuplicate || !this.annotationController.isAnnotating(editor))) {
|
if (!commit.isUncommitted && (!possibleDuplicate || !this.annotationController.isAnnotating(editor))) {
|
||||||
hoverMessage = BlameAnnotationFormatter.getAnnotationHover(cfg, blameLine, logCommit || commit);
|
hoverMessage = BlameAnnotationFormatter.getAnnotationHover(cfg, blameLine, logCommit || commit);
|
||||||
|
|
||||||
// if (commit.previousSha !== undefined) {
|
if (commit.previousSha !== undefined) {
|
||||||
// const changes = await this.git.getDiffForLine(this._uri.repoPath, this._uri.fsPath, blameLine.line + offset, commit.previousSha);
|
const changes = await this.git.getDiffForLine(this._uri, blameLine.line + offset, commit.previousSha);
|
||||||
// if (changes !== undefined) {
|
if (changes !== undefined) {
|
||||||
// const previous = changes[0];
|
let previous = changes[0];
|
||||||
// if (previous !== undefined) {
|
if (previous !== undefined) {
|
||||||
// hoverMessage += `\n\n\`Before ${commit.shortSha}\`\n\`\`\`\n${previous.trim().replace(/\n/g, '\`\n>\n> \`')}\n\`\`\``;
|
previous = previous.replace(/\n/g, '\`\n>\n> \`').trim();
|
||||||
// }
|
hoverMessage += `\n\n---\n\`\`\`\n${previous}\n\`\`\``;
|
||||||
// else {
|
}
|
||||||
// hoverMessage += `\n\n\`Added in ${commit.shortSha}\``;
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
else if (commit.isUncommitted) {
|
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) {
|
if (changes !== undefined) {
|
||||||
let original = changes[0];
|
let previous = changes[0];
|
||||||
if (original !== undefined) {
|
if (previous !== undefined) {
|
||||||
original = original.replace(/\n/g, '\`\n>\n> \`').trim();
|
previous = previous.replace(/\n/g, '\`\n>\n> \`').trim();
|
||||||
hoverMessage = `\`${'0'.repeat(8)}\` __Uncommitted change__\n\n\---\n\`\`\`\n${original}\n\`\`\``;
|
hoverMessage = `\`${'0'.repeat(8)}\` __Uncommitted change__\n\n---\n\`\`\`\n${previous}\n\`\`\``;
|
||||||
}
|
}
|
||||||
// else {
|
|
||||||
// hoverMessage = `\`${'0'.repeat(8)}\` __Uncommitted change__\n\n\`Added\``;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Functions } from './system';
|
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 { BlameAnnotationProvider } from './blameAnnotationProvider';
|
||||||
import { TextDocumentComparer, TextEditorComparer } from './comparers';
|
import { TextDocumentComparer, TextEditorComparer } from './comparers';
|
||||||
import { IBlameConfig } from './configuration';
|
import { IBlameConfig } from './configuration';
|
||||||
import { ExtensionKey } from './constants';
|
import { ExtensionKey } from './constants';
|
||||||
import { BlameabilityChangeEvent, GitService, GitUri, GitContextTracker } from './gitService';
|
import { BlameabilityChangeEvent, GitContextTracker, GitService, GitUri } from './gitService';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
import { WhitespaceController } from './whitespaceController';
|
import { WhitespaceController } from './whitespaceController';
|
||||||
|
|
||||||
@@ -176,6 +176,7 @@ export class BlameAnnotationController extends Disposable {
|
|||||||
|
|
||||||
subscriptions.push(window.onDidChangeVisibleTextEditors(Functions.debounce(this._onVisibleTextEditorsChanged, 100), this));
|
subscriptions.push(window.onDidChangeVisibleTextEditors(Functions.debounce(this._onVisibleTextEditorsChanged, 100), this));
|
||||||
subscriptions.push(window.onDidChangeTextEditorViewColumn(this._onTextEditorViewColumnChanged, this));
|
subscriptions.push(window.onDidChangeTextEditorViewColumn(this._onTextEditorViewColumnChanged, this));
|
||||||
|
subscriptions.push(workspace.onDidChangeTextDocument(this._onTextDocumentChanged, this));
|
||||||
subscriptions.push(workspace.onDidCloseTextDocument(this._onTextDocumentClosed, this));
|
subscriptions.push(workspace.onDidCloseTextDocument(this._onTextDocumentClosed, this));
|
||||||
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
|
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
|
||||||
|
|
||||||
@@ -199,7 +200,7 @@ export class BlameAnnotationController extends Disposable {
|
|||||||
async toggleBlameAnnotation(editor: TextEditor, shaOrLine?: string | number): Promise<boolean> {
|
async toggleBlameAnnotation(editor: TextEditor, shaOrLine?: string | number): Promise<boolean> {
|
||||||
if (!editor || !editor.document || !this.git.isEditorBlameable(editor)) return false;
|
if (!editor || !editor.document || !this.git.isEditorBlameable(editor)) return false;
|
||||||
|
|
||||||
let provider = this._annotationProviders.get(editor.viewColumn || -1);
|
const provider = this._annotationProviders.get(editor.viewColumn || -1);
|
||||||
if (!provider) return this.showBlameAnnotation(editor, shaOrLine);
|
if (!provider) return this.showBlameAnnotation(editor, shaOrLine);
|
||||||
|
|
||||||
await this.clear(provider.editor.viewColumn || -1);
|
await this.clear(provider.editor.viewColumn || -1);
|
||||||
@@ -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) {
|
private _onTextDocumentClosed(e: TextDocument) {
|
||||||
for (const [key, p] of this._annotationProviders) {
|
for (const [key, p] of this._annotationProviders) {
|
||||||
if (!TextDocumentComparer.equals(p.document, e)) continue;
|
if (!TextDocumentComparer.equals(p.document, e)) continue;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export class BlameAnnotationFormatter {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getAnnotationHover(config: IBlameConfig, line: IGitCommitLine, commit: GitCommit): string | Array<string> {
|
static getAnnotationHover(config: IBlameConfig, line: IGitCommitLine, commit: GitCommit): string | string[] {
|
||||||
const message = `> \`${commit.message.replace(/\n/g, '\`\n>\n> \`')}\``;
|
const message = `> \`${commit.message.replace(/\n/g, '\`\n>\n> \`')}\``;
|
||||||
if (commit.isUncommitted) {
|
if (commit.isUncommitted) {
|
||||||
return `\`${'0'.repeat(8)}\` __Uncommitted change__`;
|
return `\`${'0'.repeat(8)}\` __Uncommitted change__`;
|
||||||
@@ -103,7 +103,7 @@ export class BlameAnnotationFormatter {
|
|||||||
static getMessage(config: IBlameConfig, commit: GitCommit, truncateTo: number = 0, force: boolean = false) {
|
static getMessage(config: IBlameConfig, commit: GitCommit, truncateTo: number = 0, force: boolean = false) {
|
||||||
if (!force && !config.annotation.message) return '';
|
if (!force && !config.annotation.message) return '';
|
||||||
|
|
||||||
let message = commit.isUncommitted ? 'Uncommitted change' : commit.message;
|
const message = commit.isUncommitted ? 'Uncommitted change' : commit.message;
|
||||||
if (truncateTo && message.length > truncateTo) {
|
if (truncateTo && message.length > truncateTo) {
|
||||||
return `${message.substring(0, truncateTo - 1)}\u2026`;
|
return `${message.substring(0, truncateTo - 1)}\u2026`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
|||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks';
|
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
||||||
|
|
||||||
export interface DiffDirectoryCommandCommandArgs {
|
export interface DiffDirectoryCommandCommandArgs {
|
||||||
shaOrBranch1?: string;
|
shaOrBranch1?: string;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
|||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks';
|
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface DiffWithBranchCommandArgs {
|
export interface DiffWithBranchCommandArgs {
|
||||||
|
|||||||
@@ -32,17 +32,15 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
const gitUri = await GitUri.fromUri(uri, this.git);
|
const gitUri = await GitUri.fromUri(uri, this.git);
|
||||||
|
|
||||||
try {
|
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 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!);
|
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`);
|
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());
|
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) {
|
catch (ex) {
|
||||||
Logger.error(ex, 'DiffWithPreviousCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`);
|
Logger.error(ex, 'DiffWithPreviousCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`);
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
|
if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
|
||||||
const gitUri = await GitUri.fromUri(uri, this.git);
|
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 {
|
try {
|
||||||
args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });
|
args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });
|
||||||
|
|||||||
@@ -16,8 +16,11 @@ export const keys: Keys[] = [
|
|||||||
'.'
|
'.'
|
||||||
];
|
];
|
||||||
|
|
||||||
export declare type KeyMapping = { [id: string]: (QuickPickItem | (() => Promise<QuickPickItem>) | undefined) };
|
export declare interface KeyMapping {
|
||||||
let mappings: KeyMapping[] = [];
|
[id: string]: (QuickPickItem | (() => Promise<QuickPickItem>) | undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappings: KeyMapping[] = [];
|
||||||
|
|
||||||
let _instance: Keyboard;
|
let _instance: Keyboard;
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
|
|||||||
return command.execute();
|
return command.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
let placeHolder: string = '';
|
let placeHolder = '';
|
||||||
switch (args.resource.type) {
|
switch (args.resource.type) {
|
||||||
case 'branch':
|
case 'branch':
|
||||||
// Check to see if the remote is in the branch
|
// Check to see if the remote is in the branch
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ export class StashApplyCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async execute(args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
|
async execute(args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
|
||||||
if (!this.git.config.insiders) return undefined;
|
|
||||||
if (!this.git.repoPath) return undefined;
|
if (!this.git.repoPath) return undefined;
|
||||||
|
|
||||||
if (args.stashItem === undefined || args.stashItem.stashName === undefined) {
|
if (args.stashItem === undefined || args.stashItem.stashName === undefined) {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ export class StashDeleteCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async execute(args: StashDeleteCommandArgs = { confirm: true }) {
|
async execute(args: StashDeleteCommandArgs = { confirm: true }) {
|
||||||
if (!this.git.config.insiders) return undefined;
|
|
||||||
if (!this.git.repoPath) return undefined;
|
if (!this.git.repoPath) return undefined;
|
||||||
|
|
||||||
if (args.stashItem === undefined || args.stashItem.stashName === undefined) return undefined;
|
if (args.stashItem === undefined || args.stashItem.stashName === undefined) return undefined;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ export class StashSaveCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async execute(args: StashSaveCommandArgs = { unstagedOnly : false }) {
|
async execute(args: StashSaveCommandArgs = { unstagedOnly : false }) {
|
||||||
if (!this.git.config.insiders) return undefined;
|
|
||||||
if (!this.git.repoPath) return undefined;
|
if (!this.git.repoPath) return undefined;
|
||||||
|
|
||||||
if (args.unstagedOnly === undefined) {
|
if (args.unstagedOnly === undefined) {
|
||||||
|
|||||||
@@ -73,12 +73,13 @@ export interface ICodeLensesConfig {
|
|||||||
authors: ICodeLensConfig;
|
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 = {
|
export const StatusBarCommand = {
|
||||||
BlameAnnotate: Commands.ToggleBlame as StatusBarCommand,
|
BlameAnnotate: Commands.ToggleBlame as StatusBarCommand,
|
||||||
ShowBlameHistory: Commands.ShowBlameHistory as StatusBarCommand,
|
ShowBlameHistory: Commands.ShowBlameHistory as StatusBarCommand,
|
||||||
ShowFileHistory: Commands.ShowFileHistory as CodeLensCommand,
|
ShowFileHistory: Commands.ShowFileHistory as CodeLensCommand,
|
||||||
DiffWithPrevious: Commands.DiffWithPrevious as StatusBarCommand,
|
DiffWithPrevious: Commands.DiffWithPrevious as StatusBarCommand,
|
||||||
|
DiffWithWorking: Commands.DiffWithWorking as StatusBarCommand,
|
||||||
ToggleCodeLens: Commands.ToggleCodeLens as StatusBarCommand,
|
ToggleCodeLens: Commands.ToggleCodeLens as StatusBarCommand,
|
||||||
ShowQuickCommitDetails: Commands.ShowQuickCommitDetails as StatusBarCommand,
|
ShowQuickCommitDetails: Commands.ShowQuickCommitDetails as StatusBarCommand,
|
||||||
ShowQuickCommitFileDetails: Commands.ShowQuickCommitFileDetails as StatusBarCommand,
|
ShowQuickCommitFileDetails: Commands.ShowQuickCommitFileDetails as StatusBarCommand,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ShowBlameCommand, ToggleBlameCommand } from './commands';
|
|||||||
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
||||||
import { ShowLastQuickPickCommand } from './commands';
|
import { ShowLastQuickPickCommand } from './commands';
|
||||||
import { ShowQuickBranchHistoryCommand, ShowQuickCurrentBranchHistoryCommand, ShowQuickFileHistoryCommand } from './commands';
|
import { ShowQuickBranchHistoryCommand, ShowQuickCurrentBranchHistoryCommand, ShowQuickFileHistoryCommand } from './commands';
|
||||||
import { ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand, ShowCommitSearchCommand } from './commands';
|
import { ShowCommitSearchCommand, ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand } from './commands';
|
||||||
import { ShowQuickRepoStatusCommand, ShowQuickStashListCommand } from './commands';
|
import { ShowQuickRepoStatusCommand, ShowQuickStashListCommand } from './commands';
|
||||||
import { StashApplyCommand, StashDeleteCommand, StashSaveCommand } from './commands';
|
import { StashApplyCommand, StashDeleteCommand, StashSaveCommand } from './commands';
|
||||||
import { ToggleCodeLensCommand } from './commands';
|
import { ToggleCodeLensCommand } from './commands';
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { spawnPromise } from 'spawn-rx';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
import * as iconv from 'iconv-lite';
|
||||||
|
|
||||||
export { IGit };
|
export { IGit };
|
||||||
export * from './models/models';
|
export * from './models/models';
|
||||||
@@ -21,25 +22,43 @@ let git: IGit;
|
|||||||
const defaultLogParams = [`log`, `--name-status`, `--full-history`, `-M`, `--date=iso8601`, `--format=%H -%nauthor %an%nauthor-date %ai%nparents %P%nsummary %B%nfilename ?`];
|
const defaultLogParams = [`log`, `--name-status`, `--full-history`, `-M`, `--date=iso8601`, `--format=%H -%nauthor %an%nauthor-date %ai%nparents %P%nsummary %B%nfilename ?`];
|
||||||
const defaultStashParams = [`stash`, `list`, `--name-status`, `--full-history`, `-M`, `--format=%H -%nauthor-date %ai%nreflog-selector %gd%nsummary %B%nfilename ?`];
|
const defaultStashParams = [`stash`, `list`, `--name-status`, `--full-history`, `-M`, `--format=%H -%nauthor-date %ai%nreflog-selector %gd%nsummary %B%nfilename ?`];
|
||||||
|
|
||||||
async function gitCommand(cwd: string, ...args: any[]) {
|
let defaultEncoding = 'utf8';
|
||||||
|
export function setDefaultEncoding(encoding: string) {
|
||||||
|
defaultEncoding = iconv.encodingExists(encoding) ? encoding : 'utf8';
|
||||||
|
}
|
||||||
|
|
||||||
|
const GitWarnings = [
|
||||||
|
/Not a git repository/,
|
||||||
|
/is outside repository/,
|
||||||
|
/no such path/,
|
||||||
|
/does not have any commits/
|
||||||
|
];
|
||||||
|
|
||||||
|
async function gitCommand(options: { cwd: string, encoding?: string }, ...args: any[]) {
|
||||||
try {
|
try {
|
||||||
// Fixes https://github.com/eamodio/vscode-gitlens/issues/73
|
// Fixes https://github.com/eamodio/vscode-gitlens/issues/73
|
||||||
// See https://stackoverflow.com/questions/4144417/how-to-handle-asian-characters-in-file-names-in-git-on-os-x
|
// See https://stackoverflow.com/questions/4144417/how-to-handle-asian-characters-in-file-names-in-git-on-os-x
|
||||||
args.splice(0, 0, '-c', 'core.quotepath=false');
|
args.splice(0, 0, '-c', 'core.quotepath=false');
|
||||||
|
|
||||||
const s = await spawnPromise(git.path, args, { cwd: cwd });
|
const opts = { encoding: 'utf8', ...options };
|
||||||
Logger.log('git', ...args, ` cwd='${cwd}'`);
|
const s = await spawnPromise(git.path, args, { cwd: options.cwd, encoding: (opts.encoding === 'utf8') ? 'utf8' : 'binary' });
|
||||||
return s;
|
Logger.log('git', ...args, ` cwd='${options.cwd}'`);
|
||||||
|
if (opts.encoding === 'utf8' || opts.encoding === 'binary') return s;
|
||||||
|
|
||||||
|
return iconv.decode(Buffer.from(s, 'binary'), opts.encoding);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
const msg = ex && ex.toString();
|
const msg = ex && ex.toString();
|
||||||
if (msg && (msg.includes('Not a git repository') || msg.includes('is outside repository') || msg.includes('no such path') || msg.includes('does not have any commits'))) {
|
if (msg) {
|
||||||
Logger.warn('git', ...args, ` cwd='${cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
|
for (const warning of GitWarnings) {
|
||||||
return '';
|
if (warning.test(msg)) {
|
||||||
}
|
Logger.warn('git', ...args, ` cwd='${options.cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
|
||||||
else {
|
return '';
|
||||||
Logger.error(ex, 'git', ...args, ` cwd='${cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.error(ex, 'git', ...args, ` cwd='${options.cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,14 +81,14 @@ export class Git {
|
|||||||
static async getRepoPath(cwd: string | undefined) {
|
static async getRepoPath(cwd: string | undefined) {
|
||||||
if (cwd === undefined) return '';
|
if (cwd === undefined) return '';
|
||||||
|
|
||||||
const data = await gitCommand(cwd, 'rev-parse', '--show-toplevel');
|
const data = await gitCommand({ cwd }, 'rev-parse', '--show-toplevel');
|
||||||
if (!data) return '';
|
if (!data) return '';
|
||||||
|
|
||||||
return data.replace(/\r?\n|\r/g, '').replace(/\\/g, '/');
|
return data.replace(/\r?\n|\r/g, '').replace(/\\/g, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getVersionedFile(repoPath: string | undefined, fileName: string, branchOrSha: string) {
|
static async getVersionedFile(repoPath: string | undefined, fileName: string, branchOrSha: string) {
|
||||||
const data = await Git.show(repoPath, fileName, branchOrSha);
|
const data = await Git.show(repoPath, fileName, branchOrSha, 'binary');
|
||||||
|
|
||||||
const suffix = Git.isSha(branchOrSha) ? branchOrSha.substring(0, 8) : branchOrSha;
|
const suffix = Git.isSha(branchOrSha) ? branchOrSha.substring(0, 8) : branchOrSha;
|
||||||
const ext = path.extname(fileName);
|
const ext = path.extname(fileName);
|
||||||
@@ -82,7 +101,7 @@ export class Git {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', ${branchOrSha}); destination=${destination}`);
|
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', ${branchOrSha}); destination=${destination}`);
|
||||||
fs.appendFile(destination, data, err => {
|
fs.appendFile(destination, data, { encoding: 'binary' }, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
return;
|
return;
|
||||||
@@ -144,7 +163,7 @@ export class Git {
|
|||||||
params.push(sha);
|
params.push(sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand(root, ...params, `--`, file);
|
return gitCommand({ cwd: root }, ...params, `--`, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static branch(repoPath: string, all: boolean) {
|
static branch(repoPath: string, all: boolean) {
|
||||||
@@ -153,19 +172,19 @@ export class Git {
|
|||||||
params.push(`-a`);
|
params.push(`-a`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand(repoPath, ...params);
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async config_get(key: string, repoPath?: string) {
|
static async config_get(key: string, repoPath?: string) {
|
||||||
try {
|
try {
|
||||||
return await gitCommand(repoPath || '', `config`, `--get`, key);
|
return await gitCommand({ cwd: repoPath || '' }, `config`, `--get`, key);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static diff(repoPath: string, fileName: string, sha1?: string, sha2?: string) {
|
static diff(repoPath: string, fileName: string, sha1?: string, sha2?: string, encoding?: string) {
|
||||||
const params = [`diff`, `--diff-filter=M`, `-M`];
|
const params = [`diff`, `--diff-filter=M`, `-M`];
|
||||||
if (sha1) {
|
if (sha1) {
|
||||||
params.push(sha1);
|
params.push(sha1);
|
||||||
@@ -174,7 +193,7 @@ export class Git {
|
|||||||
params.push(sha2);
|
params.push(sha2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand(repoPath, ...params, '--', fileName);
|
return gitCommand({ cwd: repoPath, encoding: encoding || defaultEncoding }, ...params, '--', fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string) {
|
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string) {
|
||||||
@@ -186,7 +205,7 @@ export class Git {
|
|||||||
params.push(sha2);
|
params.push(sha2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand(repoPath, ...params);
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static difftool_dirDiff(repoPath: string, sha1: string, sha2?: string) {
|
static difftool_dirDiff(repoPath: string, sha1: string, sha2?: string) {
|
||||||
@@ -195,7 +214,7 @@ export class Git {
|
|||||||
params.push(sha2);
|
params.push(sha2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand(repoPath, ...params);
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static log(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false) {
|
static log(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false) {
|
||||||
@@ -213,7 +232,7 @@ export class Git {
|
|||||||
params.push(sha);
|
params.push(sha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gitCommand(repoPath, ...params);
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static log_file(repoPath: string, fileName: string, sha?: string, maxCount?: number, reverse: boolean = false, startLine?: number, endLine?: number) {
|
static log_file(repoPath: string, fileName: string, sha?: string, maxCount?: number, reverse: boolean = false, startLine?: number, endLine?: number) {
|
||||||
@@ -250,7 +269,7 @@ export class Git {
|
|||||||
params.push(`--`);
|
params.push(`--`);
|
||||||
params.push(file);
|
params.push(file);
|
||||||
|
|
||||||
return gitCommand(root, ...params);
|
return gitCommand({ cwd: root }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static log_search(repoPath: string, search: string[] = [], maxCount?: number) {
|
static log_search(repoPath: string, search: string[] = [], maxCount?: number) {
|
||||||
@@ -259,12 +278,12 @@ export class Git {
|
|||||||
params.push(`-n${maxCount}`);
|
params.push(`-n${maxCount}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand(repoPath, ...params, ...search);
|
return gitCommand({ cwd: repoPath }, ...params, ...search);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async ls_files(repoPath: string, fileName: string): Promise<string> {
|
static async ls_files(repoPath: string, fileName: string): Promise<string> {
|
||||||
try {
|
try {
|
||||||
return await gitCommand(repoPath, 'ls-files', fileName);
|
return await gitCommand({ cwd: repoPath }, 'ls-files', fileName);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return '';
|
return '';
|
||||||
@@ -272,33 +291,33 @@ export class Git {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static remote(repoPath: string): Promise<string> {
|
static remote(repoPath: string): Promise<string> {
|
||||||
return gitCommand(repoPath, 'remote', '-v');
|
return gitCommand({ cwd: repoPath }, 'remote', '-v');
|
||||||
}
|
}
|
||||||
|
|
||||||
static remote_url(repoPath: string, remote: string): Promise<string> {
|
static remote_url(repoPath: string, remote: string): Promise<string> {
|
||||||
return gitCommand(repoPath, 'remote', 'get-url', remote);
|
return gitCommand({ cwd: repoPath }, 'remote', 'get-url', remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
static show(repoPath: string | undefined, fileName: string, branchOrSha: string) {
|
static show(repoPath: string | undefined, fileName: string, branchOrSha: string, encoding?: string) {
|
||||||
const [file, root] = Git.splitPath(fileName, repoPath);
|
const [file, root] = Git.splitPath(fileName, repoPath);
|
||||||
branchOrSha = branchOrSha.replace('^', '');
|
branchOrSha = branchOrSha.replace('^', '');
|
||||||
|
|
||||||
if (Git.isUncommitted(branchOrSha)) return Promise.reject(new Error(`sha=${branchOrSha} is uncommitted`));
|
if (Git.isUncommitted(branchOrSha)) return Promise.reject(new Error(`sha=${branchOrSha} is uncommitted`));
|
||||||
return gitCommand(root, 'show', `${branchOrSha}:./${file}`);
|
return gitCommand({ cwd: root, encoding: encoding || defaultEncoding }, 'show', `${branchOrSha}:./${file}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static stash_apply(repoPath: string, stashName: string, deleteAfter: boolean) {
|
static stash_apply(repoPath: string, stashName: string, deleteAfter: boolean) {
|
||||||
if (!stashName) return undefined;
|
if (!stashName) return undefined;
|
||||||
return gitCommand(repoPath, 'stash', deleteAfter ? 'pop' : 'apply', stashName);
|
return gitCommand({ cwd: repoPath }, 'stash', deleteAfter ? 'pop' : 'apply', stashName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static stash_delete(repoPath: string, stashName: string) {
|
static stash_delete(repoPath: string, stashName: string) {
|
||||||
if (!stashName) return undefined;
|
if (!stashName) return undefined;
|
||||||
return gitCommand(repoPath, 'stash', 'drop', stashName);
|
return gitCommand({ cwd: repoPath }, 'stash', 'drop', stashName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static stash_list(repoPath: string) {
|
static stash_list(repoPath: string) {
|
||||||
return gitCommand(repoPath, ...defaultStashParams);
|
return gitCommand({ cwd: repoPath }, ...defaultStashParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
static stash_save(repoPath: string, message?: string, unstagedOnly: boolean = false) {
|
static stash_save(repoPath: string, message?: string, unstagedOnly: boolean = false) {
|
||||||
@@ -309,18 +328,18 @@ export class Git {
|
|||||||
if (message) {
|
if (message) {
|
||||||
params.push(message);
|
params.push(message);
|
||||||
}
|
}
|
||||||
return gitCommand(repoPath, ...params);
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static status(repoPath: string, porcelainVersion: number = 1): Promise<string> {
|
static status(repoPath: string, porcelainVersion: number = 1): Promise<string> {
|
||||||
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
|
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
|
||||||
return gitCommand(repoPath, 'status', porcelain, '--branch');
|
return gitCommand({ cwd: repoPath }, 'status', porcelain, '--branch');
|
||||||
}
|
}
|
||||||
|
|
||||||
static status_file(repoPath: string, fileName: string, porcelainVersion: number = 1): Promise<string> {
|
static status_file(repoPath: string, fileName: string, porcelainVersion: number = 1): Promise<string> {
|
||||||
const [file, root] = Git.splitPath(fileName, repoPath);
|
const [file, root] = Git.splitPath(fileName, repoPath);
|
||||||
|
|
||||||
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
|
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
|
||||||
return gitCommand(root, 'status', porcelain, file);
|
return gitCommand({ cwd: root }, 'status', porcelain, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,8 @@ export class GitContextTracker extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onBlameFailed(key: string) {
|
private _onBlameFailed(key: string) {
|
||||||
const fileName = this._editor && this._editor.document && this._editor.document.fileName;
|
if (this._editor === undefined || this._editor.document === undefined || this._editor.document.uri === undefined) return;
|
||||||
if (!fileName || key !== this.git.getCacheEntryKey(fileName)) return;
|
if (key !== this.git.getCacheEntryKey(this._editor.document.uri)) return;
|
||||||
|
|
||||||
this._updateBlameability(false);
|
this._updateBlameability(false);
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@ export class GitContextTracker extends Disposable {
|
|||||||
if (!TextDocumentComparer.equals(this._editor && this._editor.document, e && e.document)) return;
|
if (!TextDocumentComparer.equals(this._editor && this._editor.document, e && e.document)) return;
|
||||||
|
|
||||||
// Can't unsubscribe here because undo doesn't trigger any other event
|
// Can't unsubscribe here because undo doesn't trigger any other event
|
||||||
//this._unsubscribeToDocumentChanges();
|
// this._unsubscribeToDocumentChanges();
|
||||||
//this.updateBlameability(false);
|
// this.updateBlameability(false);
|
||||||
|
|
||||||
// We have to defer because isDirty is not reliable inside this event
|
// We have to defer because isDirty is not reliable inside this event
|
||||||
setTimeout(() => this._updateBlameability(!e.document.isDirty), 1);
|
setTimeout(() => this._updateBlameability(!e.document.isDirty), 1);
|
||||||
@@ -83,7 +83,7 @@ export class GitContextTracker extends Disposable {
|
|||||||
if (!TextDocumentComparer.equals(this._editor && this._editor.document, e)) return;
|
if (!TextDocumentComparer.equals(this._editor && this._editor.document, e)) return;
|
||||||
|
|
||||||
// Don't need to resubscribe as we aren't unsubscribing on document changes anymore
|
// Don't need to resubscribe as we aren't unsubscribing on document changes anymore
|
||||||
//this._subscribeToDocumentChanges();
|
// this._subscribeToDocumentChanges();
|
||||||
this._updateBlameability(!e.isDirty);
|
this._updateBlameability(!e.isDirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,15 +83,15 @@ export class GitUri extends Uri {
|
|||||||
|
|
||||||
if (!git.isTrackable(uri)) return new GitUri(uri, git.repoPath);
|
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 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);
|
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);
|
return new GitUri(uri, (await git.getRepoPathFromFile(uri.fsPath)) || git.repoPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export interface IGitDiffChunk {
|
export interface IGitDiffChunk {
|
||||||
|
current: (string | undefined)[];
|
||||||
|
currentStart: number;
|
||||||
|
currentEnd: number;
|
||||||
|
|
||||||
|
previous: (string | undefined)[];
|
||||||
|
previousStart: number;
|
||||||
|
previousEnd: number;
|
||||||
|
|
||||||
chunk?: string;
|
chunk?: string;
|
||||||
|
|
||||||
original: (string | undefined)[];
|
|
||||||
originalStart: number;
|
|
||||||
originalEnd: number;
|
|
||||||
|
|
||||||
changes: (string | undefined)[];
|
|
||||||
changesStart: number;
|
|
||||||
changesEnd: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitDiff {
|
export interface IGitDiff {
|
||||||
diff?: string;
|
|
||||||
chunks: IGitDiffChunk[];
|
chunks: IGitDiffChunk[];
|
||||||
|
|
||||||
|
diff?: string;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Uri } from 'vscode';
|
import { Uri } from 'vscode';
|
||||||
import { GitCommit, GitCommitType, IGitCommitLine } from './commit';
|
import { GitCommit, GitCommitType, IGitCommitLine } from './commit';
|
||||||
import { IGitStatusFile, GitStatusFileStatus } from './status';
|
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export class GitLogCommit extends GitCommit {
|
export class GitLogCommit extends GitCommit {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { IGitCommitLine } from './commit';
|
import { IGitCommitLine } from './commit';
|
||||||
import { GitLogCommit } from './logCommit';
|
import { GitLogCommit } from './logCommit';
|
||||||
import { IGitStatusFile, GitStatusFileStatus } from './status';
|
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
||||||
|
|
||||||
export class GitStashCommit extends GitLogCommit {
|
export class GitStashCommit extends GitLogCommit {
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class GitBlameParser {
|
|||||||
let entry: IBlameEntry | undefined = undefined;
|
let entry: IBlameEntry | undefined = undefined;
|
||||||
let position = -1;
|
let position = -1;
|
||||||
while (++position < lines.length) {
|
while (++position < lines.length) {
|
||||||
let lineParts = lines[position].split(' ');
|
const lineParts = lines[position].split(' ');
|
||||||
if (lineParts.length < 2) {
|
if (lineParts.length < 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ export class GitBlameParser {
|
|||||||
|
|
||||||
const authors: Map<string, IGitAuthor> = new Map();
|
const authors: Map<string, IGitAuthor> = new Map();
|
||||||
const commits: Map<string, GitCommit> = new Map();
|
const commits: Map<string, GitCommit> = new Map();
|
||||||
const lines: Array<IGitCommitLine> = [];
|
const lines: IGitCommitLine[] = [];
|
||||||
|
|
||||||
let relativeFileName = repoPath && fileName;
|
let relativeFileName = repoPath && fileName;
|
||||||
|
|
||||||
|
|||||||
@@ -15,22 +15,41 @@ export class GitDiffParser {
|
|||||||
match = unifiedDiffRegex.exec(`${data}\n@@`);
|
match = unifiedDiffRegex.exec(`${data}\n@@`);
|
||||||
if (match == null) break;
|
if (match == null) break;
|
||||||
|
|
||||||
const originalStart = +match[1];
|
const previousStart = +match[1];
|
||||||
const changedStart = +match[3];
|
const currentStart = +match[3];
|
||||||
|
|
||||||
const chunk = match[5];
|
const chunk = match[5];
|
||||||
const lines = chunk.split('\n').slice(1);
|
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({
|
chunks.push({
|
||||||
chunk: debug ? chunk : undefined,
|
chunk: debug ? chunk : undefined,
|
||||||
original: original,
|
current: current,
|
||||||
originalStart: originalStart,
|
currentStart: currentStart,
|
||||||
originalEnd: originalStart + +match[2],
|
currentEnd: currentStart + +match[4],
|
||||||
changes: changed,
|
previous: previous,
|
||||||
changesStart: changedStart,
|
previousStart: previousStart,
|
||||||
changesEnd: changedStart + +match[4]
|
previousEnd: previousStart + +match[2]
|
||||||
});
|
});
|
||||||
} while (match != null);
|
} while (match != null);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Range } from 'vscode';
|
import { Range } from 'vscode';
|
||||||
import { Git, GitStatusFileStatus, GitLogCommit, GitCommitType, IGitAuthor, IGitLog, IGitStatusFile } from './../git';
|
import { Git, GitCommitType, GitLogCommit, GitStatusFileStatus, IGitAuthor, IGitLog, IGitStatusFile } from './../git';
|
||||||
// import { Logger } from '../../logger';
|
// import { Logger } from '../../logger';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Git, GitStatusFileStatus, GitStatusFile, IGitStatus } from './../git';
|
import { Git, GitStatusFile, GitStatusFileStatus, IGitStatus } from './../git';
|
||||||
|
|
||||||
interface IFileStatusEntry {
|
interface IFileStatusEntry {
|
||||||
staged: boolean;
|
staged: boolean;
|
||||||
@@ -61,7 +61,7 @@ export class GitStatusParser {
|
|||||||
else {
|
else {
|
||||||
let entry: IFileStatusEntry;
|
let entry: IFileStatusEntry;
|
||||||
const rawStatus = line.substring(0, 2);
|
const rawStatus = line.substring(0, 2);
|
||||||
let fileName = line.substring(3);
|
const fileName = line.substring(3);
|
||||||
if (rawStatus[0] === 'R') {
|
if (rawStatus[0] === 'R') {
|
||||||
const [file1, file2] = fileName.replace(/\"/g, '').split('->');
|
const [file1, file2] = fileName.replace(/\"/g, '').split('->');
|
||||||
entry = this._parseFileEntry(rawStatus, file2.trim(), file1.trim());
|
entry = this._parseFileEntry(rawStatus, file2.trim(), file1.trim());
|
||||||
@@ -98,7 +98,7 @@ export class GitStatusParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let lineParts = line.split(' ');
|
const lineParts = line.split(' ');
|
||||||
let entry: IFileStatusEntry | undefined = undefined;
|
let entry: IFileStatusEntry | undefined = undefined;
|
||||||
switch (lineParts[0][0]) {
|
switch (lineParts[0][0]) {
|
||||||
case '1': // normal
|
case '1': // normal
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class BitbucketService extends RemoteProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
||||||
let line: string = '';
|
let line = '';
|
||||||
if (range) {
|
if (range) {
|
||||||
if (range.start.line === range.end.line) {
|
if (range.start.line === range.end.line) {
|
||||||
line = `#${fileName}-${range.start.line}`;
|
line = `#${fileName}-${range.start.line}`;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class GitHubService extends RemoteProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
||||||
let line: string = '';
|
let line = '';
|
||||||
if (range) {
|
if (range) {
|
||||||
if (range.start.line === range.end.line) {
|
if (range.start.line === range.end.line) {
|
||||||
line = `#L${range.start.line}`;
|
line = `#L${range.start.line}`;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class VisualStudioService extends RemoteProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
||||||
let line: string = '';
|
let line = '';
|
||||||
if (range) {
|
if (range) {
|
||||||
if (range.start.line === range.end.line) {
|
if (range.start.line === range.end.line) {
|
||||||
line = `&line=${range.start.line}`;
|
line = `&line=${range.start.line}`;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Functions, Iterables, Strings } from './system';
|
|||||||
import { CancellationToken, CodeLens, CodeLensProvider, Command, commands, DocumentSelector, Event, EventEmitter, ExtensionContext, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, workspace } from 'vscode';
|
import { CancellationToken, CodeLens, CodeLensProvider, Command, commands, DocumentSelector, Event, EventEmitter, ExtensionContext, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, workspace } from 'vscode';
|
||||||
import { Commands, DiffWithPreviousCommandArgs, ShowBlameHistoryCommandArgs, ShowFileHistoryCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from './commands';
|
import { Commands, DiffWithPreviousCommandArgs, ShowBlameHistoryCommandArgs, ShowFileHistoryCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from './commands';
|
||||||
import { BuiltInCommands, DocumentSchemes, ExtensionKey } from './constants';
|
import { BuiltInCommands, DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { CodeLensCommand, CodeLensLocation, IConfig, ICodeLensLanguageLocation } from './configuration';
|
import { CodeLensCommand, CodeLensLocation, ICodeLensLanguageLocation, IConfig } from './configuration';
|
||||||
import { GitCommit, GitService, GitUri, IGitBlame, IGitBlameLines } from './gitService';
|
import { GitCommit, GitService, GitUri, IGitBlame, IGitBlameLines } from './gitService';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
@@ -115,7 +115,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _validateSymbolAndGetBlameRange(document: TextDocument, symbol: SymbolInformation, languageLocation: ICodeLensLanguageLocation): Range | undefined {
|
private _validateSymbolAndGetBlameRange(document: TextDocument, symbol: SymbolInformation, languageLocation: ICodeLensLanguageLocation): Range | undefined {
|
||||||
let valid: boolean = false;
|
let valid = false;
|
||||||
let range: Range | undefined;
|
let range: Range | undefined;
|
||||||
switch (languageLocation.location) {
|
switch (languageLocation.location) {
|
||||||
case CodeLensLocation.All:
|
case CodeLensLocation.All:
|
||||||
@@ -360,7 +360,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_applyDiffWithPreviousCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_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];
|
const blameLine = blame.allLines[lens.range.start.line];
|
||||||
commit = blame.commits.get(blameLine.sha);
|
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 {
|
_applyShowQuickCommitDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: CodeLensCommand.ShowQuickCommitDetails,
|
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitDetails,
|
||||||
arguments: [
|
arguments: [
|
||||||
Uri.file(lens.uri.fsPath),
|
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 {
|
_applyShowQuickCommitFileDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: CodeLensCommand.ShowQuickCommitFileDetails,
|
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitFileDetails,
|
||||||
arguments: [
|
arguments: [
|
||||||
Uri.file(lens.uri.fsPath),
|
Uri.file(lens.uri.fsPath),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Iterables, Objects } from './system';
|
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 { CommandContext, setCommandContext } from './commands';
|
||||||
import { CodeLensVisibility, IConfig } from './configuration';
|
import { CodeLensVisibility, IConfig } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey } from './constants';
|
import { DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { Git, GitBlameParser, GitBranch, GitCommit, GitDiffParser, GitLogCommit, GitLogParser, GitRemote, GitStashParser, GitStatusFile, GitStatusParser, IGit, IGitAuthor, IGitBlame, IGitBlameLine, IGitBlameLines, IGitDiff, IGitLog, IGitStash, IGitStatus } from './git/git';
|
import { Git, GitBlameParser, GitBranch, GitCommit, GitDiffParser, GitLogCommit, GitLogParser, GitRemote, GitStashParser, GitStatusFile, GitStatusParser, IGit, IGitAuthor, IGitBlame, IGitBlameLine, IGitBlameLines, IGitDiff, IGitLog, IGitStash, IGitStatus, setDefaultEncoding } from './git/git';
|
||||||
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
|
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
|
||||||
import { GitCodeLensProvider } from './gitCodeLensProvider';
|
import { GitCodeLensProvider } from './gitCodeLensProvider';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
@@ -33,17 +33,16 @@ class GitCacheEntry {
|
|||||||
return Iterables.every(this.cache.values(), _ => _.errorMessage !== undefined);
|
return Iterables.every(this.cache.values(), _ => _.errorMessage !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
get<T extends ICachedBlame | ICachedDiff | ICachedLog > (key: string): T | undefined {
|
get<T extends ICachedBlame | ICachedDiff | ICachedLog>(key: string): T | undefined {
|
||||||
return this.cache.get(key) as T;
|
return this.cache.get(key) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
set<T extends ICachedBlame | ICachedDiff | ICachedLog > (key: string, value: T) {
|
set<T extends ICachedBlame | ICachedDiff | ICachedLog>(key: string, value: T) {
|
||||||
this.cache.set(key, value);
|
this.cache.set(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICachedItem<T> {
|
interface ICachedItem<T> {
|
||||||
//date: Date;
|
|
||||||
item: Promise<T>;
|
item: Promise<T>;
|
||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
}
|
}
|
||||||
@@ -130,6 +129,9 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onConfigurationChanged() {
|
private _onConfigurationChanged() {
|
||||||
|
const encoding = workspace.getConfiguration('files').get<string>('encoding', 'utf8');
|
||||||
|
setDefaultEncoding(encoding);
|
||||||
|
|
||||||
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
||||||
|
|
||||||
const codeLensChanged = !Objects.areEquivalent(cfg.codeLens, this.config && this.config.codeLens);
|
const codeLensChanged = !Objects.areEquivalent(cfg.codeLens, this.config && this.config.codeLens);
|
||||||
@@ -164,6 +166,7 @@ export class GitService extends Disposable {
|
|||||||
const disposables: Disposable[] = [];
|
const disposables: Disposable[] = [];
|
||||||
|
|
||||||
disposables.push(workspace.onDidCloseTextDocument(d => this._removeCachedEntry(d, RemoveCacheReason.DocumentClosed)));
|
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(workspace.onDidSaveTextDocument(d => this._removeCachedEntry(d, RemoveCacheReason.DocumentSaved)));
|
||||||
disposables.push(this._fsWatcher.onDidChange(this._onGitChanged, this));
|
disposables.push(this._fsWatcher.onDidChange(this._onGitChanged, this));
|
||||||
|
|
||||||
@@ -206,6 +209,21 @@ export class GitService extends Disposable {
|
|||||||
this.config = cfg;
|
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() {
|
private _onGitChanged() {
|
||||||
this._gitCache.clear();
|
this._gitCache.clear();
|
||||||
|
|
||||||
@@ -217,7 +235,7 @@ export class GitService extends Disposable {
|
|||||||
if (!this.UseCaching) return;
|
if (!this.UseCaching) return;
|
||||||
if (document.uri.scheme !== DocumentSchemes.File) return;
|
if (document.uri.scheme !== DocumentSchemes.File) return;
|
||||||
|
|
||||||
const cacheKey = this.getCacheEntryKey(document.fileName);
|
const cacheKey = this.getCacheEntryKey(document.uri);
|
||||||
|
|
||||||
if (reason === RemoveCacheReason.DocumentSaved) {
|
if (reason === RemoveCacheReason.DocumentSaved) {
|
||||||
// Don't remove broken blame on save (since otherwise we'll have to run the broken blame again)
|
// Don't remove broken blame on save (since otherwise we'll have to run the broken blame again)
|
||||||
@@ -238,7 +256,7 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fileExists(repoPath: string, fileName: string): Promise<boolean> {
|
private async _fileExists(repoPath: string, fileName: string): Promise<boolean> {
|
||||||
return await new Promise<boolean>((resolve, reject) => fs.exists(path.resolve(repoPath, fileName), e => resolve(e)));
|
return await new Promise<boolean>((resolve, reject) => fs.exists(path.resolve(repoPath, fileName), resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
async findNextCommit(repoPath: string, fileName: string, sha?: string): Promise<GitLogCommit | undefined> {
|
async findNextCommit(repoPath: string, fileName: string, sha?: string): Promise<GitLogCommit | undefined> {
|
||||||
@@ -311,7 +329,7 @@ export class GitService extends Disposable {
|
|||||||
public async getBlameability(uri: GitUri): Promise<boolean> {
|
public async getBlameability(uri: GitUri): Promise<boolean> {
|
||||||
if (!this.UseCaching) return await this.isTracked(uri);
|
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);
|
const entry = this._gitCache.get(cacheKey);
|
||||||
if (entry === undefined) return await this.isTracked(uri);
|
if (entry === undefined) return await this.isTracked(uri);
|
||||||
|
|
||||||
@@ -319,16 +337,14 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getBlameForFile(uri: GitUri): Promise<IGitBlame | undefined> {
|
async getBlameForFile(uri: GitUri): Promise<IGitBlame | undefined> {
|
||||||
let key: string = 'blame';
|
let key = 'blame';
|
||||||
if (uri.sha !== undefined) {
|
if (uri.sha !== undefined) {
|
||||||
key += `:${uri.sha}`;
|
key += `:${uri.sha}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = uri.fsPath;
|
|
||||||
|
|
||||||
let entry: GitCacheEntry | undefined;
|
let entry: GitCacheEntry | undefined;
|
||||||
if (this.UseCaching) {
|
if (this.UseCaching) {
|
||||||
const cacheKey = this.getCacheEntryKey(fileName);
|
const cacheKey = this.getCacheEntryKey(uri);
|
||||||
entry = this._gitCache.get(cacheKey);
|
entry = this._gitCache.get(cacheKey);
|
||||||
|
|
||||||
if (entry !== undefined) {
|
if (entry !== undefined) {
|
||||||
@@ -337,19 +353,6 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
|
Logger.log(`Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
|
||||||
return cachedBlame.item;
|
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})`);
|
Logger.log(`Not Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
|
||||||
@@ -363,13 +366,12 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
|
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) {
|
if (entry) {
|
||||||
Logger.log(`Add blame cache for '${entry.key}:${key}'`);
|
Logger.log(`Add blame cache for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedBlame>(key, {
|
entry.set<ICachedBlame>(key, {
|
||||||
//date: new Date(),
|
|
||||||
item: promise
|
item: promise
|
||||||
} as ICachedBlame);
|
} as ICachedBlame);
|
||||||
}
|
}
|
||||||
@@ -377,12 +379,12 @@ export class GitService extends Disposable {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getBlameForFile(uri: GitUri, fileName: string, entry: GitCacheEntry | undefined, key: string): Promise<IGitBlame | undefined> {
|
private async _getBlameForFile(uri: GitUri, entry: GitCacheEntry | undefined, key: string): Promise<IGitBlame | undefined> {
|
||||||
const [file, root] = Git.splitPath(fileName, uri.repoPath, false);
|
const [file, root] = Git.splitPath(uri.fsPath, uri.repoPath, false);
|
||||||
|
|
||||||
const ignore = await this._gitignore;
|
const ignore = await this._gitignore;
|
||||||
if (ignore && !ignore.filter([file]).length) {
|
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) {
|
if (entry && entry.key) {
|
||||||
this._onDidBlameFail.fire(entry.key);
|
this._onDidBlameFail.fire(entry.key);
|
||||||
}
|
}
|
||||||
@@ -400,7 +402,6 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`Replace blame cache with empty promise for '${entry.key}:${key}'`);
|
Logger.log(`Replace blame cache with empty promise for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedBlame>(key, {
|
entry.set<ICachedBlame>(key, {
|
||||||
//date: new Date(),
|
|
||||||
item: GitService.EmptyPromise,
|
item: GitService.EmptyPromise,
|
||||||
errorMessage: msg
|
errorMessage: msg
|
||||||
} as ICachedBlame);
|
} as ICachedBlame);
|
||||||
@@ -519,7 +520,7 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
const commitCount = blame.commits.size;
|
const commitCount = blame.commits.size;
|
||||||
|
|
||||||
const locations: Array<Location> = [];
|
const locations: Location[] = [];
|
||||||
Iterables.forEach(blame.commits.values(), (c, i) => {
|
Iterables.forEach(blame.commits.values(), (c, i) => {
|
||||||
if (c.isUncommitted) return;
|
if (c.isUncommitted) return;
|
||||||
|
|
||||||
@@ -550,8 +551,10 @@ export class GitService extends Disposable {
|
|||||||
return branches;
|
return branches;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCacheEntryKey(fileName: string) {
|
getCacheEntryKey(fileName: string): string;
|
||||||
return Git.normalizePath(fileName).toLowerCase();
|
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> {
|
async getConfig(key: string, repoPath?: string): Promise<string> {
|
||||||
@@ -560,14 +563,18 @@ export class GitService extends Disposable {
|
|||||||
return await Git.config_get(key, repoPath);
|
return await Git.config_get(key, repoPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
getGitUriForFile(fileName: string) {
|
getGitUriForFile(uri: Uri) {
|
||||||
const cacheKey = this.getCacheEntryKey(fileName);
|
const cacheKey = this.getCacheEntryKey(uri);
|
||||||
const entry = this._uriCache.get(cacheKey);
|
const entry = this._uriCache.get(cacheKey);
|
||||||
return entry && entry.uri;
|
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> {
|
||||||
let key: string = 'diff';
|
if (sha1 !== undefined && sha2 === undefined && uri.sha !== undefined) {
|
||||||
|
sha2 = uri.sha;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = 'diff';
|
||||||
if (sha1 !== undefined) {
|
if (sha1 !== undefined) {
|
||||||
key += `:${sha1}`;
|
key += `:${sha1}`;
|
||||||
}
|
}
|
||||||
@@ -577,18 +584,18 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
let entry: GitCacheEntry | undefined;
|
let entry: GitCacheEntry | undefined;
|
||||||
if (this.UseCaching) {
|
if (this.UseCaching) {
|
||||||
const cacheKey = this.getCacheEntryKey(fileName);
|
const cacheKey = this.getCacheEntryKey(uri);
|
||||||
entry = this._gitCache.get(cacheKey);
|
entry = this._gitCache.get(cacheKey);
|
||||||
|
|
||||||
if (entry !== undefined) {
|
if (entry !== undefined) {
|
||||||
const cachedDiff = entry.get<ICachedDiff>(key);
|
const cachedDiff = entry.get<ICachedDiff>(key);
|
||||||
if (cachedDiff !== undefined) {
|
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;
|
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) {
|
if (entry === undefined) {
|
||||||
entry = new GitCacheEntry(cacheKey);
|
entry = new GitCacheEntry(cacheKey);
|
||||||
@@ -596,16 +603,15 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
if (entry) {
|
||||||
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedDiff>(key, {
|
entry.set<ICachedDiff>(key, {
|
||||||
//date: new Date(),
|
|
||||||
item: promise
|
item: promise
|
||||||
} as ICachedDiff);
|
} as ICachedDiff);
|
||||||
}
|
}
|
||||||
@@ -618,7 +624,7 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.diff(root, file, sha1, sha2);
|
const data = await Git.diff(root, file, sha1, sha2);
|
||||||
return GitDiffParser.parse(data, this.config.debug);
|
return GitDiffParser.parse(data);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
// Trap and cache expected diff errors
|
// Trap and cache expected diff errors
|
||||||
@@ -627,7 +633,6 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`Replace diff cache with empty promise for '${entry.key}:${key}'`);
|
Logger.log(`Replace diff cache with empty promise for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedDiff>(key, {
|
entry.set<ICachedDiff>(key, {
|
||||||
//date: new Date(),
|
|
||||||
item: GitService.EmptyPromise,
|
item: GitService.EmptyPromise,
|
||||||
errorMessage: msg
|
errorMessage: msg
|
||||||
} as ICachedDiff);
|
} as ICachedDiff);
|
||||||
@@ -639,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 {
|
try {
|
||||||
const diff = await this.getDiffForFile(repoPath, fileName, sha1, sha2);
|
const diff = await this.getDiffForFile(uri, sha1, sha2);
|
||||||
if (diff === undefined) return undefined;
|
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;
|
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 [
|
return [
|
||||||
chunk.original[line - chunk.originalStart + 1],
|
chunk.previous[line + deleted - 1],
|
||||||
chunk.changes[line - chunk.changesStart + 1]
|
chunk.current[line + deleted]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
@@ -729,7 +751,7 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getLogForFile(repoPath: string | undefined, fileName: string, sha?: string, maxCount?: number, range?: Range, reverse: boolean = false): Promise<IGitLog | undefined> {
|
async getLogForFile(repoPath: string | undefined, fileName: string, sha?: string, maxCount?: number, range?: Range, reverse: boolean = false): Promise<IGitLog | undefined> {
|
||||||
let key: string = 'log';
|
let key = 'log';
|
||||||
if (sha !== undefined) {
|
if (sha !== undefined) {
|
||||||
key += `:${sha}`;
|
key += `:${sha}`;
|
||||||
}
|
}
|
||||||
@@ -785,7 +807,6 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedLog>(key, {
|
entry.set<ICachedLog>(key, {
|
||||||
//date: new Date(),
|
|
||||||
item: promise
|
item: promise
|
||||||
} as ICachedLog);
|
} as ICachedLog);
|
||||||
}
|
}
|
||||||
@@ -813,7 +834,6 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`Replace log cache with empty promise for '${entry.key}:${key}'`);
|
Logger.log(`Replace log cache with empty promise for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedLog>(key, {
|
entry.set<ICachedLog>(key, {
|
||||||
//date: new Date(),
|
|
||||||
item: GitService.EmptyPromise,
|
item: GitService.EmptyPromise,
|
||||||
errorMessage: msg
|
errorMessage: msg
|
||||||
} as ICachedLog);
|
} as ICachedLog);
|
||||||
@@ -833,7 +853,7 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
const commitCount = log.commits.size;
|
const commitCount = log.commits.size;
|
||||||
|
|
||||||
const locations: Array<Location> = [];
|
const locations: Location[] = [];
|
||||||
Iterables.forEach(log.commits.values(), (c, i) => {
|
Iterables.forEach(log.commits.values(), (c, i) => {
|
||||||
if (c.isUncommitted) return;
|
if (c.isUncommitted) return;
|
||||||
|
|
||||||
@@ -849,7 +869,6 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getRemotes(repoPath: string): Promise<GitRemote[]> {
|
async getRemotes(repoPath: string): Promise<GitRemote[]> {
|
||||||
if (!this.config.insiders) return [];
|
|
||||||
if (!repoPath) return [];
|
if (!repoPath) return [];
|
||||||
|
|
||||||
Logger.log(`getRemotes('${repoPath}')`);
|
Logger.log(`getRemotes('${repoPath}')`);
|
||||||
@@ -931,19 +950,10 @@ export class GitService extends Disposable {
|
|||||||
return Git.show(repoPath, fileName, sha);
|
return Git.show(repoPath, fileName, sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasGitUriForFile(editor: TextEditor): boolean;
|
hasGitUriForFile(editor: TextEditor): boolean {
|
||||||
hasGitUriForFile(fileName: string): boolean;
|
if (editor === undefined || editor.document === undefined || editor.document.uri === undefined) return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cacheKey = this.getCacheEntryKey(fileName);
|
const cacheKey = this.getCacheEntryKey(editor.document.uri);
|
||||||
return this._uriCache.has(cacheKey);
|
return this._uriCache.has(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export class OpenCommitFilesCommandQuickPickItem extends OpenFilesCommandQuickPi
|
|||||||
super(uris, item || {
|
super(uris, item || {
|
||||||
label: `$(file-symlink-file) Open Changed Files`,
|
label: `$(file-symlink-file) Open Changed Files`,
|
||||||
description: `\u00a0 \u2014 \u00a0\u00a0 in \u00a0$(git-commit) ${commit.shortSha}`
|
description: `\u00a0 \u2014 \u00a0\u00a0 in \u00a0$(git-commit) ${commit.shortSha}`
|
||||||
//detail: `Opens all of the changed files in $(git-commit) ${commit.shortSha}`
|
// detail: `Opens all of the changed files in $(git-commit) ${commit.shortSha}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ export class OpenCommitWorkingTreeFilesCommandQuickPickItem extends OpenFilesCom
|
|||||||
super(uris, item || {
|
super(uris, item || {
|
||||||
label: `$(file-symlink-file) Open Changed Working Files`,
|
label: `$(file-symlink-file) Open Changed Working Files`,
|
||||||
description: ''
|
description: ''
|
||||||
//detail: `Opens all of the changed file in the working tree`
|
// detail: `Opens all of the changed file in the working tree`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ export class CommitDetailsQuickPick {
|
|||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
if (stash && git.config.insiders) {
|
if (stash) {
|
||||||
items.splice(index++, 0, new CommandQuickPickItem({
|
items.splice(index++, 0, new CommandQuickPickItem({
|
||||||
label: `$(git-pull-request) Apply Stashed Changes`,
|
label: `$(git-pull-request) Apply Stashed Changes`,
|
||||||
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
|
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export class CommitFileDetailsQuickPick {
|
|||||||
|
|
||||||
if (commit.previousSha) {
|
if (commit.previousSha) {
|
||||||
items.push(new CommandQuickPickItem({
|
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}`
|
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}`
|
||||||
}, Commands.DiffWithPrevious, [
|
}, Commands.DiffWithPrevious, [
|
||||||
commit.uri,
|
commit.uri,
|
||||||
@@ -85,7 +85,7 @@ export class CommitFileDetailsQuickPick {
|
|||||||
|
|
||||||
if (commit.workingFileName) {
|
if (commit.workingFileName) {
|
||||||
items.push(new CommandQuickPickItem({
|
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}`
|
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-text) ${workingName}`
|
||||||
}, Commands.DiffWithWorking, [
|
}, Commands.DiffWithWorking, [
|
||||||
Uri.file(path.resolve(commit.repoPath, commit.workingFileName)),
|
Uri.file(path.resolve(commit.repoPath, commit.workingFileName)),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { CancellationTokenSource, commands, Disposable, QuickPickItem, QuickPickOptions, TextDocumentShowOptions, TextEditor, Uri, window, workspace } from 'vscode';
|
import { CancellationTokenSource, commands, Disposable, QuickPickItem, QuickPickOptions, TextDocumentShowOptions, TextEditor, Uri, window, workspace } from 'vscode';
|
||||||
import { Commands, Keyboard, Keys, KeyboardScope, KeyMapping, openEditor } from '../commands';
|
import { Commands, Keyboard, KeyboardScope, KeyMapping, Keys, openEditor } from '../commands';
|
||||||
import { IAdvancedConfig } from '../configuration';
|
import { IAdvancedConfig } from '../configuration';
|
||||||
import { ExtensionKey } from '../constants';
|
import { ExtensionKey } from '../constants';
|
||||||
import { GitCommit, GitLogCommit, GitStashCommit } from '../gitService';
|
import { GitCommit, GitLogCommit, GitStashCommit } from '../gitService';
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
|
|||||||
constructor(remotes: GitRemote[], resource: RemoteResource, goBackCommand?: CommandQuickPickItem) {
|
constructor(remotes: GitRemote[], resource: RemoteResource, goBackCommand?: CommandQuickPickItem) {
|
||||||
const name = getNameFromRemoteResource(resource);
|
const name = getNameFromRemoteResource(resource);
|
||||||
|
|
||||||
let description: string = '';
|
let description = '';
|
||||||
switch (resource.type) {
|
switch (resource.type) {
|
||||||
case 'branch':
|
case 'branch':
|
||||||
description = `$(git-branch) ${resource.branch}`;
|
description = `$(git-branch) ${resource.branch}`;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export class OpenStatusFileCommandQuickPickItem extends OpenFileCommandQuickPick
|
|||||||
directory = '';
|
directory = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let description = (status.status === 'R' && status.originalFileName)
|
const description = (status.status === 'R' && status.originalFileName)
|
||||||
? `${directory} \u00a0\u2190\u00a0 ${status.originalFileName}`
|
? `${directory} \u00a0\u2190\u00a0 ${status.originalFileName}`
|
||||||
: directory;
|
: directory;
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ export class OpenStatusFilesCommandQuickPickItem extends CommandQuickPickItem {
|
|||||||
super(item || {
|
super(item || {
|
||||||
label: `$(file-symlink-file) Open Changed Files`,
|
label: `$(file-symlink-file) Open Changed Files`,
|
||||||
description: ''
|
description: ''
|
||||||
//detail: `Opens all of the changed files in the repository`
|
// detail: `Opens all of the changed files in the repository`
|
||||||
}, Commands.OpenChangedFiles, [
|
}, Commands.OpenChangedFiles, [
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
@@ -211,7 +211,6 @@ export class RepoStatusQuickPick {
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (goBackCommand) {
|
if (goBackCommand) {
|
||||||
items.splice(0, 0, goBackCommand);
|
items.splice(0, 0, goBackCommand);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
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)[];
|
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({
|
items.splice(0, 0, new CommandQuickPickItem({
|
||||||
label: `$(repo-push) Stash Unstaged Changes`,
|
label: `$(repo-push) Stash Unstaged Changes`,
|
||||||
description: `\u00a0 \u2014 \u00a0\u00a0 stashes only unstaged changes`
|
description: `\u00a0 \u2014 \u00a0\u00a0 stashes only unstaged changes`
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export namespace Iterables {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function join(source: Iterable<any>, separator: string): string {
|
export function join(source: Iterable<any>, separator: string): string {
|
||||||
let value: string = '';
|
let value = '';
|
||||||
|
|
||||||
const iterator = source[Symbol.iterator]();
|
const iterator = source[Symbol.iterator]();
|
||||||
let next = iterator.next();
|
let next = iterator.next();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
//import { isEqual as _isEqual } from 'lodash';
|
|
||||||
const _isEqual = require('lodash.isequal');
|
const _isEqual = require('lodash.isequal');
|
||||||
|
|
||||||
export namespace Objects {
|
export namespace Objects {
|
||||||
@@ -8,13 +7,13 @@ export namespace Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function* entries(o: any): IterableIterator<[string, any]> {
|
export function* entries(o: any): IterableIterator<[string, any]> {
|
||||||
for (let key in o) {
|
for (const key in o) {
|
||||||
yield [key, o[key]];
|
yield [key, o[key]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flatten(o: any, prefix: string = '', stringify: boolean = false): { [key: string]: any } {
|
export function flatten(o: any, prefix: string = '', stringify: boolean = false): { [key: string]: any } {
|
||||||
let flattened = Object.create(null);
|
const flattened = Object.create(null);
|
||||||
_flatten(flattened, prefix, o, stringify);
|
_flatten(flattened, prefix, o, stringify);
|
||||||
return flattened;
|
return flattened;
|
||||||
}
|
}
|
||||||
@@ -37,7 +36,7 @@ export namespace Objects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Array.isArray(value)) {
|
else if (Array.isArray(value)) {
|
||||||
let len = value.length;
|
const len = value.length;
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
_flatten(flattened, `${key}[${i}]`, value[i], stringify);
|
_flatten(flattened, `${key}[${i}]`, value[i], stringify);
|
||||||
}
|
}
|
||||||
@@ -47,7 +46,7 @@ export namespace Objects {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let isEmpty = true;
|
let isEmpty = true;
|
||||||
for (let p in value) {
|
for (const p in value) {
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
_flatten(flattened, key ? `${key}.${p}` : p, value[p], stringify);
|
_flatten(flattened, key ? `${key}.${p}` : p, value[p], stringify);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
//import { escapeRegExp as _escapeRegExp } from 'lodash';
|
|
||||||
const _escapeRegExp = require('lodash.escaperegexp');
|
const _escapeRegExp = require('lodash.escaperegexp');
|
||||||
|
|
||||||
export namespace Strings {
|
export namespace Strings {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { env, Disposable, version, workspace } from 'vscode';
|
import { Disposable, env, version, workspace } from 'vscode';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
|
||||||
let _reporter: TelemetryReporter;
|
let _reporter: TelemetryReporter;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"lib": [ "es6" ],
|
"lib": [ "es2015" ],
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "es6"
|
"target": "es2015"
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|||||||
60
tslint.json
60
tslint.json
@@ -1,22 +1,52 @@
|
|||||||
{
|
{
|
||||||
"rules": {
|
"rules": {
|
||||||
"arrow-parens": false,
|
"adjacent-overload-signatures": true,
|
||||||
|
"array-type": [
|
||||||
|
true,
|
||||||
|
"array"
|
||||||
|
],
|
||||||
|
"arrow-parens": [
|
||||||
|
true,
|
||||||
|
"ban-single-arg-parens"
|
||||||
|
],
|
||||||
|
"arrow-return-shorthand": true,
|
||||||
"class-name": true,
|
"class-name": true,
|
||||||
"comment-format": [
|
"comment-format": [
|
||||||
false
|
true,
|
||||||
|
"check-space"
|
||||||
|
],
|
||||||
|
"curly": [
|
||||||
|
true,
|
||||||
|
"ignore-same-line"
|
||||||
],
|
],
|
||||||
"curly": false,
|
|
||||||
"indent": [
|
"indent": [
|
||||||
true,
|
true,
|
||||||
"spaces"
|
"spaces"
|
||||||
],
|
],
|
||||||
|
"interface-over-type-literal": true,
|
||||||
"new-parens": true,
|
"new-parens": true,
|
||||||
"no-duplicate-variable": true,
|
"no-angle-bracket-type-assertion": true,
|
||||||
|
"no-consecutive-blank-lines": [
|
||||||
|
true,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"no-default-export": true,
|
||||||
"no-eval": true,
|
"no-eval": true,
|
||||||
"no-for-in-array": false,
|
// "no-for-in-array": true,
|
||||||
|
"no-inferrable-types": [
|
||||||
|
true,
|
||||||
|
"ignore-params",
|
||||||
|
"ignore-properties"
|
||||||
|
],
|
||||||
"no-internal-module": true,
|
"no-internal-module": true,
|
||||||
|
"no-invalid-template-strings": true,
|
||||||
|
"no-irregular-whitespace": true,
|
||||||
"no-reference": true,
|
"no-reference": true,
|
||||||
|
"no-string-throw": true,
|
||||||
"no-trailing-whitespace": true,
|
"no-trailing-whitespace": true,
|
||||||
|
"no-unnecessary-callback-wrapper": true,
|
||||||
|
// "no-unnecessary-qualifier": true,
|
||||||
|
// "no-unsafe-any": true,
|
||||||
"no-unsafe-finally": true,
|
"no-unsafe-finally": true,
|
||||||
"no-unused-expression": false,
|
"no-unused-expression": false,
|
||||||
"no-var-keyword": true,
|
"no-var-keyword": true,
|
||||||
@@ -35,11 +65,18 @@
|
|||||||
"ignore-for-loop"
|
"ignore-for-loop"
|
||||||
],
|
],
|
||||||
"ordered-imports": [
|
"ordered-imports": [
|
||||||
false,
|
true,
|
||||||
{
|
{
|
||||||
|
"import-sources-order": "any",
|
||||||
"named-imports-order": "case-insensitive"
|
"named-imports-order": "case-insensitive"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"prefer-const": true,
|
||||||
|
"prefer-for-of": true,
|
||||||
|
"prefer-template": [
|
||||||
|
true,
|
||||||
|
"allow-single-concat"
|
||||||
|
],
|
||||||
"quotemark": [
|
"quotemark": [
|
||||||
true,
|
true,
|
||||||
"single",
|
"single",
|
||||||
@@ -50,6 +87,16 @@
|
|||||||
true,
|
true,
|
||||||
"always"
|
"always"
|
||||||
],
|
],
|
||||||
|
"space-before-function-paren": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"anonymous": "never",
|
||||||
|
"named": "never",
|
||||||
|
"asyncArrow": "always"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// "strict-boolean-expressions": true,
|
||||||
|
// "strict-type-predicates": true,
|
||||||
"trailing-comma": [
|
"trailing-comma": [
|
||||||
true,
|
true,
|
||||||
{
|
{
|
||||||
@@ -71,6 +118,7 @@
|
|||||||
"variable-declaration": "nospace"
|
"variable-declaration": "nospace"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"typeof-compare": true,
|
||||||
"use-isnan": true,
|
"use-isnan": true,
|
||||||
"variable-name": [
|
"variable-name": [
|
||||||
true,
|
true,
|
||||||
|
|||||||
Reference in New Issue
Block a user