Compare commits
57 Commits
v5.0.0-alp
...
v5.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11eacb27a1 | ||
|
|
543d39246f | ||
|
|
6837414f22 | ||
|
|
ea6fdbaaf2 | ||
|
|
ccc29e3dfc | ||
|
|
48814d4213 | ||
|
|
c3dd83cf3c | ||
|
|
77482f4930 | ||
|
|
503b2a3785 | ||
|
|
9464f7e79f | ||
|
|
77ae37c54c | ||
|
|
e20ec552b7 | ||
|
|
f911447c5e | ||
|
|
38c44c808d | ||
|
|
655afb358e | ||
|
|
21e0963600 | ||
|
|
62580da702 | ||
|
|
6b97c107eb | ||
|
|
92b57580b8 | ||
|
|
e400f27c84 | ||
|
|
4221e06ae3 | ||
|
|
a2dc65c044 | ||
|
|
4102bdd471 | ||
|
|
d420d82ab2 | ||
|
|
260874fa1d | ||
|
|
9d83fbcacb | ||
|
|
a50f04c569 | ||
|
|
df0599a832 | ||
|
|
f05d236e79 | ||
|
|
1b7610857a | ||
|
|
04d2c00ebf | ||
|
|
ece34dba32 | ||
|
|
68fcbf713d | ||
|
|
e192c547b1 | ||
|
|
3835193118 | ||
|
|
d161084ccd | ||
|
|
b9c4468cf7 | ||
|
|
4bacb6fbff | ||
|
|
c98755cc87 | ||
|
|
6d759daaad | ||
|
|
5a42ce4ed4 | ||
|
|
a5af318269 | ||
|
|
5a2bd02402 | ||
|
|
2bba14260f | ||
|
|
22378d5f25 | ||
|
|
d1d1db18e2 | ||
|
|
3dab90709b | ||
|
|
f58d085352 | ||
|
|
a77bb36ee3 | ||
|
|
5cc9365fa1 | ||
|
|
a587108cab | ||
|
|
1b4350e476 | ||
|
|
586785cfb8 | ||
|
|
04df931902 | ||
|
|
d31eb25451 | ||
|
|
35b16a78ba | ||
|
|
825b9661fb |
125
CHANGELOG.md
@@ -4,17 +4,107 @@ 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/).
|
||||||
|
|
||||||
## [4.5.0-beta] - 2017-08-27
|
## [5.0.0] - 2017-09-12
|
||||||
### Added
|
### Added
|
||||||
- Adds an all-new `Git File History` explorer to the Explorer activity -- enabled via `"gitlens.insiders": true`
|
- Adds an all-new `GitLens` custom view to the Explorer activity
|
||||||
- Shows the commit history of the active file -- automatically tracks the active editor
|
|
||||||
- Provides toolbar buttons to `Refresh`
|
- `Repository View` - provides a full repository explorer
|
||||||
- Provides a context menu with `Open Changes`, `Compare File with Working Tree`, `Open File`, `Open File Revision`, `Open File in Remote`, `Open File Revision in Remote`, and `Show Commit Details` commands
|
|
||||||
- Adds a `No stashed changes` message to the `Git Stashes` explorer when there are no stashes
|

|
||||||
- Adds `${filePath}` token to file formatting
|
|
||||||
|
- `Repository Status` node — provides the status of the repository
|
||||||
|
- Provides the name of the current branch, its upstream tracking branch (if available), and its upstream status (if available)
|
||||||
|
- Provides indicator dots on the repository icon which denote the following:
|
||||||
|
- `None` - up-to-date with the upstream
|
||||||
|
- `Green` - ahead of the upstream
|
||||||
|
- `Red` - behind the upstream
|
||||||
|
- `Yellow` - both ahead of and behind the upstream
|
||||||
|
- Provides additional nodes, if the current branch is not synchronized with the upstream, to quickly see and explore the specific commits ahead and/or behind the upstream
|
||||||
|
- Provides a context menu with `Open Repository in Remote`, and `Refresh` commands
|
||||||
|
|
||||||
|
- `Branches` node — provides a list of the local branches
|
||||||
|
- Indicates which branch is the current branch and optionally shows the remote tracking branch
|
||||||
|
- Expand each branch to easily see its revision (commit) history
|
||||||
|
- Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
|
||||||
|
- Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, `Show File History`, and `Show Commit File Details` commands
|
||||||
|
- Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each branch with `Open Branch in Remote`, and `Refresh` commands
|
||||||
|
- Provides a context menu with `Open Branches in Remote`, and `Refresh` commands
|
||||||
|
|
||||||
|
- `Remotes` node — provides a list of remotes
|
||||||
|
- Indicates the direction of the remote (fetch, push, both), remote service (if applicable), and repository path
|
||||||
|
- Expand each remote to see its list of branches
|
||||||
|
- Expand each branch to easily see its revision (commit) history
|
||||||
|
- Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
|
||||||
|
- Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
|
||||||
|
- Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`,`Show Commit Details`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each remote with `Open Branches in Remote`, `Open Repository in Remote`, and `Refresh` commands
|
||||||
|
- Provides a context menu with a `Refresh` command
|
||||||
|
|
||||||
|
- `Stashes` node — provides a list of stashed changes
|
||||||
|
- Expand each stash to quickly see the set of files stashed, complete with status indicators for adds, changes, renames, and deletes
|
||||||
|
- Provides a context menu with `Stash Changes`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each stash with `Apply Stashed Changes` (confirmation required), `Delete Stashed Changes` (confirmation required), `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit Message to Clipboard`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each stashed file with `Apply Changes`, `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, and `Show File History` commands
|
||||||
|
|
||||||
|
- `History View` - provides the revision history of the active file
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- Automatically updates to track the active editor
|
||||||
|
- Provides a context menu with `Open File`, `Open File in Remote`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each revision (commit) with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
|
||||||
|
|
||||||
|
- Quickly switch between views using the `Switch to Repository View` or `Switch to History View` commands
|
||||||
|
- Provides toolbar commands to `Search Commits`, `Switch to Repository View` or `Switch to History View`, and `Refresh`
|
||||||
|
|
||||||
|
- Adds all-new interactivity to the hover annotations
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- Adds the following command-links to the `details` hover annotation
|
||||||
|
- Clicking the commit id will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
|
- Adds the following command-links to the `changes` hover annotation
|
||||||
|
- Clicking on `Changes` will run the `Compare File Revisions` command (`gitlens.diffWith`)
|
||||||
|
- Clicking the current and previous commit ids will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
|
|
||||||
|
- Adds support for remote services with custom domains -- closes [#120](https://github.com/eamodio/vscode-gitlens/issues/120)
|
||||||
|
- Adds support for the Bitbucket Server (previously called Stash) remote service -- closes [#120](https://github.com/eamodio/vscode-gitlens/issues/120)
|
||||||
|
- Adds `gitlens.blame.ignoreWhitespace` setting to specify whether or not to ignore whitespace when comparing revisions during blame operations -- closes [#138](https://github.com/eamodio/vscode-gitlens/issues/138)
|
||||||
|
- Adds `Compare File Revisions` command (`gitlens.diffWith`) - compares the specified file revisions
|
||||||
|
- Adds `Open Branches in Remote` command (`gitlens.openBranchesInRemote`) - opens the branches in the supported remote service
|
||||||
|
- Adds `Stash Changes` command (`gitlens.stashSave`) to the source control group context menu -- can now stash a group of files
|
||||||
|
- Adds `Stash Changes` command (`gitlens.stashSave`) to the source control resource context menu -- can now stash individual files (works with multi-select too!)
|
||||||
|
- Adds `gitlens.gitExplorer.view` setting to specify the starting view (mode) of the `GitLens` custom view
|
||||||
|
- Adds `gitlens.gitExplorer.showTrackingBranch` setting to specify whether or not to show the tracking branch when displaying local branches in the `GitLens` custom view
|
||||||
|
- Adds `gitlens.gitExplorer.commitFormat` setting to specify the format of committed changes in the `GitLens` custom view
|
||||||
|
- Adds `gitlens.gitExplorer.commitFileFormat` setting to specify the format of a committed file in the `GitLens` custom view
|
||||||
|
- Adds `gitlens.gitExplorer.stashFormat` setting to specify the format of stashed changes in the `GitLens` custom view
|
||||||
|
- Adds `gitlens.gitExplorer.stashFileFormat` setting to specify the format of a stashed file in the `GitLens` custom view
|
||||||
|
- Adds `${filePath}` token to file formatting settings
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Changes `gitlens.stashExplorer.stashFileFormat` setting to defaults to `${filePath}` for better separator handling
|
- Changes `Show Stashed Changes` option icon in repository status quick pick menu to match the `GitLens` custom view
|
||||||
|
- Changes `Stash Changes` option icon in stashed changes quick pick menu to a plus (+)
|
||||||
|
- Renames `Compare File with Previous` command (`gitlens.diffWithPrevious`) to `Compare File with Previous Revision`
|
||||||
|
- Renames `Compare File with Next Commit` command (`gitlens.diffWithNext`) to `Compare File with Next Revision`
|
||||||
|
- Renames `Compare File with Working Tree` command (`gitlens.diffWithWorking`) to `Compare File with Working Revision`
|
||||||
|
- Renames `Compare Line Commit with Previous` command (`gitlens.diffLineWithPrevious`) to `Compare Line Revision with Previous`
|
||||||
|
- Renames `Compare Line Commit with Working Tree` command (`gitlens.diffLineWithWorking`) to `Compare Line Revision with Working`
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Removes `Git Stashes` custom view view - as it's functionality has been folded into the new `GitLens` custom view
|
||||||
|
- Removes `gitlens.stashExplorer.stashFormat` setting
|
||||||
|
- Removes `gitlens.stashExplorer.stashFileFormat` setting
|
||||||
|
- Removes `Stash Unstaged Changes` option from stashed changes quick pick menu -- didn't work as intended
|
||||||
|
- Removes the seeding of the commit search command from the clipboard
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixes an issue where double hover annotations could be shown on blank lines
|
||||||
|
- Fixes an issue where remote branches couldn't be opened properly in their remote service
|
||||||
|
- Fixes [#130](https://github.com/eamodio/vscode-gitlens/issues/130) - First-run "Thank you for choosing GitLens! [...]" info message shown on every start up
|
||||||
|
- Fixes an issue where sometimes diffs (via branch name) wouldn't open properly
|
||||||
|
- Fixes an issue where remotes are queried more than once on startup
|
||||||
|
|
||||||
## [4.4.3] - 2017-08-30
|
## [4.4.3] - 2017-08-30
|
||||||
## Fixed
|
## Fixed
|
||||||
@@ -63,21 +153,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
## [4.3.1] - 2017-07-03
|
## [4.3.1] - 2017-07-03
|
||||||
## Added
|
## Added
|
||||||
- Adds `gitlens.stashExplorer.enabled` setting to specify whether or not to show the `Git Stashes` explorer
|
- Adds `gitlens.stashExplorer.enabled` setting to specify whether or not to show the `Git Stashes` custom view
|
||||||
- Adds `Toggle Git Stashes Explorer` command (`gitlens.stashExplorer.toggle`) - toggles the `Git Stashes` explorer on and off
|
- Adds `Toggle Git Stashes Explorer` command (`gitlens.stashExplorer.toggle`) - toggles the `Git Stashes` custom view on and off
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- Hides the `Git Stashes` explorer by default
|
- Hides the `Git Stashes` custom view by default
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
- Fixes [#108](https://github.com/eamodio/vscode-gitlens/issues/108) - Option to remove stash explorer from the main explorer?
|
- Fixes [#108](https://github.com/eamodio/vscode-gitlens/issues/108) - Option to remove stash explorer from the main explorer?
|
||||||
|
|
||||||
## [4.3.0] - 2017-07-03
|
## [4.3.0] - 2017-07-03
|
||||||
## Added
|
## Added
|
||||||
- Adds `Git Stashes` view to the Explorer activity
|
- Adds `Git Stashes` custom view to the Explorer activity
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- Shows all of the stashed changes in the repository
|
- Shows all of the stashed changes in the repository
|
||||||
- Provides toolbar buttons to `Stash Changes` and `Refresh`
|
- Provides toolbar buttons to `Stash Changes` and `Refresh`
|
||||||
- Provides a context menu with `Apply Stashed Changes` and `Delete Stashed Changes` commands - both require a confirmation
|
- Provides a context menu with `Apply Stashed Changes` and `Delete Stashed Changes` commands - both require a confirmation
|
||||||
@@ -86,7 +173,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
## [4.2.0] - 2017-06-27
|
## [4.2.0] - 2017-06-27
|
||||||
## Added
|
## Added
|
||||||
- Adds `Compare File with Revision...` command (`gitlens.diffWithRevision`) - compare the active file with the selected revision of the same file
|
- Adds `Compare File with Revision...` command (`gitlens.diffWithRevision`) - compares the active file with the selected revision of the same file
|
||||||
- Adds `Open Changed Files` command (`gitlens.openChangedFiles`) to the source control group context menu
|
- Adds `Open Changed Files` command (`gitlens.openChangedFiles`) to the source control group context menu
|
||||||
- Adds `Close Unchanged Files` command (`gitlens.closeUnchangedFiles`) to the source control group context menu
|
- Adds `Close Unchanged Files` command (`gitlens.closeUnchangedFiles`) to the source control group context menu
|
||||||
- Adds `Open File in Remote` command (`gitlens.openFileInRemote`) to the source control resource context menu
|
- Adds `Open File in Remote` command (`gitlens.openFileInRemote`) to the source control resource context menu
|
||||||
@@ -140,7 +227,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixes excessive memory usage when parsing diffs
|
- Fixes excessive memory usage when parsing diffs
|
||||||
- Fixes extra newline in multiline commit messages
|
- Fixes extra newline in multi-line commit messages
|
||||||
- Fixes (again) [#33](https://github.com/eamodio/vscode-gitlens/issues/33) - Commit messages can causes markdown formatting in hovers
|
- Fixes (again) [#33](https://github.com/eamodio/vscode-gitlens/issues/33) - Commit messages can causes markdown formatting in hovers
|
||||||
|
|
||||||
## [4.0.1] - 2017-06-09
|
## [4.0.1] - 2017-06-09
|
||||||
@@ -224,7 +311,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
### 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 round-trips 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 (the line's previous version) into the active line hover when the current line is uncommitted
|
- Adds diff information (the line's previous version) into the active line hover when the current line is uncommitted
|
||||||
- Adds `gitlens.statusBar.alignment` settings to control the alignment of the status bar -- thanks to [PR #72](https://github.com/eamodio/vscode-gitlens/pull/72) by Zack Schuster ([@zackschuster](https://github.com/zackschuster))!
|
- Adds `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))!
|
||||||
@@ -518,7 +605,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
## [2.9.0]
|
## [2.9.0]
|
||||||
### Changed
|
### Changed
|
||||||
- To accomodate the realization that blame information is invalid when a file has unsaved changes, the following behavior changes have been made
|
- To accommodate the realization that blame information is invalid when a file has unsaved changes, the following behavior changes have been made
|
||||||
- Status bar blame information will hide
|
- Status bar blame information will hide
|
||||||
- Code lens change to a `Cannot determine...` message and become unclickable
|
- Code lens change to a `Cannot determine...` message and become unclickable
|
||||||
- Many menu choices and commands will hide
|
- Many menu choices and commands will hide
|
||||||
|
|||||||
101
README.md
@@ -1,7 +1,7 @@
|
|||||||
[](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
|
[](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
|
||||||
[](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
|
[](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
|
||||||
[](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
|
[](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
|
||||||
[](https://join.slack.com/t/vscode-gitlens/shared_invite/MjIxOTgxNDE3NzM0LTE1MDE2Nzk1MTgtMjkwMmZjMzcxNQ)
|
[](https://join.slack.com/t/vscode-gitlens/shared_invite/MjIxOTgxNDE3NzM0LTE1MDE2Nzk1MTgtMjkwMmZjMzcxNQ)
|
||||||
|
|
||||||
# GitLens
|
# GitLens
|
||||||
|
|
||||||
@@ -21,7 +21,10 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||

|

|
||||||
- Contains the author, date, and message of the line's most recent commit, by [default](#line-blame-annotation-settings)
|
- Contains the author, date, and message of the line's most recent commit, by [default](#line-blame-annotation-settings)
|
||||||
- Adds a `details` hover annotation to the current line annotation, which provides more commit details ([optional](#line-blame-annotation-settings), on by default)
|
- Adds a `details` hover annotation to the current line annotation, which provides more commit details ([optional](#line-blame-annotation-settings), on by default)
|
||||||
|
- Clicking the commit id will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
- Adds a `changes` (diff) hover annotation to the current line annotation, which provides **instant** access to the line's previous version ([optional](#line-blame-annotation-settings), on by default)
|
- Adds a `changes` (diff) hover annotation to the current line annotation, which provides **instant** access to the line's previous version ([optional](#line-blame-annotation-settings), on by default)
|
||||||
|
- Clicking on `Changes` will run the `Compare File Revisions` command (`gitlens.diffWith`)
|
||||||
|
- Clicking the current and previous commit ids will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -31,6 +34,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
- Choose between `gutter` (default) and `hover` [annotation styles](#file-blame-annotation-settings)
|
- Choose between `gutter` (default) and `hover` [annotation styles](#file-blame-annotation-settings)
|
||||||
- Contains the commit message and date, by [default](#file-blame-annotation-settings)
|
- Contains the commit message and date, by [default](#file-blame-annotation-settings)
|
||||||
- Adds a `details` hover annotation to the line's annotation, which provides more commit details ([optional](#file-blame-annotation-settings), on by default)
|
- Adds a `details` hover annotation to the line's annotation, which provides more commit details ([optional](#file-blame-annotation-settings), on by default)
|
||||||
|
- Clicking the commit id will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
- Adds a `heatmap` (age) indicator to the gutter annotations (on right edge by [default](#file-blame-annotation-settings)), which provides an easy, at-a-glance way to tell the age of a line ([optional](#file-blame-annotation-settings), on by default)
|
- Adds a `heatmap` (age) indicator to the gutter annotations (on right edge by [default](#file-blame-annotation-settings)), which provides an easy, at-a-glance way to tell the age of a line ([optional](#file-blame-annotation-settings), on by default)
|
||||||
- Indicator ranges from bright yellow (newer) to dark brown (older)
|
- Indicator ranges from bright yellow (newer) to dark brown (older)
|
||||||
- Press `Escape` to quickly toggle the annotations off
|
- Press `Escape` to quickly toggle the annotations off
|
||||||
@@ -61,7 +65,10 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
- Adds on-demand, [customizable](#file-recent-changes-annotation-settings) and [themeable](#theme-settings), **recent changes annotations** of the whole file
|
- Adds on-demand, [customizable](#file-recent-changes-annotation-settings) and [themeable](#theme-settings), **recent changes annotations** of the whole file
|
||||||
- Highlights all of lines changed in the most recent commit
|
- Highlights all of lines changed in the most recent commit
|
||||||
- Adds a `details` hover annotation to each line, which provides more commit details ([optional](#file-blame-annotation-settings), on by default)
|
- Adds a `details` hover annotation to each line, which provides more commit details ([optional](#file-blame-annotation-settings), on by default)
|
||||||
|
- Clicking the commit id will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
- Adds a `changes` (diff) hover annotation to each line, which provides **instant** access to the line's previous version ([optional](#file-recent-changes-annotation-settings), on by default)
|
- Adds a `changes` (diff) hover annotation to each line, which provides **instant** access to the line's previous version ([optional](#file-recent-changes-annotation-settings), on by default)
|
||||||
|
- Clicking on `Changes` will run the `Compare File Revisions` command (`gitlens.diffWith`)
|
||||||
|
- Clicking the current and previous commit ids will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
|
||||||
- Press `Escape` to quickly toggle the annotations off
|
- Press `Escape` to quickly toggle the annotations off
|
||||||
|
|
||||||
- Adds `Toggle Recent File Changes Annotations` command (`gitlens.toggleFileRecentChanges`) to toggle the recent changes annotations on and off
|
- Adds `Toggle Recent File Changes Annotations` command (`gitlens.toggleFileRecentChanges`) to toggle the recent changes annotations on and off
|
||||||
@@ -97,39 +104,78 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Compare File with Branch...` command (`gitlens.diffWithBranch`) to compare the active file with the same file on the selected branch
|
- Adds a `Compare File with Branch...` command (`gitlens.diffWithBranch`) to compare the active file with the same file on the selected branch
|
||||||
|
|
||||||
- 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 Revision` 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` 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 Revision` command (`gitlens.diffWithPrevious`) with a shortcut of `alt+,` to compare the active file/diff with the previous 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 Line Revision 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 Revision...` command (`gitlens.diffWithRevision`) to compare the active file with the selected revision of the same file
|
- Adds a `Compare File with Revision...` command (`gitlens.diffWithRevision`) to compare the active file with the selected revision of the same file
|
||||||
|
|
||||||
- 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 Revision` 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 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
|
- Adds a `Compare Line Revision with Working` 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
|
||||||
|
|
||||||
- Adds a [customizable](#git-file-history-explorer-settings) `Git File History` explorer to the Explorer activity -- currently [insiders](#insiders) only
|
- Adds a [customizable](#gitlens-custom-view-settings) `GitLens` custom view to the Explorer activity
|
||||||
|
|
||||||
- Shows the commit history of the active file -- automatically tracks the active editor
|
- `Repository View` - provides a full repository explorer
|
||||||
- Provides toolbar buttons to `Refresh`
|
|
||||||
- Provides a context menu with `Open Changes`, `Compare File with Working Tree`, `Open File`, `Open File Revision`, `Open File in Remote`, `Open File Revision in Remote`, and `Show Commit Details` commands
|
|
||||||
|
|
||||||
- Adds a [customizable](#git-stashes-explorer-settings) `Git Stashes` explorer to the Explorer activity
|

|
||||||
|
|
||||||

|
- `Repository Status` node — provides the status of the repository
|
||||||
|
- Provides the name of the current branch, its upstream tracking branch (if available), and its upstream status (if available)
|
||||||
|
- Provides indicator dots on the repository icon which denote the following:
|
||||||
|
- `None` - up-to-date with the upstream
|
||||||
|
- `Green` - ahead of the upstream
|
||||||
|
- `Red` - behind the upstream
|
||||||
|
- `Yellow` - both ahead of and behind the upstream
|
||||||
|
- Provides additional nodes, if the current branch is not synchronized with the upstream, to quickly see and explore the specific commits ahead and/or behind the upstream
|
||||||
|
- Provides a context menu with `Open Repository in Remote`, and `Refresh` commands
|
||||||
|
|
||||||
- Shows all of the stashed changes in the repository
|
- `Branches` node — provides a list of the local branches
|
||||||
- Provides toolbar buttons to `Stash Changes` and `Refresh`
|
- Indicates which branch is the current branch and [optionally](#gitlens-custom-view-settings) shows the remote tracking branch
|
||||||
- Provides a context menu with `Apply Stashed Changes` and `Delete Stashed Changes` commands — both require a confirmation
|
- Expand each branch to easily see its revision (commit) history
|
||||||
- Expand each stash to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
|
- Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
|
||||||
- Provides a context menu with `Open Changes`, `Open File`, `Open Stashed File`, `Open File in Remote`, and `Compare File with Working Tree` commands
|
- Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
|
||||||
|
|
||||||
|
- Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each branch with `Open Branch in Remote`, and `Refresh` commands
|
||||||
|
- Provides a context menu with `Open Branches in Remote`, and `Refresh` commands
|
||||||
|
|
||||||
|
- `Remotes` node — provides a list of remotes
|
||||||
|
- Indicates the direction of the remote (fetch, push, both), remote service (if applicable), and repository path
|
||||||
|
- Expand each remote to see its list of branches
|
||||||
|
- Expand each branch to easily see its revision (commit) history
|
||||||
|
- Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
|
||||||
|
- Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, `Show File History`, and `Show Commit File Details` commands
|
||||||
|
- Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`,`Show Commit Details`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each remote with `Open Branches in Remote`, `Open Repository in Remote`, and `Refresh` commands
|
||||||
|
- Provides a context menu with a `Refresh` command
|
||||||
|
|
||||||
|
- `Stashes` node — provides a list of stashed changes
|
||||||
|
- Expand each stash to quickly see the set of files stashed, complete with status indicators for adds, changes, renames, and deletes
|
||||||
|
- Provides a context menu with `Stash Changes`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each stash with `Apply Stashed Changes` (confirmation required), `Delete Stashed Changes` (confirmation required), `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit Message to Clipboard`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each stashed file with `Apply Changes`, `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, and `Show File History` commands
|
||||||
|
|
||||||
|
- `History View` - provides the revision history of the active file
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- Automatically updates to track the active editor
|
||||||
|
- Provides a context menu with `Open File`, `Open File in Remote`, and `Refresh` commands
|
||||||
|
- Provides a context menu on each revision (commit) with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
|
||||||
|
|
||||||
|
- Quickly switch between views using the `Switch to Repository View` or `Switch to History View` commands
|
||||||
|
- Provides toolbar commands to `Search Commits`, `Switch to Repository View` or `Switch to History View`, and `Refresh`
|
||||||
|
|
||||||
- Adds a `Search Commits` command (`gitlens.showCommitSearch`) with a shortcut of `alt+/` to search for commits by message, author, file(s), or commit id
|
- Adds a `Search Commits` command (`gitlens.showCommitSearch`) with a shortcut of `alt+/` to search for commits by message, author, file(s), or commit id
|
||||||
|
|
||||||
- Adds commands to open files, commits, branches, and the repository in the supported remote services, currently **BitBucket, GitHub, GitLab, and Visual Studio Team Services** — only available if a Git upstream service is configured in the repository
|
- Adds commands to open files, commits, branches, and the repository in the supported remote services, currently **BitBucket, GitHub, GitLab, and Visual Studio Team Services** — only available if a Git upstream service is configured in the repository
|
||||||
|
- Also supports [remote services with custom domains](#custom-remotes-settings), such as **BitBucket, Bitbucket Server (previously called Stash), GitHub, GitHub Enterprise, GitLab**
|
||||||
|
- `Open Branches in Remote` command (`gitlens.openBranchesInRemote`) — opens the branches in the supported remote service
|
||||||
- `Open Branch in Remote` command (`gitlens.openBranchInRemote`) — opens the current branch commits in the supported remote service
|
- `Open Branch in Remote` command (`gitlens.openBranchInRemote`) — opens the current branch commits in the supported remote service
|
||||||
- `Open Commit in Remote` command (`gitlens.openCommitInRemote`) — opens the commit revision of the active line in the supported remote service
|
- `Open Commit in Remote` command (`gitlens.openCommitInRemote`) — opens the commit revision of the active line in the supported remote service
|
||||||
- `Open File in Remote` command (`gitlens.openFileInRemote`) — opens the active file/revision in the supported remote service
|
- `Open File in Remote` command (`gitlens.openFileInRemote`) — opens the active file/revision in the supported remote service
|
||||||
@@ -223,6 +269,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
- 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
|
||||||
|
|
||||||
- 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
|
||||||
|
- Also adds the command to the Source Control items context menu to stash an individual or group of files, works with multi-select too!
|
||||||
|
|
||||||
## Insiders
|
## Insiders
|
||||||
|
|
||||||
@@ -240,7 +287,11 @@ GitLens is highly customizable and provides many configuration settings to allow
|
|||||||
|`gitlens.insiders`|Opts into the insiders channel -- provides access to upcoming features
|
|`gitlens.insiders`|Opts into the insiders channel -- provides access to upcoming features
|
||||||
|`gitlens.outputLevel`|Specifies how much (if any) output will be sent to the GitLens output channel
|
|`gitlens.outputLevel`|Specifies how much (if any) output will be sent to the GitLens output channel
|
||||||
|
|
||||||
### Blame Annotation Settings
|
### Blame Settings
|
||||||
|
|
||||||
|
|Name | Description
|
||||||
|
|-----|------------
|
||||||
|
|`gitlens.blame.ignoreWhitespace`|Specifies whether or not to ignore whitespace when comparing revisions during blame operations
|
||||||
|
|
||||||
#### File Blame Annotation Settings
|
#### File Blame Annotation Settings
|
||||||
|
|
||||||
@@ -295,18 +346,22 @@ GitLens is highly customizable and provides many configuration settings to allow
|
|||||||
|`gitlens.codeLens.customLocationSymbols`|Specifies the set of document symbols where Git code lens will be shown in the document
|
|`gitlens.codeLens.customLocationSymbols`|Specifies the set of document symbols where Git code lens will be shown in the document
|
||||||
|`gitlens.codeLens.perLanguageLocations`|Specifies where Git code lens will be shown in the document for the specified languages
|
|`gitlens.codeLens.perLanguageLocations`|Specifies where Git code lens will be shown in the document for the specified languages
|
||||||
|
|
||||||
### Git File History Explorer Settings
|
### GitLens Custom View Settings
|
||||||
|
|
||||||
|Name | Description
|
|Name | Description
|
||||||
|-----|------------
|
|-----|------------
|
||||||
|`gitlens.fileHistoryExplorer.commitFormat`|Specifies the format of committed changes in the `Git File History` explorer <br />Available tokens<br /> ${id} - commit id<br /> ${author} - commit author<br /> ${message} - commit message<br /> ${ago} - relative commit date (e.g. 1 day ago)<br /> ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)<br /> ${authorAgo} - commit author, relative commit date<br />See https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting
|
|`gitlens.gitExplorer.view`|Specifies the starting view (mode) of the `GitLens` custom view<br />`history` - shows the commit history of the active file<br />`repository` - shows a repository explorer"
|
||||||
|
|`gitlens.gitExplorer.showTrackingBranch`|Specifies whether or not to show the tracking branch when displaying local branches in the `GitLens` custom view"
|
||||||
|
|`gitlens.gitExplorer.commitFormat`|Specifies the format of committed changes in the `GitLens` custom view<br />Available tokens<br /> ${id} - commit id<br /> ${author} - commit author<br /> ${message} - commit message<br /> ${ago} - relative commit date (e.g. 1 day ago)<br /> ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)<br /> ${authorAgo} - commit author, relative commit date<br />See https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting
|
||||||
|
|`gitlens.gitExplorer.commitFileFormat`|Specifies the format of a committed file in the `GitLens` custom view<br />Available tokens<br /> ${file} - file name<br /> ${filePath} - file name and path<br /> ${path} - file path
|
||||||
|
|`gitlens.gitExplorer.stashFormat`|Specifies the format of stashed changes in the `GitLens` custom view<br />Available tokens<br /> ${id} - commit id<br /> ${author} - commit author<br /> ${message} - commit message<br /> ${ago} - relative commit date (e.g. 1 day ago)<br /> ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)<br /> ${authorAgo} - commit author, relative commit date<br />See https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting
|
||||||
|
|`gitlens.gitExplorer.stashFileFormat`|Specifies the format of a stashed file in the `GitLens` custom view<br />Available tokens<br /> ${file} - file name<br /> ${filePath} - file name and path<br /> ${path} - file path
|
||||||
|
|
||||||
### Git Stashes Explorer Settings
|
### Custom Remotes Settings
|
||||||
|
|
||||||
|Name | Description
|
|Name | Description
|
||||||
|-----|------------
|
|-----|------------
|
||||||
|`gitlens.stashExplorer.stashFormat`|Specifies the format of stashed changes in the `Git Stashes` explorer <br />Available tokens<br /> ${id} - commit id<br /> ${author} - commit author<br /> ${message} - commit message<br /> ${ago} - relative commit date (e.g. 1 day ago)<br /> ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)<br /> ${authorAgo} - commit author, relative commit date<br />See https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting
|
|`gitlens.remotes`|Specifies any custom domains for remote (code-hosting) services<br />Example: ```"gitlens.remotes": [{ "domain": "git.corporate-url.com", "type": "GitHub" }]```
|
||||||
|`gitlens.stashExplorer.stashFileFormat`|Specifies the format of a stashed file in the `Git Stashes` explorer <br />Available tokens<br /> ${file} - file name<br /> ${filePath} - file name and path<br /> ${path} - file path
|
|
||||||
|
|
||||||
### Status Bar Settings
|
### Status Bar Settings
|
||||||
|
|
||||||
|
|||||||
5
images/dark/icon-repo-green.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#C5C5C5" d="m6,12l-1,0l0,-1l1,0l0,1l0,0zm0,-3l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm8,-1l0,12c0,0.55 -0.45,1 -1,1l-5,0l0,2l-1.5,-1.5l-1.5,1.5l0,-2l-2,0c-0.55,0 -1,-0.45 -1,-1l0,-12c0,-0.55 0.45,-1 1,-1l10,0c0.55,0 1,0.45 1,1l0,0zm-1,10l-10,0l0,2l2,0l0,-1l3,0l0,1l5,0l0,-2l0,0zm0,-10l-9,0l0,9l9,0l0,-9l0,0z" />
|
||||||
|
<ellipse fill="#32cd32" stroke="#C5C5C5" stroke-width="0.5" rx="3" ry="3" cx="13" cy="4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 586 B |
5
images/dark/icon-repo-red.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#C5C5C5" d="m6,12l-1,0l0,-1l1,0l0,1l0,0zm0,-3l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm8,-1l0,12c0,0.55 -0.45,1 -1,1l-5,0l0,2l-1.5,-1.5l-1.5,1.5l0,-2l-2,0c-0.55,0 -1,-0.45 -1,-1l0,-12c0,-0.55 0.45,-1 1,-1l10,0c0.55,0 1,0.45 1,1l0,0zm-1,10l-10,0l0,2l2,0l0,-1l3,0l0,1l5,0l0,-2l0,0zm0,-10l-9,0l0,9l9,0l0,-9l0,0z" />
|
||||||
|
<ellipse fill="#cd3131" stroke="#C5C5C5" stroke-width="0.5" rx="3" ry="3" cx="13" cy="4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 586 B |
5
images/dark/icon-repo-yellow.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#C5C5C5" d="m6,12l-1,0l0,-1l1,0l0,1l0,0zm0,-3l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm8,-1l0,12c0,0.55 -0.45,1 -1,1l-5,0l0,2l-1.5,-1.5l-1.5,1.5l0,-2l-2,0c-0.55,0 -1,-0.45 -1,-1l0,-12c0,-0.55 0.45,-1 1,-1l10,0c0.55,0 1,0.45 1,1l0,0zm-1,10l-10,0l0,2l2,0l0,-1l3,0l0,1l5,0l0,-2l0,0zm0,-10l-9,0l0,9l9,0l0,-9l0,0z" />
|
||||||
|
<ellipse fill="#cdcd32" stroke="#C5C5C5" stroke-width="0.5" rx="3" ry="3" cx="13" cy="4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 586 B |
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="22px">
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="#C5C5C5" d="m14.687501,11.955358l-1.079554,-6.821251c-0.076429,-0.458572 -0.477679,-0.821607 -0.955357,-0.821607l-9.30518,0c-0.477679,0 -0.878929,0.363036 -0.955357,0.821607l-1.079554,6.821251l0,4.776787c0,0.525447 0.429911,0.955357 0.955357,0.955357l11.464288,0c0.525447,0 0.955357,-0.429911 0.955357,-0.955357l0,-4.776787l0,0zm-3.133572,0.525447l-0.420357,0.850268c-0.162411,0.324821 -0.496786,0.535 -0.869375,0.535l-4.547501,0c-0.363036,0 -0.687857,-0.210179 -0.850268,-0.525447l-0.420357,-0.869375c-0.162411,-0.315268 -0.496786,-0.525447 -0.850268,-0.525447l-1.327947,0l0.955357,-6.687501l9.553573,0l0.955357,6.687501l-1.318393,0c-0.372589,0 -0.697411,0.210179 -0.869375,0.525447l0.009554,0.009554z" />
|
<path fill="#C5C5C5" d="m14.687501,11.955358l-1.079554,-6.821251c-0.076429,-0.458572 -0.477679,-0.821607 -0.955357,-0.821607l-9.30518,0c-0.477679,0 -0.878929,0.363036 -0.955357,0.821607l-1.079554,6.821251l0,4.776787c0,0.525447 0.429911,0.955357 0.955357,0.955357l11.464288,0c0.525447,0 0.955357,-0.429911 0.955357,-0.955357l0,-4.776787l0,0zm-3.133572,0.525447l-0.420357,0.850268c-0.162411,0.324821 -0.496786,0.535 -0.869375,0.535l-4.547501,0c-0.363036,0 -0.687857,-0.210179 -0.850268,-0.525447l-0.420357,-0.869375c-0.162411,-0.315268 -0.496786,-0.525447 -0.850268,-0.525447l-1.327947,0l0.955357,-6.687501l9.553573,0l0.955357,6.687501l-1.318393,0c-0.372589,0 -0.697411,0.210179 -0.869375,0.525447l0.009554,0.009554z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 893 B After Width: | Height: | Size: 846 B |
4
images/dark/icon-sync.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#C5C5C5" d="m12.24,10.4c0.19,1.28 -0.2,2.62 -1.2,3.6c-1.47,1.45 -3.74,1.63 -5.41,0.54l1.17,-1.14l-4.3,-0.6l0.6,4.2l1.31,-1.26c2.36,1.74 5.7,1.57 7.84,-0.54c1.24,-1.23 1.81,-2.85 1.74,-4.46l-1.75,-0.34l0,0zm-7.28,-2.4c1.47,-1.45 3.74,-1.63 5.41,-0.54l-1.17,1.14l4.3,0.6l-0.6,-4.2l-1.31,1.26c-2.36,-1.74 -5.7,-1.57 -7.85,0.54c-1.24,1.23 -1.8,2.85 -1.73,4.46l1.75,0.35c-0.19,-1.28 0.2,-2.63 1.2,-3.61l0,0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 546 B |
4
images/dark/icon-unfold.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#C5C5C5" d="m12.5,11l2.5,2.5c0,0.55 -0.45,1 -1,1l-4,0l0,-1l3.5,0l-2,-2l-7,0l-2,2l3.5,0l0,1l-4,0c-0.55,0 -1,-0.45 -1,-1l2.5,-2.5l-2.5,-2.5c0,-0.55 0.45,-1 1,-1l4,0l0,1l-3.5,0l2,2l7,0l2,-2l-3.5,0l0,-1l4,0c0.55,0 1,0.45 1,1l-2.5,2.5l0,0zm-5.5,-1.5l2,0l0,-3l2,0l-3,-3l-3,3l2,0l0,3l0,0zm2,3l-2,0l0,3l-2,0l3,3l3,-3l-2,0l0,-3l0,0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 467 B |
5
images/light/icon-repo-green.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#424242" d="m6,12l-1,0l0,-1l1,0l0,1l0,0zm0,-3l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm8,-1l0,12c0,0.55 -0.45,1 -1,1l-5,0l0,2l-1.5,-1.5l-1.5,1.5l0,-2l-2,0c-0.55,0 -1,-0.45 -1,-1l0,-12c0,-0.55 0.45,-1 1,-1l10,0c0.55,0 1,0.45 1,1l0,0zm-1,10l-10,0l0,2l2,0l0,-1l3,0l0,1l5,0l0,-2l0,0zm0,-10l-9,0l0,9l9,0l0,-9l0,0z" />
|
||||||
|
<ellipse fill="#32cd32" stroke="#424242" stroke-width="0.5" rx="3" ry="3" cx="13" cy="4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 586 B |
5
images/light/icon-repo-red.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#424242" d="m6,12l-1,0l0,-1l1,0l0,1l0,0zm0,-3l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm8,-1l0,12c0,0.55 -0.45,1 -1,1l-5,0l0,2l-1.5,-1.5l-1.5,1.5l0,-2l-2,0c-0.55,0 -1,-0.45 -1,-1l0,-12c0,-0.55 0.45,-1 1,-1l10,0c0.55,0 1,0.45 1,1l0,0zm-1,10l-10,0l0,2l2,0l0,-1l3,0l0,1l5,0l0,-2l0,0zm0,-10l-9,0l0,9l9,0l0,-9l0,0z" />
|
||||||
|
<ellipse fill="#cd3131" stroke="#424242" stroke-width="0.5" rx="3" ry="3" cx="13" cy="4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 586 B |
5
images/light/icon-repo-yellow.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#424242" d="m6,12l-1,0l0,-1l1,0l0,1l0,0zm0,-3l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm0,-2l-1,0l0,1l1,0l0,-1l0,0zm8,-1l0,12c0,0.55 -0.45,1 -1,1l-5,0l0,2l-1.5,-1.5l-1.5,1.5l0,-2l-2,0c-0.55,0 -1,-0.45 -1,-1l0,-12c0,-0.55 0.45,-1 1,-1l10,0c0.55,0 1,0.45 1,1l0,0zm-1,10l-10,0l0,2l2,0l0,-1l3,0l0,1l5,0l0,-2l0,0zm0,-10l-9,0l0,9l9,0l0,-9l0,0z" />
|
||||||
|
<ellipse fill="#cdcd32" stroke="#424242" stroke-width="0.5" rx="3" ry="3" cx="13" cy="4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 586 B |
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="22px">
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="#424242" d="m14.687501,11.955358l-1.079554,-6.821251c-0.076429,-0.458572 -0.477679,-0.821607 -0.955357,-0.821607l-9.30518,0c-0.477679,0 -0.878929,0.363036 -0.955357,0.821607l-1.079554,6.821251l0,4.776787c0,0.525447 0.429911,0.955357 0.955357,0.955357l11.464288,0c0.525447,0 0.955357,-0.429911 0.955357,-0.955357l0,-4.776787l0,0zm-3.133572,0.525447l-0.420357,0.850268c-0.162411,0.324821 -0.496786,0.535 -0.869375,0.535l-4.547501,0c-0.363036,0 -0.687857,-0.210179 -0.850268,-0.525447l-0.420357,-0.869375c-0.162411,-0.315268 -0.496786,-0.525447 -0.850268,-0.525447l-1.327947,0l0.955357,-6.687501l9.553573,0l0.955357,6.687501l-1.318393,0c-0.372589,0 -0.697411,0.210179 -0.869375,0.525447l0.009554,0.009554z" />
|
<path fill="#424242" d="m14.687501,11.955358l-1.079554,-6.821251c-0.076429,-0.458572 -0.477679,-0.821607 -0.955357,-0.821607l-9.30518,0c-0.477679,0 -0.878929,0.363036 -0.955357,0.821607l-1.079554,6.821251l0,4.776787c0,0.525447 0.429911,0.955357 0.955357,0.955357l11.464288,0c0.525447,0 0.955357,-0.429911 0.955357,-0.955357l0,-4.776787l0,0zm-3.133572,0.525447l-0.420357,0.850268c-0.162411,0.324821 -0.496786,0.535 -0.869375,0.535l-4.547501,0c-0.363036,0 -0.687857,-0.210179 -0.850268,-0.525447l-0.420357,-0.869375c-0.162411,-0.315268 -0.496786,-0.525447 -0.850268,-0.525447l-1.327947,0l0.955357,-6.687501l9.553573,0l0.955357,6.687501l-1.318393,0c-0.372589,0 -0.697411,0.210179 -0.869375,0.525447l0.009554,0.009554z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 893 B After Width: | Height: | Size: 846 B |
4
images/light/icon-sync.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#424242" d="m12.24,10.4c0.19,1.28 -0.2,2.62 -1.2,3.6c-1.47,1.45 -3.74,1.63 -5.41,0.54l1.17,-1.14l-4.3,-0.6l0.6,4.2l1.31,-1.26c2.36,1.74 5.7,1.57 7.84,-0.54c1.24,-1.23 1.81,-2.85 1.74,-4.46l-1.75,-0.34l0,0zm-7.28,-2.4c1.47,-1.45 3.74,-1.63 5.41,-0.54l-1.17,1.14l4.3,0.6l-0.6,-4.2l-1.31,1.26c-2.36,-1.74 -5.7,-1.57 -7.85,0.54c-1.24,1.23 -1.8,2.85 -1.73,4.46l1.75,0.35c-0.19,-1.28 0.2,-2.63 1.2,-3.61l0,0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 546 B |
4
images/light/icon-unfold.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#424242" d="m12.5,11l2.5,2.5c0,0.55 -0.45,1 -1,1l-4,0l0,-1l3.5,0l-2,-2l-7,0l-2,2l3.5,0l0,1l-4,0c-0.55,0 -1,-0.45 -1,-1l2.5,-2.5l-2.5,-2.5c0,-0.55 0.45,-1 1,-1l4,0l0,1l-3.5,0l2,2l7,0l2,-2l-3.5,0l0,-1l4,0c0.55,0 1,0.45 1,1l-2.5,2.5l0,0zm-5.5,-1.5l2,0l0,-3l2,0l-3,-3l-3,3l2,0l0,3l0,0zm2,3l-2,0l0,3l-2,0l3,3l3,-3l-2,0l0,-3l0,0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 467 B |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 64 KiB |
BIN
images/screenshot-git-custom-view-history.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
images/screenshot-git-custom-view-repository.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 12 KiB |
116
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitlens",
|
"name": "gitlens",
|
||||||
"version": "4.4.3",
|
"version": "5.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -16,19 +16,19 @@
|
|||||||
"integrity": "sha1-qjuL2ivlErGuCgV7lC6GnDcKVWk=",
|
"integrity": "sha1-qjuL2ivlErGuCgV7lC6GnDcKVWk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "8.0.25"
|
"@types/node": "8.0.28"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/mocha": {
|
"@types/mocha": {
|
||||||
"version": "2.2.42",
|
"version": "2.2.43",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.42.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.43.tgz",
|
||||||
"integrity": "sha512-b6gVDoxEbAQGwbV7gSzeFw/hy3/eEAokztktdzl4bHvGgb9K5zW4mVQDlVYch2w31m8t/J7L2iqhQvz3r5edCQ==",
|
"integrity": "sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "8.0.25",
|
"version": "8.0.28",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.25.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.28.tgz",
|
||||||
"integrity": "sha512-zT+t9841g1HsjLtPMCYxmb1U4pcZ2TOegAKiomlmj6bIziuaEYHUavxLE9NRwdntY0vOCrgHho6OXjDX7fm/Kw==",
|
"integrity": "sha512-HupkFXEv3O3KSzcr3Ylfajg0kaerBg1DyaZzRBBQfrU3NN1mTBRE7sCveqHwXLS5Yrjvww8qFzkzYQQakG9FuQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/tmp": {
|
"@types/tmp": {
|
||||||
@@ -348,7 +348,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/copy-paste/-/copy-paste-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/copy-paste/-/copy-paste-1.3.0.tgz",
|
||||||
"integrity": "sha1-p+bEocKP3t8rCB5yuX3y75X0ce0=",
|
"integrity": "sha1-p+bEocKP3t8rCB5yuX3y75X0ce0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"iconv-lite": "0.4.18",
|
"iconv-lite": "0.4.19",
|
||||||
"sync-exec": "0.6.2"
|
"sync-exec": "0.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -660,7 +660,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"asynckit": "0.4.0",
|
"asynckit": "0.4.0",
|
||||||
"combined-stream": "1.0.5",
|
"combined-stream": "1.0.5",
|
||||||
"mime-types": "2.1.16"
|
"mime-types": "2.1.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"from": {
|
"from": {
|
||||||
@@ -999,7 +999,7 @@
|
|||||||
"is-typedarray": "1.0.0",
|
"is-typedarray": "1.0.0",
|
||||||
"isstream": "0.1.2",
|
"isstream": "0.1.2",
|
||||||
"json-stringify-safe": "5.0.1",
|
"json-stringify-safe": "5.0.1",
|
||||||
"mime-types": "2.1.16",
|
"mime-types": "2.1.17",
|
||||||
"oauth-sign": "0.8.2",
|
"oauth-sign": "0.8.2",
|
||||||
"qs": "6.3.2",
|
"qs": "6.3.2",
|
||||||
"stringstream": "0.0.5",
|
"stringstream": "0.0.5",
|
||||||
@@ -1248,6 +1248,12 @@
|
|||||||
"sntp": "1.0.9"
|
"sntp": "1.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"he": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"hoek": {
|
"hoek": {
|
||||||
"version": "2.16.3",
|
"version": "2.16.3",
|
||||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||||
@@ -1266,14 +1272,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.18",
|
"version": "0.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
|
||||||
"integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA=="
|
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
|
||||||
},
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz",
|
||||||
"integrity": "sha512-KjHyHxUgicfgFiTJaIA9DoeY3TIQz5thaKqm35re7RTVVB7zjF1fTMIDMXM4GUUBipR4FW8BvGnA115pZ/AxQQ=="
|
"integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw=="
|
||||||
},
|
},
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
@@ -1728,7 +1734,7 @@
|
|||||||
"normalize-path": "2.1.1",
|
"normalize-path": "2.1.1",
|
||||||
"object.omit": "2.0.1",
|
"object.omit": "2.0.1",
|
||||||
"parse-glob": "3.0.4",
|
"parse-glob": "3.0.4",
|
||||||
"regex-cache": "0.4.3"
|
"regex-cache": "0.4.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-extglob": {
|
"is-extglob": {
|
||||||
@@ -1749,18 +1755,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.29.0",
|
"version": "1.30.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
|
||||||
"integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=",
|
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mime-types": {
|
"mime-types": {
|
||||||
"version": "2.1.16",
|
"version": "2.1.17",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
|
||||||
"integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=",
|
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"mime-db": "1.29.0"
|
"mime-db": "1.30.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
@@ -1788,9 +1794,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mocha": {
|
"mocha": {
|
||||||
"version": "3.5.0",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.2.tgz",
|
||||||
"integrity": "sha512-pIU2PJjrPYvYRqVpjXzj76qltO9uBYI7woYAMoxbSefsa+vqAfptjoeevd6bUgwD0mPIO+hv9f7ltvsNreL2PA==",
|
"integrity": "sha512-iH5zl7afRZl1GvD0pnrRlazgc9Z/o34pXWmTFi8xNIMFKXgNL1SoBTDDb9sJfbV/sJV/j8X+0gvwY1QS1He7Nw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browser-stdout": "1.3.0",
|
"browser-stdout": "1.3.0",
|
||||||
@@ -1800,6 +1806,7 @@
|
|||||||
"escape-string-regexp": "1.0.5",
|
"escape-string-regexp": "1.0.5",
|
||||||
"glob": "7.1.1",
|
"glob": "7.1.1",
|
||||||
"growl": "1.9.2",
|
"growl": "1.9.2",
|
||||||
|
"he": "1.1.1",
|
||||||
"json3": "3.3.2",
|
"json3": "3.3.2",
|
||||||
"lodash.create": "3.1.1",
|
"lodash.create": "3.1.1",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
@@ -2080,13 +2087,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"regex-cache": {
|
"regex-cache": {
|
||||||
"version": "0.4.3",
|
"version": "0.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
|
||||||
"integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=",
|
"integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-equal-shallow": "0.1.3",
|
"is-equal-shallow": "0.1.3"
|
||||||
"is-primitive": "2.0.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"remove-trailing-separator": {
|
"remove-trailing-separator": {
|
||||||
@@ -2132,7 +2138,7 @@
|
|||||||
"is-typedarray": "1.0.0",
|
"is-typedarray": "1.0.0",
|
||||||
"isstream": "0.1.2",
|
"isstream": "0.1.2",
|
||||||
"json-stringify-safe": "5.0.1",
|
"json-stringify-safe": "5.0.1",
|
||||||
"mime-types": "2.1.16",
|
"mime-types": "2.1.17",
|
||||||
"oauth-sign": "0.8.2",
|
"oauth-sign": "0.8.2",
|
||||||
"performance-now": "0.2.0",
|
"performance-now": "0.2.0",
|
||||||
"qs": "6.4.0",
|
"qs": "6.4.0",
|
||||||
@@ -2235,9 +2241,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"source-map-support": {
|
"source-map-support": {
|
||||||
"version": "0.4.16",
|
"version": "0.4.18",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.16.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
|
||||||
"integrity": "sha512-A6vlydY7H/ljr4L2UOhDSajQdZQ6dMD7cLH0pzwcmwLyc9u8PNI4WGtnfDDzX7uzGL6c/T+ORL97Zlh+S4iOrg==",
|
"integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"source-map": "0.5.7"
|
"source-map": "0.5.7"
|
||||||
@@ -2328,15 +2334,6 @@
|
|||||||
"integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=",
|
"integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "5.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
@@ -2346,6 +2343,15 @@
|
|||||||
"strip-ansi": "4.0.0"
|
"strip-ansi": "4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"stringstream": {
|
"stringstream": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||||
@@ -2489,13 +2495,13 @@
|
|||||||
"resolve": "1.4.0",
|
"resolve": "1.4.0",
|
||||||
"semver": "5.4.1",
|
"semver": "5.4.1",
|
||||||
"tslib": "1.7.1",
|
"tslib": "1.7.1",
|
||||||
"tsutils": "2.8.1"
|
"tsutils": "2.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tsutils": {
|
"tsutils": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.2.tgz",
|
||||||
"integrity": "sha1-N3FATnyp8L7fXZGaR6SxiQpo7/8=",
|
"integrity": "sha1-LBSGukMSYIRbCsb5Aq/Z1wio6mo=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "1.7.1"
|
"tslib": "1.7.1"
|
||||||
@@ -2515,9 +2521,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "2.4.2",
|
"version": "2.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz",
|
||||||
"integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=",
|
"integrity": "sha1-A4qV99m7tCCxvzW6MdTFwd0//jQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"unique-stream": {
|
"unique-stream": {
|
||||||
@@ -2708,10 +2714,10 @@
|
|||||||
"gulp-symdest": "1.1.0",
|
"gulp-symdest": "1.1.0",
|
||||||
"gulp-untar": "0.0.6",
|
"gulp-untar": "0.0.6",
|
||||||
"gulp-vinyl-zip": "1.4.0",
|
"gulp-vinyl-zip": "1.4.0",
|
||||||
"mocha": "3.5.0",
|
"mocha": "3.5.2",
|
||||||
"request": "2.81.0",
|
"request": "2.81.0",
|
||||||
"semver": "5.4.1",
|
"semver": "5.4.1",
|
||||||
"source-map-support": "0.4.16",
|
"source-map-support": "0.4.18",
|
||||||
"url-parse": "1.1.9",
|
"url-parse": "1.1.9",
|
||||||
"vinyl-source-stream": "1.1.0"
|
"vinyl-source-stream": "1.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
298
package.json
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "gitlens",
|
"name": "gitlens",
|
||||||
"version": "4.5.0-beta",
|
"version": "5.0.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Eric Amodio",
|
"name": "Eric Amodio",
|
||||||
"email": "eamodio@gmail.com"
|
"email": "eamodio@gmail.com"
|
||||||
},
|
},
|
||||||
"publisher": "eamodio",
|
"publisher": "eamodio",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.15.0"
|
"vscode": "^1.16.0"
|
||||||
},
|
},
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
"displayName": "Git Lens \u2014 git blame annotations, code lens, and more",
|
"displayName": "Git Lens \u2014 git blame annotations, code lens, and more",
|
||||||
@@ -172,6 +172,11 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Specifies whether or not to trigger hover annotations over the whole line"
|
"description": "Specifies whether or not to trigger hover annotations over the whole line"
|
||||||
},
|
},
|
||||||
|
"gitlens.blame.ignoreWhitespace": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether or not to ignore whitespace when comparing revisions during blame operations"
|
||||||
|
},
|
||||||
"gitlens.blame.file.annotationType": {
|
"gitlens.blame.file.annotationType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "gutter",
|
"default": "gutter",
|
||||||
@@ -413,15 +418,6 @@
|
|||||||
"default": null,
|
"default": null,
|
||||||
"description": "Specifies how all absolute dates will be formatted by default\nSee https://momentjs.com/docs/#/displaying/format/ for valid formats"
|
"description": "Specifies how all absolute dates will be formatted by default\nSee https://momentjs.com/docs/#/displaying/format/ for valid formats"
|
||||||
},
|
},
|
||||||
"gitlens.gitExplorer.view": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "repository",
|
|
||||||
"enum": [
|
|
||||||
"history",
|
|
||||||
"repository"
|
|
||||||
],
|
|
||||||
"description": "Specifies the starting view (mode) of the `GitLens` custom view\n `history` - shows the commit history of the active file\n `repository` - shows a repository explorer"
|
|
||||||
},
|
|
||||||
"gitlens.gitExplorer.commitFormat": {
|
"gitlens.gitExplorer.commitFormat": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "${message} \u00a0\u2022\u00a0 ${authorAgo} \u00a0\u2022\u00a0 ${id}",
|
"default": "${message} \u00a0\u2022\u00a0 ${authorAgo} \u00a0\u2022\u00a0 ${id}",
|
||||||
@@ -432,6 +428,11 @@
|
|||||||
"default": "${filePath}",
|
"default": "${filePath}",
|
||||||
"description": "Specifies the format of a committed file in the `GitLens` custom view\nAvailable tokens\n ${file} - file name\n ${filePath} - file name and path\n ${path} - file path"
|
"description": "Specifies the format of a committed file in the `GitLens` custom view\nAvailable tokens\n ${file} - file name\n ${filePath} - file name and path\n ${path} - file path"
|
||||||
},
|
},
|
||||||
|
"gitlens.gitExplorer.showTrackingBranch": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Specifies whether or not to show the tracking branch when displaying local branches in the `GitLens` custom view"
|
||||||
|
},
|
||||||
"gitlens.gitExplorer.stashFormat": {
|
"gitlens.gitExplorer.stashFormat": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "${message}",
|
"default": "${message}",
|
||||||
@@ -442,6 +443,44 @@
|
|||||||
"default": "${filePath}",
|
"default": "${filePath}",
|
||||||
"description": "Specifies the format of a stashed file in the `GitLens` custom view\nAvailable tokens\n ${file} - file name\n ${filePath} - file name and path\n ${path} - file path"
|
"description": "Specifies the format of a stashed file in the `GitLens` custom view\nAvailable tokens\n ${file} - file name\n ${filePath} - file name and path\n ${path} - file path"
|
||||||
},
|
},
|
||||||
|
"gitlens.gitExplorer.view": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "repository",
|
||||||
|
"enum": [
|
||||||
|
"history",
|
||||||
|
"repository"
|
||||||
|
],
|
||||||
|
"description": "Specifies the starting view (mode) of the `GitLens` custom view\n `history` - shows the commit history of the active file\n `repository` - shows a repository explorer"
|
||||||
|
},
|
||||||
|
"gitlens.remotes": {
|
||||||
|
"type": "array",
|
||||||
|
"default": null,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"domain"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Bitbucket",
|
||||||
|
"BitbucketServer",
|
||||||
|
"GitHub",
|
||||||
|
"GitLab"
|
||||||
|
],
|
||||||
|
"description": "Specifies the type of the custom remote service\n `Bitbucket`, `BitbucketServer`, `GitHub`, or `GitLab`"
|
||||||
|
},
|
||||||
|
"domain": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Specifies the domain name of the custom remote service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueItems": true,
|
||||||
|
"description": "Specifies any custom domains for remote (code-hosting) services"
|
||||||
|
},
|
||||||
"gitlens.statusBar.enabled": {
|
"gitlens.statusBar.enabled": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true,
|
"default": true,
|
||||||
@@ -779,6 +818,11 @@
|
|||||||
"title": "Directory Compare",
|
"title": "Directory Compare",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.diffWith",
|
||||||
|
"title": "Compare File Revisions",
|
||||||
|
"category": "GitLens"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffWithBranch",
|
"command": "gitlens.diffWithBranch",
|
||||||
"title": "Compare File with Branch...",
|
"title": "Compare File with Branch...",
|
||||||
@@ -949,6 +993,11 @@
|
|||||||
"title": "Open Changed Files",
|
"title": "Open Changed Files",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openBranchesInRemote",
|
||||||
|
"title": "Open Branches in Remote",
|
||||||
|
"category": "GitLens"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openBranchInRemote",
|
"command": "gitlens.openBranchInRemote",
|
||||||
"title": "Open Branch in Remote",
|
"title": "Open Branch in Remote",
|
||||||
@@ -1050,10 +1099,25 @@
|
|||||||
"title": "Open Files",
|
"title": "Open Files",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.openChangedFileChanges",
|
||||||
|
"title": "Open All Changes",
|
||||||
|
"category": "GitLens"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.openChangedFileChangesWithWorking",
|
||||||
|
"title": "Open All Changes with Working Tree",
|
||||||
|
"category": "GitLens"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
||||||
"title": "Open Revisions",
|
"title": "Open Revisions",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.applyChanges",
|
||||||
|
"title": "Apply Changes",
|
||||||
|
"category": "GitLens"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
@@ -1062,6 +1126,10 @@
|
|||||||
"command": "gitlens.diffDirectory",
|
"command": "gitlens.diffDirectory",
|
||||||
"when": "gitlens:enabled"
|
"when": "gitlens:enabled"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.diffWith",
|
||||||
|
"when": "false"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffWithBranch",
|
"command": "gitlens.diffWithBranch",
|
||||||
"when": "gitlens:isTracked"
|
"when": "gitlens:isTracked"
|
||||||
@@ -1178,6 +1246,10 @@
|
|||||||
"command": "gitlens.openChangedFiles",
|
"command": "gitlens.openChangedFiles",
|
||||||
"when": "gitlens:enabled"
|
"when": "gitlens:enabled"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openBranchesInRemote",
|
||||||
|
"when": "gitlens:hasRemotes"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openBranchInRemote",
|
"command": "gitlens.openBranchInRemote",
|
||||||
"when": "gitlens:hasRemotes"
|
"when": "gitlens:hasRemotes"
|
||||||
@@ -1242,9 +1314,21 @@
|
|||||||
"command": "gitlens.gitExplorer.openChangedFiles",
|
"command": "gitlens.gitExplorer.openChangedFiles",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.openChangedFileChanges",
|
||||||
|
"when": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.openChangedFileChangesWithWorking",
|
||||||
|
"when": "false"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.applyChanges",
|
||||||
|
"when": "false"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"editor/context": [
|
"editor/context": [
|
||||||
@@ -1318,12 +1402,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openFileInRemote",
|
"command": "gitlens.openFileInRemote",
|
||||||
"when": "gitlens:enabled && config.gitlens.advanced.menus.editorTitleContext.remote",
|
"when": "gitlens:enabled && gitlens:hasRemotes && config.gitlens.advanced.menus.editorTitleContext.remote",
|
||||||
"group": "1_gitlens"
|
"group": "1_gitlens"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openRepoInRemote",
|
"command": "gitlens.openRepoInRemote",
|
||||||
"when": "gitlens:enabled && config.gitlens.advanced.menus.editorTitleContext.remote",
|
"when": "gitlens:enabled && gitlens:hasRemotes && config.gitlens.advanced.menus.editorTitleContext.remote",
|
||||||
"group": "1_gitlens"
|
"group": "1_gitlens"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1355,7 +1439,7 @@
|
|||||||
"editor/title/context": [
|
"editor/title/context": [
|
||||||
{
|
{
|
||||||
"command": "gitlens.openFileInRemote",
|
"command": "gitlens.openFileInRemote",
|
||||||
"when": "gitlens:enabled && config.gitlens.advanced.menus.editorTitleContext.remote",
|
"when": "gitlens:enabled && gitlens:hasRemotes && config.gitlens.advanced.menus.editorTitleContext.remote",
|
||||||
"group": "1_gitlens"
|
"group": "1_gitlens"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1382,7 +1466,7 @@
|
|||||||
"explorer/context": [
|
"explorer/context": [
|
||||||
{
|
{
|
||||||
"command": "gitlens.openFileInRemote",
|
"command": "gitlens.openFileInRemote",
|
||||||
"when": "gitlens:enabled && config.gitlens.advanced.menus.explorerContext.remote",
|
"when": "gitlens:enabled && gitlens:hasRemotes && config.gitlens.advanced.menus.explorerContext.remote",
|
||||||
"group": "navigation@100"
|
"group": "navigation@100"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1411,6 +1495,11 @@
|
|||||||
"command": "gitlens.closeUnchangedFiles",
|
"command": "gitlens.closeUnchangedFiles",
|
||||||
"when": "gitlens:enabled",
|
"when": "gitlens:enabled",
|
||||||
"group": "1_gitlens@2"
|
"group": "1_gitlens@2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.stashSave",
|
||||||
|
"when": "gitlens:enabled",
|
||||||
|
"group": "2_gitlens@1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scm/resourceState/context": [
|
"scm/resourceState/context": [
|
||||||
@@ -1428,160 +1517,235 @@
|
|||||||
"command": "gitlens.showQuickFileHistory",
|
"command": "gitlens.showQuickFileHistory",
|
||||||
"when": "gitlens:enabled",
|
"when": "gitlens:enabled",
|
||||||
"group": "1_gitlens_1@1"
|
"group": "1_gitlens_1@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.stashSave",
|
||||||
|
"when": "gitlens:enabled",
|
||||||
|
"group": "2_gitlens@1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"view/title": [
|
"view/title": [
|
||||||
{
|
{
|
||||||
"command": "gitlens.showCommitSearch",
|
"command": "gitlens.showCommitSearch",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer",
|
"when": "view == gitlens.gitExplorer",
|
||||||
"group": "navigation@1"
|
"group": "navigation@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.switchToHistoryView",
|
"command": "gitlens.gitExplorer.switchToHistoryView",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && gitlens:gitExplorer:view == repository",
|
"when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == repository",
|
||||||
"group": "navigation@2"
|
"group": "navigation@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.switchToRepositoryView",
|
"command": "gitlens.gitExplorer.switchToRepositoryView",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && gitlens:gitExplorer:view == history",
|
"when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == history",
|
||||||
"group": "navigation@3"
|
"group": "navigation@3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.refresh",
|
"command": "gitlens.gitExplorer.refresh",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer",
|
"when": "view == gitlens.gitExplorer",
|
||||||
"group": "navigation@4"
|
"group": "navigation@4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"view/item/context": [
|
"view/item/context": [
|
||||||
|
{
|
||||||
|
"command": "gitlens.openBranchesInRemote",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:branches:remote",
|
||||||
|
"group": "1_gitlens@1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openBranchInRemote",
|
"command": "gitlens.openBranchInRemote",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:branch-history",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:branch-history:remote",
|
||||||
"group": "1_gitlens@1"
|
"group": "1_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openCommitInRemote",
|
"command": "gitlens.openCommitInRemote",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
"group": "1_gitlens@1"
|
"group": "1_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.copyShaToClipboard",
|
"command": "gitlens.gitExplorer.openChangedFileChanges",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
"group": "2_gitlens@1"
|
"group": "2_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.copyMessageToClipboard",
|
"command": "gitlens.gitExplorer.openChangedFileChangesWithWorking",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
"group": "2_gitlens@2"
|
"group": "2_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangedFiles",
|
"command": "gitlens.gitExplorer.openChangedFiles",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
"group": "3_gitlens@1"
|
"group": "3_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
"group": "3_gitlens@2"
|
"group": "3_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.showQuickCommitDetails",
|
"command": "gitlens.copyShaToClipboard",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
"group": "4_gitlens@1"
|
"group": "4_gitlens@1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.copyMessageToClipboard",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
|
"group": "4_gitlens@2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.showQuickCommitDetails",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
|
||||||
|
"group": "5_gitlens@1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChanges",
|
"command": "gitlens.gitExplorer.openChanges",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "1_gitlens@1"
|
"group": "1_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangesWithWorking",
|
"command": "gitlens.gitExplorer.openChangesWithWorking",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "1_gitlens@2"
|
"group": "1_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openFile",
|
"command": "gitlens.gitExplorer.openFile",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "2_gitlens@1"
|
"group": "2_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openFileRevision",
|
"command": "gitlens.gitExplorer.openFileRevision",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "2_gitlens@2"
|
"group": "2_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openFileInRemote",
|
"command": "gitlens.openFileInRemote",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "3_gitlens@1"
|
"group": "3_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openFileRevisionInRemote",
|
"command": "gitlens.gitExplorer.openFileRevisionInRemote",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "3_gitlens@2"
|
"group": "3_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.showQuickFileHistory",
|
"command": "gitlens.gitExplorer.applyChanges",
|
||||||
"when": "gitlens:isTracked && view == gitlens.gitExplorer && viewItem == gitlens:commit-file && gitlens:gitExplorer:view == repository",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "4_gitlens@1"
|
"group": "4_gitlens@1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.showQuickFileHistory",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file && gitlens:gitExplorer:view == repository",
|
||||||
|
"group": "5_gitlens@1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.showQuickCommitFileDetails",
|
"command": "gitlens.showQuickCommitFileDetails",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
|
||||||
"group": "4_gitlens@2"
|
"group": "5_gitlens@2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.openFile",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:file-history",
|
||||||
|
"group": "1_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openFileInRemote",
|
||||||
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:file-history",
|
||||||
|
"group": "1_gitlens@2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openBranchesInRemote",
|
||||||
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:remote",
|
||||||
|
"group": "1_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openRepoInRemote",
|
||||||
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:remote",
|
||||||
|
"group": "1_gitlens@2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.stashSave",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stashes",
|
||||||
|
"group": "1_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.stashApply",
|
"command": "gitlens.stashApply",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
"group": "1_gitlens@1"
|
"group": "1_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.stashDelete",
|
"command": "gitlens.stashDelete",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
"group": "1_gitlens@2"
|
"group": "1_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.copyMessageToClipboard",
|
"command": "gitlens.gitExplorer.openChangedFileChanges",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
|
"group": "2_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.openChangedFileChangesWithWorking",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
"group": "2_gitlens@1"
|
"group": "2_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangedFiles",
|
"command": "gitlens.gitExplorer.openChangedFiles",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
"group": "3_gitlens@1"
|
"group": "3_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
"command": "gitlens.gitExplorer.openChangedFileRevisions",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
"group": "3_gitlens@2"
|
"group": "3_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChanges",
|
"command": "gitlens.copyMessageToClipboard",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
|
||||||
|
"group": "4_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.applyChanges",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
"group": "1_gitlens@1"
|
"group": "1_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openChangesWithWorking",
|
"command": "gitlens.gitExplorer.openChanges",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
"group": "1_gitlens@2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "gitlens.gitExplorer.openFile",
|
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
|
||||||
"group": "2_gitlens@1"
|
"group": "2_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.gitExplorer.openFileRevision",
|
"command": "gitlens.gitExplorer.openChangesWithWorking",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
"group": "2_gitlens@2"
|
"group": "2_gitlens@2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.openFileInRemote",
|
"command": "gitlens.gitExplorer.openFile",
|
||||||
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
"group": "3_gitlens@1"
|
"group": "3_gitlens@1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.showQuickFileHistory",
|
"command": "gitlens.gitExplorer.openFileRevision",
|
||||||
"when": "gitlens:isTracked && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
|
"group": "3_gitlens@2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openFileInRemote",
|
||||||
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
"group": "4_gitlens@1"
|
"group": "4_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.showQuickFileHistory",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
|
||||||
|
"group": "5_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.openRepoInRemote",
|
||||||
|
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:status",
|
||||||
|
"group": "1_gitlens@1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.gitExplorer.refresh",
|
||||||
|
"when": "view == gitlens.gitExplorer && viewItem != gitlens:commit-file && viewItem != gitlens:stash-file",
|
||||||
|
"group": "9_gitlens@1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -1704,8 +1868,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"applicationinsights": "0.21.0",
|
"applicationinsights": "0.21.0",
|
||||||
"copy-paste": "1.3.0",
|
"copy-paste": "1.3.0",
|
||||||
"iconv-lite": "0.4.18",
|
"iconv-lite": "0.4.19",
|
||||||
"ignore": "3.3.4",
|
"ignore": "3.3.5",
|
||||||
"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",
|
||||||
@@ -1718,12 +1882,12 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/copy-paste": "1.1.30",
|
"@types/copy-paste": "1.1.30",
|
||||||
"@types/iconv-lite": "0.0.1",
|
"@types/iconv-lite": "0.0.1",
|
||||||
"@types/mocha": "2.2.42",
|
"@types/mocha": "2.2.43",
|
||||||
"@types/node": "8.0.25",
|
"@types/node": "8.0.28",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"mocha": "3.5.0",
|
"mocha": "3.5.2",
|
||||||
"tslint": "5.7.0",
|
"tslint": "5.7.0",
|
||||||
"typescript": "2.4.2",
|
"typescript": "2.5.2",
|
||||||
"vscode": "1.1.5"
|
"vscode": "1.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Strings } from '../system';
|
import { Strings } from '../system';
|
||||||
import { DecorationInstanceRenderOptions, DecorationOptions, ThemableDecorationRenderOptions } from 'vscode';
|
import { DecorationInstanceRenderOptions, DecorationOptions, MarkdownString, ThemableDecorationRenderOptions } from 'vscode';
|
||||||
|
import { DiffWithCommand, ShowQuickCommitDetailsCommand } from '../commands';
|
||||||
import { IThemeConfig, themeDefaults } from '../configuration';
|
import { IThemeConfig, themeDefaults } from '../configuration';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
import { CommitFormatter, GitCommit, GitDiffChunkLine, GitService, GitUri, ICommitFormatOptions } from '../gitService';
|
import { CommitFormatter, GitCommit, GitDiffChunkLine, GitService, GitUri, ICommitFormatOptions } from '../gitService';
|
||||||
@@ -47,7 +48,7 @@ export class Annotations {
|
|||||||
return '#793738';
|
return '#793738';
|
||||||
}
|
}
|
||||||
|
|
||||||
static getHoverMessage(commit: GitCommit, dateFormat: string | null): string | string[] {
|
static getHoverMessage(commit: GitCommit, dateFormat: string | null): MarkdownString {
|
||||||
if (dateFormat === null) {
|
if (dateFormat === null) {
|
||||||
dateFormat = 'MMMM Do, YYYY h:MMa';
|
dateFormat = 'MMMM Do, YYYY h:MMa';
|
||||||
}
|
}
|
||||||
@@ -63,16 +64,21 @@ export class Annotations {
|
|||||||
.replace(/\n/g, ' \n');
|
.replace(/\n/g, ' \n');
|
||||||
message = `\n\n> ${message}`;
|
message = `\n\n> ${message}`;
|
||||||
}
|
}
|
||||||
return `\`${commit.shortSha}\` __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format(dateFormat)})_${message}`;
|
|
||||||
|
const markdown = new MarkdownString(`[\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.sha)}) __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format(dateFormat)})_${message}`);
|
||||||
|
markdown.isTrusted = true;
|
||||||
|
return markdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getHoverDiffMessage(commit: GitCommit, chunkLine: GitDiffChunkLine | undefined): string | undefined {
|
static getHoverDiffMessage(commit: GitCommit, chunkLine: GitDiffChunkLine | undefined): MarkdownString | undefined {
|
||||||
if (chunkLine === undefined) return undefined;
|
if (chunkLine === undefined) return undefined;
|
||||||
|
|
||||||
const codeDiff = this._getCodeDiff(chunkLine);
|
const codeDiff = this._getCodeDiff(chunkLine);
|
||||||
return commit.isUncommitted
|
const markdown = new MarkdownString(commit.isUncommitted
|
||||||
? `\`Changes\` ${GlyphChars.Dash} _uncommitted_\n${codeDiff}`
|
? `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit)}) ${GlyphChars.Dash} _uncommitted_\n${codeDiff}`
|
||||||
: `\`Changes\` ${GlyphChars.Dash} \`${commit.previousShortSha}\` ${GlyphChars.ArrowLeftRight} \`${commit.shortSha}\`\n${codeDiff}`;
|
: `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit)}) ${GlyphChars.Dash} [\`${commit.previousShortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.previousSha!)}) ${GlyphChars.ArrowLeftRight} [\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.sha)})\n${codeDiff}`);
|
||||||
|
markdown.isTrusted = true;
|
||||||
|
return markdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _getCodeDiff(chunkLine: GitDiffChunkLine): string {
|
private static _getCodeDiff(chunkLine: GitDiffChunkLine): string {
|
||||||
@@ -181,7 +187,10 @@ export class Annotations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static trailing(commit: GitCommit, format: string, dateFormat: string | null, cfgTheme: IThemeConfig): DecorationOptions {
|
static trailing(commit: GitCommit, format: string, dateFormat: string | null, cfgTheme: IThemeConfig): DecorationOptions {
|
||||||
const message = CommitFormatter.fromTemplate(format, commit, dateFormat);
|
const message = CommitFormatter.fromTemplate(format, commit, {
|
||||||
|
truncateMessageAtNewLine: true,
|
||||||
|
dateFormat: dateFormat
|
||||||
|
} as ICommitFormatOptions);
|
||||||
return {
|
return {
|
||||||
renderOptions: {
|
renderOptions: {
|
||||||
after: {
|
after: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { DecorationOptions, ExtensionContext, Position, Range, TextEditor, TextEditorDecorationType } from 'vscode';
|
import { DecorationOptions, ExtensionContext, MarkdownString, Position, Range, TextEditor, TextEditorDecorationType } from 'vscode';
|
||||||
import { Annotations, endOfLineIndex } from './annotations';
|
import { Annotations, endOfLineIndex } from './annotations';
|
||||||
import { FileAnnotationType } from './annotationController';
|
import { FileAnnotationType } from './annotationController';
|
||||||
import { AnnotationProviderBase } from './annotationProvider';
|
import { AnnotationProviderBase } from './annotationProvider';
|
||||||
@@ -48,7 +48,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
|
|||||||
} as DecorationOptions);
|
} as DecorationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
let message: string | undefined = undefined;
|
let message: MarkdownString | undefined = undefined;
|
||||||
if (cfg.hover.changes) {
|
if (cfg.hover.changes) {
|
||||||
message = Annotations.getHoverDiffMessage(commit, line);
|
message = Annotations.getHoverDiffMessage(commit, line);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ export * from './commands/copyShaToClipboard';
|
|||||||
export * from './commands/diffDirectory';
|
export * from './commands/diffDirectory';
|
||||||
export * from './commands/diffLineWithPrevious';
|
export * from './commands/diffLineWithPrevious';
|
||||||
export * from './commands/diffLineWithWorking';
|
export * from './commands/diffLineWithWorking';
|
||||||
|
export * from './commands/diffWith';
|
||||||
export * from './commands/diffWithBranch';
|
export * from './commands/diffWithBranch';
|
||||||
export * from './commands/diffWithNext';
|
export * from './commands/diffWithNext';
|
||||||
export * from './commands/diffWithPrevious';
|
export * from './commands/diffWithPrevious';
|
||||||
export * from './commands/diffWithRevision';
|
export * from './commands/diffWithRevision';
|
||||||
export * from './commands/diffWithWorking';
|
export * from './commands/diffWithWorking';
|
||||||
export * from './commands/openChangedFiles';
|
export * from './commands/openChangedFiles';
|
||||||
|
export * from './commands/openBranchesInRemote';
|
||||||
export * from './commands/openBranchInRemote';
|
export * from './commands/openBranchInRemote';
|
||||||
export * from './commands/openCommitInRemote';
|
export * from './commands/openCommitInRemote';
|
||||||
export * from './commands/openFileInRemote';
|
export * from './commands/openFileInRemote';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Disposable, SourceControlResourceGroup, SourceControlResourceState, TextDocumentShowOptions, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
import { commands, Disposable, SourceControlResourceGroup, SourceControlResourceState, TextDocumentShowOptions, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
||||||
import { ExplorerNode } from '../views/explorerNodes';
|
import { ExplorerNode } from '../views/explorerNodes';
|
||||||
import { GitBranch, GitCommit } from '../gitService';
|
import { GitBranch, GitCommit, GitRemote } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Telemetry } from '../telemetry';
|
import { Telemetry } from '../telemetry';
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ export type Commands =
|
|||||||
'gitlens.copyMessageToClipboard' |
|
'gitlens.copyMessageToClipboard' |
|
||||||
'gitlens.copyShaToClipboard' |
|
'gitlens.copyShaToClipboard' |
|
||||||
'gitlens.diffDirectory' |
|
'gitlens.diffDirectory' |
|
||||||
|
'gitlens.diffWith' |
|
||||||
'gitlens.diffWithBranch' |
|
'gitlens.diffWithBranch' |
|
||||||
'gitlens.diffWithNext' |
|
'gitlens.diffWithNext' |
|
||||||
'gitlens.diffWithPrevious' |
|
'gitlens.diffWithPrevious' |
|
||||||
@@ -19,6 +20,7 @@ export type Commands =
|
|||||||
'gitlens.diffWithWorking' |
|
'gitlens.diffWithWorking' |
|
||||||
'gitlens.diffLineWithWorking' |
|
'gitlens.diffLineWithWorking' |
|
||||||
'gitlens.openChangedFiles' |
|
'gitlens.openChangedFiles' |
|
||||||
|
'gitlens.openBranchesInRemote' |
|
||||||
'gitlens.openBranchInRemote' |
|
'gitlens.openBranchInRemote' |
|
||||||
'gitlens.openCommitInRemote' |
|
'gitlens.openCommitInRemote' |
|
||||||
'gitlens.openFileInRemote' |
|
'gitlens.openFileInRemote' |
|
||||||
@@ -51,6 +53,7 @@ export const Commands = {
|
|||||||
CopyMessageToClipboard: 'gitlens.copyMessageToClipboard' as Commands,
|
CopyMessageToClipboard: 'gitlens.copyMessageToClipboard' as Commands,
|
||||||
CopyShaToClipboard: 'gitlens.copyShaToClipboard' as Commands,
|
CopyShaToClipboard: 'gitlens.copyShaToClipboard' as Commands,
|
||||||
DiffDirectory: 'gitlens.diffDirectory' as Commands,
|
DiffDirectory: 'gitlens.diffDirectory' as Commands,
|
||||||
|
DiffWith: 'gitlens.diffWith' as Commands,
|
||||||
DiffWithBranch: 'gitlens.diffWithBranch' as Commands,
|
DiffWithBranch: 'gitlens.diffWithBranch' as Commands,
|
||||||
DiffWithNext: 'gitlens.diffWithNext' as Commands,
|
DiffWithNext: 'gitlens.diffWithNext' as Commands,
|
||||||
DiffWithPrevious: 'gitlens.diffWithPrevious' as Commands,
|
DiffWithPrevious: 'gitlens.diffWithPrevious' as Commands,
|
||||||
@@ -59,6 +62,7 @@ export const Commands = {
|
|||||||
DiffWithWorking: 'gitlens.diffWithWorking' as Commands,
|
DiffWithWorking: 'gitlens.diffWithWorking' as Commands,
|
||||||
DiffLineWithWorking: 'gitlens.diffLineWithWorking' as Commands,
|
DiffLineWithWorking: 'gitlens.diffLineWithWorking' as Commands,
|
||||||
OpenChangedFiles: 'gitlens.openChangedFiles' as Commands,
|
OpenChangedFiles: 'gitlens.openChangedFiles' as Commands,
|
||||||
|
OpenBranchesInRemote: 'gitlens.openBranchesInRemote' as Commands,
|
||||||
OpenBranchInRemote: 'gitlens.openBranchInRemote' as Commands,
|
OpenBranchInRemote: 'gitlens.openBranchInRemote' as Commands,
|
||||||
OpenCommitInRemote: 'gitlens.openCommitInRemote' as Commands,
|
OpenCommitInRemote: 'gitlens.openCommitInRemote' as Commands,
|
||||||
OpenFileInRemote: 'gitlens.openFileInRemote' as Commands,
|
OpenFileInRemote: 'gitlens.openFileInRemote' as Commands,
|
||||||
@@ -138,6 +142,10 @@ export function isCommandViewContextWithCommit<T extends GitCommit>(context: Com
|
|||||||
return context.type === 'view' && (context.node as any).commit && (context.node as any).commit instanceof GitCommit;
|
return context.type === 'view' && (context.node as any).commit && (context.node as any).commit instanceof GitCommit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isCommandViewContextWithRemote(context: CommandContext): context is CommandViewContext & { node: (ExplorerNode & { remote: GitRemote }) } {
|
||||||
|
return context.type === 'view' && (context.node as any).remote && (context.node as any).remote instanceof GitRemote;
|
||||||
|
}
|
||||||
|
|
||||||
export type CommandContext = CommandScmGroupsContext | CommandScmStatesContext | CommandUnknownContext | CommandUriContext | CommandViewContext;
|
export type CommandContext = CommandScmGroupsContext | CommandScmStatesContext | CommandUnknownContext | CommandUriContext | CommandViewContext;
|
||||||
|
|
||||||
function isScmResourceGroup(group: any): group is SourceControlResourceGroup {
|
function isScmResourceGroup(group: any): group is SourceControlResourceGroup {
|
||||||
@@ -160,6 +168,10 @@ function isTextEditor(editor: any): editor is TextEditor {
|
|||||||
|
|
||||||
export abstract class Command extends Disposable {
|
export abstract class Command extends Disposable {
|
||||||
|
|
||||||
|
static getMarkdownCommandArgsCore<T>(command: Commands, args: T): string {
|
||||||
|
return `command:${command}?${encodeURIComponent(JSON.stringify(args))}`;
|
||||||
|
}
|
||||||
|
|
||||||
protected readonly contextParsingOptions: CommandContextParsingOptions = { editor: false, uri: false };
|
protected readonly contextParsingOptions: CommandContextParsingOptions = { editor: false, uri: false };
|
||||||
|
|
||||||
private _disposable: Disposable;
|
private _disposable: Disposable;
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { BuiltInCommands, GlyphChars } from '../constants';
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { DiffWithPreviousCommandArgs } from './diffWithPrevious';
|
|
||||||
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
|
|
||||||
import { GitCommit, GitService, GitUri } from '../gitService';
|
import { GitCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export interface DiffLineWithPreviousCommandArgs {
|
export interface DiffLineWithPreviousCommandArgs {
|
||||||
commit?: GitCommit;
|
commit?: GitCommit;
|
||||||
|
|
||||||
line?: number;
|
line?: number;
|
||||||
showOptions?: TextDocumentShowOptions;
|
showOptions?: TextDocumentShowOptions;
|
||||||
}
|
}
|
||||||
@@ -43,56 +41,26 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
|
|
||||||
args.commit = blame.commit;
|
args.commit = blame.commit;
|
||||||
|
|
||||||
// If we don't have a sha or the current commit matches the blame, show the previous
|
|
||||||
if (gitUri.sha === undefined || gitUri.sha === args.commit.sha) {
|
|
||||||
return commands.executeCommand(Commands.DiffWithPrevious, new GitUri(uri, args.commit), {
|
|
||||||
line: args.line,
|
|
||||||
showOptions: args.showOptions
|
|
||||||
} as DiffWithPreviousCommandArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the line is uncommitted, find the previous commit and treat it as a DiffWithWorking
|
|
||||||
if (args.commit.isUncommitted) {
|
|
||||||
uri = args.commit.uri;
|
|
||||||
args.commit = new GitCommit(args.commit.type, args.commit.repoPath, args.commit.previousSha!, args.commit.previousFileName!, args.commit.author, args.commit.date, args.commit.message);
|
|
||||||
args.line = (blame.line.line + 1) + gitUri.offset;
|
|
||||||
|
|
||||||
return commands.executeCommand(Commands.DiffWithWorking, uri, {
|
|
||||||
commit: args.commit,
|
|
||||||
line: args.line,
|
|
||||||
showOptions: args.showOptions
|
|
||||||
} as DiffWithWorkingCommandArgs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
Logger.error(ex, 'DiffWithPreviousLineCommand', `getBlameForLine(${blameline})`);
|
Logger.error(ex, 'DiffLineWithPreviousCommand', `getBlameForLine(${blameline})`);
|
||||||
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
const [rhs, lhs] = await Promise.all([
|
repoPath: args.commit.repoPath,
|
||||||
this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha!),
|
lhs: {
|
||||||
this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha)
|
sha: args.commit.previousSha !== undefined ? args.commit.previousSha : GitService.fakeSha,
|
||||||
]);
|
uri: args.commit.previousUri
|
||||||
|
},
|
||||||
if (args.line !== undefined && args.line !== 0) {
|
rhs: {
|
||||||
if (args.showOptions === undefined) {
|
sha: args.commit.sha,
|
||||||
args.showOptions = {};
|
uri: args.commit.uri
|
||||||
}
|
},
|
||||||
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
line: args.line,
|
||||||
}
|
showOptions: args.showOptions
|
||||||
|
};
|
||||||
await commands.executeCommand(BuiltInCommands.Diff,
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
Uri.file(lhs),
|
|
||||||
Uri.file(rhs),
|
|
||||||
`${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha}) ${GlyphChars.ArrowLeftRight} ${path.basename(gitUri.fsPath)} (${gitUri.shortSha})`,
|
|
||||||
args.showOptions);
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
Logger.error(ex, 'DiffWithPreviousLineCommand', 'getVersionedFile');
|
|
||||||
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { GitCommit, GitService, GitUri } from '../gitService';
|
import { GitCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
|
||||||
export interface DiffLineWithWorkingCommandArgs {
|
export interface DiffLineWithWorkingCommandArgs {
|
||||||
commit?: GitCommit;
|
commit?: GitCommit;
|
||||||
|
|
||||||
line?: number;
|
line?: number;
|
||||||
showOptions?: TextDocumentShowOptions;
|
showOptions?: TextDocumentShowOptions;
|
||||||
}
|
}
|
||||||
@@ -52,6 +53,19 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return commands.executeCommand(Commands.DiffWithWorking, uri, args as DiffWithWorkingCommandArgs);
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
|
repoPath: args.commit.repoPath,
|
||||||
|
lhs: {
|
||||||
|
sha: args.commit.sha,
|
||||||
|
uri: args.commit.uri
|
||||||
|
},
|
||||||
|
rhs: {
|
||||||
|
sha: '',
|
||||||
|
uri: args.commit.uri
|
||||||
|
},
|
||||||
|
line: args.line,
|
||||||
|
showOptions: args.showOptions
|
||||||
|
};
|
||||||
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
142
src/commands/diffWith.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
'use strict';
|
||||||
|
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
|
import { ActiveEditorCommand, Commands } from './common';
|
||||||
|
import { BuiltInCommands, GlyphChars } from '../constants';
|
||||||
|
import { GitCommit, GitService } from '../gitService';
|
||||||
|
import { Logger } from '../logger';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
export interface DiffWithCommandArgsRevision {
|
||||||
|
sha: string;
|
||||||
|
uri: Uri;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffWithCommandArgs {
|
||||||
|
lhs?: DiffWithCommandArgsRevision;
|
||||||
|
rhs?: DiffWithCommandArgsRevision;
|
||||||
|
repoPath?: string;
|
||||||
|
|
||||||
|
line?: number;
|
||||||
|
showOptions?: TextDocumentShowOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DiffWithCommand extends ActiveEditorCommand {
|
||||||
|
|
||||||
|
static getMarkdownCommandArgs(args: DiffWithCommandArgs): string;
|
||||||
|
static getMarkdownCommandArgs(commit1: GitCommit, commit2: GitCommit): string;
|
||||||
|
static getMarkdownCommandArgs(argsOrCommit1: DiffWithCommandArgs | GitCommit, commit2?: GitCommit): string {
|
||||||
|
let args = argsOrCommit1;
|
||||||
|
if (argsOrCommit1 instanceof GitCommit) {
|
||||||
|
const commit1 = argsOrCommit1;
|
||||||
|
|
||||||
|
if (commit2 === undefined) {
|
||||||
|
if (commit1.isUncommitted) {
|
||||||
|
args = {
|
||||||
|
repoPath: commit1.repoPath,
|
||||||
|
lhs: {
|
||||||
|
sha: 'HEAD',
|
||||||
|
uri: commit1.uri
|
||||||
|
},
|
||||||
|
rhs: {
|
||||||
|
sha: '',
|
||||||
|
uri: commit1.uri
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args = {
|
||||||
|
repoPath: commit1.repoPath,
|
||||||
|
lhs: {
|
||||||
|
sha: commit1.previousSha!,
|
||||||
|
uri: commit1.previousUri!
|
||||||
|
},
|
||||||
|
rhs: {
|
||||||
|
sha: commit1.sha,
|
||||||
|
uri: commit1.uri
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args = {
|
||||||
|
repoPath: commit1.repoPath,
|
||||||
|
lhs: {
|
||||||
|
sha: commit1.sha,
|
||||||
|
uri: commit1.uri
|
||||||
|
},
|
||||||
|
rhs: {
|
||||||
|
sha: commit2.sha,
|
||||||
|
uri: commit2.uri
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getMarkdownCommandArgsCore<DiffWithCommandArgs>(Commands.DiffWith, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private git: GitService) {
|
||||||
|
super(Commands.DiffWith);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithCommandArgs = {}): Promise<any> {
|
||||||
|
args = { ...args };
|
||||||
|
if (args.repoPath === undefined || args.lhs === undefined || args.rhs === undefined) return undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [lhs, rhs] = await Promise.all([
|
||||||
|
args.lhs.sha !== '' && !GitService.isUncommitted(args.lhs.sha)
|
||||||
|
? this.git.getVersionedFile(args.repoPath, args.lhs.uri.fsPath, args.lhs.sha)
|
||||||
|
: args.lhs.uri.fsPath,
|
||||||
|
args.rhs.sha !== '' && !GitService.isUncommitted(args.rhs.sha)
|
||||||
|
? this.git.getVersionedFile(args.repoPath, args.rhs.uri.fsPath, args.rhs.sha)
|
||||||
|
: args.rhs.uri.fsPath
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (args.line !== undefined && args.line !== 0) {
|
||||||
|
if (args.showOptions === undefined) {
|
||||||
|
args.showOptions = {};
|
||||||
|
}
|
||||||
|
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rhsPrefix = '';
|
||||||
|
if (rhs === undefined) {
|
||||||
|
rhsPrefix = 'deleted in ';
|
||||||
|
}
|
||||||
|
else if (lhs === undefined || args.lhs.sha === GitService.fakeSha) {
|
||||||
|
rhsPrefix = 'added in ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.lhs.title === undefined && lhs !== undefined && args.lhs.sha !== GitService.fakeSha) {
|
||||||
|
args.lhs.title = (args.lhs.sha === '' || GitService.isUncommitted(args.lhs.sha))
|
||||||
|
? `${path.basename(args.lhs.uri.fsPath)}`
|
||||||
|
: `${path.basename(args.lhs.uri.fsPath)} (${GitService.shortenSha(args.lhs.sha)})`;
|
||||||
|
}
|
||||||
|
if (args.rhs.title === undefined && args.rhs.sha !== GitService.fakeSha) {
|
||||||
|
args.rhs.title = (args.rhs.sha === '' || GitService.isUncommitted(args.rhs.sha))
|
||||||
|
? `${path.basename(args.rhs.uri.fsPath)}`
|
||||||
|
: `${path.basename(args.rhs.uri.fsPath)} (${rhsPrefix}${GitService.shortenSha(args.rhs.sha)})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = (args.lhs.title !== undefined && args.rhs.title !== undefined)
|
||||||
|
? `${args.lhs.title} ${GlyphChars.ArrowLeftRight} ${args.rhs.title}`
|
||||||
|
: args.lhs.title || args.rhs.title;
|
||||||
|
|
||||||
|
return await commands.executeCommand(BuiltInCommands.Diff,
|
||||||
|
lhs === undefined
|
||||||
|
? GitService.toGitContentUri(GitService.fakeSha, args.lhs.uri.fsPath, args.repoPath)
|
||||||
|
: Uri.file(lhs),
|
||||||
|
rhs === undefined
|
||||||
|
? GitService.toGitContentUri(GitService.fakeSha, args.rhs.uri.fsPath, args.repoPath)
|
||||||
|
: Uri.file(rhs),
|
||||||
|
title,
|
||||||
|
args.showOptions);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
Logger.error(ex, 'DiffWithCommand', 'getVersionedFile');
|
||||||
|
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { BuiltInCommands, GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@@ -42,25 +42,20 @@ export class DiffWithBranchCommand extends ActiveEditorCommand {
|
|||||||
const branch = pick.branch.name;
|
const branch = pick.branch.name;
|
||||||
if (branch === undefined) return undefined;
|
if (branch === undefined) return undefined;
|
||||||
|
|
||||||
try {
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
const compare = await this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, branch);
|
repoPath: gitUri.repoPath,
|
||||||
|
lhs: {
|
||||||
if (args.line !== undefined && args.line !== 0) {
|
sha: pick.branch.remote ? `remotes/${branch}` : branch,
|
||||||
if (args.showOptions === undefined) {
|
uri: gitUri as Uri,
|
||||||
args.showOptions = {};
|
title: `${path.basename(gitUri.fsPath)} (${branch})`
|
||||||
}
|
},
|
||||||
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
rhs: {
|
||||||
}
|
sha: '',
|
||||||
|
uri: gitUri as Uri
|
||||||
await commands.executeCommand(BuiltInCommands.Diff,
|
},
|
||||||
Uri.file(compare),
|
line: args.line,
|
||||||
gitUri.fileUri(),
|
showOptions: args.showOptions
|
||||||
`${path.basename(gitUri.fsPath)} (${branch}) ${GlyphChars.ArrowLeftRight} ${path.basename(gitUri.fsPath)}`,
|
};
|
||||||
args.showOptions);
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
Logger.error(ex, 'DiffWithBranchCommand', 'getVersionedFile');
|
|
||||||
return window.showErrorMessage(`Unable to open branch compare. See output channel for more details`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,16 +2,16 @@
|
|||||||
import { Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { BuiltInCommands, GlyphChars } from '../constants';
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { GitLogCommit, GitService, GitUri } from '../gitService';
|
import { GitLogCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export interface DiffWithNextCommandArgs {
|
export interface DiffWithNextCommandArgs {
|
||||||
commit?: GitLogCommit;
|
commit?: GitLogCommit;
|
||||||
line?: number;
|
|
||||||
range?: Range;
|
range?: Range;
|
||||||
|
|
||||||
|
line?: number;
|
||||||
showOptions?: TextDocumentShowOptions;
|
showOptions?: TextDocumentShowOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,28 +54,19 @@ export class DiffWithNextCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
if (args.commit.nextSha === undefined) return commands.executeCommand(Commands.DiffWithWorking, uri);
|
if (args.commit.nextSha === undefined) return commands.executeCommand(Commands.DiffWithWorking, uri);
|
||||||
|
|
||||||
try {
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
const [rhs, lhs] = await Promise.all([
|
repoPath: args.commit.repoPath,
|
||||||
this.git.getVersionedFile(args.commit.repoPath, args.commit.nextUri.fsPath, args.commit.nextSha),
|
lhs: {
|
||||||
this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha)
|
sha: args.commit.sha,
|
||||||
]);
|
uri: args.commit.uri
|
||||||
|
},
|
||||||
if (args.line !== undefined && args.line !== 0) {
|
rhs: {
|
||||||
if (args.showOptions === undefined) {
|
sha: args.commit.nextSha,
|
||||||
args.showOptions = {};
|
uri: args.commit.nextUri
|
||||||
}
|
},
|
||||||
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
line: args.line,
|
||||||
}
|
showOptions: args.showOptions
|
||||||
|
};
|
||||||
await commands.executeCommand(BuiltInCommands.Diff,
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
Uri.file(lhs),
|
|
||||||
Uri.file(rhs),
|
|
||||||
`${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha}) ${GlyphChars.ArrowLeftRight} ${path.basename(args.commit.nextUri.fsPath)} (${args.commit.nextShortSha})`,
|
|
||||||
args.showOptions);
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
Logger.error(ex, 'DiffWithNextCommand', 'getVersionedFile');
|
|
||||||
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,22 +2,18 @@
|
|||||||
import { Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { BuiltInCommands, FakeSha, GlyphChars } from '../constants';
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
|
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
|
||||||
import { GitCommit, GitService, GitUri } from '../gitService';
|
import { GitCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export interface DiffWithPreviousCommandArgs {
|
export interface DiffWithPreviousCommandArgs {
|
||||||
commit?: GitCommit;
|
commit?: GitCommit;
|
||||||
line?: number;
|
|
||||||
range?: Range;
|
range?: Range;
|
||||||
showOptions?: TextDocumentShowOptions;
|
|
||||||
|
|
||||||
allowMissingPrevious?: boolean;
|
line?: number;
|
||||||
leftTitlePrefix?: string;
|
showOptions?: TextDocumentShowOptions;
|
||||||
rightTitlePrefix?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
||||||
@@ -40,6 +36,7 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
|
const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
|
||||||
|
if (sha === GitService.fakeSha) return Messages.showCommitHasNoPreviousCommitWarningMessage();
|
||||||
|
|
||||||
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, sha, { maxCount: 2, range: args.range!, skipMerges: true });
|
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, sha, { maxCount: 2, range: args.range!, skipMerges: true });
|
||||||
if (log === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
if (log === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
@@ -47,7 +44,9 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
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 and the file is uncommitted, then treat it as a DiffWithWorking
|
// If the sha is missing and the file is uncommitted, then treat it as a DiffWithWorking
|
||||||
if (gitUri.sha === undefined && await this.git.isFileUncommitted(gitUri)) return commands.executeCommand(Commands.DiffWithWorking, uri, { commit: args.commit, showOptions: args.showOptions } as DiffWithWorkingCommandArgs);
|
if (gitUri.sha === undefined && await this.git.isFileUncommitted(gitUri)) {
|
||||||
|
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})`);
|
||||||
@@ -55,32 +54,19 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.commit.previousSha === undefined && !args.allowMissingPrevious) return Messages.showCommitHasNoPreviousCommitWarningMessage(args.commit);
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
|
repoPath: args.commit.repoPath,
|
||||||
try {
|
lhs: {
|
||||||
const [rhs, lhs] = await Promise.all([
|
sha: args.commit.previousSha !== undefined ? args.commit.previousSha : GitService.fakeSha,
|
||||||
this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha),
|
uri: args.commit.previousUri
|
||||||
this.git.getVersionedFile(args.commit.repoPath, args.commit.previousUri.fsPath, args.commit.previousSha === undefined ? FakeSha : args.commit.previousSha)
|
},
|
||||||
]);
|
rhs: {
|
||||||
|
sha: args.commit.sha,
|
||||||
if (args.line !== undefined && args.line !== 0) {
|
uri: args.commit.uri
|
||||||
if (args.showOptions === undefined) {
|
},
|
||||||
args.showOptions = {};
|
line: args.line,
|
||||||
}
|
showOptions: args.showOptions
|
||||||
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
};
|
||||||
}
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
|
|
||||||
await commands.executeCommand(BuiltInCommands.Diff,
|
|
||||||
Uri.file(lhs),
|
|
||||||
Uri.file(rhs),
|
|
||||||
args.commit.previousShortSha === undefined
|
|
||||||
? `${path.basename(args.commit.uri.fsPath)} (${args.rightTitlePrefix || ''}${args.commit.shortSha})`
|
|
||||||
: `${path.basename(args.commit.previousUri.fsPath)} (${args.leftTitlePrefix || ''}${args.commit.previousShortSha}) ${GlyphChars.ArrowLeftRight} ${path.basename(args.commit.uri.fsPath)} (${args.rightTitlePrefix || ''}${args.commit.shortSha})`,
|
|
||||||
args.showOptions);
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
Logger.error(ex, 'DiffWithPreviousCommand', 'getVersionedFile');
|
|
||||||
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { BuiltInCommands, GlyphChars } from '../constants';
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks';
|
import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks';
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export interface DiffWithRevisionCommandArgs {
|
export interface DiffWithRevisionCommandArgs {
|
||||||
line?: number;
|
|
||||||
maxCount?: number;
|
maxCount?: number;
|
||||||
|
|
||||||
|
line?: number;
|
||||||
showOptions?: TextDocumentShowOptions;
|
showOptions?: TextDocumentShowOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,24 +46,24 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
if (pick instanceof CommandQuickPickItem) return pick.execute();
|
if (pick instanceof CommandQuickPickItem) return pick.execute();
|
||||||
|
|
||||||
const compare = await this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, pick.commit.sha);
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
|
repoPath: gitUri.repoPath,
|
||||||
if (args.line !== undefined && args.line !== 0) {
|
lhs: {
|
||||||
if (args.showOptions === undefined) {
|
sha: pick.commit.sha,
|
||||||
args.showOptions = {};
|
uri: gitUri as Uri
|
||||||
}
|
},
|
||||||
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
rhs: {
|
||||||
}
|
sha: '',
|
||||||
|
uri: gitUri as Uri
|
||||||
await commands.executeCommand(BuiltInCommands.Diff,
|
},
|
||||||
Uri.file(compare),
|
line: args.line,
|
||||||
gitUri.fileUri(),
|
showOptions: args.showOptions
|
||||||
`${path.basename(gitUri.fsPath)} (${pick.commit.shortSha}) ${GlyphChars.ArrowLeftRight} ${path.basename(gitUri.fsPath)}`,
|
};
|
||||||
args.showOptions);
|
return await commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
Logger.error(ex, 'DiffWithRevisionCommand', 'getVersionedFile');
|
Logger.error(ex, 'DiffWithRevisionCommand');
|
||||||
return window.showErrorMessage(`Unable to open history compare. See output channel for more details`);
|
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { BuiltInCommands, GlyphChars } from '../constants';
|
import { DiffWithCommandArgs } from './diffWith';
|
||||||
import { GitCommit, GitService, GitUri } from '../gitService';
|
import { GitCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Messages } from '../messages';
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export interface DiffWithWorkingCommandArgs {
|
export interface DiffWithWorkingCommandArgs {
|
||||||
commit?: GitCommit;
|
commit?: GitCommit;
|
||||||
|
|
||||||
line?: number;
|
line?: number;
|
||||||
showOptions?: TextDocumentShowOptions;
|
showOptions?: TextDocumentShowOptions;
|
||||||
}
|
}
|
||||||
@@ -48,25 +48,19 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
|
|||||||
const workingFileName = await this.git.findWorkingFileName(gitUri.repoPath, gitUri.fsPath);
|
const workingFileName = await this.git.findWorkingFileName(gitUri.repoPath, gitUri.fsPath);
|
||||||
if (workingFileName === undefined) return undefined;
|
if (workingFileName === undefined) return undefined;
|
||||||
|
|
||||||
try {
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
const compare = await this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha);
|
repoPath: args.commit.repoPath,
|
||||||
|
lhs: {
|
||||||
if (args.line !== undefined && args.line !== 0) {
|
sha: args.commit.sha,
|
||||||
if (args.showOptions === undefined) {
|
uri: args.commit.uri
|
||||||
args.showOptions = {};
|
},
|
||||||
}
|
rhs: {
|
||||||
args.showOptions.selection = new Range(args.line, 0, args.line, 0);
|
sha: '',
|
||||||
}
|
uri: args.commit.uri
|
||||||
|
},
|
||||||
await commands.executeCommand(BuiltInCommands.Diff,
|
line: args.line,
|
||||||
Uri.file(compare),
|
showOptions: args.showOptions
|
||||||
Uri.file(path.resolve(gitUri.repoPath, workingFileName)),
|
};
|
||||||
`${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha}) ${GlyphChars.ArrowLeftRight} ${path.basename(workingFileName)}`,
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
args.showOptions);
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
Logger.error(ex, 'DiffWithWorkingCommand', 'getVersionedFile');
|
|
||||||
return window.showErrorMessage(`Unable to open compare. See output channel for more details`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays } from '../system';
|
|
||||||
import { commands, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithBranch } from './common';
|
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithBranch } from './common';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
@@ -10,6 +9,7 @@ import { OpenInRemoteCommandArgs } from './openInRemote';
|
|||||||
|
|
||||||
export interface OpenBranchInRemoteCommandArgs {
|
export interface OpenBranchInRemoteCommandArgs {
|
||||||
branch?: string;
|
branch?: string;
|
||||||
|
remote?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
|
export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
|
||||||
@@ -22,7 +22,7 @@ export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
|
|||||||
if (isCommandViewContextWithBranch(context)) {
|
if (isCommandViewContextWithBranch(context)) {
|
||||||
args = { ...args };
|
args = { ...args };
|
||||||
args.branch = context.node.branch.name;
|
args.branch = context.node.branch.name;
|
||||||
return this.execute(context.editor, context.uri, args);
|
args.remote = context.node.branch.getRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.execute(context.editor, context.uri, args);
|
return this.execute(context.editor, context.uri, args);
|
||||||
@@ -51,12 +51,14 @@ export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
|
|||||||
if (args.branch === undefined) return undefined;
|
if (args.branch === undefined) return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remotes = Arrays.uniqueBy(await this.git.getRemotes(repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await this.git.getRemotes(repoPath)).filter(r => r.provider !== undefined);
|
||||||
|
|
||||||
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
||||||
resource: {
|
resource: {
|
||||||
type: 'branch',
|
type: 'branch',
|
||||||
branch: args.branch
|
branch: args.branch
|
||||||
},
|
},
|
||||||
|
remote: args.remote,
|
||||||
remotes
|
remotes
|
||||||
} as OpenInRemoteCommandArgs);
|
} as OpenInRemoteCommandArgs);
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/commands/openBranchesInRemote.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
|
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithRemote } from './common';
|
||||||
|
import { GitService, GitUri } from '../gitService';
|
||||||
|
import { Logger } from '../logger';
|
||||||
|
import { OpenInRemoteCommandArgs } from './openInRemote';
|
||||||
|
|
||||||
|
export interface OpenBranchesInRemoteCommandArgs {
|
||||||
|
remote?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OpenBranchesInRemoteCommand extends ActiveEditorCommand {
|
||||||
|
|
||||||
|
constructor(private git: GitService) {
|
||||||
|
super(Commands.OpenBranchesInRemote);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async preExecute(context: CommandContext, args: OpenBranchesInRemoteCommandArgs = {}): Promise<any> {
|
||||||
|
if (isCommandViewContextWithRemote(context)) {
|
||||||
|
args = { ...args };
|
||||||
|
args.remote = context.node.remote.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.execute(context.editor, context.uri, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(editor?: TextEditor, uri?: Uri, args: OpenBranchesInRemoteCommandArgs = {}) {
|
||||||
|
uri = getCommandUri(uri, editor);
|
||||||
|
|
||||||
|
const gitUri = uri && await GitUri.fromUri(uri, this.git);
|
||||||
|
|
||||||
|
const repoPath = gitUri === undefined ? this.git.repoPath : gitUri.repoPath;
|
||||||
|
if (!repoPath) return undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const remotes = (await this.git.getRemotes(repoPath)).filter(r => r.provider !== undefined);
|
||||||
|
|
||||||
|
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
||||||
|
resource: {
|
||||||
|
type: 'branches'
|
||||||
|
},
|
||||||
|
remote: args.remote,
|
||||||
|
remotes
|
||||||
|
} as OpenInRemoteCommandArgs);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
Logger.error(ex, 'OpenBranchesInRemoteCommand');
|
||||||
|
return window.showErrorMessage(`Unable to open branches in remote provider. See output channel for more details`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays } from '../system';
|
|
||||||
import { commands, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
|
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
|
||||||
import { GitBlameCommit, GitService, GitUri } from '../gitService';
|
import { GitBlameCommit, GitService, GitUri } from '../gitService';
|
||||||
@@ -53,7 +52,8 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
|
|||||||
args.sha = commit.sha;
|
args.sha = commit.sha;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await this.git.getRemotes(gitUri.repoPath)).filter(r => r.provider !== undefined);
|
||||||
|
|
||||||
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
||||||
resource: {
|
resource: {
|
||||||
type: 'commit',
|
type: 'commit',
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays } from '../system';
|
|
||||||
import { commands, Range, TextEditor, Uri, window } from 'vscode';
|
import { commands, Range, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
|
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithBranch, isCommandViewContextWithCommit } from './common';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { OpenInRemoteCommandArgs } from './openInRemote';
|
import { OpenInRemoteCommandArgs } from './openInRemote';
|
||||||
|
|
||||||
export interface OpenFileInRemoteCommandArgs {
|
export interface OpenFileInRemoteCommandArgs {
|
||||||
|
branch?: string;
|
||||||
range?: boolean;
|
range?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,10 +16,13 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
|
|||||||
super(Commands.OpenFileInRemote);
|
super(Commands.OpenFileInRemote);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async preExecute(context: CommandContext, args: OpenFileInRemoteCommandArgs = {}): Promise<any> {
|
protected async preExecute(context: CommandContext, args: OpenFileInRemoteCommandArgs = { range: true }): Promise<any> {
|
||||||
if (isCommandViewContextWithCommit(context)) {
|
if (isCommandViewContextWithCommit(context)) {
|
||||||
args = { ...args };
|
args = { ...args };
|
||||||
args.range = false;
|
args.range = false;
|
||||||
|
if (isCommandViewContextWithBranch(context)) {
|
||||||
|
args.branch = context.node.branch !== undefined ? context.node.branch.name : undefined;
|
||||||
|
}
|
||||||
return this.execute(context.editor, context.node.commit.uri, args);
|
return this.execute(context.editor, context.node.commit.uri, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,18 +36,23 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
|
|||||||
const gitUri = await GitUri.fromUri(uri, this.git);
|
const gitUri = await GitUri.fromUri(uri, this.git);
|
||||||
if (!gitUri.repoPath) return undefined;
|
if (!gitUri.repoPath) return undefined;
|
||||||
|
|
||||||
|
if (args.branch === undefined) {
|
||||||
const branch = await this.git.getBranch(gitUri.repoPath);
|
const branch = await this.git.getBranch(gitUri.repoPath);
|
||||||
|
if (branch !== undefined) {
|
||||||
|
args.branch = branch.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await this.git.getRemotes(gitUri.repoPath)).filter(r => r.provider !== undefined);
|
||||||
const range = (args.range && editor !== undefined)
|
const range = (args.range && editor !== undefined)
|
||||||
? new Range(editor.selection.start.with({ line: editor.selection.start.line + 1 }), editor.selection.end.with({ line: editor.selection.end.line + 1 }))
|
? new Range(editor.selection.start.with({ line: editor.selection.start.line + 1 }), editor.selection.end.with({ line: editor.selection.end.line + 1 }))
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
||||||
resource: {
|
resource: {
|
||||||
type: 'file',
|
type: gitUri.sha === undefined ? 'file' : 'revision',
|
||||||
branch: branch === undefined ? 'Current' : branch.name,
|
branch: args.branch === undefined ? 'Current' : args.branch,
|
||||||
fileName: gitUri.getRelativePath(),
|
fileName: gitUri.getRelativePath(),
|
||||||
range: range,
|
range: range,
|
||||||
sha: gitUri.sha
|
sha: gitUri.sha
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { Strings } from '../system';
|
|||||||
import { TextEditor, Uri, window } from 'vscode';
|
import { TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
import { GitLogCommit, GitRemote, RemoteResource } from '../gitService';
|
import { GitLogCommit, GitRemote, GitService, RemoteResource } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem, OpenRemoteCommandQuickPickItem, RemotesQuickPick } from '../quickPicks';
|
import { CommandQuickPickItem, OpenRemoteCommandQuickPickItem, RemotesQuickPick } from '../quickPicks';
|
||||||
|
|
||||||
export interface OpenInRemoteCommandArgs {
|
export interface OpenInRemoteCommandArgs {
|
||||||
|
remote?: string;
|
||||||
remotes?: GitRemote[];
|
remotes?: GitRemote[];
|
||||||
resource?: RemoteResource;
|
resource?: RemoteResource;
|
||||||
|
|
||||||
@@ -26,6 +27,14 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
|
|||||||
args = { ...args };
|
args = { ...args };
|
||||||
if (args.remotes === undefined || args.resource === undefined) return undefined;
|
if (args.remotes === undefined || args.resource === undefined) return undefined;
|
||||||
|
|
||||||
|
if (args.remote !== undefined) {
|
||||||
|
const remotes = args.remotes.filter(r => r.name === args.remote);
|
||||||
|
// Only filter if we get some results
|
||||||
|
if (remotes.length > 0) {
|
||||||
|
args.remotes = remotes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (args.remotes.length === 1) {
|
if (args.remotes.length === 1) {
|
||||||
this.ensureRemoteBranchName(args);
|
this.ensureRemoteBranchName(args);
|
||||||
@@ -41,7 +50,7 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'commit':
|
case 'commit':
|
||||||
const shortSha = args.resource.sha.substring(0, 8);
|
const shortSha = GitService.shortenSha(args.resource.sha);
|
||||||
placeHolder = `open commit ${shortSha} in${GlyphChars.Ellipsis}`;
|
placeHolder = `open commit ${shortSha} in${GlyphChars.Ellipsis}`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -61,7 +70,7 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const shortFileSha = args.resource.sha === undefined ? '' : args.resource.sha.substring(0, 8);
|
const shortFileSha = args.resource.sha === undefined ? '' : GitService.shortenSha(args.resource.sha);
|
||||||
const shaSuffix = shortFileSha ? ` ${Strings.pad(GlyphChars.Dot, 1, 1)} ${shortFileSha}` : '';
|
const shaSuffix = shortFileSha ? ` ${Strings.pad(GlyphChars.Dot, 1, 1)} ${shortFileSha}` : '';
|
||||||
|
|
||||||
placeHolder = `open ${args.resource.fileName}${shaSuffix} in${GlyphChars.Ellipsis}`;
|
placeHolder = `open ${args.resource.fileName}${shaSuffix} in${GlyphChars.Ellipsis}`;
|
||||||
|
|||||||
@@ -1,18 +1,30 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays } from '../system';
|
|
||||||
import { commands, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithRemote } from './common';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { OpenInRemoteCommandArgs } from './openInRemote';
|
import { OpenInRemoteCommandArgs } from './openInRemote';
|
||||||
|
|
||||||
|
export interface OpenRepoInRemoteCommandArgs {
|
||||||
|
remote?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class OpenRepoInRemoteCommand extends ActiveEditorCommand {
|
export class OpenRepoInRemoteCommand extends ActiveEditorCommand {
|
||||||
|
|
||||||
constructor(private git: GitService) {
|
constructor(private git: GitService) {
|
||||||
super(Commands.OpenRepoInRemote);
|
super(Commands.OpenRepoInRemote);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(editor?: TextEditor, uri?: Uri) {
|
protected async preExecute(context: CommandContext, args: OpenRepoInRemoteCommandArgs = {}): Promise<any> {
|
||||||
|
if (isCommandViewContextWithRemote(context)) {
|
||||||
|
args = { ...args };
|
||||||
|
args.remote = context.node.remote.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.execute(context.editor, context.uri, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(editor?: TextEditor, uri?: Uri, args: OpenRepoInRemoteCommandArgs = {}) {
|
||||||
uri = getCommandUri(uri, editor);
|
uri = getCommandUri(uri, editor);
|
||||||
|
|
||||||
const gitUri = uri && await GitUri.fromUri(uri, this.git);
|
const gitUri = uri && await GitUri.fromUri(uri, this.git);
|
||||||
@@ -21,11 +33,13 @@ export class OpenRepoInRemoteCommand extends ActiveEditorCommand {
|
|||||||
if (!repoPath) return undefined;
|
if (!repoPath) return undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const remotes = Arrays.uniqueBy(await this.git.getRemotes(repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await this.git.getRemotes(repoPath)).filter(r => r.provider !== undefined);
|
||||||
|
|
||||||
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
return commands.executeCommand(Commands.OpenInRemote, uri, {
|
||||||
resource: {
|
resource: {
|
||||||
type: 'repo'
|
type: 'repo'
|
||||||
},
|
},
|
||||||
|
remote: args.remote,
|
||||||
remotes
|
remotes
|
||||||
} as OpenInRemoteCommandArgs);
|
} as OpenInRemoteCommandArgs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,20 +20,29 @@ export interface ShowQuickCommitDetailsCommandArgs {
|
|||||||
|
|
||||||
export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
|
export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
|
||||||
|
|
||||||
|
static getMarkdownCommandArgs(sha: string): string;
|
||||||
|
static getMarkdownCommandArgs(args: ShowQuickCommitDetailsCommandArgs): string;
|
||||||
|
static getMarkdownCommandArgs(argsOrSha: ShowQuickCommitDetailsCommandArgs | string): string {
|
||||||
|
const args = typeof argsOrSha === 'string'
|
||||||
|
? { sha: argsOrSha }
|
||||||
|
: argsOrSha;
|
||||||
|
return super.getMarkdownCommandArgsCore<ShowQuickCommitDetailsCommandArgs>(Commands.ShowQuickCommitDetails, args);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(private git: GitService) {
|
constructor(private git: GitService) {
|
||||||
super(Commands.ShowQuickCommitDetails);
|
super(Commands.ShowQuickCommitDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async preExecute(context: CommandContext, ...args: any[]): Promise<any> {
|
protected async preExecute(context: CommandContext, args: ShowQuickCommitDetailsCommandArgs = {}): Promise<any> {
|
||||||
if (context.type === 'view') {
|
if (context.type === 'view') {
|
||||||
|
args = { ...args };
|
||||||
|
args.sha = context.node.uri.sha;
|
||||||
|
|
||||||
if (isCommandViewContextWithCommit(context)) {
|
if (isCommandViewContextWithCommit(context)) {
|
||||||
args = [{ sha: context.node.uri.sha, commit: context.node.commit }];
|
args.commit = context.node.commit;
|
||||||
}
|
|
||||||
else {
|
|
||||||
args = [{ sha: context.node.uri.sha }];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.execute(context.editor, context.uri, ...args);
|
return this.execute(context.editor, context.uri, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitDetailsCommandArgs = {}) {
|
async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitDetailsCommandArgs = {}) {
|
||||||
|
|||||||
@@ -20,20 +20,29 @@ export interface ShowQuickCommitFileDetailsCommandArgs {
|
|||||||
|
|
||||||
export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand {
|
export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand {
|
||||||
|
|
||||||
|
static getMarkdownCommandArgs(sha: string): string;
|
||||||
|
static getMarkdownCommandArgs(args: ShowQuickCommitFileDetailsCommandArgs): string;
|
||||||
|
static getMarkdownCommandArgs(argsOrSha: ShowQuickCommitFileDetailsCommandArgs | string): string {
|
||||||
|
const args = typeof argsOrSha === 'string'
|
||||||
|
? { sha: argsOrSha }
|
||||||
|
: argsOrSha;
|
||||||
|
return super.getMarkdownCommandArgsCore<ShowQuickCommitFileDetailsCommandArgs>(Commands.ShowQuickCommitFileDetails, args);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(private git: GitService) {
|
constructor(private git: GitService) {
|
||||||
super(Commands.ShowQuickCommitFileDetails);
|
super(Commands.ShowQuickCommitFileDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async preExecute(context: CommandContext, ...args: any[]): Promise<any> {
|
protected async preExecute(context: CommandContext, args: ShowQuickCommitFileDetailsCommandArgs = {}): Promise<any> {
|
||||||
if (context.type === 'view') {
|
if (context.type === 'view') {
|
||||||
|
args = { ...args };
|
||||||
|
args.sha = context.node.uri.sha;
|
||||||
|
|
||||||
if (isCommandViewContextWithCommit(context)) {
|
if (isCommandViewContextWithCommit(context)) {
|
||||||
args = [{ sha: context.node.uri.sha, commit: context.node.commit }];
|
args.commit = context.node.commit;
|
||||||
}
|
|
||||||
else {
|
|
||||||
args = [{ sha: context.node.uri.sha }];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.execute(context.editor, context.uri, ...args);
|
return this.execute(context.editor, context.uri, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitFileDetailsCommandArgs = {}) {
|
async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitFileDetailsCommandArgs = {}) {
|
||||||
@@ -95,7 +104,7 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
|
|||||||
args.commit.workingFileName = workingFileName;
|
args.commit.workingFileName = workingFileName;
|
||||||
args.commit.workingFileName = await this.git.findWorkingFileName(args.commit);
|
args.commit.workingFileName = await this.git.findWorkingFileName(args.commit);
|
||||||
|
|
||||||
const shortSha = args.sha!.substring(0, 8);
|
const shortSha = GitService.shortenSha(args.sha!);
|
||||||
|
|
||||||
if (args.goBackCommand === undefined) {
|
if (args.goBackCommand === undefined) {
|
||||||
// Create a command to get back to the commit details
|
// Create a command to get back to the commit details
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class StashApplyCommand extends Command {
|
|||||||
return this.execute(args);
|
return this.execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.preExecute(context, args);
|
return this.execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
|
async execute(args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class StashDeleteCommand extends Command {
|
|||||||
return this.execute(args);
|
return this.execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.preExecute(context, args);
|
return this.execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(args: StashDeleteCommandArgs = { confirm: true }) {
|
async execute(args: StashDeleteCommandArgs = { confirm: true }) {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { InputBoxOptions, window } from 'vscode';
|
import { InputBoxOptions, Uri, window } from 'vscode';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
|
import { CommandContext } from '../commands';
|
||||||
import { Command, Commands } from './common';
|
import { Command, Commands } from './common';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem } from '../quickPicks';
|
import { CommandQuickPickItem } from '../quickPicks';
|
||||||
|
|
||||||
export interface StashSaveCommandArgs {
|
export interface StashSaveCommandArgs {
|
||||||
message?: string;
|
message?: string;
|
||||||
unstagedOnly?: boolean;
|
uris?: Uri[];
|
||||||
|
|
||||||
goBackCommand?: CommandQuickPickItem;
|
goBackCommand?: CommandQuickPickItem;
|
||||||
}
|
}
|
||||||
@@ -18,16 +19,28 @@ export class StashSaveCommand extends Command {
|
|||||||
super(Commands.StashSave);
|
super(Commands.StashSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(args: StashSaveCommandArgs = { unstagedOnly: false }) {
|
protected async preExecute(context: CommandContext, args: StashSaveCommandArgs = {}): Promise<any> {
|
||||||
if (!this.git.repoPath) return undefined;
|
if (context.type === 'scm-states') {
|
||||||
|
|
||||||
args = { ...args };
|
args = { ...args };
|
||||||
if (args.unstagedOnly === undefined) {
|
args.uris = context.scmResourceStates.map(s => s.resourceUri);
|
||||||
args.unstagedOnly = false;
|
return this.execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.type === 'scm-groups') {
|
||||||
|
args = { ...args };
|
||||||
|
args.uris = context.scmResourceGroups.reduce<Uri[]>((a, b) => a.concat(b.resourceStates.map(s => s.resourceUri)), []);
|
||||||
|
return this.execute(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.execute(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(args: StashSaveCommandArgs = {}) {
|
||||||
|
if (!this.git.repoPath) return undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (args.message == null) {
|
if (args.message == null) {
|
||||||
|
args = { ...args };
|
||||||
args.message = await window.showInputBox({
|
args.message = await window.showInputBox({
|
||||||
prompt: `Please provide a stash message`,
|
prompt: `Please provide a stash message`,
|
||||||
placeHolder: `Stash message`
|
placeHolder: `Stash message`
|
||||||
@@ -35,7 +48,7 @@ export class StashSaveCommand extends Command {
|
|||||||
if (args.message === undefined) return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
|
if (args.message === undefined) return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.git.stashSave(this.git.repoPath, args.message, args.unstagedOnly);
|
return await this.git.stashSave(this.git.repoPath, args.message, args.uris);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
Logger.error(ex, 'StashSaveCommand');
|
Logger.error(ex, 'StashSaveCommand');
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import { OutputLevel } from './logger';
|
|||||||
|
|
||||||
export { ExtensionKey } from './constants';
|
export { ExtensionKey } from './constants';
|
||||||
|
|
||||||
export type CodeLensCommand = 'gitlens.toggleFileBlame' |
|
export type CodeLensCommand =
|
||||||
|
'gitlens.toggleFileBlame' |
|
||||||
'gitlens.showBlameHistory' |
|
'gitlens.showBlameHistory' |
|
||||||
'gitlens.showFileHistory' |
|
'gitlens.showFileHistory' |
|
||||||
'gitlens.diffWithPrevious' |
|
'gitlens.diffWithPrevious' |
|
||||||
@@ -41,7 +42,19 @@ export const LineHighlightLocations = {
|
|||||||
OverviewRuler: 'overviewRuler' as LineHighlightLocations
|
OverviewRuler: 'overviewRuler' as LineHighlightLocations
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StatusBarCommand = 'gitlens.toggleFileBlame' |
|
export type CustomRemoteType =
|
||||||
|
'Bitbucket' |
|
||||||
|
'GitHub' |
|
||||||
|
'GitLab';
|
||||||
|
export const CustomRemoteType = {
|
||||||
|
Bitbucket: 'Bitbucket' as CustomRemoteType,
|
||||||
|
BitbucketServer: 'BitbucketServer' as CustomRemoteType,
|
||||||
|
GitHub: 'GitHub' as CustomRemoteType,
|
||||||
|
GitLab: 'GitLab' as CustomRemoteType
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StatusBarCommand =
|
||||||
|
'gitlens.toggleFileBlame' |
|
||||||
'gitlens.showBlameHistory' |
|
'gitlens.showBlameHistory' |
|
||||||
'gitlens.showFileHistory' |
|
'gitlens.showFileHistory' |
|
||||||
'gitlens.toggleCodeLens' |
|
'gitlens.toggleCodeLens' |
|
||||||
@@ -119,6 +132,11 @@ export interface ICodeLensLanguageLocation {
|
|||||||
customSymbols?: string[];
|
customSymbols?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRemotesConfig {
|
||||||
|
type: CustomRemoteType;
|
||||||
|
domain: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IThemeConfig {
|
export interface IThemeConfig {
|
||||||
annotations: {
|
annotations: {
|
||||||
file: {
|
file: {
|
||||||
@@ -257,6 +275,8 @@ export interface IConfig {
|
|||||||
};
|
};
|
||||||
|
|
||||||
blame: {
|
blame: {
|
||||||
|
ignoreWhitespace: boolean;
|
||||||
|
|
||||||
file: {
|
file: {
|
||||||
annotationType: FileAnnotationType;
|
annotationType: FileAnnotationType;
|
||||||
lineHighlight: {
|
lineHighlight: {
|
||||||
@@ -299,6 +319,7 @@ export interface IConfig {
|
|||||||
|
|
||||||
gitExplorer: {
|
gitExplorer: {
|
||||||
view: GitExplorerView;
|
view: GitExplorerView;
|
||||||
|
showTrackingBranch: boolean;
|
||||||
commitFormat: string;
|
commitFormat: string;
|
||||||
commitFileFormat: string;
|
commitFileFormat: string;
|
||||||
stashFormat: string;
|
stashFormat: string;
|
||||||
@@ -306,6 +327,8 @@ export interface IConfig {
|
|||||||
// dateFormat: string | null;
|
// dateFormat: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
remotes: IRemotesConfig[];
|
||||||
|
|
||||||
statusBar: {
|
statusBar: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
alignment: 'left' | 'right';
|
alignment: 'left' | 'right';
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ export const QualifiedExtensionId = `eamodio.${ExtensionId}`;
|
|||||||
|
|
||||||
export const ApplicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
|
export const ApplicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
|
||||||
|
|
||||||
export const FakeSha = 'ffffffffffffffffffffffffffffffffffffffff';
|
|
||||||
|
|
||||||
export type BuiltInCommands = 'cursorMove' |
|
export type BuiltInCommands = 'cursorMove' |
|
||||||
'editor.action.showReferences' |
|
'editor.action.showReferences' |
|
||||||
'editor.action.toggleRenderWhitespace' |
|
'editor.action.toggleRenderWhitespace' |
|
||||||
@@ -79,6 +77,7 @@ export type GlyphChars = '\u21a9' |
|
|||||||
'\u2937' |
|
'\u2937' |
|
||||||
'\u2190' |
|
'\u2190' |
|
||||||
'\u2194' |
|
'\u2194' |
|
||||||
|
'\u2192' |
|
||||||
'\u21e8' |
|
'\u21e8' |
|
||||||
'\u2191' |
|
'\u2191' |
|
||||||
'\u2713' |
|
'\u2713' |
|
||||||
@@ -93,6 +92,7 @@ export const GlyphChars = {
|
|||||||
ArrowDropRight: '\u2937' as GlyphChars,
|
ArrowDropRight: '\u2937' as GlyphChars,
|
||||||
ArrowLeft: '\u2190' as GlyphChars,
|
ArrowLeft: '\u2190' as GlyphChars,
|
||||||
ArrowLeftRight: '\u2194' as GlyphChars,
|
ArrowLeftRight: '\u2194' as GlyphChars,
|
||||||
|
ArrowRight: '\u2192' as GlyphChars,
|
||||||
ArrowRightHollow: '\u21e8' as GlyphChars,
|
ArrowRightHollow: '\u21e8' as GlyphChars,
|
||||||
ArrowUp: '\u2191' as GlyphChars,
|
ArrowUp: '\u2191' as GlyphChars,
|
||||||
Check: '\u2713' as GlyphChars,
|
Check: '\u2713' as GlyphChars,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Commands } from './commands';
|
|||||||
import { TextEditorComparer } from './comparers';
|
import { TextEditorComparer } from './comparers';
|
||||||
import { IConfig, StatusBarCommand } from './configuration';
|
import { IConfig, StatusBarCommand } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey } from './constants';
|
import { DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { BlameabilityChangeEvent, CommitFormatter, GitCommit, GitCommitLine, GitContextTracker, GitService, GitUri } from './gitService';
|
import { BlameabilityChangeEvent, CommitFormatter, GitCommit, GitCommitLine, GitContextTracker, GitService, GitUri, ICommitFormatOptions } from './gitService';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
|
|
||||||
const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
||||||
@@ -432,7 +432,7 @@ export class CurrentLineController extends Disposable {
|
|||||||
decoration.range = editor.document.validateRange(new Range(line, showDetailsStartIndex, line, endOfLineIndex));
|
decoration.range = editor.document.validateRange(new Range(line, showDetailsStartIndex, line, endOfLineIndex));
|
||||||
decorationOptions.push(decoration);
|
decorationOptions.push(decoration);
|
||||||
|
|
||||||
if (showDetailsInStartingWhitespace && showDetailsStartIndex !== 0) {
|
if (showDetailsInStartingWhitespace && showDetailsStartIndex !== 0 && decoration.range.end.character !== 0) {
|
||||||
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,7 +446,7 @@ export class CurrentLineController extends Disposable {
|
|||||||
decoration.range = editor.document.validateRange(new Range(line, showChangesStartIndex, line, endOfLineIndex));
|
decoration.range = editor.document.validateRange(new Range(line, showChangesStartIndex, line, endOfLineIndex));
|
||||||
decorationOptions.push(decoration);
|
decorationOptions.push(decoration);
|
||||||
|
|
||||||
if (showChangesInStartingWhitespace && showChangesStartIndex !== 0) {
|
if (showChangesInStartingWhitespace && showChangesStartIndex !== 0 && decoration.range.end.character !== 0) {
|
||||||
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,10 @@ export class CurrentLineController extends Disposable {
|
|||||||
const cfg = this._config.statusBar;
|
const cfg = this._config.statusBar;
|
||||||
if (!cfg.enabled || this._statusBarItem === undefined) return;
|
if (!cfg.enabled || this._statusBarItem === undefined) return;
|
||||||
|
|
||||||
this._statusBarItem.text = `$(git-commit) ${CommitFormatter.fromTemplate(cfg.format, commit, cfg.dateFormat === null ? this._config.defaultDateFormat : cfg.dateFormat)}`;
|
this._statusBarItem.text = `$(git-commit) ${CommitFormatter.fromTemplate(cfg.format, commit, {
|
||||||
|
truncateMessageAtNewLine: true,
|
||||||
|
dateFormat: cfg.dateFormat === null ? this._config.defaultDateFormat : cfg.dateFormat
|
||||||
|
} as ICommitFormatOptions)}`;
|
||||||
|
|
||||||
switch (cfg.command) {
|
switch (cfg.command) {
|
||||||
case StatusBarCommand.BlameAnnotate:
|
case StatusBarCommand.BlameAnnotate:
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
import { commands, ExtensionContext, extensions, languages, window, workspace } from 'vscode';
|
import { commands, ExtensionContext, extensions, languages, window, workspace } from 'vscode';
|
||||||
import { AnnotationController } from './annotations/annotationController';
|
import { AnnotationController } from './annotations/annotationController';
|
||||||
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
|
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
|
||||||
import { OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands';
|
import { OpenBranchesInRemoteCommand, OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands';
|
||||||
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
|
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
|
||||||
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithRevisionCommand, DiffWithWorkingCommand } from './commands';
|
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithRevisionCommand, DiffWithWorkingCommand } from './commands';
|
||||||
import { ResetSuppressedWarningsCommand } from './commands';
|
import { ResetSuppressedWarningsCommand } from './commands';
|
||||||
import { ClearFileAnnotationsCommand, ShowFileBlameCommand, ShowLineBlameCommand, ToggleFileBlameCommand, ToggleFileRecentChangesCommand, ToggleLineBlameCommand } from './commands';
|
import { ClearFileAnnotationsCommand, ShowFileBlameCommand, ShowLineBlameCommand, ToggleFileBlameCommand, ToggleFileRecentChangesCommand, ToggleLineBlameCommand } from './commands';
|
||||||
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
||||||
@@ -19,6 +19,7 @@ import { CodeLensLocations, IConfig, LineHighlightLocations } from './configurat
|
|||||||
import { ApplicationInsightsKey, CommandContext, ExtensionKey, QualifiedExtensionId, setCommandContext, WorkspaceState } from './constants';
|
import { ApplicationInsightsKey, CommandContext, ExtensionKey, QualifiedExtensionId, setCommandContext, WorkspaceState } from './constants';
|
||||||
import { CodeLensController } from './codeLensController';
|
import { CodeLensController } from './codeLensController';
|
||||||
import { CurrentLineController, LineAnnotationType } from './currentLineController';
|
import { CurrentLineController, LineAnnotationType } from './currentLineController';
|
||||||
|
import { RemoteProviderFactory } from './git/remotes/factory';
|
||||||
import { GitContentProvider } from './gitContentProvider';
|
import { GitContentProvider } from './gitContentProvider';
|
||||||
import { GitExplorer } from './views/gitExplorer';
|
import { GitExplorer } from './views/gitExplorer';
|
||||||
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
||||||
@@ -33,6 +34,7 @@ export async function activate(context: ExtensionContext) {
|
|||||||
Logger.configure(context);
|
Logger.configure(context);
|
||||||
Messages.configure(context);
|
Messages.configure(context);
|
||||||
Telemetry.configure(ApplicationInsightsKey);
|
Telemetry.configure(ApplicationInsightsKey);
|
||||||
|
RemoteProviderFactory.configure(context);
|
||||||
|
|
||||||
const gitlens = extensions.getExtension(QualifiedExtensionId)!;
|
const gitlens = extensions.getExtension(QualifiedExtensionId)!;
|
||||||
const gitlensVersion = gitlens.packageJSON.version;
|
const gitlensVersion = gitlens.packageJSON.version;
|
||||||
@@ -103,11 +105,13 @@ export async function activate(context: ExtensionContext) {
|
|||||||
context.subscriptions.push(new DiffDirectoryCommand(git));
|
context.subscriptions.push(new DiffDirectoryCommand(git));
|
||||||
context.subscriptions.push(new DiffLineWithPreviousCommand(git));
|
context.subscriptions.push(new DiffLineWithPreviousCommand(git));
|
||||||
context.subscriptions.push(new DiffLineWithWorkingCommand(git));
|
context.subscriptions.push(new DiffLineWithWorkingCommand(git));
|
||||||
|
context.subscriptions.push(new DiffWithCommand(git));
|
||||||
context.subscriptions.push(new DiffWithBranchCommand(git));
|
context.subscriptions.push(new DiffWithBranchCommand(git));
|
||||||
context.subscriptions.push(new DiffWithNextCommand(git));
|
context.subscriptions.push(new DiffWithNextCommand(git));
|
||||||
context.subscriptions.push(new DiffWithPreviousCommand(git));
|
context.subscriptions.push(new DiffWithPreviousCommand(git));
|
||||||
context.subscriptions.push(new DiffWithRevisionCommand(git));
|
context.subscriptions.push(new DiffWithRevisionCommand(git));
|
||||||
context.subscriptions.push(new DiffWithWorkingCommand(git));
|
context.subscriptions.push(new DiffWithWorkingCommand(git));
|
||||||
|
context.subscriptions.push(new OpenBranchesInRemoteCommand(git));
|
||||||
context.subscriptions.push(new OpenBranchInRemoteCommand(git));
|
context.subscriptions.push(new OpenBranchInRemoteCommand(git));
|
||||||
context.subscriptions.push(new OpenCommitInRemoteCommand(git));
|
context.subscriptions.push(new OpenCommitInRemoteCommand(git));
|
||||||
context.subscriptions.push(new OpenFileInRemoteCommand(git));
|
context.subscriptions.push(new OpenFileInRemoteCommand(git));
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ import { Strings } from '../../system';
|
|||||||
import { GitCommit } from '../models/commit';
|
import { GitCommit } from '../models/commit';
|
||||||
import { Formatter, IFormatOptions } from './formatter';
|
import { Formatter, IFormatOptions } from './formatter';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
import { GlyphChars } from '../../constants';
|
||||||
|
|
||||||
export interface ICommitFormatOptions extends IFormatOptions {
|
export interface ICommitFormatOptions extends IFormatOptions {
|
||||||
|
truncateMessageAtNewLine?: boolean;
|
||||||
|
|
||||||
tokenOptions?: {
|
tokenOptions?: {
|
||||||
ago?: Strings.ITokenOptions;
|
ago?: Strings.ITokenOptions;
|
||||||
author?: Strings.ITokenOptions;
|
author?: Strings.ITokenOptions;
|
||||||
@@ -41,7 +44,14 @@ export class CommitFormatter extends Formatter<GitCommit, ICommitFormatOptions>
|
|||||||
}
|
}
|
||||||
|
|
||||||
get message() {
|
get message() {
|
||||||
const message = this._item.isUncommitted ? 'Uncommitted change' : this._item.message;
|
let message = this._item.isUncommitted ? 'Uncommitted change' : this._item.message;
|
||||||
|
if (this._options.truncateMessageAtNewLine) {
|
||||||
|
const index = message.indexOf('\n');
|
||||||
|
if (index !== -1) {
|
||||||
|
message = `${message.substring(0, index)}${GlyphChars.Space}${GlyphChars.Ellipsis}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this._padOrTruncate(message, this._options.tokenOptions!.message);
|
return this._padOrTruncate(message, this._options.tokenOptions!.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
115
src/git/git.ts
@@ -1,4 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
import { Strings } from '../system';
|
||||||
import { findGitPath, IGit } from './gitLocator';
|
import { findGitPath, IGit } from './gitLocator';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { spawnPromise } from 'spawn-rx';
|
import { spawnPromise } from 'spawn-rx';
|
||||||
@@ -10,8 +11,10 @@ import * as iconv from 'iconv-lite';
|
|||||||
export { IGit };
|
export { IGit };
|
||||||
export * from './models/models';
|
export * from './models/models';
|
||||||
export * from './parsers/blameParser';
|
export * from './parsers/blameParser';
|
||||||
|
export * from './parsers/branchParser';
|
||||||
export * from './parsers/diffParser';
|
export * from './parsers/diffParser';
|
||||||
export * from './parsers/logParser';
|
export * from './parsers/logParser';
|
||||||
|
export * from './parsers/remoteParser';
|
||||||
export * from './parsers/stashParser';
|
export * from './parsers/stashParser';
|
||||||
export * from './parsers/statusParser';
|
export * from './parsers/statusParser';
|
||||||
export * from './remotes/provider';
|
export * from './remotes/provider';
|
||||||
@@ -33,11 +36,28 @@ const GitWarnings = [
|
|||||||
/no such path/,
|
/no such path/,
|
||||||
/does not have any commits/,
|
/does not have any commits/,
|
||||||
/Path \'.*?\' does not exist in/,
|
/Path \'.*?\' does not exist in/,
|
||||||
/Path \'.*?\' exists on disk, but not in/
|
/Path \'.*?\' exists on disk, but not in/,
|
||||||
|
/no upstream configured for branch/
|
||||||
];
|
];
|
||||||
|
|
||||||
async function gitCommand(options: { cwd: string, encoding?: string }, ...args: any[]) {
|
interface GitCommandOptions {
|
||||||
|
cwd: string;
|
||||||
|
encoding?: string;
|
||||||
|
overrideErrorHandling?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function gitCommand(options: GitCommandOptions, ...args: any[]): Promise<string> {
|
||||||
|
if (options.overrideErrorHandling) return gitCommandCore(options, ...args);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
return await gitCommandCore(options, ...args);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
return gitCommandDefaultErrorHandler(ex, options, ...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function gitCommandCore(options: GitCommandOptions, ...args: any[]): Promise<string> {
|
||||||
// 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');
|
||||||
@@ -49,7 +69,8 @@ async function gitCommand(options: { cwd: string, encoding?: string }, ...args:
|
|||||||
|
|
||||||
return iconv.decode(Buffer.from(s, 'binary'), opts.encoding);
|
return iconv.decode(Buffer.from(s, 'binary'), opts.encoding);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
|
||||||
|
function gitCommandDefaultErrorHandler(ex: Error, options: GitCommandOptions, ...args: any[]): string {
|
||||||
const msg = ex && ex.toString();
|
const msg = ex && ex.toString();
|
||||||
if (msg) {
|
if (msg) {
|
||||||
for (const warning of GitWarnings) {
|
for (const warning of GitWarnings) {
|
||||||
@@ -63,7 +84,6 @@ async function gitCommand(options: { cwd: string, encoding?: string }, ...args:
|
|||||||
Logger.error(ex, 'git', ...args, ` cwd='${options.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;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export class Git {
|
export class Git {
|
||||||
|
|
||||||
@@ -91,8 +111,9 @@ export class Git {
|
|||||||
|
|
||||||
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, 'binary');
|
const data = await Git.show(repoPath, fileName, branchOrSha, 'binary');
|
||||||
|
if (data === undefined) return undefined;
|
||||||
|
|
||||||
const suffix = Git.isSha(branchOrSha) ? branchOrSha.substring(0, 8) : branchOrSha;
|
const suffix = Strings.truncate(Strings.sanitizeForFS(Git.isSha(branchOrSha) ? Git.shortenSha(branchOrSha) : branchOrSha), 50, '');
|
||||||
const ext = path.extname(fileName);
|
const ext = path.extname(fileName);
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
tmp.file({ prefix: `${path.basename(fileName, ext)}-${suffix}__`, postfix: ext },
|
tmp.file({ prefix: `${path.basename(fileName, ext)}-${suffix}__`, postfix: ext },
|
||||||
@@ -127,6 +148,10 @@ export class Git {
|
|||||||
return fileName && fileName.replace(/\\/g, '/');
|
return fileName && fileName.replace(/\\/g, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static shortenSha(sha: string) {
|
||||||
|
return sha.substring(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
static splitPath(fileName: string, repoPath: string | undefined, extract: boolean = true): [string, string] {
|
static splitPath(fileName: string, repoPath: string | undefined, extract: boolean = true): [string, string] {
|
||||||
if (repoPath) {
|
if (repoPath) {
|
||||||
fileName = this.normalizePath(fileName);
|
fileName = this.normalizePath(fileName);
|
||||||
@@ -152,15 +177,17 @@ export class Git {
|
|||||||
|
|
||||||
// Git commands
|
// Git commands
|
||||||
|
|
||||||
static blame(repoPath: string | undefined, fileName: string, sha?: string, startLine?: number, endLine?: number) {
|
static blame(repoPath: string | undefined, fileName: string, sha?: string, options: { ignoreWhitespace?: boolean, startLine?: number, endLine?: number } = {}) {
|
||||||
const [file, root] = Git.splitPath(fileName, repoPath);
|
const [file, root] = Git.splitPath(fileName, repoPath);
|
||||||
|
|
||||||
const params = [`blame`, `--root`, `--incremental`];
|
const params = [`blame`, `--root`, `--incremental`];
|
||||||
|
|
||||||
if (startLine != null && endLine != null) {
|
if (options.ignoreWhitespace) {
|
||||||
params.push(`-L ${startLine},${endLine}`);
|
params.push('-w');
|
||||||
|
}
|
||||||
|
if (options.startLine != null && options.endLine != null) {
|
||||||
|
params.push(`-L ${options.startLine},${options.endLine}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sha) {
|
if (sha) {
|
||||||
params.push(sha);
|
params.push(sha);
|
||||||
}
|
}
|
||||||
@@ -168,20 +195,42 @@ export class Git {
|
|||||||
return gitCommand({ cwd: root }, ...params, `--`, file);
|
return gitCommand({ cwd: root }, ...params, `--`, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static branch(repoPath: string, all: boolean) {
|
static branch(repoPath: string, options: { all: boolean } = { all: false }) {
|
||||||
const params = [`branch`];
|
const params = [`branch`, `-vv`];
|
||||||
if (all) {
|
if (options.all) {
|
||||||
params.push(`-a`);
|
params.push(`-a`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gitCommand({ cwd: repoPath }, ...params);
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async config_get(key: string, repoPath?: string) {
|
static async branch_current(repoPath: string) {
|
||||||
|
const params = [`rev-parse`, `--abbrev-ref`, `--symbolic-full-name`, `@`, `@{u}`];
|
||||||
|
|
||||||
|
const opts = { cwd: repoPath, overrideErrorHandling: true };
|
||||||
try {
|
try {
|
||||||
return await gitCommand({ cwd: repoPath || '' }, `config`, `--get`, key);
|
return await gitCommand(opts, ...params);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
|
if (/no upstream configured for branch/.test(ex && ex.toString())) {
|
||||||
|
return ex.message.split('\n')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return gitCommandDefaultErrorHandler(ex, opts, ...params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static checkout(repoPath: string, fileName: string, sha: string) {
|
||||||
|
const [file, root] = Git.splitPath(fileName, repoPath);
|
||||||
|
|
||||||
|
return gitCommand({ cwd: root }, `checkout`, sha, `--`, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async config_get(key: string, repoPath?: string) {
|
||||||
|
try {
|
||||||
|
return await gitCommand({ cwd: repoPath || '', overrideErrorHandling: true }, `config`, `--get`, key);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,9 +334,9 @@ export class Git {
|
|||||||
|
|
||||||
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({ cwd: repoPath }, 'ls-files', fileName);
|
return await gitCommand({ cwd: repoPath, overrideErrorHandling: true }, 'ls-files', fileName);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,12 +349,25 @@ export class Git {
|
|||||||
return gitCommand({ cwd: repoPath }, 'remote', 'get-url', remote);
|
return gitCommand({ cwd: repoPath }, 'remote', 'get-url', remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
static show(repoPath: string | undefined, fileName: string, branchOrSha: string, encoding?: string) {
|
static async 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)) throw new Error(`sha=${branchOrSha} is uncommitted`);
|
||||||
return gitCommand({ cwd: root, encoding: encoding || defaultEncoding }, 'show', `${branchOrSha}:./${file}`);
|
|
||||||
|
const opts = { cwd: root, encoding: encoding || defaultEncoding, overrideErrorHandling: true };
|
||||||
|
const args = `${branchOrSha}:./${file}`;
|
||||||
|
try {
|
||||||
|
return await gitCommand(opts, 'show', args);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
const msg = ex && ex.toString();
|
||||||
|
if (/Path \'.*?\' does not exist in/.test(msg) || /Path \'.*?\' exists on disk, but not in /.test(msg)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gitCommandDefaultErrorHandler(ex, opts, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static stash_apply(repoPath: string, stashName: string, deleteAfter: boolean) {
|
static stash_apply(repoPath: string, stashName: string, deleteAfter: boolean) {
|
||||||
@@ -322,11 +384,18 @@ export class Git {
|
|||||||
return gitCommand({ cwd: repoPath }, ...defaultStashParams);
|
return gitCommand({ cwd: repoPath }, ...defaultStashParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
static stash_save(repoPath: string, message?: string, unstagedOnly: boolean = false) {
|
static stash_push(repoPath: string, pathspecs: string[], message?: string) {
|
||||||
const params = [`stash`, `save`, `--include-untracked`];
|
const params = [`stash`, `push`, `-u`];
|
||||||
if (unstagedOnly) {
|
if (message) {
|
||||||
params.push(`--keep-index`);
|
params.push(`-m`);
|
||||||
|
params.push(message);
|
||||||
}
|
}
|
||||||
|
params.splice(params.length, 0, `--`, ...pathspecs);
|
||||||
|
return gitCommand({ cwd: repoPath }, ...params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static stash_save(repoPath: string, message?: string) {
|
||||||
|
const params = [`stash`, `save`, `-u`];
|
||||||
if (message) {
|
if (message) {
|
||||||
params.push(message);
|
params.push(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { Disposable, Event, EventEmitter, TextDocument, TextDocumentChangeEvent, TextEditor, window, workspace } from 'vscode';
|
import { Disposable, Event, EventEmitter, TextDocument, TextDocumentChangeEvent, TextEditor, window, workspace } from 'vscode';
|
||||||
import { TextDocumentComparer } from '../comparers';
|
import { TextDocumentComparer } from '../comparers';
|
||||||
import { CommandContext, setCommandContext } from '../constants';
|
import { CommandContext, setCommandContext } from '../constants';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri, RepoChangedReasons } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
|
||||||
export interface BlameabilityChangeEvent {
|
export interface BlameabilityChangeEvent {
|
||||||
@@ -32,13 +32,13 @@ export class GitContextTracker extends Disposable {
|
|||||||
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
||||||
subscriptions.push(workspace.onDidSaveTextDocument(this._onTextDocumentSaved, this));
|
subscriptions.push(workspace.onDidSaveTextDocument(this._onTextDocumentSaved, this));
|
||||||
subscriptions.push(this.git.onDidBlameFail(this._onBlameFailed, this));
|
subscriptions.push(this.git.onDidBlameFail(this._onBlameFailed, this));
|
||||||
|
subscriptions.push(this.git.onDidChangeRepo(this._onRepoChanged, this));
|
||||||
|
|
||||||
this._disposable = Disposable.from(...subscriptions);
|
this._disposable = Disposable.from(...subscriptions);
|
||||||
|
|
||||||
setCommandContext(CommandContext.IsRepository, !!this.git.repoPath);
|
setCommandContext(CommandContext.IsRepository, !!this.git.repoPath);
|
||||||
|
|
||||||
this._onConfigurationChanged();
|
this._onConfigurationChanged();
|
||||||
this._onActiveTextEditorChanged(window.activeTextEditor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
@@ -55,6 +55,13 @@ export class GitContextTracker extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _onRepoChanged(reasons: RepoChangedReasons[]) {
|
||||||
|
if (!reasons.includes(RepoChangedReasons.Remotes)) return;
|
||||||
|
|
||||||
|
const gitUri = this._editor === undefined ? undefined : await GitUri.fromUri(this._editor.document.uri, this.git);
|
||||||
|
this._updateContextHasRemotes(gitUri);
|
||||||
|
}
|
||||||
|
|
||||||
private _onActiveTextEditorChanged(editor: TextEditor | undefined) {
|
private _onActiveTextEditorChanged(editor: TextEditor | undefined) {
|
||||||
this._editor = editor;
|
this._editor = editor;
|
||||||
this._updateContext(this._gitEnabled ? editor : undefined);
|
this._updateContext(this._gitEnabled ? editor : undefined);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export class GitUri extends Uri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get shortSha() {
|
get shortSha() {
|
||||||
return this.sha && this.sha.substring(0, 8);
|
return this.sha && GitService.shortenSha(this.sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
fileUri() {
|
fileUri() {
|
||||||
|
|||||||
@@ -5,25 +5,32 @@ export class GitBranch {
|
|||||||
current: boolean;
|
current: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
remote: boolean;
|
remote: boolean;
|
||||||
|
tracking?: string;
|
||||||
|
|
||||||
constructor(branch: string) {
|
constructor(public readonly repoPath: string, branch: string, current: boolean = false, tracking?: string) {
|
||||||
branch = branch.trim();
|
|
||||||
|
|
||||||
if (branch.startsWith('* ')) {
|
|
||||||
branch = branch.substring(2);
|
|
||||||
this.current = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (branch.startsWith('remotes/')) {
|
if (branch.startsWith('remotes/')) {
|
||||||
branch = branch.substring(8);
|
branch = branch.substring(8);
|
||||||
this.remote = true;
|
this.remote = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = branch.indexOf(' ');
|
this.current = current;
|
||||||
if (index !== -1) {
|
this.name = branch;
|
||||||
branch = branch.substring(0, index);
|
this.tracking = tracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.name = branch;
|
getName(): string {
|
||||||
|
return this.remote
|
||||||
|
? this.name.substring(this.name.indexOf('/') + 1)
|
||||||
|
: this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRemote(): string | undefined {
|
||||||
|
if (this.remote) return GitBranch.getRemote(this.name);
|
||||||
|
if (this.tracking !== undefined) return GitBranch.getRemote(this.tracking);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getRemote(branch: string): string {
|
||||||
|
return branch.substring(0, branch.indexOf('/'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ export class GitCommit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get shortSha() {
|
get shortSha() {
|
||||||
return this.sha.substring(0, 8);
|
return Git.shortenSha(this.sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isUncommitted(): boolean {
|
get isUncommitted(): boolean {
|
||||||
@@ -62,7 +62,7 @@ export class GitCommit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get previousShortSha() {
|
get previousShortSha() {
|
||||||
return this.previousSha && this.previousSha.substring(0, 8);
|
return this.previousSha && Git.shortenSha(this.previousSha);
|
||||||
}
|
}
|
||||||
|
|
||||||
get previousUri(): Uri {
|
get previousUri(): Uri {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Uri } from 'vscode';
|
import { Uri } from 'vscode';
|
||||||
import { GitCommit, GitCommitType } from './commit';
|
import { GitCommit, GitCommitType } from './commit';
|
||||||
|
import { Git } from '../git';
|
||||||
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ export class GitLogCommit extends GitCommit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get nextShortSha() {
|
get nextShortSha() {
|
||||||
return this.nextSha && this.nextSha.substring(0, 8);
|
return this.nextSha && Git.shortenSha(this.nextSha);
|
||||||
}
|
}
|
||||||
|
|
||||||
get nextUri(): Uri {
|
get nextUri(): Uri {
|
||||||
|
|||||||
@@ -5,23 +5,9 @@ export type GitRemoteType = 'fetch' | 'push';
|
|||||||
|
|
||||||
export class GitRemote {
|
export class GitRemote {
|
||||||
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
type: GitRemoteType;
|
|
||||||
|
|
||||||
provider?: RemoteProvider;
|
provider?: RemoteProvider;
|
||||||
|
|
||||||
constructor(remote: string) {
|
constructor(public readonly repoPath: string, public readonly name: string, public readonly url: string, public readonly domain: string, public readonly path: string, public readonly types: GitRemoteType[]) {
|
||||||
remote = remote.trim();
|
this.provider = RemoteProviderFactory.getRemoteProvider(this.domain, this.path);
|
||||||
|
|
||||||
const [name, info] = remote.split('\t');
|
|
||||||
this.name = name;
|
|
||||||
|
|
||||||
const [url, typeInfo] = info.split(' ');
|
|
||||||
this.url = url;
|
|
||||||
|
|
||||||
this.type = typeInfo.substring(1, typeInfo.length - 1) as GitRemoteType;
|
|
||||||
|
|
||||||
this.provider = RemoteProviderFactory.getRemoteProvider(this.url);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
24
src/git/parsers/branchParser.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
import { GitBranch } from './../git';
|
||||||
|
const branchWithTrackingRegex = /^(\*?)\s+(.+?)\s+([0-9,a-f]+)\s+(?:\[(.*?\/.*?)(?:\:|\]))?/gm;
|
||||||
|
|
||||||
|
export class GitBranchParser {
|
||||||
|
|
||||||
|
static parse(data: string, repoPath: string): GitBranch[] | undefined {
|
||||||
|
if (!data) return undefined;
|
||||||
|
|
||||||
|
const branches: GitBranch[] = [];
|
||||||
|
|
||||||
|
let match: RegExpExecArray | null = null;
|
||||||
|
do {
|
||||||
|
match = branchWithTrackingRegex.exec(data);
|
||||||
|
if (match == null) break;
|
||||||
|
|
||||||
|
branches.push(new GitBranch(repoPath, match[2], match[1] === '*', match[4]));
|
||||||
|
} while (match != null);
|
||||||
|
|
||||||
|
if (!branches.length) return undefined;
|
||||||
|
|
||||||
|
return branches;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/git/parsers/remoteParser.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
'use strict';
|
||||||
|
import { GitRemote } from './../git';
|
||||||
|
import { GitRemoteType } from '../models/remote';
|
||||||
|
|
||||||
|
const remoteRegex = /^(.*)\t(.*)\s\((.*)\)$/gm;
|
||||||
|
const urlRegex = /^(?:git:\/\/(.*?)\/|https:\/\/(.*?)\/|http:\/\/(.*?)\/|git@(.*):|ssh:\/\/(?:.*@)?(.*?)(?::.*?)?\/)(.*)$/;
|
||||||
|
|
||||||
|
export class GitRemoteParser {
|
||||||
|
|
||||||
|
static parse(data: string, repoPath: string): GitRemote[] {
|
||||||
|
if (!data) return [];
|
||||||
|
|
||||||
|
const remotes: GitRemote[] = [];
|
||||||
|
const groups = Object.create(null);
|
||||||
|
|
||||||
|
let match: RegExpExecArray | null = null;
|
||||||
|
do {
|
||||||
|
match = remoteRegex.exec(data);
|
||||||
|
if (match == null) break;
|
||||||
|
|
||||||
|
const url = match[2];
|
||||||
|
|
||||||
|
const [domain, path] = this.parseGitUrl(url);
|
||||||
|
|
||||||
|
let remote: GitRemote | undefined = groups[url];
|
||||||
|
if (remote === undefined) {
|
||||||
|
remote = new GitRemote(repoPath, match[1], url, domain, path, [match[3] as GitRemoteType]);
|
||||||
|
remotes.push(remote);
|
||||||
|
groups[url] = remote;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
remote.types.push(match[3] as GitRemoteType);
|
||||||
|
}
|
||||||
|
} while (match != null);
|
||||||
|
|
||||||
|
if (!remotes.length) return [];
|
||||||
|
|
||||||
|
return remotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static parseGitUrl(url: string): [string, string] {
|
||||||
|
const match = urlRegex.exec(url);
|
||||||
|
if (match == null) return ['', ''];
|
||||||
|
|
||||||
|
return [
|
||||||
|
match[1] || match[2] || match[3] || match[4] || match[5],
|
||||||
|
match[6].replace(/\.git\/?$/, '')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/git/remotes/bitbucket-server.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
import { Range } from 'vscode';
|
||||||
|
import { RemoteProvider } from './provider';
|
||||||
|
|
||||||
|
export class BitbucketServerService extends RemoteProvider {
|
||||||
|
|
||||||
|
constructor(public domain: string, public path: string, public custom: boolean = false) {
|
||||||
|
super(domain, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.formatName('Bitbucket Server');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get baseUrl() {
|
||||||
|
const [project, repo] = super.splitPath();
|
||||||
|
return `https://${this.domain}/projects/${project}/repos/${repo}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getUrlForBranches(): string {
|
||||||
|
return `${this.baseUrl}/branches`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getUrlForBranch(branch: string): string {
|
||||||
|
return `${this.baseUrl}/commits?until=${branch}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getUrlForCommit(sha: string): string {
|
||||||
|
return `${this.baseUrl}/commits/${sha}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
|
||||||
|
let line = '';
|
||||||
|
if (range) {
|
||||||
|
if (range.start.line === range.end.line) {
|
||||||
|
line = `#${range.start.line}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line = `#${range.start.line}-${range.end.line}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sha) return `${this.baseUrl}/browse/${fileName}?at=${sha}${line}`;
|
||||||
|
if (branch) return `${this.baseUrl}/browse/${fileName}?at=${branch}${line}`;
|
||||||
|
return `${this.baseUrl}/browse/${fileName}${line}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,16 @@ import { RemoteProvider } from './provider';
|
|||||||
|
|
||||||
export class BitbucketService extends RemoteProvider {
|
export class BitbucketService extends RemoteProvider {
|
||||||
|
|
||||||
constructor(public domain: string, public path: string) {
|
constructor(public domain: string, public path: string, public custom: boolean = false) {
|
||||||
super(domain, path);
|
super(domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return 'Bitbucket';
|
return this.formatName('Bitbucket');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getUrlForBranches(): string {
|
||||||
|
return `${this.baseUrl}/branches`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getUrlForBranch(branch: string): string {
|
protected getUrlForBranch(branch: string): string {
|
||||||
|
|||||||
@@ -1,38 +1,49 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { RemoteProvider } from './provider';
|
import { Objects } from '../../system';
|
||||||
|
import { Event, EventEmitter, ExtensionContext, workspace } from 'vscode';
|
||||||
import { BitbucketService } from './bitbucket';
|
import { BitbucketService } from './bitbucket';
|
||||||
|
import { BitbucketServerService } from './bitbucket-server';
|
||||||
|
import { CustomRemoteType, IConfig, IRemotesConfig } from '../../configuration';
|
||||||
|
import { ExtensionKey } from '../../constants';
|
||||||
import { GitHubService } from './github';
|
import { GitHubService } from './github';
|
||||||
import { GitLabService } from './gitlab';
|
import { GitLabService } from './gitlab';
|
||||||
import { VisualStudioService } from './visualStudio';
|
|
||||||
import { Logger } from '../../logger';
|
import { Logger } from '../../logger';
|
||||||
|
import { RemoteProvider } from './provider';
|
||||||
|
import { VisualStudioService } from './visualStudio';
|
||||||
|
|
||||||
export { RemoteProvider };
|
export { RemoteProvider };
|
||||||
|
|
||||||
const providerMap = new Map<string, (domain: string, path: string) => RemoteProvider>([
|
const defaultProviderMap = new Map<string, (domain: string, path: string) => RemoteProvider>([
|
||||||
['bitbucket.org', (domain: string, path: string) => new BitbucketService(domain, path)],
|
['bitbucket.org', (domain: string, path: string) => new BitbucketService(domain, path)],
|
||||||
['github.com', (domain: string, path: string) => new GitHubService(domain, path)],
|
['github.com', (domain: string, path: string) => new GitHubService(domain, path)],
|
||||||
['gitlab.com', (domain: string, path: string) => new GitLabService(domain, path)],
|
['gitlab.com', (domain: string, path: string) => new GitLabService(domain, path)],
|
||||||
['visualstudio.com', (domain: string, path: string) => new VisualStudioService(domain, path)]
|
['visualstudio.com', (domain: string, path: string) => new VisualStudioService(domain, path)]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const UrlRegex = /^(?:git:\/\/(.*?)\/|https:\/\/(.*?)\/|http:\/\/(.*?)\/|git@(.*):|ssh:\/\/(?:.*@)?(.*?)(?::.*?)?\/)(.*)$/;
|
|
||||||
|
|
||||||
export class RemoteProviderFactory {
|
export class RemoteProviderFactory {
|
||||||
|
|
||||||
static getRemoteProvider(url: string): RemoteProvider | undefined {
|
private static _providerMap: Map<string, (domain: string, path: string) => RemoteProvider>;
|
||||||
|
private static _remotesCfg: IRemotesConfig[];
|
||||||
|
|
||||||
|
private static _onDidChange = new EventEmitter<void>();
|
||||||
|
public static get onDidChange(): Event<void> {
|
||||||
|
return this._onDidChange.event;
|
||||||
|
}
|
||||||
|
|
||||||
|
static configure(context: ExtensionContext) {
|
||||||
|
context.subscriptions.push(workspace.onDidChangeConfiguration(() => this.onConfigurationChanged()));
|
||||||
|
this.onConfigurationChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getRemoteProvider(domain: string, path: string): RemoteProvider | undefined {
|
||||||
try {
|
try {
|
||||||
const match = UrlRegex.exec(url);
|
let key = domain.toLowerCase();
|
||||||
if (match == null) return undefined;
|
if (key.endsWith('visualstudio.com')) {
|
||||||
|
key = 'visualstudio.com';
|
||||||
|
}
|
||||||
|
|
||||||
const domain = match[1] || match[2] || match[3] || match[4] || match[5];
|
const creator = this._providerMap.get(key);
|
||||||
const path = match[6].replace(/\.git\/?$/, '');
|
if (creator === undefined) return undefined;
|
||||||
|
|
||||||
const key = domain.toLowerCase().endsWith('visualstudio.com')
|
|
||||||
? 'visualstudio.com'
|
|
||||||
: domain;
|
|
||||||
|
|
||||||
const creator = providerMap.get(key.toLowerCase());
|
|
||||||
if (!creator) return undefined;
|
|
||||||
|
|
||||||
return creator(domain, path);
|
return creator(domain, path);
|
||||||
}
|
}
|
||||||
@@ -41,4 +52,37 @@ export class RemoteProviderFactory {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static onConfigurationChanged(silent: boolean = false) {
|
||||||
|
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey);
|
||||||
|
if (cfg === undefined) return;
|
||||||
|
|
||||||
|
if (!Objects.areEquivalent(cfg.remotes, this._remotesCfg)) {
|
||||||
|
this._providerMap = new Map(defaultProviderMap);
|
||||||
|
|
||||||
|
this._remotesCfg = cfg.remotes;
|
||||||
|
if (this._remotesCfg != null && this._remotesCfg.length > 0) {
|
||||||
|
for (const svc of this._remotesCfg) {
|
||||||
|
const provider = this.getCustomProvider(svc.type);
|
||||||
|
if (provider === undefined) continue;
|
||||||
|
|
||||||
|
this._providerMap.set(svc.domain.toLowerCase(), provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!silent) {
|
||||||
|
this._onDidChange.fire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getCustomProvider(type: CustomRemoteType) {
|
||||||
|
switch (type) {
|
||||||
|
case CustomRemoteType.Bitbucket: return (domain: string, path: string) => new BitbucketService(domain, path, true);
|
||||||
|
case CustomRemoteType.BitbucketServer: return (domain: string, path: string) => new BitbucketServerService(domain, path, true);
|
||||||
|
case CustomRemoteType.GitHub: return (domain: string, path: string) => new GitHubService(domain, path, true);
|
||||||
|
case CustomRemoteType.GitLab: return (domain: string, path: string) => new GitLabService(domain, path, true);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,12 +4,16 @@ import { RemoteProvider } from './provider';
|
|||||||
|
|
||||||
export class GitHubService extends RemoteProvider {
|
export class GitHubService extends RemoteProvider {
|
||||||
|
|
||||||
constructor(public domain: string, public path: string) {
|
constructor(public domain: string, public path: string, public custom: boolean = false) {
|
||||||
super(domain, path);
|
super(domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return 'GitHub';
|
return this.formatName('GitHub');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getUrlForBranches(): string {
|
||||||
|
return `${this.baseUrl}/branches`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getUrlForBranch(branch: string): string {
|
protected getUrlForBranch(branch: string): string {
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import { GitHubService } from './github';
|
|||||||
|
|
||||||
export class GitLabService extends GitHubService {
|
export class GitLabService extends GitHubService {
|
||||||
|
|
||||||
constructor(public domain: string, public path: string) {
|
constructor(public domain: string, public path: string, public custom: boolean = false) {
|
||||||
super(domain, path);
|
super(domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return 'GitLab';
|
return this.formatName('GitLab');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,10 @@ import { commands, Range, Uri } from 'vscode';
|
|||||||
import { BuiltInCommands } from '../../constants';
|
import { BuiltInCommands } from '../../constants';
|
||||||
import { GitLogCommit } from '../../gitService';
|
import { GitLogCommit } from '../../gitService';
|
||||||
|
|
||||||
export type RemoteResourceType = 'branch' | 'commit' | 'file' | 'repo' | 'revision';
|
export type RemoteResourceType = 'branch' | 'branches' | 'commit' | 'file' | 'repo' | 'revision';
|
||||||
export type RemoteResource =
|
export type RemoteResource =
|
||||||
{ type: 'branch', branch: string } |
|
{ type: 'branch', branch: string } |
|
||||||
|
{ type: 'branches' } |
|
||||||
{ type: 'commit', sha: string } |
|
{ type: 'commit', sha: string } |
|
||||||
{ type: 'file', branch?: string, fileName: string, range?: Range } |
|
{ type: 'file', branch?: string, fileName: string, range?: Range } |
|
||||||
{ type: 'repo' } |
|
{ type: 'repo' } |
|
||||||
@@ -14,6 +15,7 @@ export type RemoteResource =
|
|||||||
export function getNameFromRemoteResource(resource: RemoteResource) {
|
export function getNameFromRemoteResource(resource: RemoteResource) {
|
||||||
switch (resource.type) {
|
switch (resource.type) {
|
||||||
case 'branch': return 'Branch';
|
case 'branch': return 'Branch';
|
||||||
|
case 'branches': return 'Branches';
|
||||||
case 'commit': return 'Commit';
|
case 'commit': return 'Commit';
|
||||||
case 'file': return 'File';
|
case 'file': return 'File';
|
||||||
case 'repo': return 'Repository';
|
case 'repo': return 'Repository';
|
||||||
@@ -24,7 +26,7 @@ export function getNameFromRemoteResource(resource: RemoteResource) {
|
|||||||
|
|
||||||
export abstract class RemoteProvider {
|
export abstract class RemoteProvider {
|
||||||
|
|
||||||
constructor(public domain: string, public path: string) { }
|
constructor(public domain: string, public path: string, public custom: boolean = false) { }
|
||||||
|
|
||||||
abstract get name(): string;
|
abstract get name(): string;
|
||||||
|
|
||||||
@@ -32,6 +34,16 @@ export abstract class RemoteProvider {
|
|||||||
return `https://${this.domain}/${this.path}`;
|
return `https://${this.domain}/${this.path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected formatName(name: string) {
|
||||||
|
return `${name}${this.custom ? ` (${this.domain})` : ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected splitPath(): [string, string] {
|
||||||
|
const index = this.path.indexOf('/');
|
||||||
|
return [ this.path.substring(0, index), this.path.substring(index + 1) ];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract getUrlForBranches(): string;
|
||||||
protected abstract getUrlForBranch(branch: string): string;
|
protected abstract getUrlForBranch(branch: string): string;
|
||||||
protected abstract getUrlForCommit(sha: string): string;
|
protected abstract getUrlForCommit(sha: string): string;
|
||||||
protected abstract getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string;
|
protected abstract getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string;
|
||||||
@@ -45,6 +57,7 @@ export abstract class RemoteProvider {
|
|||||||
open(resource: RemoteResource): Promise<{} | undefined> {
|
open(resource: RemoteResource): Promise<{} | undefined> {
|
||||||
switch (resource.type) {
|
switch (resource.type) {
|
||||||
case 'branch': return this.openBranch(resource.branch);
|
case 'branch': return this.openBranch(resource.branch);
|
||||||
|
case 'branches': return this.openBranches();
|
||||||
case 'commit': return this.openCommit(resource.sha);
|
case 'commit': return this.openCommit(resource.sha);
|
||||||
case 'file': return this.openFile(resource.fileName, resource.branch, undefined, resource.range);
|
case 'file': return this.openFile(resource.fileName, resource.branch, undefined, resource.range);
|
||||||
case 'repo': return this.openRepo();
|
case 'repo': return this.openRepo();
|
||||||
@@ -56,6 +69,10 @@ export abstract class RemoteProvider {
|
|||||||
return this._openUrl(this.baseUrl);
|
return this._openUrl(this.baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openBranches() {
|
||||||
|
return this._openUrl(this.getUrlForBranches());
|
||||||
|
}
|
||||||
|
|
||||||
openBranch(branch: string) {
|
openBranch(branch: string) {
|
||||||
return this._openUrl(this.getUrlForBranch(branch));
|
return this._openUrl(this.getUrlForBranch(branch));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ export class VisualStudioService extends RemoteProvider {
|
|||||||
return 'Visual Studio Team Services';
|
return 'Visual Studio Team Services';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getUrlForBranches(): string {
|
||||||
|
return `${this.baseUrl}/branches`;
|
||||||
|
}
|
||||||
|
|
||||||
protected getUrlForBranch(branch: string): string {
|
protected getUrlForBranch(branch: string): string {
|
||||||
return `${this.baseUrl}/?version=GB${branch}&_a=history`;
|
return `${this.baseUrl}/?version=GB${branch}&_a=history`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ export class GitContentProvider implements TextDocumentContentProvider {
|
|||||||
const data = GitService.fromGitContentUri(uri);
|
const data = GitService.fromGitContentUri(uri);
|
||||||
const fileName = data.originalFileName || data.fileName;
|
const fileName = data.originalFileName || data.fileName;
|
||||||
try {
|
try {
|
||||||
let text = await this.git.getVersionedFileText(data.repoPath, fileName, data.sha);
|
let text = data.sha !== GitService.fakeSha
|
||||||
|
? await this.git.getVersionedFileText(data.repoPath, fileName, data.sha)
|
||||||
|
: '';
|
||||||
if (data.decoration) {
|
if (data.decoration) {
|
||||||
text = `${data.decoration}\n${text}`;
|
text = `${data.decoration}\n${text}`;
|
||||||
}
|
}
|
||||||
@@ -23,7 +25,7 @@ export class GitContentProvider implements TextDocumentContentProvider {
|
|||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
Logger.error(ex, 'GitContentProvider', 'getVersionedFileText');
|
Logger.error(ex, 'GitContentProvider', 'getVersionedFileText');
|
||||||
window.showErrorMessage(`Unable to show Git revision ${data.sha.substring(0, 8)} of '${path.relative(data.repoPath, fileName)}'`);
|
window.showErrorMessage(`Unable to show Git revision ${GitService.shortenSha(data.sha)} of '${path.relative(data.repoPath, fileName)}'`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { Functions, Iterables, Objects } from './system';
|
|||||||
import { Disposable, Event, EventEmitter, FileSystemWatcher, Location, Position, Range, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, workspace } from 'vscode';
|
import { Disposable, Event, EventEmitter, FileSystemWatcher, Location, Position, Range, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, workspace } from 'vscode';
|
||||||
import { IConfig } from './configuration';
|
import { IConfig } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey, GlyphChars } from './constants';
|
import { DocumentSchemes, ExtensionKey, GlyphChars } from './constants';
|
||||||
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitCommit, GitDiff, GitDiffChunkLine, GitDiffParser, GitLog, GitLogCommit, GitLogParser, GitRemote, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, IGit, setDefaultEncoding } from './git/git';
|
import { RemoteProviderFactory } from './git/remotes/factory';
|
||||||
|
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitBranchParser, GitCommit, GitDiff, GitDiffChunkLine, GitDiffParser, GitLog, GitLogCommit, GitLogParser, GitRemote, GitRemoteParser, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, IGit, setDefaultEncoding } from './git/git';
|
||||||
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
|
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
@@ -64,10 +65,17 @@ export const GitRepoSearchBy = {
|
|||||||
Sha: 'sha' as GitRepoSearchBy
|
Sha: 'sha' as GitRepoSearchBy
|
||||||
};
|
};
|
||||||
|
|
||||||
type RepoChangedReasons = 'stash' | 'unknown';
|
export type RepoChangedReasons = 'remotes' | 'stash' | 'unknown';
|
||||||
|
export const RepoChangedReasons = {
|
||||||
|
Remotes: 'remotes' as RepoChangedReasons,
|
||||||
|
Stash: 'stash' as RepoChangedReasons,
|
||||||
|
Unknown: 'unknown' as RepoChangedReasons
|
||||||
|
};
|
||||||
|
|
||||||
export class GitService extends Disposable {
|
export class GitService extends Disposable {
|
||||||
|
|
||||||
|
static fakeSha = 'ffffffffffffffffffffffffffffffffffffffff';
|
||||||
|
|
||||||
private _onDidBlameFail = new EventEmitter<string>();
|
private _onDidBlameFail = new EventEmitter<string>();
|
||||||
get onDidBlameFail(): Event<string> {
|
get onDidBlameFail(): Event<string> {
|
||||||
return this._onDidBlameFail.event;
|
return this._onDidBlameFail.event;
|
||||||
@@ -92,7 +100,6 @@ export class GitService extends Disposable {
|
|||||||
private _disposable: Disposable | undefined;
|
private _disposable: Disposable | undefined;
|
||||||
private _gitignore: Promise<ignore.Ignore | undefined>;
|
private _gitignore: Promise<ignore.Ignore | undefined>;
|
||||||
private _repoWatcher: FileSystemWatcher | undefined;
|
private _repoWatcher: FileSystemWatcher | undefined;
|
||||||
private _stashWatcher: FileSystemWatcher | undefined;
|
|
||||||
|
|
||||||
static EmptyPromise: Promise<GitBlame | GitDiff | GitLog | undefined> = Promise.resolve(undefined);
|
static EmptyPromise: Promise<GitBlame | GitDiff | GitLog | undefined> = Promise.resolve(undefined);
|
||||||
|
|
||||||
@@ -108,6 +115,7 @@ export class GitService extends Disposable {
|
|||||||
const subscriptions: Disposable[] = [];
|
const subscriptions: Disposable[] = [];
|
||||||
|
|
||||||
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
||||||
|
subscriptions.push(RemoteProviderFactory.onDidChange(this._onRemoteProviderChanged, this));
|
||||||
|
|
||||||
this._disposable = Disposable.from(...subscriptions);
|
this._disposable = Disposable.from(...subscriptions);
|
||||||
}
|
}
|
||||||
@@ -121,9 +129,6 @@ export class GitService extends Disposable {
|
|||||||
this._repoWatcher && this._repoWatcher.dispose();
|
this._repoWatcher && this._repoWatcher.dispose();
|
||||||
this._repoWatcher = undefined;
|
this._repoWatcher = undefined;
|
||||||
|
|
||||||
this._stashWatcher && this._stashWatcher.dispose();
|
|
||||||
this._stashWatcher = undefined;
|
|
||||||
|
|
||||||
this._gitCache.clear();
|
this._gitCache.clear();
|
||||||
this._remotesCache.clear();
|
this._remotesCache.clear();
|
||||||
this._uriCache.clear();
|
this._uriCache.clear();
|
||||||
@@ -143,8 +148,7 @@ export class GitService extends Disposable {
|
|||||||
if (cfg.advanced.caching.enabled) {
|
if (cfg.advanced.caching.enabled) {
|
||||||
this._cacheDisposable && this._cacheDisposable.dispose();
|
this._cacheDisposable && this._cacheDisposable.dispose();
|
||||||
|
|
||||||
this._repoWatcher = this._repoWatcher || workspace.createFileSystemWatcher('**/.git/index', true, false, true);
|
this._repoWatcher = this._repoWatcher || workspace.createFileSystemWatcher('**/.git/{index,HEAD,refs/stash,refs/heads/**,refs/remotes/**}');
|
||||||
this._stashWatcher = this._stashWatcher || workspace.createFileSystemWatcher('**/.git/refs/stash', true, false, true);
|
|
||||||
|
|
||||||
const disposables: Disposable[] = [];
|
const disposables: Disposable[] = [];
|
||||||
|
|
||||||
@@ -152,7 +156,6 @@ export class GitService extends Disposable {
|
|||||||
disposables.push(workspace.onDidChangeTextDocument(this._onTextDocumentChanged, this));
|
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._repoWatcher.onDidChange(this._onRepoChanged, this));
|
disposables.push(this._repoWatcher.onDidChange(this._onRepoChanged, this));
|
||||||
disposables.push(this._stashWatcher.onDidChange(this._onStashChanged, this));
|
|
||||||
|
|
||||||
this._cacheDisposable = Disposable.from(...disposables);
|
this._cacheDisposable = Disposable.from(...disposables);
|
||||||
}
|
}
|
||||||
@@ -163,9 +166,6 @@ export class GitService extends Disposable {
|
|||||||
this._repoWatcher && this._repoWatcher.dispose();
|
this._repoWatcher && this._repoWatcher.dispose();
|
||||||
this._repoWatcher = undefined;
|
this._repoWatcher = undefined;
|
||||||
|
|
||||||
this._stashWatcher && this._stashWatcher.dispose();
|
|
||||||
this._stashWatcher = undefined;
|
|
||||||
|
|
||||||
this._gitCache.clear();
|
this._gitCache.clear();
|
||||||
this._remotesCache.clear();
|
this._remotesCache.clear();
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,19 @@ export class GitService extends Disposable {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ignoreWhitespace = this.config && this.config.blame.ignoreWhitespace;
|
||||||
|
|
||||||
this.config = cfg;
|
this.config = cfg;
|
||||||
|
|
||||||
|
if (this.config.blame.ignoreWhitespace !== ignoreWhitespace) {
|
||||||
|
this._gitCache.clear();
|
||||||
|
this._fireGitCacheChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onRemoteProviderChanged() {
|
||||||
|
this._remotesCache.clear();
|
||||||
|
this._fireRepoChange(RepoChangedReasons.Remotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onTextDocumentChanged(e: TextDocumentChangeEvent) {
|
private _onTextDocumentChanged(e: TextDocumentChangeEvent) {
|
||||||
@@ -212,17 +224,19 @@ export class GitService extends Disposable {
|
|||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onRepoChanged() {
|
private _onRepoChanged(uri: Uri) {
|
||||||
|
if (uri !== undefined && uri.path.endsWith('ref/stash')) {
|
||||||
|
this._fireRepoChange('stash');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._gitCache.clear();
|
this._gitCache.clear();
|
||||||
|
|
||||||
this._fireRepoChange();
|
this._fireRepoChange();
|
||||||
this._fireGitCacheChange();
|
this._fireGitCacheChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onStashChanged() {
|
|
||||||
this._fireRepoChange('stash');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _fireGitCacheChangeDebounced: (() => void) | undefined = undefined;
|
private _fireGitCacheChangeDebounced: (() => void) | undefined = undefined;
|
||||||
|
|
||||||
private _fireGitCacheChange() {
|
private _fireGitCacheChange() {
|
||||||
@@ -277,6 +291,13 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkoutFile(uri: GitUri, sha?: string) {
|
||||||
|
sha = sha || uri.sha;
|
||||||
|
Logger.log(`checkoutFile('${uri.repoPath}', '${uri.fsPath}', ${sha})`);
|
||||||
|
|
||||||
|
return Git.checkout(uri.repoPath!, uri.fsPath, sha!);
|
||||||
|
}
|
||||||
|
|
||||||
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), resolve));
|
return await new Promise<boolean>((resolve, reject) => fs.exists(path.resolve(repoPath, fileName), resolve));
|
||||||
}
|
}
|
||||||
@@ -414,7 +435,7 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.blame(root, file, uri.sha);
|
const data = await Git.blame(root, file, uri.sha, { ignoreWhitespace: this.config.blame.ignoreWhitespace });
|
||||||
const blame = GitBlameParser.parse(data, root, file);
|
const blame = GitBlameParser.parse(data, root, file);
|
||||||
return blame;
|
return blame;
|
||||||
}
|
}
|
||||||
@@ -463,7 +484,7 @@ export class GitService extends Disposable {
|
|||||||
const fileName = uri.fsPath;
|
const fileName = uri.fsPath;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.blame(uri.repoPath, fileName, uri.sha, line + 1, line + 1);
|
const data = await Git.blame(uri.repoPath, fileName, uri.sha, { ignoreWhitespace: this.config.blame.ignoreWhitespace, startLine: line + 1, endLine: line + 1 });
|
||||||
const blame = GitBlameParser.parse(data, uri.repoPath, fileName);
|
const blame = GitBlameParser.parse(data, uri.repoPath, fileName);
|
||||||
if (blame === undefined) return undefined;
|
if (blame === undefined) return undefined;
|
||||||
|
|
||||||
@@ -561,17 +582,16 @@ export class GitService extends Disposable {
|
|||||||
async getBranch(repoPath: string): Promise<GitBranch | undefined> {
|
async getBranch(repoPath: string): Promise<GitBranch | undefined> {
|
||||||
Logger.log(`getBranch('${repoPath}')`);
|
Logger.log(`getBranch('${repoPath}')`);
|
||||||
|
|
||||||
const data = await Git.branch(repoPath, false);
|
const data = await Git.branch_current(repoPath);
|
||||||
const branches = data.split('\n').filter(_ => !!_).map(_ => new GitBranch(_));
|
const branch = data.split('\n');
|
||||||
return branches.find(_ => _.current);
|
return new GitBranch(repoPath, branch[0], true, branch[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBranches(repoPath: string): Promise<GitBranch[]> {
|
async getBranches(repoPath: string): Promise<GitBranch[]> {
|
||||||
Logger.log(`getBranches('${repoPath}')`);
|
Logger.log(`getBranches('${repoPath}')`);
|
||||||
|
|
||||||
const data = await Git.branch(repoPath, true);
|
const data = await Git.branch(repoPath, { all: true });
|
||||||
const branches = data.split('\n').filter(_ => !!_).map(_ => new GitBranch(_));
|
return GitBranchParser.parse(data, repoPath) || [];
|
||||||
return branches;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCacheEntryKey(fileName: string): string;
|
getCacheEntryKey(fileName: string): string;
|
||||||
@@ -890,7 +910,7 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await Git.remote(repoPath);
|
const data = await Git.remote(repoPath);
|
||||||
const remotes = data.split('\n').filter(_ => !!_).map(_ => new GitRemote(_));
|
const remotes = GitRemoteParser.parse(data, repoPath);
|
||||||
if (this.UseCaching) {
|
if (this.UseCaching) {
|
||||||
this._remotesCache.set(repoPath, remotes);
|
this._remotesCache.set(repoPath, remotes);
|
||||||
}
|
}
|
||||||
@@ -951,6 +971,8 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', ${sha})`);
|
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', ${sha})`);
|
||||||
|
|
||||||
const file = await Git.getVersionedFile(repoPath, fileName, sha);
|
const file = await Git.getVersionedFile(repoPath, fileName, sha);
|
||||||
|
if (file === undefined) return undefined;
|
||||||
|
|
||||||
const cacheKey = this.getCacheEntryKey(file);
|
const cacheKey = this.getCacheEntryKey(file);
|
||||||
const entry = new UriCacheEntry(new GitUri(Uri.file(fileName), { sha, repoPath: repoPath!, fileName }));
|
const entry = new UriCacheEntry(new GitUri(Uri.file(fileName), { sha, repoPath: repoPath!, fileName }));
|
||||||
this._uriCache.set(cacheKey, entry);
|
this._uriCache.set(cacheKey, entry);
|
||||||
@@ -1014,10 +1036,12 @@ export class GitService extends Disposable {
|
|||||||
return Git.stash_delete(repoPath, stashName);
|
return Git.stash_delete(repoPath, stashName);
|
||||||
}
|
}
|
||||||
|
|
||||||
stashSave(repoPath: string, message?: string, unstagedOnly: boolean = false) {
|
stashSave(repoPath: string, message?: string, uris?: Uri[]) {
|
||||||
Logger.log(`stashSave('${repoPath}', ${message}, ${unstagedOnly})`);
|
Logger.log(`stashSave('${repoPath}', ${message}, ${uris})`);
|
||||||
|
|
||||||
return Git.stash_save(repoPath, message, unstagedOnly);
|
if (uris === undefined) return Git.stash_save(repoPath, message);
|
||||||
|
const pathspecs = uris.map(u => Git.splitPath(u.fsPath, repoPath)[0]);
|
||||||
|
return Git.stash_push(repoPath, pathspecs, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getGitPath(gitPath?: string): Promise<IGit> {
|
static getGitPath(gitPath?: string): Promise<IGit> {
|
||||||
@@ -1056,11 +1080,17 @@ export class GitService extends Disposable {
|
|||||||
return Git.normalizePath(fileName, repoPath);
|
return Git.normalizePath(fileName, repoPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static toGitContentUri(sha: string, shortSha: string, fileName: string, repoPath: string, originalFileName?: string): Uri;
|
static shortenSha(sha: string | undefined) {
|
||||||
|
if (sha === undefined) return undefined;
|
||||||
|
return Git.shortenSha(sha);
|
||||||
|
}
|
||||||
|
|
||||||
|
static toGitContentUri(sha: string, fileName: string, repoPath: string, originalFileName?: string): Uri;
|
||||||
static toGitContentUri(commit: GitCommit): Uri;
|
static toGitContentUri(commit: GitCommit): Uri;
|
||||||
static toGitContentUri(uri: GitUri): Uri;
|
static toGitContentUri(uri: GitUri): Uri;
|
||||||
static toGitContentUri(shaOrcommitOrUri: string | GitCommit | GitUri, shortSha?: string, fileName?: string, repoPath?: string, originalFileName?: string): Uri {
|
static toGitContentUri(shaOrcommitOrUri: string | GitCommit | GitUri, fileName?: string, repoPath?: string, originalFileName?: string): Uri {
|
||||||
let data: IGitUriData;
|
let data: IGitUriData;
|
||||||
|
let shortSha: string | undefined;
|
||||||
if (typeof shaOrcommitOrUri === 'string') {
|
if (typeof shaOrcommitOrUri === 'string') {
|
||||||
data = GitService._toGitUriData({
|
data = GitService._toGitUriData({
|
||||||
sha: shaOrcommitOrUri,
|
sha: shaOrcommitOrUri,
|
||||||
@@ -1068,6 +1098,7 @@ export class GitService extends Disposable {
|
|||||||
repoPath: repoPath!,
|
repoPath: repoPath!,
|
||||||
originalFileName: originalFileName
|
originalFileName: originalFileName
|
||||||
});
|
});
|
||||||
|
shortSha = GitService.shortenSha(shaOrcommitOrUri);
|
||||||
}
|
}
|
||||||
else if (shaOrcommitOrUri instanceof GitCommit) {
|
else if (shaOrcommitOrUri instanceof GitCommit) {
|
||||||
data = GitService._toGitUriData(shaOrcommitOrUri, undefined, shaOrcommitOrUri.originalFileName);
|
data = GitService._toGitUriData(shaOrcommitOrUri, undefined, shaOrcommitOrUri.originalFileName);
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ export type SuppressedKeys = 'suppressCommitHasNoPreviousCommitWarning' |
|
|||||||
'suppressGitVersionWarning' |
|
'suppressGitVersionWarning' |
|
||||||
'suppressLineUncommittedWarning' |
|
'suppressLineUncommittedWarning' |
|
||||||
'suppressNoRepositoryWarning' |
|
'suppressNoRepositoryWarning' |
|
||||||
'suppressUpdateNotice';
|
'suppressUpdateNotice' |
|
||||||
|
'suppressWelcomeNotice';
|
||||||
export const SuppressedKeys = {
|
export const SuppressedKeys = {
|
||||||
CommitHasNoPreviousCommitWarning: 'suppressCommitHasNoPreviousCommitWarning' as SuppressedKeys,
|
CommitHasNoPreviousCommitWarning: 'suppressCommitHasNoPreviousCommitWarning' as SuppressedKeys,
|
||||||
CommitNotFoundWarning: 'suppressCommitNotFoundWarning' as SuppressedKeys,
|
CommitNotFoundWarning: 'suppressCommitNotFoundWarning' as SuppressedKeys,
|
||||||
@@ -19,7 +20,8 @@ export const SuppressedKeys = {
|
|||||||
GitVersionWarning: 'suppressGitVersionWarning' as SuppressedKeys,
|
GitVersionWarning: 'suppressGitVersionWarning' as SuppressedKeys,
|
||||||
LineUncommittedWarning: 'suppressLineUncommittedWarning' as SuppressedKeys,
|
LineUncommittedWarning: 'suppressLineUncommittedWarning' as SuppressedKeys,
|
||||||
NoRepositoryWarning: 'suppressNoRepositoryWarning' as SuppressedKeys,
|
NoRepositoryWarning: 'suppressNoRepositoryWarning' as SuppressedKeys,
|
||||||
UpdateNotice: 'suppressUpdateNotice' as SuppressedKeys
|
UpdateNotice: 'suppressUpdateNotice' as SuppressedKeys,
|
||||||
|
WelcomeNotice: 'suppressWelcomeNotice' as SuppressedKeys
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Messages {
|
export class Messages {
|
||||||
@@ -30,7 +32,8 @@ export class Messages {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static showCommitHasNoPreviousCommitWarningMessage(commit: GitCommit): Promise<string | undefined> {
|
static showCommitHasNoPreviousCommitWarningMessage(commit?: GitCommit): Promise<string | undefined> {
|
||||||
|
if (commit === undefined) return Messages._showMessage('info', `Commit has no previous commit`, SuppressedKeys.CommitHasNoPreviousCommitWarning);
|
||||||
return Messages._showMessage('info', `Commit ${commit.shortSha} (${commit.author}, ${moment(commit.date).fromNow()}) has no previous commit`, SuppressedKeys.CommitHasNoPreviousCommitWarning);
|
return Messages._showMessage('info', `Commit ${commit.shortSha} (${commit.author}, ${moment(commit.date).fromNow()}) has no previous commit`, SuppressedKeys.CommitHasNoPreviousCommitWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +68,7 @@ export class Messages {
|
|||||||
|
|
||||||
static async showWelcomeMessage(): Promise<string | undefined> {
|
static async showWelcomeMessage(): Promise<string | undefined> {
|
||||||
const viewDocs = 'View Docs';
|
const viewDocs = 'View Docs';
|
||||||
const result = await window.showInformationMessage(`Thank you for choosing GitLens! GitLens is powerful, feature rich, and highly configurable, so please be sure to view the docs and tailor it to suit your needs.`, viewDocs);
|
const result = await Messages._showMessage('info', `Thank you for choosing GitLens! GitLens is powerful, feature rich, and highly configurable, so please be sure to view the docs and tailor it to suit your needs.`, SuppressedKeys.WelcomeNotice, null, viewDocs);
|
||||||
if (result === viewDocs) {
|
if (result === viewDocs) {
|
||||||
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens'));
|
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens'));
|
||||||
}
|
}
|
||||||
@@ -73,7 +76,7 @@ export class Messages {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static async _showMessage(type: 'info' | 'warn' | 'error', message: string, suppressionKey: SuppressedKeys, dontShowAgain: string | null = 'Don\'t Show Again', ...actions: any[]): Promise<string | undefined> {
|
private static async _showMessage(type: 'info' | 'warn' | 'error', message: string, suppressionKey: SuppressedKeys, dontShowAgain: string | null = 'Don\'t Show Again', ...actions: any[]): Promise<string | undefined> {
|
||||||
Logger.log(`ShowMessage(${type}, "${message}", ${suppressionKey}, ${dontShowAgain})`);
|
Logger.log(`ShowMessage(${type}, '${message}', ${suppressionKey}, ${dontShowAgain})`);
|
||||||
|
|
||||||
if (Messages.context.globalState.get(suppressionKey, false)) {
|
if (Messages.context.globalState.get(suppressionKey, false)) {
|
||||||
Logger.log(`ShowMessage(${type}, ${message}, ${suppressionKey}, ${dontShowAgain}) skipped`);
|
Logger.log(`ShowMessage(${type}, ${message}, ${suppressionKey}, ${dontShowAgain}) skipped`);
|
||||||
@@ -100,12 +103,13 @@ export class Messages {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dontShowAgain === null || result === dontShowAgain) {
|
if (dontShowAgain === null || result === dontShowAgain) {
|
||||||
Logger.log(`ShowMessage(${type}, ${message}, ${suppressionKey}, ${dontShowAgain}) don't show again requested`);
|
Logger.log(`ShowMessage(${type}, '${message}', ${suppressionKey}, ${dontShowAgain}) don't show again requested`);
|
||||||
await Messages.context.globalState.update(suppressionKey, true);
|
await Messages.context.globalState.update(suppressionKey, true);
|
||||||
return undefined;
|
|
||||||
|
if (result === dontShowAgain) return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.log(`ShowMessage(${type}, ${message}, ${suppressionKey}, ${dontShowAgain}) returned ${result}`);
|
Logger.log(`ShowMessage(${type}, '${message}', ${suppressionKey}, ${dontShowAgain}) returned ${result}`);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays, Iterables, Strings } from '../system';
|
import { Iterables, Strings } from '../system';
|
||||||
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, ShowCommitSearchCommandArgs, ShowQuickBranchHistoryCommandArgs } from '../commands';
|
import { Commands, ShowCommitSearchCommandArgs, ShowQuickBranchHistoryCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
||||||
@@ -35,7 +35,7 @@ export class BranchHistoryQuickPick {
|
|||||||
} as ShowQuickBranchHistoryCommandArgs
|
} as ShowQuickBranchHistoryCommandArgs
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const remotes = Arrays.uniqueBy(await git.getRemotes((uri && uri.repoPath) || git.repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await git.getRemotes((uri && uri.repoPath) || git.repoPath)).filter(r => r.provider !== undefined);
|
||||||
if (remotes.length) {
|
if (remotes.length) {
|
||||||
items.splice(0, 0, new OpenRemotesCommandQuickPickItem(remotes, {
|
items.splice(0, 0, new OpenRemotesCommandQuickPickItem(remotes, {
|
||||||
type: 'branch',
|
type: 'branch',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays, Iterables, Strings } from '../system';
|
import { Iterables, Strings } from '../system';
|
||||||
import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from 'vscode';
|
import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffDirectoryCommandCommandArgs, DiffWithPreviousCommandArgs, ShowQuickCommitDetailsCommandArgs, StashApplyCommandArgs, StashDeleteCommandArgs } from '../commands';
|
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffDirectoryCommandCommandArgs, DiffWithPreviousCommandArgs, ShowQuickCommitDetailsCommandArgs, StashApplyCommandArgs, StashDeleteCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem, QuickPickItem } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem, QuickPickItem } from './common';
|
||||||
@@ -24,17 +24,14 @@ export class CommitWithFileStatusQuickPickItem extends OpenFileCommandQuickPickI
|
|||||||
const description = GitStatusFile.getFormattedDirectory(status, true);
|
const description = GitStatusFile.getFormattedDirectory(status, true);
|
||||||
|
|
||||||
let sha;
|
let sha;
|
||||||
let shortSha;
|
|
||||||
if (status.status === 'D') {
|
if (status.status === 'D') {
|
||||||
sha = commit.previousSha!;
|
sha = commit.previousSha!;
|
||||||
shortSha = commit.previousShortSha!;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sha = commit.sha;
|
sha = commit.sha;
|
||||||
shortSha = commit.shortSha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super(GitService.toGitContentUri(sha, shortSha, status.fileName, commit.repoPath, status.originalFileName), {
|
super(GitService.toGitContentUri(sha, status.fileName, commit.repoPath, status.originalFileName), {
|
||||||
label: `${Strings.pad(octicon, 4, 2)} ${path.basename(status.fileName)}`,
|
label: `${Strings.pad(octicon, 4, 2)} ${path.basename(status.fileName)}`,
|
||||||
description: description
|
description: description
|
||||||
});
|
});
|
||||||
@@ -48,7 +45,7 @@ export class CommitWithFileStatusQuickPickItem extends OpenFileCommandQuickPickI
|
|||||||
originalFileName: status.originalFileName
|
originalFileName: status.originalFileName
|
||||||
} as IGitCommitInfo);
|
} as IGitCommitInfo);
|
||||||
this.sha = sha;
|
this.sha = sha;
|
||||||
this.shortSha = shortSha;
|
this.shortSha = GitService.shortenSha(sha)!;
|
||||||
this.status = status.status;
|
this.status = status.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +85,7 @@ export class OpenCommitFileRevisionsCommandQuickPickItem extends OpenFilesComman
|
|||||||
constructor(commit: GitLogCommit, item?: QuickPickItem) {
|
constructor(commit: GitLogCommit, item?: QuickPickItem) {
|
||||||
const uris = commit.fileStatuses
|
const uris = commit.fileStatuses
|
||||||
.filter(s => s.status !== 'D')
|
.filter(s => s.status !== 'D')
|
||||||
.map(s => GitService.toGitContentUri(commit.sha, commit.shortSha, s.fileName, commit.repoPath, s.originalFileName));
|
.map(s => GitService.toGitContentUri(commit.sha, s.fileName, commit.repoPath, s.originalFileName));
|
||||||
|
|
||||||
super(uris, item || {
|
super(uris, item || {
|
||||||
label: `$(file-symlink-file) Open Changed Revisions`,
|
label: `$(file-symlink-file) Open Changed Revisions`,
|
||||||
@@ -156,7 +153,7 @@ export class CommitDetailsQuickPick {
|
|||||||
]));
|
]));
|
||||||
|
|
||||||
if (!stash) {
|
if (!stash) {
|
||||||
const remotes = Arrays.uniqueBy(await git.getRemotes(commit.repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await git.getRemotes(commit.repoPath)).filter(r => r.provider !== undefined);
|
||||||
if (remotes.length) {
|
if (remotes.length) {
|
||||||
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, {
|
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, {
|
||||||
type: 'commit',
|
type: 'commit',
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays, Iterables, Strings } from '../system';
|
import { Iterables, Strings } from '../system';
|
||||||
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
|
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './common';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
import { GitBranch, GitLog, GitLogCommit, GitService, GitUri, RemoteResource } from '../gitService';
|
import { GitLog, GitLogCommit, GitService, GitUri, RemoteResource } from '../gitService';
|
||||||
import { Keyboard, KeyCommand, KeyNoopCommand } from '../keyboard';
|
import { Keyboard, KeyCommand, KeyNoopCommand } from '../keyboard';
|
||||||
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
@@ -27,7 +27,7 @@ export class OpenCommitFileRevisionCommandQuickPickItem extends OpenFileCommandQ
|
|||||||
let description: string;
|
let description: string;
|
||||||
let uri: Uri;
|
let uri: Uri;
|
||||||
if (commit.status === 'D') {
|
if (commit.status === 'D') {
|
||||||
uri = GitService.toGitContentUri(commit.previousSha!, commit.previousShortSha!, commit.previousFileName!, commit.repoPath, undefined);
|
uri = GitService.toGitContentUri(commit.previousSha!, commit.previousFileName!, commit.repoPath, undefined);
|
||||||
description = `${Strings.pad(GlyphChars.Dash, 2, 3)} ${path.basename(commit.fileName)} in ${GlyphChars.Space}$(git-commit) ${commit.previousShortSha} (deleted in ${GlyphChars.Space}$(git-commit) ${commit.shortSha})`;
|
description = `${Strings.pad(GlyphChars.Dash, 2, 3)} ${path.basename(commit.fileName)} in ${GlyphChars.Space}$(git-commit) ${commit.previousShortSha} (deleted in ${GlyphChars.Space}$(git-commit) ${commit.shortSha})`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -125,14 +125,14 @@ export class CommitFileDetailsQuickPick {
|
|||||||
}
|
}
|
||||||
items.push(new OpenCommitFileRevisionCommandQuickPickItem(commit));
|
items.push(new OpenCommitFileRevisionCommandQuickPickItem(commit));
|
||||||
|
|
||||||
const remotes = Arrays.uniqueBy(await git.getRemotes(commit.repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = (await git.getRemotes(commit.repoPath)).filter(r => r.provider !== undefined);
|
||||||
if (remotes.length) {
|
if (remotes.length) {
|
||||||
if (commit.workingFileName && commit.status !== 'D') {
|
if (commit.workingFileName && commit.status !== 'D') {
|
||||||
const branch = await git.getBranch(commit.repoPath || git.repoPath) as GitBranch;
|
const branch = await git.getBranch(commit.repoPath || git.repoPath);
|
||||||
items.push(new OpenRemotesCommandQuickPickItem(remotes, {
|
items.push(new OpenRemotesCommandQuickPickItem(remotes, {
|
||||||
type: 'file',
|
type: 'file',
|
||||||
fileName: commit.workingFileName,
|
fileName: commit.workingFileName,
|
||||||
branch: branch.name
|
branch: branch!.name
|
||||||
} as RemoteResource, currentCommand));
|
} as RemoteResource, currentCommand));
|
||||||
}
|
}
|
||||||
if (!stash) {
|
if (!stash) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays, Iterables, Strings } from '../system';
|
import { Iterables, Strings } from '../system';
|
||||||
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, ShowQuickCurrentBranchHistoryCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
import { Commands, ShowQuickCurrentBranchHistoryCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
||||||
@@ -136,7 +136,7 @@ export class FileHistoryQuickPick {
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const remotes = Arrays.uniqueBy(await git.getRemotes(uri.repoPath!), _ => _.url, _ => !!_.provider);
|
const remotes = (await git.getRemotes(uri.repoPath!)).filter(r => r.provider !== undefined);
|
||||||
if (remotes.length) {
|
if (remotes.length) {
|
||||||
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, {
|
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, {
|
||||||
type: 'revision',
|
type: 'revision',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { QuickPickOptions, window } from 'vscode';
|
|||||||
import { Commands, OpenInRemoteCommandArgs } from '../commands';
|
import { Commands, OpenInRemoteCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './common';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
import { getNameFromRemoteResource, GitLogCommit, GitRemote, RemoteResource } from '../gitService';
|
import { getNameFromRemoteResource, GitLogCommit, GitRemote, GitService, RemoteResource } from '../gitService';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export class OpenRemoteCommandQuickPickItem extends CommandQuickPickItem {
|
export class OpenRemoteCommandQuickPickItem extends CommandQuickPickItem {
|
||||||
@@ -38,8 +38,12 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
|
|||||||
description = `$(git-branch) ${resource.branch}`;
|
description = `$(git-branch) ${resource.branch}`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'branches':
|
||||||
|
description = `$(git-branch) Branches`;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'commit':
|
case 'commit':
|
||||||
const shortSha = resource.sha.substring(0, 8);
|
const shortSha = GitService.shortenSha(resource.sha);
|
||||||
description = `$(git-commit) ${shortSha}`;
|
description = `$(git-commit) ${shortSha}`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -63,7 +67,7 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const shortFileSha = resource.sha === undefined ? '' : resource.sha.substring(0, 8);
|
const shortFileSha = resource.sha === undefined ? '' : GitService.shortenSha(resource.sha);
|
||||||
description = `$(file-text) ${path.basename(resource.fileName)}${shortFileSha ? ` in ${GlyphChars.Space}$(git-commit) ${shortFileSha}` : ''}`;
|
description = `$(file-text) ${path.basename(resource.fileName)}${shortFileSha ? ` in ${GlyphChars.Space}$(git-commit) ${shortFileSha}` : ''}`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from
|
|||||||
import { Commands, DiffWithWorkingCommandArgs, OpenChangedFilesCommandArgs, ShowQuickBranchHistoryCommandArgs, ShowQuickRepoStatusCommandArgs, ShowQuickStashListCommandArgs } from '../commands';
|
import { Commands, DiffWithWorkingCommandArgs, OpenChangedFilesCommandArgs, ShowQuickBranchHistoryCommandArgs, ShowQuickRepoStatusCommandArgs, ShowQuickStashListCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem, QuickPickItem } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem, QuickPickItem } from './common';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
import { GitStatus, GitStatusFile, GitUri } from '../gitService';
|
import { GitService, GitStatus, GitStatusFile, GitUri } from '../gitService';
|
||||||
import { Keyboard, Keys } from '../keyboard';
|
import { Keyboard, Keys } from '../keyboard';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ export class RepoStatusQuickPick {
|
|||||||
}
|
}
|
||||||
|
|
||||||
items.splice(0, 0, new CommandQuickPickItem({
|
items.splice(0, 0, new CommandQuickPickItem({
|
||||||
label: `$(repo) Show Stashed Changes`,
|
label: `$(inbox) Show Stashed Changes`,
|
||||||
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows stashed changes in the repository`
|
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows stashed changes in the repository`
|
||||||
}, Commands.ShowQuickStashList, [
|
}, Commands.ShowQuickStashList, [
|
||||||
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath }),
|
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath }),
|
||||||
@@ -182,7 +182,7 @@ export class RepoStatusQuickPick {
|
|||||||
if (status.upstream && status.state.behind) {
|
if (status.upstream && status.state.behind) {
|
||||||
items.splice(0, 0, new CommandQuickPickItem({
|
items.splice(0, 0, new CommandQuickPickItem({
|
||||||
label: `$(cloud-download)${GlyphChars.Space} ${status.state.behind} Commit${status.state.behind > 1 ? 's' : ''} behind ${GlyphChars.Space}$(git-branch) ${status.upstream}`,
|
label: `$(cloud-download)${GlyphChars.Space} ${status.state.behind} Commit${status.state.behind > 1 ? 's' : ''} behind ${GlyphChars.Space}$(git-branch) ${status.upstream}`,
|
||||||
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows commits in ${GlyphChars.Space}$(git-branch) ${status.upstream} but not ${GlyphChars.Space}$(git-branch) ${status.branch}${status.sha ? ` (since ${GlyphChars.Space}$(git-commit) ${status.sha.substring(0, 8)})` : ''}`
|
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} shows commits in ${GlyphChars.Space}$(git-branch) ${status.upstream} but not ${GlyphChars.Space}$(git-branch) ${status.branch}${status.sha ? ` (since ${GlyphChars.Space}$(git-commit) ${GitService.shortenSha(status.sha)})` : ''}`
|
||||||
}, Commands.ShowQuickBranchHistory, [
|
}, Commands.ShowQuickBranchHistory, [
|
||||||
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath, sha: `${status.branch}..${status.upstream}` }),
|
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath, sha: `${status.branch}..${status.upstream}` }),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,21 +14,10 @@ export class StashListQuickPick {
|
|||||||
|
|
||||||
if (mode === 'list') {
|
if (mode === 'list') {
|
||||||
items.splice(0, 0, new CommandQuickPickItem({
|
items.splice(0, 0, new CommandQuickPickItem({
|
||||||
label: `$(repo-push) Stash Unstaged Changes`,
|
label: `$(plus) Stash Changes`,
|
||||||
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} stashes only unstaged changes`
|
|
||||||
}, Commands.StashSave, [
|
|
||||||
{
|
|
||||||
unstagedOnly: true,
|
|
||||||
goBackCommand: currentCommand
|
|
||||||
} as StashSaveCommandArgs
|
|
||||||
]));
|
|
||||||
|
|
||||||
items.splice(0, 0, new CommandQuickPickItem({
|
|
||||||
label: `$(repo-force-push) Stash Changes`,
|
|
||||||
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} stashes all changes`
|
description: `${Strings.pad(GlyphChars.Dash, 2, 3)} stashes all changes`
|
||||||
}, Commands.StashSave, [
|
}, Commands.StashSave, [
|
||||||
{
|
{
|
||||||
unstagedOnly: false,
|
|
||||||
goBackCommand: currentCommand
|
goBackCommand: currentCommand
|
||||||
} as StashSaveCommandArgs
|
} as StashSaveCommandArgs
|
||||||
]));
|
]));
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export namespace Arrays {
|
export namespace Arrays {
|
||||||
|
export function groupBy<T>(array: T[], accessor: (item: T) => any): T[] {
|
||||||
|
return array.reduce((previous, current) => {
|
||||||
|
const value = accessor(current);
|
||||||
|
previous[value] = previous[value] || [];
|
||||||
|
previous[value].push(current);
|
||||||
|
return previous;
|
||||||
|
}, Object.create(null));
|
||||||
|
}
|
||||||
|
|
||||||
export function uniqueBy<T>(array: T[], accessor: (item: T) => any, predicate?: (item: T) => boolean): T[] {
|
export function uniqueBy<T>(array: T[], accessor: (item: T) => any, predicate?: (item: T) => boolean): T[] {
|
||||||
const uniqueValues = Object.create(null);
|
const uniqueValues = Object.create(null);
|
||||||
return array.filter(_ => {
|
return array.filter(_ => {
|
||||||
|
|||||||
@@ -101,12 +101,20 @@ export namespace Strings {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function truncate(s: string, truncateTo?: number) {
|
// Removes \ / : * ? " < > | and C0 and C1 control codes
|
||||||
if (!s || truncateTo === undefined) return s;
|
const illegalCharsForFSRegEx = /[\\/:*?"<>|\x00-\x1f\x80-\x9f]/g;
|
||||||
|
|
||||||
|
export function sanitizeForFS(s: string, replacement: string = '_') {
|
||||||
|
if (!s) return s;
|
||||||
|
return s.replace(illegalCharsForFSRegEx, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function truncate(s: string, truncateTo: number, ellipsis: string = '\u2026') {
|
||||||
|
if (!s) return s;
|
||||||
|
|
||||||
const len = getWidth(s);
|
const len = getWidth(s);
|
||||||
if (len <= truncateTo) return s;
|
if (len <= truncateTo) return s;
|
||||||
if (len === s.length) return `${s.substring(0, truncateTo - 1)}\u2026`;
|
if (len === s.length) return `${s.substring(0, truncateTo - 1)}${ellipsis}`;
|
||||||
|
|
||||||
// Skip ahead to start as far as we can by assuming all the double-width characters won't be truncated
|
// Skip ahead to start as far as we can by assuming all the double-width characters won't be truncated
|
||||||
let chars = Math.floor(truncateTo / (len / s.length));
|
let chars = Math.floor(truncateTo / (len / s.length));
|
||||||
@@ -119,6 +127,6 @@ export namespace Strings {
|
|||||||
chars--;
|
chars--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${s.substring(0, chars)}\u2026`;
|
return `${s.substring(0, chars)}${ellipsis}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,30 +3,36 @@ import { Iterables } from '../system';
|
|||||||
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
||||||
import { CommitNode } from './commitNode';
|
import { CommitNode } from './commitNode';
|
||||||
import { GlyphChars } from '../constants';
|
import { GlyphChars } from '../constants';
|
||||||
import { ExplorerNode, ResourceType } from './explorerNode';
|
import { ExplorerNode, ResourceType, ShowAllCommitsNode } from './explorerNode';
|
||||||
import { GitBranch, GitRemote, GitService, GitUri } from '../gitService';
|
import { GitBranch, GitService, GitUri } from '../gitService';
|
||||||
|
|
||||||
export class BranchHistoryNode extends ExplorerNode {
|
export class BranchHistoryNode extends ExplorerNode {
|
||||||
|
|
||||||
readonly resourceType: ResourceType = 'gitlens:branch-history';
|
readonly resourceType: ResourceType = 'gitlens:branch-history';
|
||||||
|
|
||||||
constructor(public readonly branch: GitBranch, private readonly remote: GitRemote | undefined, uri: GitUri, private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService) {
|
maxCount: number | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(public readonly branch: GitBranch, uri: GitUri, private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService) {
|
||||||
super(uri);
|
super(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getChildren(): Promise<ExplorerNode[]> {
|
async getChildren(): Promise<ExplorerNode[]> {
|
||||||
const log = await this.git.getLogForRepo(this.uri.repoPath!, this.branch.name);
|
const log = await this.git.getLogForRepo(this.uri.repoPath!, this.branch.name, this.maxCount);
|
||||||
if (log === undefined) return [];
|
if (log === undefined) return [];
|
||||||
|
|
||||||
return [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.template, this.context, this.git))];
|
const children = Iterables.map(log.commits.values(), c => new CommitNode(c, this.template, this.context, this.git, this.branch));
|
||||||
|
if (!log.truncated) return [...children];
|
||||||
|
|
||||||
|
return [...children, new ShowAllCommitsNode(this, this.context)];
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTreeItem(): Promise<TreeItem> {
|
async getTreeItem(): Promise<TreeItem> {
|
||||||
const name = this.remote !== undefined
|
let name = this.branch.getName();
|
||||||
? this.branch.name.substring(this.remote.name.length + 1)
|
if (!this.branch.remote && this.branch.tracking !== undefined && this.git.config.gitExplorer.showTrackingBranch) {
|
||||||
: this.branch.name;
|
name += ` ${GlyphChars.Space}${GlyphChars.ArrowLeftRight}${GlyphChars.Space} ${this.branch.tracking}`;
|
||||||
const item = new TreeItem(`${name}${this.branch!.current ? ` ${GlyphChars.Space} ${GlyphChars.Check}` : ''}`, TreeItemCollapsibleState.Collapsed);
|
}
|
||||||
item.contextValue = this.resourceType;
|
const item = new TreeItem(`${this.branch!.current ? `${GlyphChars.Check} ${GlyphChars.Space}` : ''}${name}`, TreeItemCollapsibleState.Collapsed);
|
||||||
|
item.contextValue = this.branch.tracking ? `${this.resourceType}:remote` : this.resourceType;
|
||||||
|
|
||||||
item.iconPath = {
|
item.iconPath = {
|
||||||
dark: this.context.asAbsolutePath('images/dark/icon-branch.svg'),
|
dark: this.context.asAbsolutePath('images/dark/icon-branch.svg'),
|
||||||
|
|||||||
@@ -18,12 +18,16 @@ export class BranchesNode extends ExplorerNode {
|
|||||||
if (branches === undefined) return [];
|
if (branches === undefined) return [];
|
||||||
|
|
||||||
branches.sort((a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || a.name.localeCompare(b.name));
|
branches.sort((a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || a.name.localeCompare(b.name));
|
||||||
return [...Iterables.filterMap(branches, b => b.remote ? undefined : new BranchHistoryNode(b, undefined, this.uri, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
|
return [...Iterables.filterMap(branches, b => b.remote ? undefined : new BranchHistoryNode(b, this.uri, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTreeItem(): TreeItem {
|
async getTreeItem(): Promise<TreeItem> {
|
||||||
const item = new TreeItem(`Branches`, TreeItemCollapsibleState.Expanded);
|
const item = new TreeItem(`Branches`, TreeItemCollapsibleState.Expanded);
|
||||||
item.contextValue = this.resourceType;
|
|
||||||
|
const remotes = await this.git.getRemotes(this.uri.repoPath!);
|
||||||
|
item.contextValue = (remotes !== undefined && remotes.length > 0)
|
||||||
|
? `${this.resourceType}:remote`
|
||||||
|
: this.resourceType;
|
||||||
|
|
||||||
item.iconPath = {
|
item.iconPath = {
|
||||||
dark: this.context.asAbsolutePath('images/dark/icon-branch.svg'),
|
dark: this.context.asAbsolutePath('images/dark/icon-branch.svg'),
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
|
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
|
||||||
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
|
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
|
||||||
import { ExplorerNode, ResourceType } from './explorerNode';
|
import { ExplorerNode, ResourceType } from './explorerNode';
|
||||||
import { getGitStatusIcon, GitCommit, GitService, GitUri, IGitStatusFile, StatusFileFormatter } from '../gitService';
|
import { getGitStatusIcon, GitBranch, GitCommit, GitService, GitUri, IGitStatusFile, StatusFileFormatter } from '../gitService';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export class CommitFileNode extends ExplorerNode {
|
export class CommitFileNode extends ExplorerNode {
|
||||||
|
|
||||||
readonly resourceType: ResourceType = 'gitlens:commit-file';
|
readonly resourceType: ResourceType = 'gitlens:commit-file';
|
||||||
|
|
||||||
constructor(public readonly status: IGitStatusFile, public commit: GitCommit, protected readonly context: ExtensionContext, protected readonly git: GitService) {
|
constructor(public readonly status: IGitStatusFile, public commit: GitCommit, protected readonly context: ExtensionContext, protected readonly git: GitService, public readonly branch?: GitBranch) {
|
||||||
super(new GitUri(Uri.file(path.resolve(commit.repoPath, status.fileName)), { repoPath: commit.repoPath, fileName: status.fileName, sha: commit.sha }));
|
super(new GitUri(Uri.file(path.resolve(commit.repoPath, status.fileName)), { repoPath: commit.repoPath, fileName: status.fileName, sha: commit.sha }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,16 +40,6 @@ export class CommitFileNode extends ExplorerNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCommand(): Command | undefined {
|
getCommand(): Command | undefined {
|
||||||
let allowMissingPrevious = false;
|
|
||||||
let prefix = undefined;
|
|
||||||
if (this.status.status === 'A') {
|
|
||||||
allowMissingPrevious = true;
|
|
||||||
prefix = 'added in ';
|
|
||||||
}
|
|
||||||
else if (this.status.status === 'D') {
|
|
||||||
prefix = 'deleted in ';
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: 'Compare File with Previous Revision',
|
title: 'Compare File with Previous Revision',
|
||||||
command: Commands.DiffWithPrevious,
|
command: Commands.DiffWithPrevious,
|
||||||
@@ -61,9 +51,7 @@ export class CommitFileNode extends ExplorerNode {
|
|||||||
showOptions: {
|
showOptions: {
|
||||||
preserveFocus: true,
|
preserveFocus: true,
|
||||||
preview: true
|
preview: true
|
||||||
},
|
}
|
||||||
allowMissingPrevious: allowMissingPrevious,
|
|
||||||
rightTitlePrefix: prefix
|
|
||||||
} as DiffWithPreviousCommandArgs
|
} as DiffWithPreviousCommandArgs
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'v
|
|||||||
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
|
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
|
||||||
import { CommitFileNode } from './commitFileNode';
|
import { CommitFileNode } from './commitFileNode';
|
||||||
import { ExplorerNode, ResourceType } from './explorerNode';
|
import { ExplorerNode, ResourceType } from './explorerNode';
|
||||||
import { CommitFormatter, GitLogCommit, GitService, GitUri } from '../gitService';
|
import { CommitFormatter, getGitStatusIcon, GitBranch, GitLogCommit, GitService, GitUri, ICommitFormatOptions } from '../gitService';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
export class CommitNode extends ExplorerNode {
|
export class CommitNode extends ExplorerNode {
|
||||||
|
|
||||||
readonly resourceType: ResourceType = 'gitlens:commit';
|
readonly resourceType: ResourceType = 'gitlens:commit';
|
||||||
|
|
||||||
constructor(public readonly commit: GitLogCommit, private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService) {
|
constructor(public readonly commit: GitLogCommit, private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService, public readonly branch?: GitBranch) {
|
||||||
super(new GitUri(commit.uri, commit));
|
super(new GitUri(commit.uri, commit));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,42 +24,41 @@ export class CommitNode extends ExplorerNode {
|
|||||||
const commit = Iterables.first(log.commits.values());
|
const commit = Iterables.first(log.commits.values());
|
||||||
if (commit === undefined) return [];
|
if (commit === undefined) return [];
|
||||||
|
|
||||||
return [...Iterables.map(commit.fileStatuses, s => new CommitFileNode(s, commit, this.context, this.git))];
|
return [...Iterables.map(commit.fileStatuses, s => new CommitFileNode(s, commit, this.context, this.git, this.branch))];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTreeItem(): TreeItem {
|
getTreeItem(): TreeItem {
|
||||||
const item = new TreeItem(CommitFormatter.fromTemplate(this.template, this.commit, this.git.config.defaultDateFormat));
|
const item = new TreeItem(CommitFormatter.fromTemplate(this.template, this.commit, {
|
||||||
|
truncateMessageAtNewLine: true,
|
||||||
|
dataFormat: this.git.config.defaultDateFormat
|
||||||
|
} as ICommitFormatOptions));
|
||||||
|
|
||||||
if (this.commit.type === 'file') {
|
if (this.commit.type === 'file') {
|
||||||
item.collapsibleState = TreeItemCollapsibleState.None;
|
item.collapsibleState = TreeItemCollapsibleState.None;
|
||||||
item.command = this.getCommand();
|
item.command = this.getCommand();
|
||||||
const resourceType: ResourceType = 'gitlens:commit-file';
|
const resourceType: ResourceType = 'gitlens:commit-file';
|
||||||
item.contextValue = resourceType;
|
item.contextValue = resourceType;
|
||||||
|
|
||||||
|
const icon = getGitStatusIcon(this.commit.status!);
|
||||||
|
item.iconPath = {
|
||||||
|
dark: this.context.asAbsolutePath(path.join('images', 'dark', icon)),
|
||||||
|
light: this.context.asAbsolutePath(path.join('images', 'light', icon))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
item.collapsibleState = TreeItemCollapsibleState.Collapsed;
|
item.collapsibleState = TreeItemCollapsibleState.Collapsed;
|
||||||
item.contextValue = this.resourceType;
|
item.contextValue = this.resourceType;
|
||||||
}
|
|
||||||
|
|
||||||
item.iconPath = {
|
item.iconPath = {
|
||||||
dark: this.context.asAbsolutePath('images/dark/icon-commit.svg'),
|
dark: this.context.asAbsolutePath('images/dark/icon-commit.svg'),
|
||||||
light: this.context.asAbsolutePath('images/light/icon-commit.svg')
|
light: this.context.asAbsolutePath('images/light/icon-commit.svg')
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCommand(): Command | undefined {
|
getCommand(): Command | undefined {
|
||||||
let allowMissingPrevious = false;
|
|
||||||
let prefix = undefined;
|
|
||||||
const status = this.commit.fileStatuses[0];
|
|
||||||
if (status.status === 'A') {
|
|
||||||
allowMissingPrevious = true;
|
|
||||||
prefix = 'added in ';
|
|
||||||
}
|
|
||||||
else if (status.status === 'D') {
|
|
||||||
prefix = 'deleted in ';
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: 'Compare File with Previous Revision',
|
title: 'Compare File with Previous Revision',
|
||||||
command: Commands.DiffWithPrevious,
|
command: Commands.DiffWithPrevious,
|
||||||
@@ -70,9 +70,7 @@ export class CommitNode extends ExplorerNode {
|
|||||||
showOptions: {
|
showOptions: {
|
||||||
preserveFocus: true,
|
preserveFocus: true,
|
||||||
preview: true
|
preview: true
|
||||||
},
|
}
|
||||||
allowMissingPrevious: allowMissingPrevious,
|
|
||||||
rightTitlePrefix: prefix
|
|
||||||
} as DiffWithPreviousCommandArgs
|
} as DiffWithPreviousCommandArgs
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Command, Event, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
||||||
|
import { GlyphChars } from '../constants';
|
||||||
import { GitUri } from '../gitService';
|
import { GitUri } from '../gitService';
|
||||||
|
import { RefreshNodeCommandArgs } from './gitExplorer';
|
||||||
|
|
||||||
export declare type ResourceType =
|
export declare type ResourceType =
|
||||||
'gitlens:branches' |
|
'gitlens:branches' |
|
||||||
@@ -10,6 +12,7 @@ export declare type ResourceType =
|
|||||||
'gitlens:file-history' |
|
'gitlens:file-history' |
|
||||||
'gitlens:history' |
|
'gitlens:history' |
|
||||||
'gitlens:message' |
|
'gitlens:message' |
|
||||||
|
'gitlens:pager' |
|
||||||
'gitlens:remote' |
|
'gitlens:remote' |
|
||||||
'gitlens:remotes' |
|
'gitlens:remotes' |
|
||||||
'gitlens:repository' |
|
'gitlens:repository' |
|
||||||
@@ -31,10 +34,6 @@ export abstract class ExplorerNode {
|
|||||||
getCommand(): Command | undefined {
|
getCommand(): Command | undefined {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
onDidChangeTreeData?: Event<ExplorerNode>;
|
|
||||||
|
|
||||||
refresh?(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageNode extends ExplorerNode {
|
export class MessageNode extends ExplorerNode {
|
||||||
@@ -55,3 +54,45 @@ export class MessageNode extends ExplorerNode {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PagerNode extends ExplorerNode {
|
||||||
|
|
||||||
|
readonly resourceType: ResourceType = 'gitlens:pager';
|
||||||
|
args: RefreshNodeCommandArgs = {};
|
||||||
|
|
||||||
|
constructor(private message: string, private node: ExplorerNode, protected readonly context: ExtensionContext) {
|
||||||
|
super(new GitUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
getChildren(): ExplorerNode[] | Promise<ExplorerNode[]> {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getTreeItem(): TreeItem | Promise<TreeItem> {
|
||||||
|
const item = new TreeItem(this.message, TreeItemCollapsibleState.None);
|
||||||
|
item.contextValue = this.resourceType;
|
||||||
|
item.command = this.getCommand();
|
||||||
|
item.iconPath = {
|
||||||
|
dark: this.context.asAbsolutePath('images/dark/icon-unfold.svg'),
|
||||||
|
light: this.context.asAbsolutePath('images/light/icon-unfold.svg')
|
||||||
|
};
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommand(): Command | undefined {
|
||||||
|
return {
|
||||||
|
title: 'Refresh',
|
||||||
|
command: 'gitlens.gitExplorer.refreshNode',
|
||||||
|
arguments: [this.node, this.args]
|
||||||
|
} as Command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ShowAllCommitsNode extends PagerNode {
|
||||||
|
|
||||||
|
args: RefreshNodeCommandArgs = { maxCount: 0 };
|
||||||
|
|
||||||
|
constructor(node: ExplorerNode, context: ExtensionContext) {
|
||||||
|
super(`Show All Commits ${GlyphChars.Space}${GlyphChars.Dash}${GlyphChars.Space} this may take a while`, node, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Functions } from '../system';
|
import { Functions, Objects } from '../system';
|
||||||
import { commands, Event, EventEmitter, ExtensionContext, TextDocumentShowOptions, TextEditor, TreeDataProvider, TreeItem, Uri, window } from 'vscode';
|
import { commands, Event, EventEmitter, ExtensionContext, TextDocumentShowOptions, TextEditor, TreeDataProvider, TreeItem, Uri, window, workspace } from 'vscode';
|
||||||
import { Commands, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, openEditor, OpenFileInRemoteCommandArgs } from '../commands';
|
import { Commands, DiffWithCommandArgs, DiffWithCommandArgsRevision, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, openEditor, OpenFileInRemoteCommandArgs } from '../commands';
|
||||||
import { UriComparer } from '../comparers';
|
import { UriComparer } from '../comparers';
|
||||||
|
import { ExtensionKey, IConfig } from '../configuration';
|
||||||
import { CommandContext, setCommandContext } from '../constants';
|
import { CommandContext, setCommandContext } from '../constants';
|
||||||
import { CommitFileNode, CommitNode, ExplorerNode, HistoryNode, MessageNode, RepositoryNode, StashNode } from './explorerNodes';
|
import { BranchHistoryNode, CommitFileNode, CommitNode, ExplorerNode, HistoryNode, MessageNode, RepositoryNode, StashNode } from './explorerNodes';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri, RepoChangedReasons } from '../gitService';
|
||||||
|
|
||||||
export * from './explorerNodes';
|
export * from './explorerNodes';
|
||||||
|
|
||||||
@@ -22,8 +23,13 @@ export interface OpenFileRevisionCommandArgs {
|
|||||||
showOptions?: TextDocumentShowOptions;
|
showOptions?: TextDocumentShowOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RefreshNodeCommandArgs {
|
||||||
|
maxCount?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
||||||
|
|
||||||
|
private _config: IConfig;
|
||||||
private _root?: ExplorerNode;
|
private _root?: ExplorerNode;
|
||||||
private _view: GitExplorerView = GitExplorerView.Repository;
|
private _view: GitExplorerView = GitExplorerView.Repository;
|
||||||
|
|
||||||
@@ -36,18 +42,28 @@ export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
|||||||
commands.registerCommand('gitlens.gitExplorer.switchToHistoryView', () => this.switchTo(GitExplorerView.History), this);
|
commands.registerCommand('gitlens.gitExplorer.switchToHistoryView', () => this.switchTo(GitExplorerView.History), this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.switchToRepositoryView', () => this.switchTo(GitExplorerView.Repository), this);
|
commands.registerCommand('gitlens.gitExplorer.switchToRepositoryView', () => this.switchTo(GitExplorerView.Repository), this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.refresh', this.refresh, this);
|
commands.registerCommand('gitlens.gitExplorer.refresh', this.refresh, this);
|
||||||
|
commands.registerCommand('gitlens.gitExplorer.refreshNode', this.refreshNode, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openChanges', this.openChanges, this);
|
commands.registerCommand('gitlens.gitExplorer.openChanges', this.openChanges, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openChangesWithWorking', this.openChangesWithWorking, this);
|
commands.registerCommand('gitlens.gitExplorer.openChangesWithWorking', this.openChangesWithWorking, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openFile', this.openFile, this);
|
commands.registerCommand('gitlens.gitExplorer.openFile', this.openFile, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openFileRevision', this.openFileRevision, this);
|
commands.registerCommand('gitlens.gitExplorer.openFileRevision', this.openFileRevision, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openFileRevisionInRemote', this.openFileRevisionInRemote, this);
|
commands.registerCommand('gitlens.gitExplorer.openFileRevisionInRemote', this.openFileRevisionInRemote, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openChangedFiles', this.openChangedFiles, this);
|
commands.registerCommand('gitlens.gitExplorer.openChangedFiles', this.openChangedFiles, this);
|
||||||
|
commands.registerCommand('gitlens.gitExplorer.openChangedFileChanges', this.openChangedFileChanges, this);
|
||||||
|
commands.registerCommand('gitlens.gitExplorer.openChangedFileChangesWithWorking', this.openChangedFileChangesWithWorking, this);
|
||||||
commands.registerCommand('gitlens.gitExplorer.openChangedFileRevisions', this.openChangedFileRevisions, this);
|
commands.registerCommand('gitlens.gitExplorer.openChangedFileRevisions', this.openChangedFileRevisions, this);
|
||||||
|
commands.registerCommand('gitlens.gitExplorer.applyChanges', this.applyChanges, this);
|
||||||
|
|
||||||
const fn = Functions.debounce(this.onActiveEditorChanged, 500);
|
const repoChangedFn = Functions.debounce(this.onRepoChanged, 250);
|
||||||
context.subscriptions.push(window.onDidChangeActiveTextEditor(fn, this));
|
context.subscriptions.push(this.git.onDidChangeRepo(repoChangedFn, this));
|
||||||
|
|
||||||
this._view = this.git.config.gitExplorer.view;
|
const editorChangedFn = Functions.debounce(this.onActiveEditorChanged, 500);
|
||||||
|
context.subscriptions.push(window.onDidChangeActiveTextEditor(editorChangedFn, this));
|
||||||
|
context.subscriptions.push(workspace.onDidChangeConfiguration(this.onConfigurationChanged, this));
|
||||||
|
|
||||||
|
this.onConfigurationChanged();
|
||||||
|
|
||||||
|
this._view = this._config.gitExplorer.view;
|
||||||
setCommandContext(CommandContext.GitExplorerView, this._view);
|
setCommandContext(CommandContext.GitExplorerView, this._view);
|
||||||
this._root = this.getRootNode();
|
this._root = this.getRootNode();
|
||||||
}
|
}
|
||||||
@@ -89,15 +105,47 @@ export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
|||||||
|
|
||||||
private onActiveEditorChanged(editor: TextEditor | undefined) {
|
private onActiveEditorChanged(editor: TextEditor | undefined) {
|
||||||
if (this._view !== GitExplorerView.History) return;
|
if (this._view !== GitExplorerView.History) return;
|
||||||
|
|
||||||
const root = this.getRootNode(editor);
|
const root = this.getRootNode(editor);
|
||||||
if (root === this._root) return;
|
if (root === this._root) return;
|
||||||
|
|
||||||
this.refresh(root);
|
this._root = root;
|
||||||
|
this.refresh(undefined, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(root?: ExplorerNode) {
|
private onConfigurationChanged() {
|
||||||
this._root = root || this.getRootNode();
|
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
||||||
this._onDidChangeTreeData.fire();
|
|
||||||
|
if (!Objects.areEquivalent(cfg.gitExplorer, this._config && this._config.gitExplorer)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this._root = this.getRootNode(window.activeTextEditor);
|
||||||
|
this.refresh();
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._config = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private onRepoChanged(reasons: RepoChangedReasons[]) {
|
||||||
|
if (this._view !== GitExplorerView.Repository) return;
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(node?: ExplorerNode, root?: ExplorerNode) {
|
||||||
|
if (root === undefined && this._view === GitExplorerView.History) {
|
||||||
|
this._root = this.getRootNode(window.activeTextEditor);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onDidChangeTreeData.fire(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshNode(node: ExplorerNode, args: RefreshNodeCommandArgs) {
|
||||||
|
if (node instanceof BranchHistoryNode) {
|
||||||
|
node.maxCount = args.maxCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refresh(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
switchTo(view: GitExplorerView) {
|
switchTo(view: GitExplorerView) {
|
||||||
@@ -106,10 +154,15 @@ export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
|||||||
this._view = view;
|
this._view = view;
|
||||||
setCommandContext(CommandContext.GitExplorerView, this._view);
|
setCommandContext(CommandContext.GitExplorerView, this._view);
|
||||||
|
|
||||||
this._root = undefined;
|
this._root = this.getRootNode(window.activeTextEditor);
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async applyChanges(node: CommitNode | StashNode) {
|
||||||
|
await this.git.checkoutFile(node.uri);
|
||||||
|
return this.openFile(node);
|
||||||
|
}
|
||||||
|
|
||||||
private openChanges(node: CommitNode | StashNode) {
|
private openChanges(node: CommitNode | StashNode) {
|
||||||
const command = node.getCommand();
|
const command = node.getCommand();
|
||||||
if (command === undefined || command.arguments === undefined) return;
|
if (command === undefined || command.arguments === undefined) return;
|
||||||
@@ -139,6 +192,29 @@ export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
|||||||
return openEditor(options.uri || GitService.toGitContentUri(node.uri), options.showOptions || { preserveFocus: true, preview: false });
|
return openEditor(options.uri || GitService.toGitContentUri(node.uri), options.showOptions || { preserveFocus: true, preview: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async openChangedFileChanges(node: CommitNode | StashNode, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
||||||
|
const repoPath = node.commit.repoPath;
|
||||||
|
const uris = node.commit.fileStatuses
|
||||||
|
.map(s => GitUri.fromFileStatus(s, repoPath));
|
||||||
|
for (const uri of uris) {
|
||||||
|
await this.openDiffWith(repoPath,
|
||||||
|
{ uri: uri, sha: node.commit.previousSha !== undefined ? node.commit.previousSha : GitService.fakeSha },
|
||||||
|
{ uri: uri, sha: node.commit.sha }, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async openChangedFileChangesWithWorking(node: CommitNode | StashNode, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
||||||
|
const repoPath = node.commit.repoPath;
|
||||||
|
const uris = node.commit.fileStatuses
|
||||||
|
.filter(s => s.status !== 'D')
|
||||||
|
.map(s => GitUri.fromFileStatus(s, repoPath));
|
||||||
|
for (const uri of uris) {
|
||||||
|
await this.openDiffWith(repoPath,
|
||||||
|
{ uri: uri, sha: node.commit.sha },
|
||||||
|
{ uri: uri, sha: '' }, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async openChangedFiles(node: CommitNode | StashNode, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
private async openChangedFiles(node: CommitNode | StashNode, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
||||||
const repoPath = node.commit.repoPath;
|
const repoPath = node.commit.repoPath;
|
||||||
const uris = node.commit.fileStatuses.filter(s => s.status !== 'D').map(s => GitUri.fromFileStatus(s, repoPath));
|
const uris = node.commit.fileStatuses.filter(s => s.status !== 'D').map(s => GitUri.fromFileStatus(s, repoPath));
|
||||||
@@ -150,12 +226,22 @@ export class GitExplorer implements TreeDataProvider<ExplorerNode> {
|
|||||||
private async openChangedFileRevisions(node: CommitNode | StashNode, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
private async openChangedFileRevisions(node: CommitNode | StashNode, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
||||||
const uris = node.commit.fileStatuses
|
const uris = node.commit.fileStatuses
|
||||||
.filter(s => s.status !== 'D')
|
.filter(s => s.status !== 'D')
|
||||||
.map(s => GitService.toGitContentUri(node.commit.sha, node.commit.shortSha, s.fileName, node.commit.repoPath, s.originalFileName));
|
.map(s => GitService.toGitContentUri(node.commit.sha, s.fileName, node.commit.repoPath, s.originalFileName));
|
||||||
for (const uri of uris) {
|
for (const uri of uris) {
|
||||||
await openEditor(uri, options);
|
await openEditor(uri, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async openDiffWith(repoPath: string, lhs: DiffWithCommandArgsRevision, rhs: DiffWithCommandArgsRevision, options: TextDocumentShowOptions = { preserveFocus: false, preview: false }) {
|
||||||
|
const diffArgs: DiffWithCommandArgs = {
|
||||||
|
repoPath: repoPath,
|
||||||
|
lhs: lhs,
|
||||||
|
rhs: rhs,
|
||||||
|
showOptions: options
|
||||||
|
};
|
||||||
|
return commands.executeCommand(Commands.DiffWith, diffArgs);
|
||||||
|
}
|
||||||
|
|
||||||
private async openFileRevisionInRemote(node: CommitNode | StashNode) {
|
private async openFileRevisionInRemote(node: CommitNode | StashNode) {
|
||||||
return commands.executeCommand(Commands.OpenFileInRemote, new GitUri(node.commit.uri, node.commit), { range: false } as OpenFileInRemoteCommandArgs);
|
return commands.executeCommand(Commands.OpenFileInRemote, new GitUri(node.commit.uri, node.commit), { range: false } as OpenFileInRemoteCommandArgs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
||||||
import { BranchHistoryNode } from './branchHistoryNode';
|
import { BranchHistoryNode } from './branchHistoryNode';
|
||||||
|
import { GlyphChars } from '../constants';
|
||||||
import { ExplorerNode, ResourceType } from './explorerNode';
|
import { ExplorerNode, ResourceType } from './explorerNode';
|
||||||
import { GitRemote, GitService, GitUri } from '../gitService';
|
import { GitRemote, GitService, GitUri } from '../gitService';
|
||||||
|
|
||||||
@@ -18,11 +19,30 @@ export class RemoteNode extends ExplorerNode {
|
|||||||
if (branches === undefined) return [];
|
if (branches === undefined) return [];
|
||||||
|
|
||||||
branches.sort((a, b) => a.name.localeCompare(b.name));
|
branches.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
return [...Iterables.filterMap(branches, b => !b.remote || !b.name.startsWith(this.remote.name) ? undefined : new BranchHistoryNode(b, this.remote, this.uri, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
|
return [...Iterables.filterMap(branches, b => !b.remote || !b.name.startsWith(this.remote.name) ? undefined : new BranchHistoryNode(b, this.uri, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTreeItem(): TreeItem {
|
getTreeItem(): TreeItem {
|
||||||
const item = new TreeItem(this.remote.name, TreeItemCollapsibleState.Collapsed);
|
const fetch = this.remote.types.includes('push');
|
||||||
|
const push = this.remote.types.includes('push');
|
||||||
|
|
||||||
|
let separator;
|
||||||
|
if (fetch && push) {
|
||||||
|
separator = GlyphChars.ArrowLeftRight;
|
||||||
|
}
|
||||||
|
else if (fetch) {
|
||||||
|
separator = GlyphChars.ArrowLeft;
|
||||||
|
}
|
||||||
|
else if (push) {
|
||||||
|
separator = GlyphChars.ArrowRight;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
separator = GlyphChars.Dash;
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = `${this.remote.name} ${GlyphChars.Space}${separator}${GlyphChars.Space} ${(this.remote.provider !== undefined) ? this.remote.provider.name : this.remote.domain} ${GlyphChars.Space}${GlyphChars.Dot}${GlyphChars.Space} ${this.remote.path}`;
|
||||||
|
|
||||||
|
const item = new TreeItem(label, TreeItemCollapsibleState.Collapsed);
|
||||||
item.contextValue = this.resourceType;
|
item.contextValue = this.resourceType;
|
||||||
|
|
||||||
// item.iconPath = {
|
// item.iconPath = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Arrays, Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
||||||
import { ExplorerNode, ResourceType } from './explorerNode';
|
import { ExplorerNode, MessageNode, ResourceType } from './explorerNode';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { RemoteNode } from './remoteNode';
|
import { RemoteNode } from './remoteNode';
|
||||||
|
|
||||||
@@ -14,8 +14,8 @@ export class RemotesNode extends ExplorerNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getChildren(): Promise<ExplorerNode[]> {
|
async getChildren(): Promise<ExplorerNode[]> {
|
||||||
const remotes = Arrays.uniqueBy(await this.git.getRemotes(this.uri.repoPath!), r => r.url, r => !!r.provider);
|
const remotes = await this.git.getRemotes(this.uri.repoPath!);
|
||||||
if (remotes === undefined) return [];
|
if (remotes === undefined || remotes.length === 0) return [new MessageNode('No remotes configured')];
|
||||||
|
|
||||||
remotes.sort((a, b) => a.name.localeCompare(b.name));
|
remotes.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
return [...Iterables.map(remotes, r => new RemoteNode(r, this.uri, this.context, this.git))];
|
return [...Iterables.map(remotes, r => new RemoteNode(r, this.uri, this.context, this.git))];
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Event, EventEmitter, ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
|
||||||
import { ExplorerNode, ResourceType } from './explorerNode';
|
import { ExplorerNode, ResourceType } from './explorerNode';
|
||||||
import { CommitFormatter, GitService, GitStashCommit, GitUri } from '../gitService';
|
import { CommitFormatter, GitService, GitStashCommit, GitUri, ICommitFormatOptions } from '../gitService';
|
||||||
import { StashFileNode } from './stashFileNode';
|
import { StashFileNode } from './stashFileNode';
|
||||||
|
|
||||||
export class StashNode extends ExplorerNode {
|
export class StashNode extends ExplorerNode {
|
||||||
|
|
||||||
readonly resourceType: ResourceType = 'gitlens:stash';
|
readonly resourceType: ResourceType = 'gitlens:stash';
|
||||||
|
|
||||||
private _onDidChangeTreeData = new EventEmitter<ExplorerNode>();
|
|
||||||
public get onDidChangeTreeData(): Event<ExplorerNode> {
|
|
||||||
return this._onDidChangeTreeData.event;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(public readonly commit: GitStashCommit, protected readonly context: ExtensionContext, protected readonly git: GitService) {
|
constructor(public readonly commit: GitStashCommit, protected readonly context: ExtensionContext, protected readonly git: GitService) {
|
||||||
super(new GitUri(commit.uri, commit));
|
super(new GitUri(commit.uri, commit));
|
||||||
}
|
}
|
||||||
@@ -22,14 +17,11 @@ export class StashNode extends ExplorerNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTreeItem(): TreeItem {
|
getTreeItem(): TreeItem {
|
||||||
const label = CommitFormatter.fromTemplate(this.git.config.gitExplorer.stashFormat, this.commit, this.git.config.defaultDateFormat);
|
const item = new TreeItem(CommitFormatter.fromTemplate(this.git.config.gitExplorer.stashFormat, this.commit, {
|
||||||
|
truncateMessageAtNewLine: true,
|
||||||
const item = new TreeItem(label, TreeItemCollapsibleState.Collapsed);
|
dataFormat: this.git.config.defaultDateFormat
|
||||||
|
} as ICommitFormatOptions), TreeItemCollapsibleState.Collapsed);
|
||||||
item.contextValue = this.resourceType;
|
item.contextValue = this.resourceType;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh() {
|
|
||||||
this._onDidChangeTreeData.fire();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -34,6 +34,7 @@ export class StatusNode extends ExplorerNode {
|
|||||||
|
|
||||||
let hasChildren = false;
|
let hasChildren = false;
|
||||||
let label = '';
|
let label = '';
|
||||||
|
let iconSuffix = '';
|
||||||
if (status.upstream) {
|
if (status.upstream) {
|
||||||
if (!status.state.ahead && !status.state.behind) {
|
if (!status.state.ahead && !status.state.behind) {
|
||||||
label = `${status.branch} is up-to-date with ${status.upstream}`;
|
label = `${status.branch} is up-to-date with ${status.upstream}`;
|
||||||
@@ -41,6 +42,15 @@ export class StatusNode extends ExplorerNode {
|
|||||||
else {
|
else {
|
||||||
label = `${status.branch} is not up-to-date with ${status.upstream}`;
|
label = `${status.branch} is not up-to-date with ${status.upstream}`;
|
||||||
hasChildren = true;
|
hasChildren = true;
|
||||||
|
if (status.state.ahead && status.state.behind) {
|
||||||
|
iconSuffix = '-yellow';
|
||||||
|
}
|
||||||
|
else if (status.state.ahead) {
|
||||||
|
iconSuffix = '-green';
|
||||||
|
}
|
||||||
|
else if (status.state.behind) {
|
||||||
|
iconSuffix = '-red';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -51,8 +61,8 @@ export class StatusNode extends ExplorerNode {
|
|||||||
item.contextValue = this.resourceType;
|
item.contextValue = this.resourceType;
|
||||||
|
|
||||||
item.iconPath = {
|
item.iconPath = {
|
||||||
dark: this.context.asAbsolutePath('images/dark/icon-repo.svg'),
|
dark: this.context.asAbsolutePath(`images/dark/icon-repo${iconSuffix}.svg`),
|
||||||
light: this.context.asAbsolutePath('images/light/icon-repo.svg')
|
light: this.context.asAbsolutePath(`images/light/icon-repo${iconSuffix}.svg`)
|
||||||
};
|
};
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export class StatusUpstreamNode extends ExplorerNode {
|
|||||||
const range = this.direction === 'ahead'
|
const range = this.direction === 'ahead'
|
||||||
? `${this.status.upstream}..${this.status.branch}`
|
? `${this.status.upstream}..${this.status.branch}`
|
||||||
: `${this.status.branch}..${this.status.upstream}`;
|
: `${this.status.branch}..${this.status.upstream}`;
|
||||||
let log = await this.git.getLogForRepo(this.uri.repoPath!, range);
|
let log = await this.git.getLogForRepo(this.uri.repoPath!, range, 0);
|
||||||
if (log === undefined) return [];
|
if (log === undefined) return [];
|
||||||
|
|
||||||
if (this.direction !== 'ahead') return [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.template, this.context, this.git))];
|
if (this.direction !== 'ahead') return [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.template, this.context, this.git))];
|
||||||
@@ -37,8 +37,8 @@ export class StatusUpstreamNode extends ExplorerNode {
|
|||||||
|
|
||||||
async getTreeItem(): Promise<TreeItem> {
|
async getTreeItem(): Promise<TreeItem> {
|
||||||
const label = this.direction === 'ahead'
|
const label = this.direction === 'ahead'
|
||||||
? `${this.status.state.ahead} commit${this.status.state.ahead > 1 ? 's' : ''} ahead` // of ${this.status.upstream}`
|
? `${this.status.state.ahead} commit${this.status.state.ahead > 1 ? 's' : ''} ahead (local changes)` // of ${this.status.upstream}`
|
||||||
: `${this.status.state.behind} commit${this.status.state.behind > 1 ? 's' : ''} behind`; // ${this.status.upstream}`;
|
: `${this.status.state.behind} commit${this.status.state.behind > 1 ? 's' : ''} behind (remote changes)`; // ${this.status.upstream}`;
|
||||||
|
|
||||||
const item = new TreeItem(label, TreeItemCollapsibleState.Collapsed);
|
const item = new TreeItem(label, TreeItemCollapsibleState.Collapsed);
|
||||||
item.contextValue = this.resourceType;
|
item.contextValue = this.resourceType;
|
||||||
|
|||||||