70 Commits

Author SHA1 Message Date
Eric Amodio
11eacb27a1 Preps v5.0.0 2017-09-12 19:06:15 -04:00
Eric Amodio
543d39246f Closes #138 - adds ignore whitespace setting 2017-09-12 17:46:22 -04:00
Eric Amodio
6837414f22 Adds more details to remotes in custom view 2017-09-12 15:48:36 -04:00
Eric Amodio
ea6fdbaaf2 Adds groupBy function 2017-09-12 15:47:57 -04:00
Eric Amodio
ccc29e3dfc Reworks remote parsing
Combines same url into same remote
Adds a change event for custom remote providers
Adds a repo change event for custom remote providers
2017-09-12 15:46:44 -04:00
Eric Amodio
48814d4213 Changes show all commits icon 2017-09-12 13:02:04 -04:00
Eric Amodio
c3dd83cf3c Updates documention with remotes exanple 2017-09-12 11:56:17 -04:00
Eric Amodio
77482f4930 Adds openChangedFileChanges to custom view
Adds openChangedFileChangesWithWorking to custom view
Removes unneeded context checks from custom view commands
2017-09-12 11:11:03 -04:00
Eric Amodio
503b2a3785 Fixes issue where the revision wasn't properly opened
Adds ability to provide a branch to open file in remote
2017-09-12 10:38:51 -04:00
Eric Amodio
9464f7e79f Preps v5.0.0-beta.2 2017-09-11 23:51:27 -04:00
Eric Amodio
77ae37c54c Adds rudimentary "paging" to custom view branch history 2017-09-11 23:47:51 -04:00
Eric Amodio
e20ec552b7 Removes branches remote commands if no remotes
Removes branch remote commands if not tracked
2017-09-11 23:41:47 -04:00
Eric Amodio
f911447c5e Formats svg like other icons 2017-09-11 23:38:47 -04:00
Eric Amodio
38c44c808d Fixes double getRemotes call 2017-09-11 21:32:52 -04:00
Eric Amodio
655afb358e Fixes double hovers on blank lines 2017-09-11 21:32:52 -04:00
Eric Amodio
21e0963600 Adds bitbucket server support 2017-09-11 21:32:40 -04:00
Eric Amodio
62580da702 Preps v5.0.0-beta 2017-09-11 03:02:56 -04:00
Eric Amodio
6b97c107eb Updates dependencies 2017-09-11 02:27:49 -04:00
Eric Amodio
92b57580b8 Fixes #120 - Adds custom remotes support 2017-09-11 02:09:32 -04:00
Eric Amodio
e400f27c84 Adds refs changes into repo watcher
Catches branch & remote changes
2017-09-11 00:50:40 -04:00
Eric Amodio
4221e06ae3 Removes history limit for custom view 2017-09-11 00:41:32 -04:00
Eric Amodio
a2dc65c044 Adds message truncation at newline 2017-09-11 00:41:11 -04:00
Eric Amodio
4102bdd471 Reworks git command error handling
Switches to use the new diffWith command
2017-09-11 00:39:52 -04:00
Eric Amodio
d420d82ab2 Removes unneeded shortSha parameter 2017-09-11 00:36:38 -04:00
Eric Amodio
260874fa1d Adds better filename sanitization 2017-09-10 17:44:26 -04:00
Eric Amodio
9d83fbcacb Switches to use the new diffWith command 2017-09-09 15:48:44 -04:00
Eric Amodio
a50f04c569 Adds commands to hover links 2017-09-09 01:57:12 -04:00
Eric Amodio
df0599a832 Adds shortenSha method 2017-09-09 00:43:20 -04:00
Eric Amodio
f05d236e79 Updates dependencies
Updates to latest vscode engine
2017-09-08 18:47:25 -04:00
Eric Amodio
1b7610857a Fixes issue where repo change wasn't fired in some cases
Consolidates repo watching into a single watcher
Adds debounce to repo changes in the custom view
2017-09-08 18:02:43 -04:00
Eric Amodio
04d2c00ebf Fixes issue with branch name truncations (rebase) 2017-09-08 17:03:21 -04:00
Eric Amodio
ece34dba32 Cleans up some command overrides 2017-09-05 21:30:07 -04:00
Eric Amodio
68fcbf713d Fixes regression with not opening line in remote 2017-09-05 21:29:22 -04:00
Eric Amodio
e192c547b1 Fixes #130 - Stops repeated welcome for some users
No idea why the version check fails, but hopefully this will help
2017-09-04 03:30:19 -04:00
Eric Amodio
3835193118 Updates images 2017-09-04 03:05:26 -04:00
Eric Amodio
d161084ccd Fixes issue with stashing untracked files 2017-09-04 03:04:05 -04:00
Eric Amodio
b9c4468cf7 Updates changelog 2017-09-04 01:46:29 -04:00
Eric Amodio
4bacb6fbff Hides remote menus if there are no remotes 2017-09-04 01:46:28 -04:00
Eric Amodio
c98755cc87 Adds refresh of custom view on settings change 2017-09-04 01:46:28 -04:00
Eric Amodio
6d759daaad Avoids remote disambiguation quick pick 2017-09-04 01:46:28 -04:00
Eric Amodio
5a42ce4ed4 Adds remote tracking branch to custom view
Adds setting to show remote tracking branch in custom view
2017-09-04 01:46:28 -04:00
Eric Amodio
a5af318269 Adds message in custom view if no remotes 2017-09-04 01:46:28 -04:00
Eric Amodio
5a2bd02402 Reworks branch parsing to include tracking info
Reworks current branch retrieval for better performance
2017-09-04 01:46:21 -04:00
Eric Amodio
2bba14260f Adds Open Branches in Remote command to the Remote custom view items
Adds Open Repository in Remote command to the Remote custom view items
2017-09-03 16:33:52 -04:00
Eric Amodio
22378d5f25 Updates changelog and readme 2017-09-03 16:03:33 -04:00
Eric Amodio
d1d1db18e2 Changes the icon of the File History custom view items
Provides more information rather than just a commit icon
2017-09-03 15:49:50 -04:00
Eric Amodio
3dab90709b Adds Open File command to History custom view item
Adds Open File in Remote command to History custom view item
2017-09-03 15:44:18 -04:00
Eric Amodio
f58d085352 Adds Open Branches in Remote command
Adds Open Branches in Remote command to the Branches custom view item
Adds Open Repository in Remote command to the Repository Status custom view item
2017-09-03 15:37:52 -04:00
Eric Amodio
a77bb36ee3 Preps v5.0.0-alpha.2 2017-09-03 13:47:13 -04:00
Eric Amodio
5cc9365fa1 Adds more info to the status nodes 2017-09-03 13:40:46 -04:00
Eric Amodio
a587108cab Adds Stash Changes command to the Stashes custom view item 2017-09-03 13:29:33 -04:00
Eric Amodio
1b4350e476 Removes Stash Unstaged Changes option
Changes Stash Changes icon to a +
2017-09-03 13:23:17 -04:00
Eric Amodio
586785cfb8 Changes stashes icon to match custom view 2017-09-03 13:22:40 -04:00
Eric Amodio
04df931902 Adds Refresh command to most custom view items
Updates custom view when repo changes (brute force for now)
2017-09-03 12:59:16 -04:00
Eric Amodio
d31eb25451 Adds Apply Changes command to custom view files
Adds Stash Changes command to SCM view items
2017-09-03 12:58:05 -04:00
Eric Amodio
35b16a78ba Adds status indicator to repo icon 2017-09-03 00:25:01 -04:00
Eric Amodio
825b9661fb Preps v5.0.0-alpha
Updates dependencies
2017-09-02 01:53:04 -04:00
Eric Amodio
9782a81e46 Adds new GitLens custom view 2017-09-02 01:43:08 -04:00
Eric Amodio
ed58dc3b49 Preps v4.5.0-beta 2017-08-30 12:25:51 -04:00
Eric Amodio
480dcb95fb Adds a file history explorer view 2017-08-30 12:25:07 -04:00
Eric Amodio
ef41176ea7 Defaults stashes format to ${filePath}
Adds message when there are no stashes
Cleans up the stash explorer
2017-08-30 12:25:07 -04:00
Eric Amodio
bcd83566a1 Reworks ExplorerNode base class
Adds TextExplorerNode for messages
2017-08-30 12:25:07 -04:00
Eric Amodio
ca089777db Adds ${filePath} support to status file formatting 2017-08-30 12:25:07 -04:00
Eric Amodio
a255eea949 Splits code lens out of GitService 2017-08-30 12:25:07 -04:00
Eric Amodio
1ffb42a090 Updates dependencies 2017-08-30 12:25:07 -04:00
Eric Amodio
bc2f1b192a Preps v4.4.3 2017-08-30 12:19:57 -04:00
Eric Amodio
7d99624068 Adds more logging to track down #130 2017-08-30 12:19:33 -04:00
Eric Amodio
c258d04381 Fixes #135 - Full-width chars break gutter annotations (really) 2017-08-30 11:46:41 -04:00
Eric Amodio
4c4926c8b5 Preps v4.4.2 2017-08-29 22:48:59 -04:00
Eric Amodio
6255b26fd2 Fixes #135 - Full-width chars break gutter annotations 2017-08-29 22:47:12 -04:00
131 changed files with 3935 additions and 2151 deletions

View File

@@ -4,6 +4,116 @@ 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/).
## [5.0.0] - 2017-09-12
### Added
- Adds an all-new `GitLens` custom view to the Explorer activity
- `Repository View` - provides a full repository explorer
![GitLens Repository view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-custom-view-repository.png)
- `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
![GitLens History view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-custom-view-history.png)
- 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
![Hover Annotations](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-line-blame-annotations.png)
- 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
- 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
## Fixed
- Fixes [#135](https://github.com/eamodio/vscode-gitlens/issues/135) - Full-width characters break gutter annotations (really this time)
## [4.4.2] - 2017-08-29
## Fixed
- Fixes [#135](https://github.com/eamodio/vscode-gitlens/issues/135) - Full-width characters break gutter annotations
## [4.4.1] - 2017-08-23 ## [4.4.1] - 2017-08-23
## Fixed ## Fixed
- Fixes [#114](https://github.com/eamodio/vscode-gitlens/issues/114) - Stylus files makes code lens freak out - Fixes [#114](https://github.com/eamodio/vscode-gitlens/issues/114) - Stylus files makes code lens freak out
@@ -21,7 +131,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## Removed ## Removed
- Removes unneeded `gitlens.stashExplorer.enabled` configuration setting since users can add or remove custom views natively now - Removes unneeded `gitlens.stashExplorer.enabled` configuration setting since users can add or remove custom views natively now
- Removes unneeded `Toggle Git Stashed Explorer` command (`gitlens.stashExplorer.toggle`) since users can add or remove custom views natively now - Removes unneeded `Toggle Git Stashes Explorer` command (`gitlens.stashExplorer.toggle`) since users can add or remove custom views natively now
- Removes the `gitlens.theme.annotations.file.hover.separateLines` configuration setting - Removes the `gitlens.theme.annotations.file.hover.separateLines` configuration setting
## Fixed ## Fixed
@@ -43,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 Stashed 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
![Git Stashes view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-stashes.png)
- 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
@@ -66,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
@@ -120,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
@@ -204,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))!
@@ -395,7 +502,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Fixed ### Fixed
- Fixes issue with `gitlens.diffWithPrevious` command execution via code lens when the code lens was not at the document/file level - Fixes issue with `gitlens.diffWithPrevious` command execution via code lens when the code lens was not at the document/file level
- Fixes issue where full shas were displayed on the file/blame history explorers - Fixes issue where full shas were displayed on the file/blame history explorers
- Fixes [#30](https://github.com/eamodio/vscode-gitlens/issues/30) - Diff with Working Tree fails from repo/commit quickpick list if file was renamed (and the commit was before the rename) - Fixes [#30](https://github.com/eamodio/vscode-gitlens/issues/30) - Diff with Working Tree fails from repo/commit quick pick list if file was renamed (and the commit was before the rename)
- Fixes various other quick pick menu command issues when a file was renamed - Fixes various other quick pick menu command issues when a file was renamed
- Fixes various issues when caching is disabled - Fixes various issues when caching is disabled
- Fixes issues with parsing commits history - Fixes issues with parsing commits history
@@ -498,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
@@ -536,7 +643,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Fixed ### Fixed
- Fixes [#34](https://github.com/eamodio/vscode-gitlens/issues/34) - Open file should open the selected version of the file - Fixes [#34](https://github.com/eamodio/vscode-gitlens/issues/34) - Open file should open the selected version of the file
- Fixes some issue where some editors opened by the quickpick would not be opened in preview tabs - Fixes some issue where some editors opened by the quick pick would not be opened in preview tabs
- Fixes issue where copy to clipboard commands would fail if there was no active editor - Fixes issue where copy to clipboard commands would fail if there was no active editor
- Fixes issue where active line annotations would show for opened versioned files - Fixes issue where active line annotations would show for opened versioned files
- Fixes issue where code lens compare commands on opened versioned files would fail - Fixes issue where code lens compare commands on opened versioned files would fail

101
README.md
View File

@@ -1,7 +1,7 @@
[![](https://vsmarketplacebadge.apphb.com/version/eamodio.gitlens.svg)](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) [![](https://vsmarketplacebadge.apphb.com/version/eamodio.gitlens.svg)](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
[![](https://vsmarketplacebadge.apphb.com/installs/eamodio.gitlens.svg)](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) [![](https://vsmarketplacebadge.apphb.com/installs/eamodio.gitlens.svg)](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
[![](https://vsmarketplacebadge.apphb.com/rating/eamodio.gitlens.svg)](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) [![](https://vsmarketplacebadge.apphb.com/rating/eamodio.gitlens.svg)](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
[![Chat at https://vscode-gitlens.slack.com/](https://raw.githubusercontent.com/eamodio/vscode-gitlens/develop/images/chat-badge.png)](https://join.slack.com/t/vscode-gitlens/shared_invite/MjIxOTgxNDE3NzM0LTE1MDE2Nzk1MTgtMjkwMmZjMzcxNQ) [![Chat at https://vscode-gitlens.slack.com/](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/chat-badge.png)](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,
![Line Blame Annotation](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-line-blame-annotation.png) ![Line Blame Annotation](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-line-blame-annotation.png)
- 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`)
![Line Blame Annotations](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-line-blame-annotations.png) ![Line Blame Annotations](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-line-blame-annotations.png)
@@ -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,33 +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 `Git Stashes` explorer to the Explorer activity ([optional](#git-stashes-explorer-settings), off by default) - Adds a [customizable](#gitlens-custom-view-settings) `GitLens` custom view to the Explorer activity
![Git Stashes explorer](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-stashes.png) - `Repository View` - provides a full repository explorer
- Shows all of the stashed changes in the repository ![GitLens Repository view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-custom-view-repository.png)
- 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 - `Repository Status` node — provides the status of the repository
- Expand each stash to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes - Provides the name of the current branch, its upstream tracking branch (if available), and its upstream status (if available)
- Provides a context menu with `Open Changes`, `Open File`, `Open Stashed File`, `Open File in Remote`, and `Compare File with Working Tree` commands - 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](#gitlens-custom-view-settings) 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`, 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
![GitLens History view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-custom-view-history.png)
- 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
@@ -217,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
@@ -234,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
@@ -289,12 +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 Stashes Explorer Settings ### GitLens Custom View 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.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.stashExplorer.stashFileFormat`|Specifies the format of a stashed file in the `Git Stashes` explorer <br />Available tokens<br /> ${file} - file name<br /> ${path} - file path |`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
### Custom Remotes Settings
|Name | Description
|-----|------------
|`gitlens.remotes`|Specifies any custom domains for remote (code-hosting) services<br />Example: ```"gitlens.remotes": [{ "domain": "git.corporate-url.com", "type": "GitHub" }]```
### Status Bar Settings ### Status Bar Settings

View File

@@ -1 +1,5 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#C5C5C5"/><rect height="3" width="11" y="7" x="3" fill="#C5C5C5"/></svg> <?xml version="1.0" encoding="utf-8"?>
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect fill="#C5C5C5" x="6.5" y="5.5" width="3" height="11"/>
<rect fill="#C5C5C5" x="2.5" y="9.5" width="11" height="3"/>
</svg>

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 253 B

View 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="m13,8c0,-1.11 -0.89,-2 -2,-2c-1.11,0 -2,0.89 -2,2c0,0.73 0.41,1.38 1,1.72l0,0.3c-0.02,0.52 -0.23,0.98 -0.63,1.38c-0.4,0.4 -0.86,0.61 -1.38,0.63c-0.83,0.02 -1.48,0.16 -2,0.45l0,-4.76c0.59,-0.34 1,-0.98 1,-1.72c0,-1.11 -0.89,-2 -2,-2c-1.11,0 -1.99,0.89 -1.99,2c0,0.73 0.41,1.38 1,1.72l0,6.56c-0.59,0.35 -1,0.99 -1,1.72c0,1.11 0.89,2 2,2c1.11,0 2,-0.89 2,-2c0,-0.53 -0.2,-1 -0.53,-1.36c0.09,-0.06 0.48,-0.41 0.59,-0.47c0.25,-0.11 0.56,-0.17 0.94,-0.17c1.05,-0.05 1.95,-0.45 2.75,-1.25c0.8,-0.8 1.2,-1.98 1.25,-3.02l-0.02,0c0.61,-0.36 1.02,-1 1.02,-1.73l0,0zm-8,-3.2c0.66,0 1.2,0.55 1.2,1.2c0,0.65 -0.55,1.2 -1.2,1.2c-0.65,0 -1.2,-0.55 -1.2,-1.2c0,-0.65 0.55,-1.2 1.2,-1.2l0,0zm0,12.41c-0.66,0 -1.2,-0.55 -1.2,-1.2c0,-0.65 0.55,-1.2 1.2,-1.2c0.65,0 1.2,0.55 1.2,1.2c0,0.65 -0.55,1.2 -1.2,1.2l0,0zm6,-8c-0.66,0 -1.2,-0.55 -1.2,-1.2c0,-0.65 0.55,-1.2 1.2,-1.2c0.65,0 1.2,0.55 1.2,1.2c0,0.65 -0.55,1.2 -1.2,1.2l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -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" x="0px" y="0px" width="256" height="256" viewBox="0 0 14 16" xml:space="preserve"> <svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path fill="#C5C5C5" d="M10.86 7c-.45-1.72-2-3-3.86-3-1.86 0-3.41 1.28-3.86 3H0v2h3.14c.45 1.72 2 3 3.86 3 1.86 0 3.41-1.28 3.86-3H14V7h-3.14zM7 10.2c-1.22 0-2.2-.98-2.2-2.2 0-1.22.98-2.2 2.2-2.2 1.22 0 2.2.98 2.2 2.2 0 1.22-.98 2.2-2.2 2.2z"></path> <path fill="#C5C5C5" d="m11.86,10c-0.45,-1.72 -2,-3 -3.86,-3c-1.86,0 -3.41,1.28 -3.86,3l-3.14,0l0,2l3.14,0c0.45,1.72 2,3 3.86,3c1.86,0 3.41,-1.28 3.86,-3l3.14,0l0,-2l-3.14,0zm-3.86,3.2c-1.22,0 -2.2,-0.98 -2.2,-2.2c0,-1.22 0.98,-2.2 2.2,-2.2c1.22,0 2.2,0.98 2.2,2.2c0,1.22 -0.98,2.2 -2.2,2.2z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 480 B

After

Width:  |  Height:  |  Size: 428 B

View 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="m9,15l2,0l-3,3l-3,-3l2,0l0,-5l2,0l0,5l0,0zm3,-8c0,-0.44 -0.91,-3 -4.5,-3c-2.42,0 -4.5,1.92 -4.5,4c-1.98,0 -3,1.52 -3,3c0,1.53 1,3 3,3l3,0l0,-1.3l-3,0c-1.62,0 -1.7,-1.42 -1.7,-1.7c0,-0.17 0.05,-1.7 1.7,-1.7l1.3,0l0,-1.3c0,-1.39 1.56,-2.7 3.2,-2.7c2.55,0 3.13,1.55 3.2,1.8l0,1.2l1.3,0c0.81,0 2.7,0.22 2.7,2.2c0,2.09 -2.25,2.2 -2.7,2.2l-2,0l0,1.3l2,0c2.08,0 4,-1.16 4,-3.5c0,-2.44 -1.92,-3.5 -4,-3.5l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 557 B

View 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="m9,16l-2,0l0,-7l5,0l0,2l-3,0l0,5l0,0zm-1,-12c-2.19,0 -4.13,1.02 -5.41,2.59l-1.59,-1.59l0,4l4,0l-1.5,-1.5c1.05,-1.33 2.67,-2.2 4.5,-2.2c3.14,0 5.7,2.56 5.7,5.7c0,3.14 -2.56,5.7 -5.7,5.7c-3.14,0 -5.7,-2.56 -5.7,-5.7c0,-0.34 0.03,-0.67 0.09,-1l-1.31,0c-0.05,0.33 -0.08,0.66 -0.08,1c0,3.86 3.14,7 7,7c3.86,0 7,-3.14 7,-7c0,-3.86 -3.14,-7 -7,-7l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 500 B

View File

@@ -1,5 +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="16" height="16"> <svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3a2.98 2.98 0 0 1-2.107-.868 2.98 2.98 0 0 1-.873-2.111 3.004 3.004 0 0 1 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012L13.115 4.1 8.196 0H7.059v2.404A6.759 6.759 0 0 0 .938 9.125c0 1.809.707 3.508 1.986 4.782a6.707 6.707 0 0 0 4.784 1.988 6.758 6.758 0 0 0 6.75-6.75 6.741 6.741 0 0 0-1.007-3.536z" fill="#2D2D30"/> <path fill="#C5C5C5" d="m12.901149,9.091851l-0.094,0.071c-0.269,0.333 -0.746,1.096 -0.91,2.375c0.057,0.277 0.092,0.495 0.092,0.545c0,2.206 -1.794,4 -4,4a3.986,3.986 0 0 1 -2.817,-1.164a3.987,3.987 0 0 1 -1.163,-2.815c0,-2.206 1.794,-4 4,-4l0.351,0.025l0,1.85s1.626,-1.342 1.631,-1.339l1.869,-1.577l-3.5,-2.917l0,2.218l-0.371,-0.03a5.75,5.75 0 0 0 -4.055,9.826a5.75,5.75 0 0 0 9.826,-4.056a5.725,5.725 0 0 0 -0.859,-3.012z" />
<path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4a3.986 3.986 0 0 1-2.817-1.164 3.987 3.987 0 0 1-1.163-2.815c0-2.206 1.794-4 4-4l.351.025v1.85S9.685 5.679 9.69 5.682l1.869-1.577-3.5-2.917v2.218l-.371-.03a5.75 5.75 0 0 0-4.055 9.826 5.75 5.75 0 0 0 9.826-4.056 5.725 5.725 0 0 0-.859-3.012z" fill="#C5C5C5"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 987 B

After

Width:  |  Height:  |  Size: 553 B

View 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.519592,15.157073l-9.039184,0c-1.367793,0 -2.480539,-1.112828 -2.480539,-2.480622s1.112746,-2.480539 2.480539,-2.480539l0.281314,0c0.349178,-0.47173 0.888523,-0.771191 1.476341,-0.815025c0.321917,-1.471535 1.619609,-2.537962 3.165139,-2.537962c1.221543,0 2.341663,0.699516 2.889377,1.772488c0.083027,-0.008618 0.166386,-0.012926 0.250076,-0.012926c1.190221,0 2.194667,0.874105 2.378785,2.027867c0.670514,0.460047 1.07869,1.225023 1.07869,2.046096c0,1.367793 -1.112828,2.480622 -2.480539,2.480622z" />
</svg>

After

Width:  |  Height:  |  Size: 655 B

View 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

View 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

View 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

View 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="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" />
</svg>

After

Width:  |  Height:  |  Size: 490 B

View 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="m14.414133,16.199437l-3.415492,-3.433421c0.627518,-0.878526 0.995065,-1.945307 0.995065,-3.110698c0,-2.967265 -2.411463,-5.378728 -5.378728,-5.378728c-2.967265,0 -5.378728,2.411463 -5.378728,5.378728c0,2.967265 2.411463,5.378728 5.378728,5.378728c1.165391,0 2.223207,-0.367546 3.110698,-0.995065l3.433421,3.415492c0.170326,0.179291 0.403405,0.268936 0.627518,0.268936c0.224114,0 0.466156,-0.080681 0.627518,-0.268936c0.349617,-0.349617 0.349617,-0.914384 0,-1.264001l0,0.008965zm-7.799155,-2.330782c-2.321817,0 -4.213337,-1.891519 -4.213337,-4.213337c0,-2.321817 1.891519,-4.213337 4.213337,-4.213337c2.321817,0 4.213337,1.891519 4.213337,4.213337c0,2.321817 -1.891519,4.213337 -4.213337,4.213337l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 857 B

View 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="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>

After

Width:  |  Height:  |  Size: 846 B

View 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

View 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

View 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="m7,12l-2,0l3,-3l3,3l-2,0l0,5l-2,0l0,-5l0,0zm5,-4c0,-0.44 -0.91,-3 -4.5,-3c-2.42,0 -4.5,1.92 -4.5,4c-1.98,0 -3,1.52 -3,3c0,1.53 1,3 3,3l3,0l0,-1.3l-3,0c-1.62,0 -1.7,-1.42 -1.7,-1.7c0,-0.17 0.05,-1.7 1.7,-1.7l1.3,0l0,-1.3c0,-1.39 1.56,-2.7 3.2,-2.7c2.55,0 3.13,1.55 3.2,1.8l0,1.2l1.3,0c0.81,0 2.7,0.22 2.7,2.2c0,2.09 -2.25,2.2 -2.7,2.2l-2,0l0,1.3l2,0c2.08,0 4,-1.16 4,-3.5c0,-2.44 -1.92,-3.5 -4,-3.5l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 558 B

View File

@@ -1 +1,5 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#424242"/><rect height="3" width="11" y="7" x="3" fill="#424242"/></svg> <?xml version="1.0" encoding="utf-8"?>
<svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect fill="#424242" x="6.5" y="5.5" width="3" height="11"/>
<rect fill="#424242" x="2.5" y="9.5" width="11" height="3"/>
</svg>

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 253 B

View 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="m13,8c0,-1.11 -0.89,-2 -2,-2c-1.11,0 -2,0.89 -2,2c0,0.73 0.41,1.38 1,1.72l0,0.3c-0.02,0.52 -0.23,0.98 -0.63,1.38c-0.4,0.4 -0.86,0.61 -1.38,0.63c-0.83,0.02 -1.48,0.16 -2,0.45l0,-4.76c0.59,-0.34 1,-0.98 1,-1.72c0,-1.11 -0.89,-2 -2,-2c-1.11,0 -1.99,0.89 -1.99,2c0,0.73 0.41,1.38 1,1.72l0,6.56c-0.59,0.35 -1,0.99 -1,1.72c0,1.11 0.89,2 2,2c1.11,0 2,-0.89 2,-2c0,-0.53 -0.2,-1 -0.53,-1.36c0.09,-0.06 0.48,-0.41 0.59,-0.47c0.25,-0.11 0.56,-0.17 0.94,-0.17c1.05,-0.05 1.95,-0.45 2.75,-1.25c0.8,-0.8 1.2,-1.98 1.25,-3.02l-0.02,0c0.61,-0.36 1.02,-1 1.02,-1.73l0,0zm-8,-3.2c0.66,0 1.2,0.55 1.2,1.2c0,0.65 -0.55,1.2 -1.2,1.2c-0.65,0 -1.2,-0.55 -1.2,-1.2c0,-0.65 0.55,-1.2 1.2,-1.2l0,0zm0,12.41c-0.66,0 -1.2,-0.55 -1.2,-1.2c0,-0.65 0.55,-1.2 1.2,-1.2c0.65,0 1.2,0.55 1.2,1.2c0,0.65 -0.55,1.2 -1.2,1.2l0,0zm6,-8c-0.66,0 -1.2,-0.55 -1.2,-1.2c0,-0.65 0.55,-1.2 1.2,-1.2c0.65,0 1.2,0.55 1.2,1.2c0,0.65 -0.55,1.2 -1.2,1.2l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -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" x="0px" y="0px" width="256" height="256" viewBox="0 0 14 16" xml:space="preserve"> <svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path fill="#6c6c6c" d="M10.86 7c-.45-1.72-2-3-3.86-3-1.86 0-3.41 1.28-3.86 3H0v2h3.14c.45 1.72 2 3 3.86 3 1.86 0 3.41-1.28 3.86-3H14V7h-3.14zM7 10.2c-1.22 0-2.2-.98-2.2-2.2 0-1.22.98-2.2 2.2-2.2 1.22 0 2.2.98 2.2 2.2 0 1.22-.98 2.2-2.2 2.2z"></path> <path fill="#424242" d="m11.86,10c-0.45,-1.72 -2,-3 -3.86,-3c-1.86,0 -3.41,1.28 -3.86,3l-3.14,0l0,2l3.14,0c0.45,1.72 2,3 3.86,3c1.86,0 3.41,-1.28 3.86,-3l3.14,0l0,-2l-3.14,0zm-3.86,3.2c-1.22,0 -2.2,-0.98 -2.2,-2.2c0,-1.22 0.98,-2.2 2.2,-2.2c1.22,0 2.2,0.98 2.2,2.2c0,1.22 -0.98,2.2 -2.2,2.2z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 480 B

After

Width:  |  Height:  |  Size: 428 B

View 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="m9,15l2,0l-3,3l-3,-3l2,0l0,-5l2,0l0,5l0,0zm3,-8c0,-0.44 -0.91,-3 -4.5,-3c-2.42,0 -4.5,1.92 -4.5,4c-1.98,0 -3,1.52 -3,3c0,1.53 1,3 3,3l3,0l0,-1.3l-3,0c-1.62,0 -1.7,-1.42 -1.7,-1.7c0,-0.17 0.05,-1.7 1.7,-1.7l1.3,0l0,-1.3c0,-1.39 1.56,-2.7 3.2,-2.7c2.55,0 3.13,1.55 3.2,1.8l0,1.2l1.3,0c0.81,0 2.7,0.22 2.7,2.2c0,2.09 -2.25,2.2 -2.7,2.2l-2,0l0,1.3l2,0c2.08,0 4,-1.16 4,-3.5c0,-2.44 -1.92,-3.5 -4,-3.5l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 557 B

View 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="m9,16l-2,0l0,-7l5,0l0,2l-3,0l0,5l0,0zm-1,-12c-2.19,0 -4.13,1.02 -5.41,2.59l-1.59,-1.59l0,4l4,0l-1.5,-1.5c1.05,-1.33 2.67,-2.2 4.5,-2.2c3.14,0 5.7,2.56 5.7,5.7c0,3.14 -2.56,5.7 -5.7,5.7c-3.14,0 -5.7,-2.56 -5.7,-5.7c0,-0.34 0.03,-0.67 0.09,-1l-1.31,0c-0.05,0.33 -0.08,0.66 -0.08,1c0,3.86 3.14,7 7,7c3.86,0 7,-3.14 7,-7c0,-3.86 -3.14,-7 -7,-7l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 500 B

View File

@@ -1,5 +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="16" height="16"> <svg width="16" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d='M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3a2.98 2.98 0 0 1-2.107-.868 2.98 2.98 0 0 1-.873-2.111 3.004 3.004 0 0 1 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012L13.115 4.1 8.196 0H7.059v2.404A6.759 6.759 0 0 0 .938 9.125c0 1.809.707 3.508 1.986 4.782a6.707 6.707 0 0 0 4.784 1.988 6.758 6.758 0 0 0 6.75-6.75 6.741 6.741 0 0 0-1.007-3.536z' fill='#F6F6F6'/> <path fill="#424242" d="m12.901149,9.091851l-0.094,0.071c-0.269,0.333 -0.746,1.096 -0.91,2.375c0.057,0.277 0.092,0.495 0.092,0.545c0,2.206 -1.794,4 -4,4a3.986,3.986 0 0 1 -2.817,-1.164a3.987,3.987 0 0 1 -1.163,-2.815c0,-2.206 1.794,-4 4,-4l0.351,0.025l0,1.85s1.626,-1.342 1.631,-1.339l1.869,-1.577l-3.5,-2.917l0,2.218l-0.371,-0.03a5.75,5.75 0 0 0 -4.055,9.826a5.75,5.75 0 0 0 9.826,-4.056a5.725,5.725 0 0 0 -0.859,-3.012z" />
<path d='M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4a3.986 3.986 0 0 1-2.817-1.164 3.987 3.987 0 0 1-1.163-2.815c0-2.206 1.794-4 4-4l.351.025v1.85S9.685 5.679 9.69 5.682l1.869-1.577-3.5-2.917v2.218l-.371-.03a5.75 5.75 0 0 0-4.055 9.826 5.75 5.75 0 0 0 9.826-4.056 5.725 5.725 0 0 0-.859-3.012z' fill='#424242'/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 987 B

After

Width:  |  Height:  |  Size: 553 B

View 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.519592,15.157073l-9.039184,0c-1.367793,0 -2.480539,-1.112828 -2.480539,-2.480622s1.112746,-2.480539 2.480539,-2.480539l0.281314,0c0.349178,-0.47173 0.888523,-0.771191 1.476341,-0.815025c0.321917,-1.471535 1.619609,-2.537962 3.165139,-2.537962c1.221543,0 2.341663,0.699516 2.889377,1.772488c0.083027,-0.008618 0.166386,-0.012926 0.250076,-0.012926c1.190221,0 2.194667,0.874105 2.378785,2.027867c0.670514,0.460047 1.07869,1.225023 1.07869,2.046096c0,1.367793 -1.112828,2.480622 -2.480539,2.480622z" />
</svg>

After

Width:  |  Height:  |  Size: 655 B

View 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

View 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

View 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

View 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="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" />
</svg>

After

Width:  |  Height:  |  Size: 490 B

View 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="m14.414133,16.199437l-3.415492,-3.433421c0.627518,-0.878526 0.995065,-1.945307 0.995065,-3.110698c0,-2.967265 -2.411463,-5.378728 -5.378728,-5.378728c-2.967265,0 -5.378728,2.411463 -5.378728,5.378728c0,2.967265 2.411463,5.378728 5.378728,5.378728c1.165391,0 2.223207,-0.367546 3.110698,-0.995065l3.433421,3.415492c0.170326,0.179291 0.403405,0.268936 0.627518,0.268936c0.224114,0 0.466156,-0.080681 0.627518,-0.268936c0.349617,-0.349617 0.349617,-0.914384 0,-1.264001l0,0.008965zm-7.799155,-2.330782c-2.321817,0 -4.213337,-1.891519 -4.213337,-4.213337c0,-2.321817 1.891519,-4.213337 4.213337,-4.213337c2.321817,0 4.213337,1.891519 4.213337,4.213337c0,2.321817 -1.891519,4.213337 -4.213337,4.213337l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 857 B

View 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="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>

After

Width:  |  Height:  |  Size: 846 B

View 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

View 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

View 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="m7,12l-2,0l3,-3l3,3l-2,0l0,5l-2,0l0,-5l0,0zm5,-4c0,-0.44 -0.91,-3 -4.5,-3c-2.42,0 -4.5,1.92 -4.5,4c-1.98,0 -3,1.52 -3,3c0,1.53 1,3 3,3l3,0l0,-1.3l-3,0c-1.62,0 -1.7,-1.42 -1.7,-1.7c0,-0.17 0.05,-1.7 1.7,-1.7l1.3,0l0,-1.3c0,-1.39 1.56,-2.7 3.2,-2.7c2.55,0 3.13,1.55 3.2,1.8l0,1.2l1.3,0c0.81,0 2.7,0.22 2.7,2.2c0,2.09 -2.25,2.2 -2.7,2.2l-2,0l0,1.3l2,0c2.08,0 4,-1.16 4,-3.5c0,-2.44 -1.92,-3.5 -4,-3.5l0,0z" />
</svg>

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 12 KiB

122
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "gitlens", "name": "gitlens",
"version": "4.4.1", "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.24" "@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.24", "version": "8.0.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.24.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.28.tgz",
"integrity": "sha512-c3Npme+2JGqxW8+B+aXdN5SPIlCf1C8WxQC6Ea39rO/ASPosnMkWVR16mDJtRE+2dr2xwOQ7DiLxb+wO/TWuPg==", "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.3", "version": "3.3.5",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz",
"integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=" "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",
@@ -2475,9 +2481,9 @@
"dev": true "dev": true
}, },
"tslint": { "tslint": {
"version": "5.6.0", "version": "5.7.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.6.0.tgz", "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz",
"integrity": "sha1-CIqmxgJmIzOGULKQCCirPt9Z9s8=", "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=",
"dev": true, "dev": true,
"requires": { "requires": {
"babel-code-frame": "6.26.0", "babel-code-frame": "6.26.0",
@@ -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"
} }

View File

@@ -1,13 +1,13 @@
{ {
"name": "gitlens", "name": "gitlens",
"version": "4.4.1", "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,68 @@
"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.stashExplorer.stashFormat": { "gitlens.gitExplorer.commitFormat": {
"type": "string",
"default": "${message} \u00a0\u2022\u00a0 ${authorAgo} \u00a0\u2022\u00a0 ${id}",
"description": "Specifies the format of committed changes in the `GitLens` custom view\nAvailable tokens\n ${id} - commit id\n ${author} - commit author\n ${message} - commit message\n ${ago} - relative commit date (e.g. 1 day ago)\n ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)\n ${authorAgo} - commit author, relative commit date\nSee https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting"
},
"gitlens.gitExplorer.commitFileFormat": {
"type": "string",
"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"
},
"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": {
"type": "string", "type": "string",
"default": "${message}", "default": "${message}",
"description": "Specifies the format of stashed changes in the `Git Stashes` explorer\nAvailable tokens\n ${id} - commit id\n ${author} - commit author\n ${message} - commit message\n ${ago} - relative commit date (e.g. 1 day ago)\n ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)\n ${authorAgo} - commit author, relative commit date\nSee https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting" "description": "Specifies the format of stashed changes in the `GitLens` custom view\nAvailable tokens\n ${id} - commit id\n ${author} - commit author\n ${message} - commit message\n ${ago} - relative commit date (e.g. 1 day ago)\n ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)\n ${authorAgo} - commit author, relative commit date\nSee https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting"
}, },
"gitlens.stashExplorer.stashFileFormat": { "gitlens.gitExplorer.stashFileFormat": {
"type": "string", "type": "string",
"default": "${file} \u00a0\u2022\u00a0 ${path}", "default": "${filePath}",
"description": "Specifies the format of a stashed file in the `Git Stashes` explorer\nAvailable tokens\n ${file} - file name\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",
@@ -760,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...",
@@ -767,17 +830,17 @@
}, },
{ {
"command": "gitlens.diffWithNext", "command": "gitlens.diffWithNext",
"title": "Compare File with Next Commit", "title": "Compare File with Next Revision",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.diffWithPrevious", "command": "gitlens.diffWithPrevious",
"title": "Compare File with Previous", "title": "Compare File with Previous Revision",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.diffLineWithPrevious", "command": "gitlens.diffLineWithPrevious",
"title": "Compare Line Commit with Previous", "title": "Compare Line Revision with Previous",
"category": "GitLens" "category": "GitLens"
}, },
{ {
@@ -787,12 +850,12 @@
}, },
{ {
"command": "gitlens.diffWithWorking", "command": "gitlens.diffWithWorking",
"title": "Compare File with Working Tree", "title": "Compare File with Working Revision",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.diffLineWithWorking", "command": "gitlens.diffLineWithWorking",
"title": "Compare Line Commit with Working Tree", "title": "Compare Line Revision with Working",
"category": "GitLens" "category": "GitLens"
}, },
{ {
@@ -859,7 +922,11 @@
{ {
"command": "gitlens.showCommitSearch", "command": "gitlens.showCommitSearch",
"title": "Search Commits", "title": "Search Commits",
"category": "GitLens" "category": "GitLens",
"icon": {
"dark": "images/dark/icon-search.svg",
"light": "images/light/icon-search.svg"
}
}, },
{ {
"command": "gitlens.showFileHistory", "command": "gitlens.showFileHistory",
@@ -926,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",
@@ -980,32 +1052,71 @@
} }
}, },
{ {
"command": "gitlens.stashExplorer.refresh", "command": "gitlens.gitExplorer.switchToHistoryView",
"title": "Refresh", "title": "Switch to History View",
"category": "GitLens", "category": "GitLens",
"icon": { "icon": {
"dark": "images/dark/icon-refresh.svg", "dark": "images/dark/icon-history.svg",
"light": "images/light/icon-refresh.svg" "light": "images/light/icon-history.svg"
} }
}, },
{ {
"command": "gitlens.stashExplorer.openChanges", "command": "gitlens.gitExplorer.switchToRepositoryView",
"title": "Switch to Repository View",
"category": "GitLens",
"icon": {
"dark": "images/dark/icon-repo.svg",
"light": "images/light/icon-repo.svg"
}
},
{
"command": "gitlens.gitExplorer.openChanges",
"title": "Open Changes", "title": "Open Changes",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.stashExplorer.openFile", "command": "gitlens.gitExplorer.openChangesWithWorking",
"title": "Open Changes with Working Tree",
"category": "GitLens"
},
{
"command": "gitlens.gitExplorer.openFile",
"title": "Open File", "title": "Open File",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.stashExplorer.openStashedFile", "command": "gitlens.gitExplorer.openFileRevision",
"title": "Open Stashed File", "title": "Open Revision",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.stashExplorer.openFileInRemote", "command": "gitlens.gitExplorer.openFileRevisionInRemote",
"title": "Open File in Remote", "title": "Open Revision in Remote",
"category": "GitLens"
},
{
"command": "gitlens.gitExplorer.openChangedFiles",
"title": "Open Files",
"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",
"title": "Open Revisions",
"category": "GitLens"
},
{
"command": "gitlens.gitExplorer.applyChanges",
"title": "Apply Changes",
"category": "GitLens" "category": "GitLens"
} }
], ],
@@ -1015,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"
@@ -1131,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"
@@ -1161,26 +1280,54 @@
}, },
{ {
"command": "gitlens.gitExplorer.refresh", "command": "gitlens.gitExplorer.refresh",
"when": "gitlens:enabled"
},
{
"command": "gitlens.stashExplorer.refresh",
"when": "gitlens:enabled"
},
{
"command": "gitlens.stashExplorer.openChanges",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.stashExplorer.openFile", "command": "gitlens.gitExplorer.switchToHistoryView",
"when": "gitlens:gitExplorer:view == repository"
},
{
"command": "gitlens.gitExplorer.switchToRepositoryView",
"when": "gitlens:gitExplorer:view == history"
},
{
"command": "gitlens.gitExplorer.openChanges",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.stashExplorer.openStashedFile", "command": "gitlens.gitExplorer.openChangesWithWorking",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.stashExplorer.openFileInRemote", "command": "gitlens.gitExplorer.openFile",
"when": "false"
},
{
"command": "gitlens.gitExplorer.openFileRevision",
"when": "false"
},
{
"command": "gitlens.gitExplorer.openFileRevisionInRemote",
"when": "false"
},
{
"command": "gitlens.gitExplorer.openChangedFiles",
"when": "false"
},
{
"command": "gitlens.gitExplorer.openChangedFileChanges",
"when": "false"
},
{
"command": "gitlens.gitExplorer.openChangedFileChangesWithWorking",
"when": "false"
},
{
"command": "gitlens.gitExplorer.openChangedFileRevisions",
"when": "false"
},
{
"command": "gitlens.gitExplorer.applyChanges",
"when": "false" "when": "false"
} }
], ],
@@ -1255,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"
}, },
{ {
@@ -1292,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"
}, },
{ {
@@ -1319,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"
}, },
{ {
@@ -1348,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": [
@@ -1365,80 +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.gitExplorer.refresh", "command": "gitlens.showCommitSearch",
"when": "gitlens:enabled && view == gitlens.gitExplorer", "when": "view == gitlens.gitExplorer",
"group": "navigation"
},
{
"command": "gitlens.stashSave",
"when": "gitlens:enabled && view == gitlens.stashExplorer",
"group": "navigation@1" "group": "navigation@1"
}, },
{ {
"command": "gitlens.stashExplorer.refresh", "command": "gitlens.gitExplorer.switchToHistoryView",
"when": "gitlens:enabled && view == gitlens.stashExplorer", "when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == repository",
"group": "navigation@2" "group": "navigation@2"
},
{
"command": "gitlens.gitExplorer.switchToRepositoryView",
"when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == history",
"group": "navigation@3"
},
{
"command": "gitlens.gitExplorer.refresh",
"when": "view == gitlens.gitExplorer",
"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",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:branch-history:remote",
"group": "1_gitlens@1"
},
{ {
"command": "gitlens.openCommitInRemote", "command": "gitlens.openCommitInRemote",
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == commit", "when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:commit",
"group": "1_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangedFileChanges",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
"group": "2_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangedFileChangesWithWorking",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
"group": "2_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangedFiles",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
"group": "3_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangedFileRevisions",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
"group": "3_gitlens@2"
},
{
"command": "gitlens.copyShaToClipboard",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit",
"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",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "1_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangesWithWorking",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "1_gitlens@2"
},
{
"command": "gitlens.gitExplorer.openFile",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "2_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openFileRevision",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "2_gitlens@2"
},
{
"command": "gitlens.openFileInRemote",
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "3_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openFileRevisionInRemote",
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "3_gitlens@2"
},
{
"command": "gitlens.gitExplorer.applyChanges",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"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",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:commit-file",
"group": "5_gitlens@2"
},
{
"command": "gitlens.gitExplorer.openFile",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:file-history",
"group": "1_gitlens@1" "group": "1_gitlens@1"
}, },
{ {
"command": "gitlens.openFileInRemote", "command": "gitlens.openFileInRemote",
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == commit-file", "when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:file-history",
"group": "1_gitlens@1"
},
{
"command": "gitlens.diffWithPrevious",
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == commit-file",
"group": "2_gitlens@1"
},
{
"command": "gitlens.diffWithWorking",
"when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == commit-file",
"group": "2_gitlens@2"
},
{
"command": "gitlens.stashApply",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == stash-commit",
"group": "3_gitlens@1"
},
{
"command": "gitlens.stashDelete",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == stash-commit",
"group": "3_gitlens@1"
},
{
"command": "gitlens.stashExplorer.openChanges",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == commit-file",
"group": "1_gitlens@1"
},
{
"command": "gitlens.stashExplorer.openFile",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == commit-file",
"group": "1_gitlens@2" "group": "1_gitlens@2"
}, },
{ {
"command": "gitlens.stashExplorer.openStashedFile", "command": "gitlens.openBranchesInRemote",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == commit-file", "when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:remote",
"group": "1_gitlens@3" "group": "1_gitlens@1"
}, },
{ {
"command": "gitlens.stashExplorer.openFileInRemote", "command": "gitlens.openRepoInRemote",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == commit-file", "when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:remote",
"group": "1_gitlens@4" "group": "1_gitlens@2"
}, },
{ {
"command": "gitlens.diffWithWorking", "command": "gitlens.stashSave",
"when": "gitlens:enabled && view == gitlens.stashExplorer && viewItem == commit-file", "when": "view == gitlens.gitExplorer && viewItem == gitlens:stashes",
"group": "1_gitlens@1"
},
{
"command": "gitlens.stashApply",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
"group": "1_gitlens@1"
},
{
"command": "gitlens.stashDelete",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
"group": "1_gitlens@2"
},
{
"command": "gitlens.gitExplorer.openChangedFileChanges",
"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"
},
{
"command": "gitlens.gitExplorer.openChangedFiles",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
"group": "3_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangedFileRevisions",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash",
"group": "3_gitlens@2"
},
{
"command": "gitlens.copyMessageToClipboard",
"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"
},
{
"command": "gitlens.gitExplorer.openChanges",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
"group": "2_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangesWithWorking",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
"group": "2_gitlens@2" "group": "2_gitlens@2"
},
{
"command": "gitlens.gitExplorer.openFile",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:stash-file",
"group": "3_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openFileRevision",
"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"
},
{
"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"
} }
] ]
}, },
@@ -1537,8 +1844,8 @@
"views": { "views": {
"explorer": [ "explorer": [
{ {
"id": "gitlens.stashExplorer", "id": "gitlens.gitExplorer",
"name": "Git Stashes", "name": "GitLens",
"when": "gitlens:enabled" "when": "gitlens:enabled"
} }
] ]
@@ -1561,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.3", "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",
@@ -1575,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.24", "@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.6.0", "tslint": "5.7.0",
"typescript": "2.4.2", "typescript": "2.5.2",
"vscode": "1.1.5" "vscode": "1.1.5"
} }
} }

View File

@@ -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}\` &nbsp; __${commit.author}__, ${moment(commit.date).fromNow()} &nbsp; _(${moment(commit.date).format(dateFormat)})_${message}`;
const markdown = new MarkdownString(`[\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.sha)}) &nbsp; __${commit.author}__, ${moment(commit.date).fromNow()} &nbsp; _(${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\` &nbsp; ${GlyphChars.Dash} &nbsp; _uncommitted_\n${codeDiff}` ? `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit)}) &nbsp; ${GlyphChars.Dash} &nbsp; _uncommitted_\n${codeDiff}`
: `\`Changes\` &nbsp; ${GlyphChars.Dash} &nbsp; \`${commit.previousShortSha}\` ${GlyphChars.ArrowLeftRight} \`${commit.shortSha}\`\n${codeDiff}`; : `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit)}) &nbsp; ${GlyphChars.Dash} &nbsp; [\`${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: {

View File

@@ -61,7 +61,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
gutter.renderOptions = { ...gutter.renderOptions }; gutter.renderOptions = { ...gutter.renderOptions };
gutter.renderOptions.before = { gutter.renderOptions.before = {
...gutter.renderOptions.before, ...gutter.renderOptions.before,
...{ contentText: GlyphChars.Space.repeat(gutter.renderOptions!.before!.contentText!.length) } ...{ contentText: GlyphChars.Space.repeat(Strings.getWidth(gutter.renderOptions!.before!.contentText!)) }
}; };
if (separateLines) { if (separateLines) {

View File

@@ -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);
} }

81
src/codeLensController.ts Normal file
View File

@@ -0,0 +1,81 @@
'use strict';
import { Objects } from './system';
import { Disposable, ExtensionContext, languages, TextEditor, workspace } from 'vscode';
import { IConfig } from './configuration';
import { CommandContext, ExtensionKey, setCommandContext } from './constants';
import { GitCodeLensProvider } from './gitCodeLensProvider';
import { GitService } from './gitService';
import { Logger } from './logger';
export class CodeLensController extends Disposable {
private _codeLensProvider: GitCodeLensProvider | undefined;
private _codeLensProviderDisposable: Disposable | undefined;
private _config: IConfig;
private _disposable: Disposable | undefined;
constructor(private context: ExtensionContext, private git: GitService) {
super(() => this.dispose());
this._onConfigurationChanged();
const subscriptions: Disposable[] = [];
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
subscriptions.push(git.onDidChangeGitCache(this._onGitCacheChanged, this));
this._disposable = Disposable.from(...subscriptions);
}
dispose() {
this._disposable && this._disposable.dispose();
this._codeLensProviderDisposable && this._codeLensProviderDisposable.dispose();
this._codeLensProviderDisposable = undefined;
this._codeLensProvider = undefined;
}
private _onConfigurationChanged() {
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
if (!Objects.areEquivalent(cfg.codeLens, this._config && this._config.codeLens)) {
Logger.log('CodeLens config changed; resetting CodeLens provider');
if (cfg.codeLens.enabled && (cfg.codeLens.recentChange.enabled || cfg.codeLens.authors.enabled)) {
if (this._codeLensProvider) {
this._codeLensProvider.reset();
}
else {
this._codeLensProvider = new GitCodeLensProvider(this.context, this.git);
this._codeLensProviderDisposable = languages.registerCodeLensProvider(GitCodeLensProvider.selector, this._codeLensProvider);
}
}
else {
this._codeLensProviderDisposable && this._codeLensProviderDisposable.dispose();
this._codeLensProviderDisposable = undefined;
this._codeLensProvider = undefined;
}
setCommandContext(CommandContext.CanToggleCodeLens, cfg.codeLens.recentChange.enabled || cfg.codeLens.authors.enabled);
}
this._config = cfg;
}
private _onGitCacheChanged() {
Logger.log('Git cache changed; resetting CodeLens provider');
this._codeLensProvider && this._codeLensProvider.reset();
}
toggleCodeLens(editor: TextEditor) {
if (!this._config.codeLens.recentChange.enabled && !this._config.codeLens.authors.enabled) return;
Logger.log(`toggleCodeLens()`);
if (this._codeLensProviderDisposable) {
this._codeLensProviderDisposable.dispose();
this._codeLensProviderDisposable = undefined;
return;
}
this._codeLensProviderDisposable = languages.registerCodeLensProvider(GitCodeLensProvider.selector, new GitCodeLensProvider(this.context, this.git));
}
}

View File

@@ -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';

View File

@@ -1,6 +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, GitRemote } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { Telemetry } from '../telemetry'; import { Telemetry } from '../telemetry';
@@ -10,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' |
@@ -18,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' |
@@ -50,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,
@@ -58,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,
@@ -125,6 +130,22 @@ export interface CommandViewContext extends CommandBaseContext {
node: ExplorerNode; node: ExplorerNode;
} }
export function isCommandViewContextWithBranch(context: CommandContext): context is CommandViewContext & { node: (ExplorerNode & { branch: GitBranch }) } {
return context.type === 'view' && (context.node as any).branch && (context.node as any).branch instanceof GitBranch;
}
interface ICommandViewContextWithCommit<T extends GitCommit> extends CommandViewContext {
node: (ExplorerNode & { commit: T });
}
export function isCommandViewContextWithCommit<T extends GitCommit>(context: CommandContext): context is ICommandViewContextWithCommit<T> {
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 {
@@ -147,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;

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri } from './common'; import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { copy } from 'copy-paste'; import { copy } from 'copy-paste';
@@ -17,6 +17,16 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
super(Commands.CopyMessageToClipboard); super(Commands.CopyMessageToClipboard);
} }
protected async preExecute(context: CommandContext, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.sha = context.node.commit.sha;
return this.execute(context.editor, context.node.commit.uri, args);
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> { async execute(editor?: TextEditor, uri?: Uri, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor); uri = getCommandUri(uri, editor);
@@ -64,7 +74,7 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
// Get the full commit message -- since blame only returns the summary // Get the full commit message -- since blame only returns the summary
const commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, args.sha); const commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, args.sha);
if (!commit) return undefined; if (commit === undefined) return undefined;
args.message = commit.message; args.message = commit.message;
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri } from './common'; import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { copy } from 'copy-paste'; import { copy } from 'copy-paste';
@@ -16,6 +16,16 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
super(Commands.CopyShaToClipboard); super(Commands.CopyShaToClipboard);
} }
protected async preExecute(context: CommandContext, args: CopyShaToClipboardCommandArgs = {}): Promise<any> {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
args.sha = context.node.commit.sha;
return this.execute(context.editor, context.node.commit.uri, args);
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: CopyShaToClipboardCommandArgs = {}): Promise<any> { async execute(editor?: TextEditor, uri?: Uri, args: CopyShaToClipboardCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor); uri = getCommandUri(uri, editor);
@@ -45,7 +55,7 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
try { try {
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return undefined; if (blame === undefined) return undefined;
args.sha = blame.commit.sha; args.sha = blame.commit.sha;
} }

View File

@@ -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`);
}
} }
} }

View File

@@ -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
View 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`);
}
}
}

View File

@@ -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`);
}
} }
} }

View File

@@ -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`);
}
} }
} }

View File

@@ -2,17 +2,17 @@
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 { 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;
line?: number;
showOptions?: TextDocumentShowOptions; showOptions?: TextDocumentShowOptions;
} }
@@ -36,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');
@@ -43,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})`);
@@ -51,30 +54,19 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
} }
} }
if (args.commit.previousSha === undefined) 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) },
]); 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),
`${path.basename(args.commit.previousUri.fsPath)} (${args.commit.previousShortSha}) ${GlyphChars.ArrowLeftRight} ${path.basename(args.commit.uri.fsPath)} (${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`);
}
} }
} }

View File

@@ -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`);
} }
} }
} }

View File

@@ -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`);
}
} }
} }

View File

@@ -1,7 +1,6 @@
'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, isCommandViewContextWithBranch } from './common';
import { GlyphChars } from '../constants'; import { GlyphChars } from '../constants';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
@@ -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 {
@@ -18,6 +18,16 @@ export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
super(Commands.OpenBranchInRemote); super(Commands.OpenBranchInRemote);
} }
protected async preExecute(context: CommandContext, args: OpenBranchInRemoteCommandArgs = {}): Promise<any> {
if (isCommandViewContextWithBranch(context)) {
args = { ...args };
args.branch = context.node.branch.name;
args.remote = context.node.branch.getRemote();
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: OpenBranchInRemoteCommandArgs = {}) { async execute(editor?: TextEditor, uri?: Uri, args: OpenBranchInRemoteCommandArgs = {}) {
uri = getCommandUri(uri, editor); uri = getCommandUri(uri, editor);
@@ -41,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);
} }

View 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`);
}
}
}

View File

@@ -1,12 +1,10 @@
'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 } from './common'; import { ActiveEditorCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
import { GitBlameCommit, GitService, GitUri } from '../gitService'; import { GitBlameCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { Messages } from '../messages'; import { Messages } from '../messages';
import { OpenInRemoteCommandArgs } from './openInRemote'; import { OpenInRemoteCommandArgs } from './openInRemote';
import { CommitNode } from '../views/explorerNodes';
export interface OpenCommitInRemoteCommandArgs { export interface OpenCommitInRemoteCommandArgs {
sha?: string; sha?: string;
@@ -19,7 +17,7 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
} }
protected async preExecute(context: CommandContext, args: OpenCommitInRemoteCommandArgs = {}): Promise<any> { protected async preExecute(context: CommandContext, args: OpenCommitInRemoteCommandArgs = {}): Promise<any> {
if (context.type === 'view' && context.node instanceof CommitNode) { if (isCommandViewContextWithCommit(context)) {
args = { ...args }; args = { ...args };
args.sha = context.node.commit.sha; args.sha = context.node.commit.sha;
return this.execute(context.editor, context.node.commit.uri, args); return this.execute(context.editor, context.node.commit.uri, args);
@@ -54,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',

View File

@@ -1,34 +1,58 @@
'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, Commands, getCommandUri } 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 {
branch?: string;
range?: boolean;
}
export class OpenFileInRemoteCommand extends ActiveEditorCommand { export class OpenFileInRemoteCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.OpenFileInRemote); super(Commands.OpenFileInRemote);
} }
async execute(editor?: TextEditor, uri?: Uri) { protected async preExecute(context: CommandContext, args: OpenFileInRemoteCommandArgs = { range: true }): Promise<any> {
if (isCommandViewContextWithCommit(context)) {
args = { ...args };
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.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: OpenFileInRemoteCommandArgs = { range: true }) {
uri = getCommandUri(uri, editor); uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined; if (uri === undefined) return undefined;
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;
const branch = await this.git.getBranch(gitUri.repoPath); if (args.branch === undefined) {
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 = editor === undefined ? undefined : new Range(editor.selection.start.with({ line: editor.selection.start.line + 1 }), editor.selection.end.with({ line: editor.selection.end.line + 1 })); 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 }))
: 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

View File

@@ -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,8 +27,17 @@ 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);
const command = new OpenRemoteCommandQuickPickItem(args.remotes[0], args.resource); const command = new OpenRemoteCommandQuickPickItem(args.remotes[0], args.resource);
return command.execute(); return command.execute();
} }
@@ -35,25 +45,20 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
let placeHolder = ''; let placeHolder = '';
switch (args.resource.type) { switch (args.resource.type) {
case 'branch': case 'branch':
// Check to see if the remote is in the branch this.ensureRemoteBranchName(args);
const index = args.resource.branch.indexOf('/');
if (index >= 0) {
const remoteName = args.resource.branch.substring(0, index);
const remote = args.remotes.find(r => r.name === remoteName);
if (remote !== undefined) {
args.resource.branch = args.resource.branch.substring(index + 1);
args.remotes = [remote];
}
}
placeHolder = `open ${args.resource.branch} branch in${GlyphChars.Ellipsis}`; placeHolder = `open ${args.resource.branch} branch in${GlyphChars.Ellipsis}`;
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;
case 'file': case 'file':
placeHolder = `open ${args.resource.fileName} in${GlyphChars.Ellipsis}`;
break;
case 'revision':
if (args.resource.commit !== undefined && args.resource.commit instanceof GitLogCommit) { if (args.resource.commit !== undefined && args.resource.commit instanceof GitLogCommit) {
if (args.resource.commit.status === 'D') { if (args.resource.commit.status === 'D') {
args.resource.sha = args.resource.commit.previousSha; args.resource.sha = args.resource.commit.previousSha;
@@ -65,16 +70,12 @@ 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}`;
} }
break; break;
case 'working-file':
placeHolder = `open ${args.resource.fileName} in${GlyphChars.Ellipsis}`;
break;
} }
if (args.remotes.length === 1) { if (args.remotes.length === 1) {
@@ -93,4 +94,19 @@ export class OpenInRemoteCommand extends ActiveEditorCommand {
return window.showErrorMessage(`Unable to open in remote provider. See output channel for more details`); return window.showErrorMessage(`Unable to open in remote provider. See output channel for more details`);
} }
} }
private ensureRemoteBranchName(args: OpenInRemoteCommandArgs) {
if (args.remotes === undefined || args.resource === undefined || args.resource.type !== 'branch') return;
// Check to see if the remote is in the branch
const index = args.resource.branch.indexOf('/');
if (index >= 0) {
const remoteName = args.resource.branch.substring(0, index);
const remote = args.remotes.find(r => r.name === remoteName);
if (remote !== undefined) {
args.resource.branch = args.resource.branch.substring(index + 1);
args.remotes = [remote];
}
}
}
} }

View File

@@ -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);
} }

View File

@@ -8,7 +8,6 @@ import { Logger } from '../logger';
import { Messages } from '../messages'; import { Messages } from '../messages';
import { CommandQuickPickItem, CommitsQuickPick } from '../quickPicks'; import { CommandQuickPickItem, CommitsQuickPick } from '../quickPicks';
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails'; import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
import { paste } from 'copy-paste';
const searchByRegex = /^([@:#])/; const searchByRegex = /^([@:#])/;
const searchByMap = new Map<string, GitRepoSearchBy>([ const searchByMap = new Map<string, GitRepoSearchBy>([
@@ -49,12 +48,6 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
args.search = `#${blameLine.commit.shortSha}`; args.search = `#${blameLine.commit.shortSha}`;
} }
} }
if (!args.search) {
args.search = await new Promise<string>((resolve, reject) => {
paste((err: Error, content: string) => resolve(err ? '' : content));
});
}
} }
} }
catch (ex) { catch (ex) {

View File

@@ -2,7 +2,7 @@
import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
import { Commands, EditorCommand, getCommandUri } from './common'; import { Commands, EditorCommand, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitExplorer } from '../views/gitExplorer'; // import { GitExplorer } from '../views/gitExplorer';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Messages } from '../messages'; import { Messages } from '../messages';
import { Logger } from '../logger'; import { Logger } from '../logger';
@@ -15,7 +15,7 @@ export interface ShowFileHistoryCommandArgs {
export class ShowFileHistoryCommand extends EditorCommand { export class ShowFileHistoryCommand extends EditorCommand {
constructor(private git: GitService, private explorer?: GitExplorer) { constructor(private git: GitService) {
super(Commands.ShowFileHistory); super(Commands.ShowFileHistory);
} }
@@ -33,10 +33,10 @@ export class ShowFileHistoryCommand extends EditorCommand {
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
try { try {
if (this.explorer !== undefined) { // if (this.explorer !== undefined) {
this.explorer.addHistory(gitUri); // this.explorer.addHistory(gitUri);
return undefined; // return undefined;
} // }
const locations = await this.git.getLogLocations(gitUri, args.sha, args.line); const locations = await this.git.getLogLocations(gitUri, args.sha, args.line);
if (locations === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show file history'); if (locations === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show file history');

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Strings } from '../system'; import { Strings } from '../system';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common'; import { ActiveEditorCachedCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
import { GlyphChars } from '../constants'; import { GlyphChars } from '../constants';
import { GitCommit, GitLog, GitLogCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitLog, GitLogCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
@@ -20,10 +20,31 @@ 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: ShowQuickCommitDetailsCommandArgs = {}): Promise<any> {
if (context.type === 'view') {
args = { ...args };
args.sha = context.node.uri.sha;
if (isCommandViewContextWithCommit(context)) {
args.commit = context.node.commit;
}
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitDetailsCommandArgs = {}) { async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitDetailsCommandArgs = {}) {
uri = getCommandUri(uri, editor); uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined; if (uri === undefined) return undefined;

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Strings } from '../system'; import { Strings } from '../system';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common'; import { ActiveEditorCachedCommand, CommandContext, Commands, getCommandUri, isCommandViewContextWithCommit } from './common';
import { GlyphChars } from '../constants'; import { GlyphChars } from '../constants';
import { GitCommit, GitLog, GitLogCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitLog, GitLogCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
@@ -20,10 +20,31 @@ 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: ShowQuickCommitFileDetailsCommandArgs = {}): Promise<any> {
if (context.type === 'view') {
args = { ...args };
args.sha = context.node.uri.sha;
if (isCommandViewContextWithCommit(context)) {
args.commit = context.node.commit;
}
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitFileDetailsCommandArgs = {}) { async execute(editor?: TextEditor, uri?: Uri, args: ShowQuickCommitFileDetailsCommandArgs = {}) {
uri = getCommandUri(uri, editor); uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined; if (uri === undefined) return undefined;
@@ -83,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

View File

@@ -1,13 +1,11 @@
'use strict'; 'use strict';
import { Strings } from '../system'; import { Strings } from '../system';
import { MessageItem, window } from 'vscode'; import { MessageItem, window } from 'vscode';
import { GitService, GitStashCommit } from '../gitService'; import { Command, CommandContext, Commands, isCommandViewContextWithCommit } from './common';
import { Command, CommandContext, Commands } from './common';
import { GlyphChars } from '../constants'; import { GlyphChars } from '../constants';
import { CommitQuickPickItem, StashListQuickPick } from '../quickPicks'; import { GitService, GitStashCommit } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem, CommitQuickPickItem, StashListQuickPick } from '../quickPicks';
import { StashCommitNode } from '../views/stashCommitNode';
export interface StashApplyCommandArgs { export interface StashApplyCommandArgs {
confirm?: boolean; confirm?: boolean;
@@ -24,16 +22,13 @@ export class StashApplyCommand extends Command {
} }
protected async preExecute(context: CommandContext, args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) { protected async preExecute(context: CommandContext, args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
if (context.type === 'view' && context.node instanceof StashCommitNode) { if (isCommandViewContextWithCommit<GitStashCommit>(context)) {
args = { ...args }; args = { ...args };
args.stashItem = { stashName: context.node.commit.stashName, message: context.node.commit.message };
const stash = context.node.commit;
args.stashItem = { stashName: stash.stashName, message: stash.message };
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 }) {

View File

@@ -1,11 +1,10 @@
'use strict'; 'use strict';
import { MessageItem, window } from 'vscode'; import { MessageItem, window } from 'vscode';
import { Command, CommandContext, Commands } from './common'; import { Command, CommandContext, Commands, isCommandViewContextWithCommit } from './common';
import { GlyphChars } from '../constants'; import { GlyphChars } from '../constants';
import { GitService } from '../gitService'; import { GitService, GitStashCommit } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem } from '../quickPicks';
import { StashCommitNode } from '../views/stashCommitNode';
export interface StashDeleteCommandArgs { export interface StashDeleteCommandArgs {
confirm?: boolean; confirm?: boolean;
@@ -21,16 +20,13 @@ export class StashDeleteCommand extends Command {
} }
protected async preExecute(context: CommandContext, args: StashDeleteCommandArgs = { confirm: true }) { protected async preExecute(context: CommandContext, args: StashDeleteCommandArgs = { confirm: true }) {
if (context.type === 'view' && context.node instanceof StashCommitNode) { if (isCommandViewContextWithCommit<GitStashCommit>(context)) {
args = { ...args }; args = { ...args };
args.stashItem = { stashName: context.node.commit.stashName, message: context.node.commit.message };
const stash = context.node.commit;
args.stashItem = { stashName: stash.stashName, message: stash.message };
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 }) {

View File

@@ -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 }; args.uris = context.scmResourceStates.map(s => s.resourceUri);
if (args.unstagedOnly === undefined) { return this.execute(args);
args.unstagedOnly = false;
} }
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');

View File

@@ -1,15 +1,15 @@
'use strict'; 'use strict';
import { TextEditor, TextEditorEdit } from 'vscode'; import { TextEditor, TextEditorEdit } from 'vscode';
import { CodeLensController } from '../codeLensController';
import { Commands, EditorCommand } from './common'; import { Commands, EditorCommand } from './common';
import { GitService } from '../gitService';
export class ToggleCodeLensCommand extends EditorCommand { export class ToggleCodeLensCommand extends EditorCommand {
constructor(private git: GitService) { constructor(private codeLensController: CodeLensController) {
super(Commands.ToggleCodeLens); super(Commands.ToggleCodeLens);
} }
execute(editor: TextEditor, edit: TextEditorEdit) { execute(editor: TextEditor, edit: TextEditorEdit) {
return this.git.toggleCodeLens(editor); return this.codeLensController.toggleCodeLens(editor);
} }
} }

View File

@@ -2,11 +2,13 @@
import { FileAnnotationType } from './annotations/annotationController'; import { FileAnnotationType } from './annotations/annotationController';
import { Commands } from './commands'; import { Commands } from './commands';
import { LineAnnotationType } from './currentLineController'; import { LineAnnotationType } from './currentLineController';
import { GitExplorerView } from './views/gitExplorer';
import { OutputLevel } from './logger'; 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' |
@@ -40,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' |
@@ -118,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: {
@@ -256,6 +275,8 @@ export interface IConfig {
}; };
blame: { blame: {
ignoreWhitespace: boolean;
file: { file: {
annotationType: FileAnnotationType; annotationType: FileAnnotationType;
lineHighlight: { lineHighlight: {
@@ -297,19 +318,17 @@ export interface IConfig {
defaultDateFormat: string | null; defaultDateFormat: string | null;
gitExplorer: { gitExplorer: {
enabled: boolean; view: GitExplorerView;
showTrackingBranch: boolean;
commitFormat: string; commitFormat: string;
commitFileFormat: string; commitFileFormat: string;
// dateFormat: string | null;
};
stashExplorer: {
enabled: boolean;
stashFormat: string; stashFormat: string;
stashFileFormat: string; stashFileFormat: string;
// dateFormat: string | null; // dateFormat: string | null;
}; };
remotes: IRemotesConfig[];
statusBar: { statusBar: {
enabled: boolean; enabled: boolean;
alignment: 'left' | 'right'; alignment: 'left' | 'right';

View File

@@ -40,23 +40,25 @@ export const BuiltInCommands = {
}; };
export type CommandContext = export type CommandContext =
'gitlens:annotationStatus' |
'gitlens:canToggleCodeLens' | 'gitlens:canToggleCodeLens' |
'gitlens:enabled' | 'gitlens:enabled' |
'gitlens:hasRemotes' | 'gitlens:hasRemotes' |
'gitlens:gitExplorer:view' |
'gitlens:isBlameable' | 'gitlens:isBlameable' |
'gitlens:isRepository' | 'gitlens:isRepository' |
'gitlens:isTracked' | 'gitlens:isTracked' |
'gitlens:key' | 'gitlens:key';
'gitlens:annotationStatus';
export const CommandContext = { export const CommandContext = {
AnnotationStatus: 'gitlens:annotationStatus' as CommandContext,
CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext, CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext,
Enabled: 'gitlens:enabled' as CommandContext, Enabled: 'gitlens:enabled' as CommandContext,
GitExplorerView: 'gitlens:gitExplorer:view' as CommandContext,
HasRemotes: 'gitlens:hasRemotes' as CommandContext, HasRemotes: 'gitlens:hasRemotes' as CommandContext,
IsBlameable: 'gitlens:isBlameable' as CommandContext, IsBlameable: 'gitlens:isBlameable' as CommandContext,
IsRepository: 'gitlens:isRepository' as CommandContext, IsRepository: 'gitlens:isRepository' as CommandContext,
IsTracked: 'gitlens:isTracked' as CommandContext, IsTracked: 'gitlens:isTracked' as CommandContext,
Key: 'gitlens:key' as CommandContext, Key: 'gitlens:key' as CommandContext
AnnotationStatus: 'gitlens:annotationStatus' as CommandContext
}; };
export function setCommandContext(key: CommandContext | string, value: any) { export function setCommandContext(key: CommandContext | string, value: any) {
@@ -75,8 +77,10 @@ export type GlyphChars = '\u21a9' |
'\u2937' | '\u2937' |
'\u2190' | '\u2190' |
'\u2194' | '\u2194' |
'\u2192' |
'\u21e8' | '\u21e8' |
'\u2191' | '\u2191' |
'\u2713' |
'\u2014' | '\u2014' |
'\u2022' | '\u2022' |
'\u2026' | '\u2026' |
@@ -88,8 +92,10 @@ 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,
Dash: '\u2014' as GlyphChars, Dash: '\u2014' as GlyphChars,
Dot: '\u2022' as GlyphChars, Dot: '\u2022' as GlyphChars,
Ellipsis: '\u2026' as GlyphChars, Ellipsis: '\u2026' as GlyphChars,

View File

@@ -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:
@@ -476,11 +479,11 @@ export class CurrentLineController extends Disposable {
break; break;
case StatusBarCommand.DiffWithPrevious: case StatusBarCommand.DiffWithPrevious:
this._statusBarItem.command = Commands.DiffLineWithPrevious; this._statusBarItem.command = Commands.DiffLineWithPrevious;
this._statusBarItem.tooltip = 'Compare Line Commit with Previous'; this._statusBarItem.tooltip = 'Compare Line Revision with Previous';
break; break;
case StatusBarCommand.DiffWithWorking: case StatusBarCommand.DiffWithWorking:
this._statusBarItem.command = Commands.DiffLineWithWorking; this._statusBarItem.command = Commands.DiffLineWithWorking;
this._statusBarItem.tooltip = 'Compare Line Commit with Working Tree'; this._statusBarItem.tooltip = 'Compare Line Revision with Working';
break; break;
case StatusBarCommand.ToggleCodeLens: case StatusBarCommand.ToggleCodeLens:
this._statusBarItem.tooltip = 'Toggle Git CodeLens'; this._statusBarItem.tooltip = 'Toggle Git CodeLens';

View File

@@ -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';
@@ -17,10 +17,11 @@ import { StashApplyCommand, StashDeleteCommand, StashSaveCommand } from './comma
import { ToggleCodeLensCommand } from './commands'; import { ToggleCodeLensCommand } from './commands';
import { CodeLensLocations, IConfig, LineHighlightLocations } from './configuration'; import { CodeLensLocations, IConfig, LineHighlightLocations } from './configuration';
import { ApplicationInsightsKey, CommandContext, ExtensionKey, QualifiedExtensionId, setCommandContext, WorkspaceState } from './constants'; import { ApplicationInsightsKey, CommandContext, ExtensionKey, QualifiedExtensionId, setCommandContext, WorkspaceState } from './constants';
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 { StashExplorer } from './views/stashExplorer';
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider'; import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
import { GitContextTracker, GitService } from './gitService'; import { GitContextTracker, GitService } from './gitService';
import { Keyboard } from './keyboard'; import { Keyboard } from './keyboard';
@@ -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;
@@ -71,7 +73,7 @@ export async function activate(context: ExtensionContext) {
await context.globalState.update(WorkspaceState.GitLensVersion, gitlensVersion); await context.globalState.update(WorkspaceState.GitLensVersion, gitlensVersion);
const git = new GitService(context, repoPath); const git = new GitService(repoPath);
context.subscriptions.push(git); context.subscriptions.push(git);
const gitContextTracker = new GitContextTracker(git); const gitContextTracker = new GitContextTracker(git);
@@ -84,15 +86,15 @@ export async function activate(context: ExtensionContext) {
const annotationController = new AnnotationController(context, git, gitContextTracker); const annotationController = new AnnotationController(context, git, gitContextTracker);
context.subscriptions.push(annotationController); context.subscriptions.push(annotationController);
const codeLensController = new CodeLensController(context, git);
context.subscriptions.push(codeLensController);
const currentLineController = new CurrentLineController(context, git, gitContextTracker, annotationController); const currentLineController = new CurrentLineController(context, git, gitContextTracker, annotationController);
context.subscriptions.push(currentLineController); context.subscriptions.push(currentLineController);
context.subscriptions.push(new Keyboard()); context.subscriptions.push(new Keyboard());
// const explorer = new GitExplorer(context, git); context.subscriptions.push(window.registerTreeDataProvider('gitlens.gitExplorer', new GitExplorer(context, git)));
// context.subscriptions.push(window.registerTreeDataProvider('gitlens.gitExplorer', explorer));
context.subscriptions.push(window.registerTreeDataProvider('gitlens.stashExplorer', new StashExplorer(context, git)));
context.subscriptions.push(commands.registerTextEditorCommand('gitlens.computingFileAnnotations', () => { })); context.subscriptions.push(commands.registerTextEditorCommand('gitlens.computingFileAnnotations', () => { }));
@@ -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));
@@ -134,7 +138,7 @@ export async function activate(context: ExtensionContext) {
context.subscriptions.push(new StashApplyCommand(git)); context.subscriptions.push(new StashApplyCommand(git));
context.subscriptions.push(new StashDeleteCommand(git)); context.subscriptions.push(new StashDeleteCommand(git));
context.subscriptions.push(new StashSaveCommand(git)); context.subscriptions.push(new StashSaveCommand(git));
context.subscriptions.push(new ToggleCodeLensCommand(git)); context.subscriptions.push(new ToggleCodeLensCommand(codeLensController));
// Constantly over my data cap so stop collecting initialized event // Constantly over my data cap so stop collecting initialized event
// Telemetry.trackEvent('initialized', Objects.flatten(cfg, 'config', true)); // Telemetry.trackEvent('initialized', Objects.flatten(cfg, 'config', true));
@@ -273,10 +277,13 @@ async function notifyOnNewGitLensVersion(context: ExtensionContext, version: str
const previousVersion = context.globalState.get<string>(WorkspaceState.GitLensVersion); const previousVersion = context.globalState.get<string>(WorkspaceState.GitLensVersion);
if (previousVersion === undefined) { if (previousVersion === undefined) {
Logger.log(`GitLens first-time install`);
await Messages.showWelcomeMessage(); await Messages.showWelcomeMessage();
return; return;
} }
Logger.log(`GitLens upgraded from v${previousVersion} to v${version}`);
const [major, minor] = version.split('.'); const [major, minor] = version.split('.');
const [prevMajor, prevMinor] = previousVersion.split('.'); const [prevMajor, prevMinor] = previousVersion.split('.');
if (major === prevMajor && minor === prevMinor) return; if (major === prevMajor && minor === prevMinor) return;

View File

@@ -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);
} }

View File

@@ -7,6 +7,7 @@ import * as path from 'path';
export interface IStatusFormatOptions extends IFormatOptions { export interface IStatusFormatOptions extends IFormatOptions {
tokenOptions?: { tokenOptions?: {
file?: Strings.ITokenOptions; file?: Strings.ITokenOptions;
filePath?: Strings.ITokenOptions;
path?: Strings.ITokenOptions; path?: Strings.ITokenOptions;
}; };
} }
@@ -18,6 +19,11 @@ export class StatusFileFormatter extends Formatter<IGitStatusFile, IStatusFormat
return this._padOrTruncate(file, this._options.tokenOptions!.file); return this._padOrTruncate(file, this._options.tokenOptions!.file);
} }
get filePath() {
const filePath = GitStatusFile.getFormattedPath(this._item);
return this._padOrTruncate(filePath, this._options.tokenOptions!.filePath);
}
get path() { get path() {
const directory = GitStatusFile.getFormattedDirectory(this._item, false); const directory = GitStatusFile.getFormattedDirectory(this._item, false);
return this._padOrTruncate(directory, this._options.tokenOptions!.file); return this._padOrTruncate(directory, this._options.tokenOptions!.file);

View File

@@ -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';
@@ -31,36 +34,55 @@ const GitWarnings = [
/Not a git repository/, /Not a git repository/,
/is outside repository/, /is outside repository/,
/no such path/, /no such path/,
/does not have any commits/ /does not have any commits/,
/Path \'.*?\' does not exist 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 {
// Fixes https://github.com/eamodio/vscode-gitlens/issues/73 return await gitCommandCore(options, ...args);
// 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');
const opts = { encoding: 'utf8', ...options };
const s = await spawnPromise(git.path, args, { cwd: options.cwd, encoding: (opts.encoding === 'utf8') ? 'utf8' : 'binary' });
Logger.log('git', ...args, ` cwd='${options.cwd}'`);
if (opts.encoding === 'utf8' || opts.encoding === 'binary') return s;
return iconv.decode(Buffer.from(s, 'binary'), opts.encoding);
} }
catch (ex) { catch (ex) {
const msg = ex && ex.toString(); return gitCommandDefaultErrorHandler(ex, options, ...args);
if (msg) { }
for (const warning of GitWarnings) { }
if (warning.test(msg)) {
Logger.warn('git', ...args, ` cwd='${options.cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`); async function gitCommandCore(options: GitCommandOptions, ...args: any[]): Promise<string> {
return ''; // 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
args.splice(0, 0, '-c', 'core.quotepath=false');
const opts = { encoding: 'utf8', ...options };
const s = await spawnPromise(git.path, args, { cwd: options.cwd, encoding: (opts.encoding === 'utf8') ? 'utf8' : 'binary' });
Logger.log('git', ...args, ` cwd='${options.cwd}'`);
if (opts.encoding === 'utf8' || opts.encoding === 'binary') return s;
return iconv.decode(Buffer.from(s, 'binary'), opts.encoding);
}
function gitCommandDefaultErrorHandler(ex: Error, options: GitCommandOptions, ...args: any[]): string {
const msg = ex && ex.toString();
if (msg) {
for (const warning of GitWarnings) {
if (warning.test(msg)) {
Logger.warn('git', ...args, ` cwd='${options.cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
return '';
} }
} }
Logger.error(ex, 'git', ...args, ` cwd='${options.cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
throw ex;
} }
Logger.error(ex, 'git', ...args, ` cwd='${options.cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
throw ex;
} }
export class Git { export class Git {
@@ -89,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 },
@@ -125,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);
@@ -150,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);
} }
@@ -166,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 '';
} }
} }
@@ -283,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 '';
} }
} }
@@ -298,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) {
@@ -320,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);
} }

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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) {
branch = branch.substring(0, index);
}
this.name = branch; this.name = branch;
this.tracking = tracking;
}
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('/'));
} }
} }

View File

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

View File

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

View File

@@ -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);
} }
} }

View File

@@ -40,7 +40,7 @@ export class GitStatusFile implements IGitStatusFile {
} }
getFormattedPath(separator: string = Strings.pad(GlyphChars.Dot, 2, 2)): string { getFormattedPath(separator: string = Strings.pad(GlyphChars.Dot, 2, 2)): string {
return GitUri.getFormattedPath(this.fileName, separator); return GitStatusFile.getFormattedPath(this, separator);
} }
getOcticon() { getOcticon() {
@@ -57,6 +57,10 @@ export class GitStatusFile implements IGitStatusFile {
? `${directory} ${Strings.pad(GlyphChars.ArrowLeft, 1, 1)} ${status.originalFileName}` ? `${directory} ${Strings.pad(GlyphChars.ArrowLeft, 1, 1)} ${status.originalFileName}`
: directory; : directory;
} }
static getFormattedPath(status: IGitStatusFile, separator: string = Strings.pad(GlyphChars.Dot, 2, 2)): string {
return GitUri.getFormattedPath(status.fileName, separator);
}
} }
const statusOcticonsMap = { const statusOcticonsMap = {

View 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;
}
}

View 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\/?$/, '')
];
}
}

View 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}`;
}
}

View File

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

View File

@@ -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;
}
} }

View File

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

View File

@@ -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');
} }
} }

View File

@@ -3,27 +3,30 @@ 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' | 'working-file'; export type RemoteResourceType = 'branch' | 'branches' | 'commit' | 'file' | 'repo' | 'revision';
export type RemoteResource = { type: 'branch', branch: string } | export type RemoteResource =
{ type: 'branch', branch: string } |
{ type: 'branches' } |
{ type: 'commit', sha: string } | { type: 'commit', sha: string } |
{ type: 'file', branch?: string, commit?: GitLogCommit, fileName: string, range?: Range, sha?: string } | { type: 'file', branch?: string, fileName: string, range?: Range } |
{ type: 'repo' } | { type: 'repo' } |
{ type: 'working-file', branch?: string, fileName: string, range?: Range }; { type: 'revision', branch?: string, commit?: GitLogCommit, fileName: string, range?: Range, sha?: string };
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';
case 'working-file': return 'Working File'; case 'revision': return 'Revision';
default: return ''; default: return '';
} }
} }
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;
@@ -31,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;
@@ -43,16 +56,12 @@ export abstract class RemoteProvider {
open(resource: RemoteResource): Promise<{} | undefined> { open(resource: RemoteResource): Promise<{} | undefined> {
switch (resource.type) { switch (resource.type) {
case 'branch': case 'branch': return this.openBranch(resource.branch);
return this.openBranch(resource.branch); case 'branches': return this.openBranches();
case 'commit': case 'commit': return this.openCommit(resource.sha);
return this.openCommit(resource.sha); case 'file': return this.openFile(resource.fileName, resource.branch, undefined, resource.range);
case 'file': case 'repo': return this.openRepo();
return this.openFile(resource.fileName, resource.branch, resource.sha, resource.range); case 'revision': return this.openFile(resource.fileName, resource.branch, resource.sha, resource.range);
case 'repo':
return this.openRepo();
case 'working-file':
return this.openFile(resource.fileName, resource.branch, undefined, resource.range);
} }
} }
@@ -60,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));
} }

View File

@@ -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`;
} }

View File

@@ -1,5 +1,5 @@
'use strict'; 'use strict';
import { ExtensionContext, TextDocumentContentProvider, Uri, window } from 'vscode'; import { CancellationToken, ExtensionContext, TextDocumentContentProvider, Uri, window } from 'vscode';
import { DocumentSchemes } from './constants'; import { DocumentSchemes } from './constants';
import { GitService } from './gitService'; import { GitService } from './gitService';
import { Logger } from './logger'; import { Logger } from './logger';
@@ -11,11 +11,13 @@ export class GitContentProvider implements TextDocumentContentProvider {
constructor(context: ExtensionContext, private git: GitService) { } constructor(context: ExtensionContext, private git: GitService) { }
async provideTextDocumentContent(uri: Uri): Promise<string> { async provideTextDocumentContent(uri: Uri, token: CancellationToken): Promise<string | undefined> {
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,8 +25,8 @@ export class GitContentProvider implements TextDocumentContentProvider {
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'GitContentProvider', 'getVersionedFileText'); Logger.error(ex, 'GitContentProvider', 'getVersionedFileText');
await 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 ''; return undefined;
} }
} }
} }

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