mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-12 11:08:34 -05:00
Compare commits
16 Commits
v4.0.0-bet
...
v4.0.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23c7171d7f | ||
|
|
dd0b95498e | ||
|
|
e6316400f0 | ||
|
|
eeff31cf27 | ||
|
|
eb3b9ad6c9 | ||
|
|
10674124c8 | ||
|
|
e0f66247cf | ||
|
|
badd999db1 | ||
|
|
9ae4cc36a1 | ||
|
|
30bb4398a3 | ||
|
|
9c7a971e21 | ||
|
|
ba59fb29ad | ||
|
|
50ba3e1446 | ||
|
|
62e5ef6225 | ||
|
|
ed54d289dd | ||
|
|
2a8dafd9e9 |
33
CHANGELOG.md
33
CHANGELOG.md
@@ -4,16 +4,29 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
|
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [4.0.0-beta.2] - 2017-06-07
|
## [4.0.2-beta] - 2017-06-10
|
||||||
|
### Added
|
||||||
|
- Improves performance
|
||||||
|
- Optimized git output parsing to increase speed and reduce memory usage
|
||||||
|
- Defers diff chunk parsing until it is actually required
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixes excessive memory usage when parsing diffs
|
||||||
|
|
||||||
|
## [4.0.1] - 2017-06-09
|
||||||
|
### Fixed
|
||||||
|
- Fixes [#87](https://github.com/eamodio/vscode-gitlens/issues/87) - Can't open files in remote when using git@ urls (ssh)
|
||||||
|
|
||||||
|
## [4.0.0] - 2017-06-09
|
||||||
### Added
|
### Added
|
||||||
- Adds all-new, beautiful, highly customizable and themeable, file blame annotations
|
- Adds all-new, beautiful, highly customizable and themeable, file blame annotations
|
||||||
- Can now fully customize the [layout and content](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#file-blame-annotation-settings), as well as the [theme](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#theme-settings)
|
- Can now fully customize the [layout and content](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#file-blame-annotation-settings), as well as the [theme](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#theme-settings)
|
||||||
- Adds all-new configurability and themeability to the current line blame annotations
|
- Adds all-new configurability and themeability to the current line blame annotations
|
||||||
- Can now fully customize the [layout and content](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#line-blame-annotation-settings), as well as the [theme](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#theme-settings)
|
- Can now fully customize the [layout and content](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#line-blame-annotation-settings), as well as the [theme](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#theme-settings)
|
||||||
- Adds all-new configurability to the status bar blame information
|
- Adds all-new configurability to the status bar blame information
|
||||||
- Can now fully customize the [layout and content](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#status-bar-settings)
|
- Can now fully customize the [layout and content](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#status-bar-settings)
|
||||||
- Adds all-new [configurability](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#advanced-settings) over which commands are added to which menus via the `gitlens.advanced.menus` setting
|
- Adds all-new [configurability](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#advanced-settings) over which commands are added to which menus via the `gitlens.advanced.menus` setting
|
||||||
- Adds better [configurability](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#code-lens-settings) over where Git code lens will be shown -- both by default and per language
|
- Adds better [configurability](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#code-lens-settings) over where Git code lens will be shown -- both by default and per language
|
||||||
- Adds an all-new `changes` (diff) hover annotation to the current line - provides instant access to the line's previous version
|
- Adds an all-new `changes` (diff) hover annotation to the current line - provides instant access to the line's previous version
|
||||||
- Adds `Toggle Line Blame Annotations` command (`gitlens.toggleLineBlame`) - toggles the current line blame annotations on and off
|
- Adds `Toggle Line Blame Annotations` command (`gitlens.toggleLineBlame`) - toggles the current line blame annotations on and off
|
||||||
- Adds `Show Line Blame Annotations` command (`gitlens.showLineBlame`) - shows the current line blame annotations
|
- Adds `Show Line Blame Annotations` command (`gitlens.showLineBlame`) - shows the current line blame annotations
|
||||||
@@ -24,12 +37,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
- Adds `gitlens.strings.*` settings to allow for the customization of certain strings displayed
|
- Adds `gitlens.strings.*` settings to allow for the customization of certain strings displayed
|
||||||
- Adds `gitlens.theme.*` settings to allow for the theming of certain elements
|
- Adds `gitlens.theme.*` settings to allow for the theming of certain elements
|
||||||
- Adds `gitlens.advanced.telemetry.enabled` settings to explicitly opt-in or out of telemetry, but still ultimately honors the `telemetry.enableTelemetry` setting
|
- Adds `gitlens.advanced.telemetry.enabled` settings to explicitly opt-in or out of telemetry, but still ultimately honors the `telemetry.enableTelemetry` setting
|
||||||
|
- Adds ability to suppress most warning messages - which can be re-enabled using the `Reset Suppressed Warnings` command (`gitlens.resetSuppressedWarnings`)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- (BREAKING) Almost all of the GitLens settings have either been renamed, removed, or otherwise changed - see the [README](https://github.com/eamodio/vscode-gitlens/blob/develop/README.md#extension-settings)`
|
- (BREAKING) Almost all of the GitLens settings have either been renamed, removed, or otherwise changed - see the [README](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#extension-settings)`
|
||||||
- Changes the positioning of the Git code lens to try to be at the end of any other code lens on the same line
|
- Changes the positioning of the Git code lens to try to be at the end of any other code lens on the same line
|
||||||
- Changes the position of the `Open File in Remote` command (`gitlens.openFileInRemote`) in the context menus - now in the `navigation` group
|
- Changes the position of the `Open File in Remote` command (`gitlens.openFileInRemote`) in the context menus - now in the `navigation` group
|
||||||
- Changes the `Toggle Git Code Lens` command (`gitlens.toggleCodeLens`) to always toggle the Git code lens on and off
|
- Changes the `Toggle Git Code Lens` command (`gitlens.toggleCodeLens`) to always toggle the Git code lens on and off
|
||||||
|
- Changes the default of `gitlens.advanced.toggleWhitespace.enabled` back to `true`, but automatically disables whitespace toggling if whitespace rendering is not on
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Removes the on-demand `trailing` file blame annotations -- didn't work out and just ended up with a ton of visual noise
|
- Removes the on-demand `trailing` file blame annotations -- didn't work out and just ended up with a ton of visual noise
|
||||||
@@ -38,7 +53,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixes [#81](https://github.com/eamodio/vscode-gitlens/issues/81) - Current line annotation feels too sticky
|
- Fixes [#81](https://github.com/eamodio/vscode-gitlens/issues/81) - Current line annotation feels too sticky
|
||||||
|
- Fixes [#83](https://github.com/eamodio/vscode-gitlens/issues/83) - Calling "close unchanged files" results in no new files being openable
|
||||||
- Fixes issues with the zone.js monkey patching done by application insights (telemetry) - disables all the monkey patching
|
- Fixes issues with the zone.js monkey patching done by application insights (telemetry) - disables all the monkey patching
|
||||||
|
- Fixes issue with `Open Branch in Remote` & `Open Repository in Remote` not showing when there are no open editors
|
||||||
|
|
||||||
## [3.6.1] - 2017-06-07
|
## [3.6.1] - 2017-06-07
|
||||||
### Fixed
|
### Fixed
|
||||||
@@ -136,7 +153,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|||||||
|
|
||||||
## [3.4.5] - 2017-04-13
|
## [3.4.5] - 2017-04-13
|
||||||
### Added
|
### Added
|
||||||
- Completely overhauls the [GitLens documentation](https://github.com/eamodio/vscode-gitlens/blob/master/README.md) and messaging -- make sure to check it out to see all the powerful features GitLen provides!
|
- Completely overhauls the [GitLens documentation](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) and messaging -- make sure to check it out to see all the powerful features GitLen provides!
|
||||||
- Adds `gitlens.blame.annotation.activeLineDarkColor` & `gitlens.blame.annotation.activeLineLightColor` settings to control the colors of the active line blame annotation
|
- Adds `gitlens.blame.annotation.activeLineDarkColor` & `gitlens.blame.annotation.activeLineLightColor` settings to control the colors of the active line blame annotation
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
42
README.md
42
README.md
@@ -9,36 +9,32 @@ GitLens **supercharges** the built-in Visual Studio Code Git capabilities. It he
|
|||||||
|
|
||||||
GitLens provides an unobtrusive blame annotation at the end of the current line, a status bar item showing the commit information (author and date, by default) of the current line, code lens showing the most recent commit and # of authors of the file and/or code block, and many commands for exploring commits and histories, comparing and navigating revisions, stash access, repository status, and more. GitLens is also [highly customizable](#extension-settings) to meet your specific needs — find code lens intrusive or the current line blame annotation distracting — no problem, it is easy to [turn them off or change how they behave](#extension-settings).
|
GitLens provides an unobtrusive blame annotation at the end of the current line, a status bar item showing the commit information (author and date, by default) of the current line, code lens showing the most recent commit and # of authors of the file and/or code block, and many commands for exploring commits and histories, comparing and navigating revisions, stash access, repository status, and more. GitLens is also [highly customizable](#extension-settings) to meet your specific needs — find code lens intrusive or the current line blame annotation distracting — no problem, it is easy to [turn them off or change how they behave](#extension-settings).
|
||||||
|
|
||||||
## Previews
|
### Preview — featuring blame annotations, code lens, status bar details, quick pick menus for navigation and exploration, compare with previous, and more
|
||||||
#### Featuring code lens, file blame annotations, and navigation and exploration via quick pick menus
|

|
||||||

|
|
||||||
|
|
||||||
#### Featuring current line blame annotation and hovers, status bar commit details, quick pick menus, compare with previous, and more
|
|
||||||

|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
#### Git Blame Annotations
|
### Git Blame Annotations
|
||||||
|
|
||||||
- Adds an unobtrusive, highly [customizable](#line-blame-annotation-settings) and [themeable](#theme-settings), **Git blame annotation** to the end of the current line ([optional](#line-blame-annotation-settings), on by default)
|
- Adds an unobtrusive, highly [customizable](#line-blame-annotation-settings) and [themeable](#theme-settings), **Git blame annotation** to the end of the current line ([optional](#line-blame-annotation-settings), on by default)
|
||||||
|
|
||||||

|

|
||||||
- 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)
|
||||||
- Also adds a `details` hover annotation to the current line annotation which provides more commit details ([optional](#line-blame-annotation-settings), on by default)
|
- Also adds a `details` hover annotation to the current line annotation which provides more commit details ([optional](#line-blame-annotation-settings), on by default)
|
||||||
- Also 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)
|
- Also 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 on-demand, beautiful, highly [customizable](#file-blame-annotation-settings) and [themeable](#theme-settings), **Git blame annotations** of the whole file
|
- Adds on-demand, beautiful, highly [customizable](#file-blame-annotation-settings) and [themeable](#theme-settings), **Git blame annotations** of the whole file
|
||||||
|
|
||||||

|

|
||||||
- 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)
|
||||||
- Also adds a `details` hover annotation to the line's annotation which provides more commit details ([optional](#file-blame-annotation-settings), on by default)
|
- Also adds a `details` hover annotation to the line's annotation which provides more commit details ([optional](#file-blame-annotation-settings), on by default)
|
||||||
|
|
||||||
- Adds [customizable](#status-bar-settings) **blame information** about the current line to the **status bar** ([optional](#status-bar-settings), on by default)
|
- Adds [customizable](#status-bar-settings) **blame information** about the current line to the **status bar** ([optional](#status-bar-settings), on by default)
|
||||||
|
|
||||||

|

|
||||||
- Contains the commit author and date, by [default](#status-bar-settings)
|
- Contains the commit author and date, by [default](#status-bar-settings)
|
||||||
- Clicking the status bar item will, by [default](#status-bar-settings), show a **commit details quick pick menu** with commands for comparing, navigating and exploring commits, and more
|
- Clicking the status bar item will, by [default](#status-bar-settings), show a **commit details quick pick menu** with commands for comparing, navigating and exploring commits, and more
|
||||||
- Provides [customizable](#status-bar-settings) click behavior — choose between one of the following
|
- Provides [customizable](#status-bar-settings) click behavior — choose between one of the following
|
||||||
@@ -57,11 +53,11 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
- Adds a `Toggle Line Blame Annotations` command (`gitlens.toggleLineBlame`) to toggle the current line blame annotations on and off
|
- Adds a `Toggle Line Blame Annotations` command (`gitlens.toggleLineBlame`) to toggle the current line blame annotations on and off
|
||||||
- Also adds a `Show Line Blame Annotations` command (`gitlens.showLineBlame`)
|
- Also adds a `Show Line Blame Annotations` command (`gitlens.showLineBlame`)
|
||||||
|
|
||||||
#### Git Code Lens
|
### Git Code Lens
|
||||||
|
|
||||||
- Adds **code lens** to the top of the file and on code blocks ([optional](#code-lens-settings), on by default)
|
- Adds **code lens** to the top of the file and on code blocks ([optional](#code-lens-settings), on by default)
|
||||||
|
|
||||||

|

|
||||||
- **Recent Change** — author and date of the most recent commit for the file or code block
|
- **Recent Change** — author and date of the most recent commit for the file or code block
|
||||||
- Clicking the code lens will, by [default](#code-lens-settings), show a **commit file details quick pick menu** with commands for comparing, navigating and exploring commits, and more
|
- Clicking the code lens will, by [default](#code-lens-settings), show a **commit file details quick pick menu** with commands for comparing, navigating and exploring commits, and more
|
||||||
- **Authors** — number of authors of the file or code block and the most prominent author (if there is more than one)
|
- **Authors** — number of authors of the file or code block and the most prominent author (if there is more than one)
|
||||||
@@ -78,7 +74,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Toggle Git Code Lens` command (`gitlens.toggleCodeLens`) with a shortcut of `shift+alt+b` to toggle the code lens on and off
|
- Adds a `Toggle Git Code Lens` command (`gitlens.toggleCodeLens`) with a shortcut of `shift+alt+b` to toggle the code lens on and off
|
||||||
|
|
||||||
#### Powerful Comparison Tools
|
### Powerful Comparison Tools
|
||||||
|
|
||||||
- Effortlessly navigate between comparisions via the `alt+,` and `alt+.` shortcut keys to go back and forth through a file's revisions
|
- Effortlessly navigate between comparisions via the `alt+,` and `alt+.` shortcut keys to go back and forth through a file's revisions
|
||||||
|
|
||||||
@@ -98,7 +94,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- 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 Commit with Working Tree` command (`gitlens.diffLineWithWorking`) with a shortcut of `alt+w` to compare the commit revision of the active line with the working tree
|
||||||
|
|
||||||
#### Navigate and Explore
|
### Navigate and Explore
|
||||||
|
|
||||||
- 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
|
||||||
|
|
||||||
@@ -110,7 +106,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Show Current Branch History` command (`gitlens.showQuickRepoHistory`) with a shortcut of `shift+alt+h` to show a paged **branch history quick pick menu** of the current branch for exploring its commit history
|
- Adds a `Show Current Branch History` command (`gitlens.showQuickRepoHistory`) with a shortcut of `shift+alt+h` to show a paged **branch history quick pick menu** of the current branch for exploring its commit history
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Provides entries to `Show Commit Search` and `Open Branch in <remote-service>` when available
|
- Provides entries to `Show Commit Search` and `Open Branch in <remote-service>` when available
|
||||||
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
||||||
@@ -121,7 +117,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Show File History` command (`gitlens.showQuickFileHistory`) to show a paged **file history quick pick menu** of the active file for exploring its commit history
|
- Adds a `Show File History` command (`gitlens.showQuickFileHistory`) to show a paged **file history quick pick menu** of the active file for exploring its commit history
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Provides entries to `Show Branch History` and `Open File in <remote-service>` when available
|
- Provides entries to `Show Branch History` and `Open File in <remote-service>` when available
|
||||||
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
||||||
@@ -129,7 +125,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Show Commit Details` command (`gitlens.showQuickCommitDetails`) to show a **commit details quick pick menu** of the most recent commit of the active file
|
- Adds a `Show Commit Details` command (`gitlens.showQuickCommitDetails`) to show a **commit details quick pick menu** of the most recent commit of the active file
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Quickly see the set of files changed in the commit, complete with status indicators for adds, changes, renames, and deletes
|
- Quickly see the set of files changed in the commit, complete with status indicators for adds, changes, renames, and deletes
|
||||||
- Provides entries to `Copy to Clipboard`, `Directory Compare`, `Open Changed Files`, `Open File in <remote-service>` when available, and more
|
- Provides entries to `Copy to Clipboard`, `Directory Compare`, `Open Changed Files`, `Open File in <remote-service>` when available, and more
|
||||||
@@ -140,7 +136,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Show Line Commit Details` command (`gitlens.showQuickCommitFileDetails`) with a shortcut of `alt+c` to show a **file commit details quick pick menu** of the most recent commit of the active file
|
- Adds a `Show Line Commit Details` command (`gitlens.showQuickCommitFileDetails`) with a shortcut of `alt+c` to show a **file commit details quick pick menu** of the most recent commit of the active file
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Provides entries to `Show Commit Details`, `Show File History`, `Compare File with...`, `Copy to Clipboard`, `Open File`, `Open File in <remote-service>` when available, and more
|
- Provides entries to `Show Commit Details`, `Show File History`, `Compare File with...`, `Copy to Clipboard`, `Open File`, `Open File in <remote-service>` when available, and more
|
||||||
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
||||||
@@ -148,7 +144,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Show Repository Status` command (`gitlens.showQuickRepoStatus`) with a shortcut of `alt+s` to show a **repository status quick pick menu** for visualizing the current repository status
|
- Adds a `Show Repository Status` command (`gitlens.showQuickRepoStatus`) with a shortcut of `alt+s` to show a **repository status quick pick menu** for visualizing the current repository status
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Quickly see upstream status (if an Git upstream is configured) — complete with ahead and behind information
|
- Quickly see upstream status (if an Git upstream is configured) — complete with ahead and behind information
|
||||||
- If you are ahead of the upstream, an entry will be shown with the number of commits ahead. Chosing it will show a limited **branch history quick pick menu** containing just the commits ahead of the upstream
|
- If you are ahead of the upstream, an entry will be shown with the number of commits ahead. Chosing it will show a limited **branch history quick pick menu** containing just the commits ahead of the upstream
|
||||||
@@ -161,14 +157,14 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
|
|
||||||
- Adds a `Show Stashed Changes` command (`gitlens.showQuickStashList`) to show a **stashed changes quick pick menu** for exploring your repository stash history
|
- Adds a `Show Stashed Changes` command (`gitlens.showQuickStashList`) to show a **stashed changes quick pick menu** for exploring your repository stash history
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Provides entries to `Stash Changes`
|
- Provides entries to `Stash Changes`
|
||||||
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
- Navigate back to the previous quick pick menu via `alt+left arrow`, if available
|
||||||
|
|
||||||
- Chosing a stash entry shows a **stash details quick pick menu** which is very similar to the **commit details quick pick menu** above
|
- Chosing a stash entry shows a **stash details quick pick menu** which is very similar to the **commit details quick pick menu** above
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Quickly see the set of files changed in the stash, complete with status indicators for adds, changes, renames, and deletes
|
- Quickly see the set of files changed in the stash, complete with status indicators for adds, changes, renames, and deletes
|
||||||
- Provides entries to `Copy Message to Clipboard`, `Directory Compare`, and `Open Changed Files`
|
- Provides entries to `Copy Message to Clipboard`, `Directory Compare`, and `Open Changed Files`
|
||||||
@@ -186,7 +182,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
|
|||||||
- Adds a `Open Blame History Explorer` command (`gitlens.showBlameHistory`) to show a **blame history explorer** (peek style) to visualize the blame history of a file or code block
|
- Adds a `Open Blame History Explorer` command (`gitlens.showBlameHistory`) to show a **blame history explorer** (peek style) to visualize the blame history of a file or code block
|
||||||
- Likely to be deprecated in a future release, add your voice to [#66](https://github.com/eamodio/vscode-gitlens/issues/66) if you feel it should not be removed
|
- Likely to be deprecated in a future release, add your voice to [#66](https://github.com/eamodio/vscode-gitlens/issues/66) if you feel it should not be removed
|
||||||
|
|
||||||
#### And More
|
### And More
|
||||||
|
|
||||||
- Adds a `Copy Commit ID to Clipboard` command (`gitlens.copyShaToClipboard`) to copy the commit id (sha) of the active line to the clipboard
|
- Adds a `Copy Commit ID to Clipboard` command (`gitlens.copyShaToClipboard`) to copy the commit id (sha) of the active line to the clipboard
|
||||||
|
|
||||||
|
|||||||
BIN
images/gitlens-preview-full.gif
Normal file
BIN
images/gitlens-preview-full.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 MiB |
BIN
images/gitlens-preview.gif
Normal file
BIN
images/gitlens-preview.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
45
package-lock.json
generated
45
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitlens",
|
"name": "gitlens",
|
||||||
"version": "4.0.0-beta.2",
|
"version": "4.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/copy-paste": {
|
"@types/copy-paste": {
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "7.0.28",
|
"version": "7.0.29",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.28.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.29.tgz",
|
||||||
"integrity": "sha512-9rLhvgupMpC7Yh24yB8zj+4L6SZ9BYUwqknEC8+R7gqCg3KL65UHg7yu9X6J8mSmmtVr1Hbey564yZ3C9nXqtQ==",
|
"integrity": "sha512-+8JrLZny/uR+d/jLK9eaV63buRM7X/gNzQk57q76NS4KNKLSKOmxJYFIlwuP2zDvA7wqZj05POPhSd9Z1hYQpQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/tmp": {
|
"@types/tmp": {
|
||||||
@@ -1026,13 +1026,6 @@
|
|||||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"jodid25519": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz",
|
||||||
@@ -1503,9 +1496,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.2.10",
|
"version": "2.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.11.tgz",
|
||||||
"integrity": "sha512-HQEnnoV404e0EtwB9yNiuk2tJ+egeVC8Y9QBAxzDg8DBJt4BzRp+yQuIb/t3FIWkSTmIi+sgx7yVv/ZM0GNoqw==",
|
"integrity": "sha512-h+8+r3MKEhkiVrwdKL8aWs1oc1VvBu33ueshOvS26RsZQ3Amhx/oO3TKe4lApSV9ueY6as8EAh7mtuFjdlhg9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"regex-cache": {
|
"regex-cache": {
|
||||||
@@ -1515,9 +1508,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"remove-trailing-separator": {
|
"remove-trailing-separator": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz",
|
||||||
"integrity": "sha1-YV67lq9VlVLUv0BXyENtSGq2PMQ=",
|
"integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"repeat-element": {
|
"repeat-element": {
|
||||||
@@ -1588,9 +1581,9 @@
|
|||||||
"integrity": "sha1-p9sUqxV/nXqsalbmVeejhg05vyY="
|
"integrity": "sha1-p9sUqxV/nXqsalbmVeejhg05vyY="
|
||||||
},
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.0",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
||||||
"integrity": "sha512-aSLEDudu6OoRr/2rU609gRmnYboRLxgDG1z9o2Q0os7236FwvcqIOO8r8U5JUEwivZOhDaKlFO4SbPTJYyBEyQ==",
|
"integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
@@ -1634,9 +1627,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"sshpk": {
|
"sshpk": {
|
||||||
"version": "1.13.0",
|
"version": "1.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
|
||||||
"integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=",
|
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assert-plus": {
|
"assert-plus": {
|
||||||
@@ -1678,9 +1671,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz",
|
||||||
"integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=",
|
"integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"stringstream": {
|
"stringstream": {
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitlens",
|
"name": "gitlens",
|
||||||
"version": "4.0.0-beta.2",
|
"version": "4.0.2-beta",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Eric Amodio",
|
"name": "Eric Amodio",
|
||||||
"email": "eamodio@gmail.com"
|
"email": "eamodio@gmail.com"
|
||||||
@@ -698,7 +698,7 @@
|
|||||||
},
|
},
|
||||||
"gitlens.advanced.toggleWhitespace.enabled": {
|
"gitlens.advanced.toggleWhitespace.enabled": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": true,
|
||||||
"description": "Specifies whether or not to toggle whitespace off then showing blame annotations (*may* be required by certain fonts/themes)"
|
"description": "Specifies whether or not to toggle whitespace off then showing blame annotations (*may* be required by certain fonts/themes)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -872,6 +872,11 @@
|
|||||||
"command": "gitlens.stashSave",
|
"command": "gitlens.stashSave",
|
||||||
"title": "Stash Changes",
|
"title": "Stash Changes",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.resetSuppressedWarnings",
|
||||||
|
"title": "Reset Suppressed Warnings",
|
||||||
|
"category": "GitLens"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
@@ -1003,6 +1008,10 @@
|
|||||||
{
|
{
|
||||||
"command": "gitlens.stashSave",
|
"command": "gitlens.stashSave",
|
||||||
"when": "gitlens:enabled"
|
"when": "gitlens:enabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.resetSuppressedWarnings",
|
||||||
|
"when": "gitlens:enabled"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"editor/context": [
|
"editor/context": [
|
||||||
@@ -1281,7 +1290,7 @@
|
|||||||
"@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.41",
|
"@types/mocha": "2.2.41",
|
||||||
"@types/node": "7.0.28",
|
"@types/node": "7.0.29",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"mocha": "3.4.2",
|
"mocha": "3.4.2",
|
||||||
"tslint": "5.4.3",
|
"tslint": "5.4.3",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
import { Functions } from './system';
|
||||||
import { commands, Disposable, TextEditor, window } from 'vscode';
|
import { commands, Disposable, TextEditor, window } from 'vscode';
|
||||||
import { BuiltInCommands } from './constants';
|
import { BuiltInCommands } from './constants';
|
||||||
|
|
||||||
@@ -11,19 +12,20 @@ export class ActiveEditorTracker extends Disposable {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super(() => this.dispose());
|
super(() => this.dispose());
|
||||||
|
|
||||||
this._disposable = window.onDidChangeActiveTextEditor(e => this._resolver && this._resolver(e));
|
const fn = Functions.debounce((e: TextEditor) => this._resolver && this._resolver(e), 50);
|
||||||
|
this._disposable = window.onDidChangeActiveTextEditor(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this._disposable && this._disposable.dispose();
|
this._disposable && this._disposable.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
async awaitClose(timeout: number = 500): Promise<TextEditor> {
|
async awaitClose(timeout: number = 500): Promise<TextEditor | undefined> {
|
||||||
this.close();
|
this.close();
|
||||||
return this.wait(timeout);
|
return this.wait(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
async awaitNext(timeout: number = 500): Promise<TextEditor> {
|
async awaitNext(timeout: number = 500): Promise<TextEditor | undefined> {
|
||||||
this.next();
|
this.next();
|
||||||
return this.wait(timeout);
|
return this.wait(timeout);
|
||||||
}
|
}
|
||||||
@@ -36,15 +38,15 @@ export class ActiveEditorTracker extends Disposable {
|
|||||||
return commands.executeCommand(BuiltInCommands.NextEditor);
|
return commands.executeCommand(BuiltInCommands.NextEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
async wait(timeout: number = 500): Promise<TextEditor> {
|
async wait(timeout: number = 500): Promise<TextEditor | undefined> {
|
||||||
const editor = await new Promise<TextEditor>((resolve, reject) => {
|
const editor = await new Promise<TextEditor>((resolve, reject) => {
|
||||||
let timer: any;
|
let timer: any;
|
||||||
|
|
||||||
this._resolver = (editor: TextEditor) => {
|
this._resolver = (e: TextEditor) => {
|
||||||
if (timer) {
|
if (timer) {
|
||||||
clearTimeout(timer as any);
|
clearTimeout(timer as any);
|
||||||
timer = 0;
|
timer = 0;
|
||||||
resolve(editor);
|
resolve(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,6 +55,7 @@ export class ActiveEditorTracker extends Disposable {
|
|||||||
timer = 0;
|
timer = 0;
|
||||||
}, timeout) as any;
|
}, timeout) as any;
|
||||||
});
|
});
|
||||||
|
|
||||||
this._resolver = undefined;
|
this._resolver = undefined;
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,16 +56,27 @@ export class AnnotationController extends Disposable {
|
|||||||
|
|
||||||
private _onConfigurationChanged() {
|
private _onConfigurationChanged() {
|
||||||
let toggleWhitespace = workspace.getConfiguration(`${ExtensionKey}.advanced.toggleWhitespace`).get<boolean>('enabled');
|
let toggleWhitespace = workspace.getConfiguration(`${ExtensionKey}.advanced.toggleWhitespace`).get<boolean>('enabled');
|
||||||
if (!toggleWhitespace) {
|
// Until https://github.com/Microsoft/vscode/issues/11485 is fixed we need to toggle whitespace for non-monospace fonts and ligatures
|
||||||
// Until https://github.com/Microsoft/vscode/issues/11485 is fixed we need to toggle whitespace for non-monospace fonts and ligatures
|
// TODO: detect monospace vs non-monospace font
|
||||||
// TODO: detect monospace font
|
|
||||||
toggleWhitespace = workspace.getConfiguration('editor').get<boolean>('fontLigatures');
|
// if (!toggleWhitespace) {
|
||||||
|
// // Since we know ligatures will break the whitespace rendering -- turn it back on
|
||||||
|
// toggleWhitespace = workspace.getConfiguration('editor').get<boolean>('fontLigatures', false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// If the setting is on and we aren't showing any annotations, make sure it is necessary (i.e. only when rendering whitespace)
|
||||||
|
if (toggleWhitespace && this._annotationProviders.size === 0) {
|
||||||
|
toggleWhitespace = (workspace.getConfiguration('editor').get<string>('renderWhitespace') !== 'none');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toggleWhitespace && !this._whitespaceController) {
|
let changed = false;
|
||||||
|
|
||||||
|
if (toggleWhitespace && this._whitespaceController === undefined) {
|
||||||
|
changed = true;
|
||||||
this._whitespaceController = new WhitespaceController();
|
this._whitespaceController = new WhitespaceController();
|
||||||
}
|
}
|
||||||
else if (!toggleWhitespace && this._whitespaceController) {
|
else if (!toggleWhitespace && this._whitespaceController !== undefined) {
|
||||||
|
changed = true;
|
||||||
this._whitespaceController.dispose();
|
this._whitespaceController.dispose();
|
||||||
this._whitespaceController = undefined;
|
this._whitespaceController = undefined;
|
||||||
}
|
}
|
||||||
@@ -74,8 +85,6 @@ export class AnnotationController extends Disposable {
|
|||||||
const cfgHighlight = cfg.blame.file.lineHighlight;
|
const cfgHighlight = cfg.blame.file.lineHighlight;
|
||||||
const cfgTheme = cfg.theme.lineHighlight;
|
const cfgTheme = cfg.theme.lineHighlight;
|
||||||
|
|
||||||
let changed = false;
|
|
||||||
|
|
||||||
if (!Objects.areEquivalent(cfgHighlight, this._config && this._config.blame.file.lineHighlight) ||
|
if (!Objects.areEquivalent(cfgHighlight, this._config && this._config.blame.file.lineHighlight) ||
|
||||||
!Objects.areEquivalent(cfgTheme, this._config && this._config.theme.lineHighlight)) {
|
!Objects.areEquivalent(cfgTheme, this._config && this._config.theme.lineHighlight)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
@@ -129,7 +138,7 @@ export class AnnotationController extends Disposable {
|
|||||||
for (const provider of this._annotationProviders.values()) {
|
for (const provider of this._annotationProviders.values()) {
|
||||||
if (provider === undefined) continue;
|
if (provider === undefined) continue;
|
||||||
|
|
||||||
provider.reset();
|
provider.reset(this._whitespaceController);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,10 +60,11 @@ import { WhitespaceController } from './whitespaceController';
|
|||||||
this.whitespaceController && await this.whitespaceController.restore();
|
this.whitespaceController && await this.whitespaceController.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
async reset() {
|
async reset(whitespaceController: WhitespaceController | undefined) {
|
||||||
await this.clear();
|
await this.clear();
|
||||||
|
|
||||||
this._config = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
this._config = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
||||||
|
this.whitespaceController = whitespaceController;
|
||||||
|
|
||||||
await this.provideAnnotation(this.editor === undefined ? undefined : this.editor.selection.active.line);
|
await this.provideAnnotation(this.editor === undefined ? undefined : this.editor.selection.active.line);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
import { Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { ExtensionContext, Range, TextEditor, TextEditorDecorationType } from 'vscode';
|
import { ExtensionContext, Range, TextEditor, TextEditorDecorationType } from 'vscode';
|
||||||
import { AnnotationProviderBase } from './annotationProvider';
|
import { AnnotationProviderBase } from './annotationProvider';
|
||||||
import { GitService, GitUri, IGitBlame } from '../gitService';
|
import { GitBlame, GitService, GitUri } from '../gitService';
|
||||||
import { WhitespaceController } from './whitespaceController';
|
import { WhitespaceController } from './whitespaceController';
|
||||||
|
|
||||||
export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase {
|
export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase {
|
||||||
|
|
||||||
protected _blame: Promise<IGitBlame>;
|
protected _blame: Promise<GitBlame>;
|
||||||
|
|
||||||
constructor(context: ExtensionContext, editor: TextEditor, decoration: TextEditorDecorationType, highlightDecoration: TextEditorDecorationType | undefined, whitespaceController: WhitespaceController | undefined, protected git: GitService, protected uri: GitUri) {
|
constructor(context: ExtensionContext, editor: TextEditor, decoration: TextEditorDecorationType, highlightDecoration: TextEditorDecorationType | undefined, whitespaceController: WhitespaceController | undefined, protected git: GitService, protected uri: GitUri) {
|
||||||
super(context, editor, decoration, highlightDecoration, whitespaceController);
|
super(context, editor, decoration, highlightDecoration, whitespaceController);
|
||||||
@@ -15,7 +15,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
|
|||||||
this._blame = this.git.getBlameForFile(this.uri);
|
this._blame = this.git.getBlameForFile(this.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
async selection(shaOrLine?: string | number, blame?: IGitBlame) {
|
async selection(shaOrLine?: string | number, blame?: GitBlame) {
|
||||||
if (!this.highlightDecoration) return;
|
if (!this.highlightDecoration) return;
|
||||||
|
|
||||||
if (blame === undefined) {
|
if (blame === undefined) {
|
||||||
@@ -57,14 +57,14 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
|
|||||||
return blame !== undefined && blame.lines.length !== 0;
|
return blame !== undefined && blame.lines.length !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getBlame(requiresWhitespaceHack: boolean): Promise<IGitBlame | undefined> {
|
protected async getBlame(requiresWhitespaceHack: boolean): Promise<GitBlame | undefined> {
|
||||||
let whitespacePromise: Promise<void> | undefined;
|
let whitespacePromise: Promise<void> | undefined;
|
||||||
// HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- override whitespace (turn off)
|
// HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- override whitespace (turn off)
|
||||||
if (requiresWhitespaceHack) {
|
if (requiresWhitespaceHack) {
|
||||||
whitespacePromise = this.whitespaceController && this.whitespaceController.override();
|
whitespacePromise = this.whitespaceController && this.whitespaceController.override();
|
||||||
}
|
}
|
||||||
|
|
||||||
let blame: IGitBlame;
|
let blame: GitBlame;
|
||||||
if (whitespacePromise) {
|
if (whitespacePromise) {
|
||||||
[blame] = await Promise.all([this._blame, whitespacePromise]);
|
[blame] = await Promise.all([this._blame, whitespacePromise]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class DiffAnnotationProvider extends AnnotationProviderBase {
|
|||||||
const decorators: DecorationOptions[] = [];
|
const decorators: DecorationOptions[] = [];
|
||||||
|
|
||||||
for (const chunk of diff.chunks) {
|
for (const chunk of diff.chunks) {
|
||||||
let count = chunk.currentStart - 2;
|
let count = chunk.currentPosition.start - 2;
|
||||||
for (const change of chunk.current) {
|
for (const change of chunk.current) {
|
||||||
if (change === undefined) continue;
|
if (change === undefined) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export * from './commands/openCommitInRemote';
|
|||||||
export * from './commands/openFileInRemote';
|
export * from './commands/openFileInRemote';
|
||||||
export * from './commands/openInRemote';
|
export * from './commands/openInRemote';
|
||||||
export * from './commands/openRepoInRemote';
|
export * from './commands/openRepoInRemote';
|
||||||
|
export * from './commands/resetSuppressedWarnings';
|
||||||
export * from './commands/showBlameHistory';
|
export * from './commands/showBlameHistory';
|
||||||
export * from './commands/showFileBlame';
|
export * from './commands/showFileBlame';
|
||||||
export * from './commands/showFileHistory';
|
export * from './commands/showFileHistory';
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { TextEditor, Uri, window } from 'vscode';
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorTracker } from '../activeEditorTracker';
|
import { ActiveEditorTracker } from '../activeEditorTracker';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { TextEditorComparer, UriComparer } from '../comparers';
|
import { TextEditorComparer, UriComparer } from '../comparers';
|
||||||
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
|
|
||||||
export interface CloseUnchangedFilesCommandArgs {
|
export interface CloseUnchangedFilesCommandArgs {
|
||||||
uris?: Uri[];
|
uris?: Uri[];
|
||||||
@@ -22,7 +24,7 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
|
|||||||
try {
|
try {
|
||||||
if (args.uris === undefined) {
|
if (args.uris === undefined) {
|
||||||
const repoPath = await this.git.getRepoPathFromUri(uri);
|
const repoPath = await this.git.getRepoPathFromUri(uri);
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to close unchanged files`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to close unchanged files`);
|
||||||
|
|
||||||
const status = await this.git.getStatusForRepo(repoPath);
|
const status = await this.git.getStatusForRepo(repoPath);
|
||||||
if (status === undefined) return window.showWarningMessage(`Unable to close unchanged files`);
|
if (status === undefined) return window.showWarningMessage(`Unable to close unchanged files`);
|
||||||
@@ -30,34 +32,41 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
|
|||||||
args.uris = status.files.map(_ => _.Uri);
|
args.uris = status.files.map(_ => _.Uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.uris.length === 0) return commands.executeCommand(BuiltInCommands.CloseAllEditors);
|
||||||
|
|
||||||
const editorTracker = new ActiveEditorTracker();
|
const editorTracker = new ActiveEditorTracker();
|
||||||
|
|
||||||
let active = window.activeTextEditor;
|
let count = 0;
|
||||||
let editor = active;
|
let previous = undefined;
|
||||||
do {
|
let editor = window.activeTextEditor;
|
||||||
|
while (true) {
|
||||||
if (editor !== undefined) {
|
if (editor !== undefined) {
|
||||||
if ((editor.document !== undefined && editor.document.isDirty) ||
|
if (TextEditorComparer.equals(previous, editor, { useId: true, usePosition: true })) {
|
||||||
args.uris.some(_ => UriComparer.equals(_, editor!.document && editor!.document.uri))) {
|
break;
|
||||||
// If we didn't start with a valid editor, set one once we find it
|
|
||||||
if (active === undefined) {
|
|
||||||
active = editor;
|
|
||||||
}
|
|
||||||
editor = await editorTracker.awaitNext(500);
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (active === editor) {
|
if (editor.document !== undefined &&
|
||||||
active = undefined;
|
(editor.document.isDirty || args.uris.some(_ => UriComparer.equals(_, editor!.document && editor!.document.uri)))) {
|
||||||
}
|
previous = editor;
|
||||||
editor = await editorTracker.awaitClose(500);
|
editor = await editorTracker.awaitNext(500);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = editor;
|
||||||
|
editor = await editorTracker.awaitClose(500);
|
||||||
|
|
||||||
|
if (previous === undefined && editor === undefined) {
|
||||||
|
count++;
|
||||||
|
// This is such a shitty hack, but I can't figure out any other reliable way to know that we've cycled through all the editors :(
|
||||||
|
if (count >= 4) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (active === editor) {
|
count = 0;
|
||||||
active = undefined;
|
|
||||||
}
|
|
||||||
editor = await editorTracker.awaitClose(500);
|
|
||||||
}
|
}
|
||||||
} while ((active === undefined && editor === undefined) || !TextEditorComparer.equals(active, editor, { useId: true, usePosition: true }));
|
}
|
||||||
|
|
||||||
editorTracker.dispose();
|
editorTracker.dispose();
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,42 @@ import { BuiltInCommands } from '../constants';
|
|||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { Telemetry } from '../telemetry';
|
import { Telemetry } from '../telemetry';
|
||||||
|
|
||||||
export type Commands = 'gitlens.closeUnchangedFiles' | 'gitlens.copyMessageToClipboard' | 'gitlens.copyShaToClipboard' |
|
export type Commands = 'gitlens.closeUnchangedFiles' |
|
||||||
'gitlens.diffDirectory' | 'gitlens.diffWithBranch' | 'gitlens.diffWithNext' | 'gitlens.diffWithPrevious' | 'gitlens.diffLineWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.diffLineWithWorking' |
|
'gitlens.copyMessageToClipboard' |
|
||||||
'gitlens.openChangedFiles' | 'gitlens.openBranchInRemote' | 'gitlens.openCommitInRemote' | 'gitlens.openFileInRemote' | 'gitlens.openInRemote' | 'gitlens.openRepoInRemote' |
|
'gitlens.copyShaToClipboard' |
|
||||||
'gitlens.showBlameHistory' | 'gitlens.showCommitSearch' | 'gitlens.showFileBlame' | 'gitlens.showFileHistory' |
|
'gitlens.diffDirectory' |
|
||||||
'gitlens.showLastQuickPick' | 'gitlens.showLineBlame' | 'gitlens.showQuickBranchHistory' |
|
'gitlens.diffWithBranch' |
|
||||||
'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' |
|
'gitlens.diffWithNext' |
|
||||||
'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory' |
|
'gitlens.diffWithPrevious' |
|
||||||
'gitlens.showQuickRepoStatus' | 'gitlens.showQuickStashList' |
|
'gitlens.diffLineWithPrevious' |
|
||||||
'gitlens.stashApply' | 'gitlens.stashDelete' | 'gitlens.stashSave' |
|
'gitlens.diffWithWorking' |
|
||||||
'gitlens.toggleCodeLens' | 'gitlens.toggleFileBlame' | 'gitlens.toggleLineBlame';
|
'gitlens.diffLineWithWorking' |
|
||||||
|
'gitlens.openChangedFiles' |
|
||||||
|
'gitlens.openBranchInRemote' |
|
||||||
|
'gitlens.openCommitInRemote' |
|
||||||
|
'gitlens.openFileInRemote' |
|
||||||
|
'gitlens.openInRemote' |
|
||||||
|
'gitlens.openRepoInRemote' |
|
||||||
|
'gitlens.resetSuppressedWarnings' |
|
||||||
|
'gitlens.showBlameHistory' |
|
||||||
|
'gitlens.showCommitSearch' |
|
||||||
|
'gitlens.showFileBlame' |
|
||||||
|
'gitlens.showFileHistory' |
|
||||||
|
'gitlens.showLastQuickPick' |
|
||||||
|
'gitlens.showLineBlame' |
|
||||||
|
'gitlens.showQuickBranchHistory' |
|
||||||
|
'gitlens.showQuickCommitDetails' |
|
||||||
|
'gitlens.showQuickCommitFileDetails' |
|
||||||
|
'gitlens.showQuickFileHistory' |
|
||||||
|
'gitlens.showQuickRepoHistory' |
|
||||||
|
'gitlens.showQuickRepoStatus' |
|
||||||
|
'gitlens.showQuickStashList' |
|
||||||
|
'gitlens.stashApply' |
|
||||||
|
'gitlens.stashDelete' |
|
||||||
|
'gitlens.stashSave' |
|
||||||
|
'gitlens.toggleCodeLens' |
|
||||||
|
'gitlens.toggleFileBlame' |
|
||||||
|
'gitlens.toggleLineBlame';
|
||||||
export const Commands = {
|
export const Commands = {
|
||||||
CloseUnchangedFiles: 'gitlens.closeUnchangedFiles' as Commands,
|
CloseUnchangedFiles: 'gitlens.closeUnchangedFiles' as Commands,
|
||||||
CopyMessageToClipboard: 'gitlens.copyMessageToClipboard' as Commands,
|
CopyMessageToClipboard: 'gitlens.copyMessageToClipboard' as Commands,
|
||||||
@@ -31,12 +57,13 @@ export const Commands = {
|
|||||||
OpenFileInRemote: 'gitlens.openFileInRemote' as Commands,
|
OpenFileInRemote: 'gitlens.openFileInRemote' as Commands,
|
||||||
OpenInRemote: 'gitlens.openInRemote' as Commands,
|
OpenInRemote: 'gitlens.openInRemote' as Commands,
|
||||||
OpenRepoInRemote: 'gitlens.openRepoInRemote' as Commands,
|
OpenRepoInRemote: 'gitlens.openRepoInRemote' as Commands,
|
||||||
ShowFileBlame: 'gitlens.showFileBlame' as Commands,
|
ResetSuppressedWarnings: 'gitlens.resetSuppressedWarnings' as Commands,
|
||||||
ShowLineBlame: 'gitlens.showLineBlame' as Commands,
|
|
||||||
ShowBlameHistory: 'gitlens.showBlameHistory' as Commands,
|
ShowBlameHistory: 'gitlens.showBlameHistory' as Commands,
|
||||||
ShowCommitSearch: 'gitlens.showCommitSearch' as Commands,
|
ShowCommitSearch: 'gitlens.showCommitSearch' as Commands,
|
||||||
|
ShowFileBlame: 'gitlens.showFileBlame' as Commands,
|
||||||
ShowFileHistory: 'gitlens.showFileHistory' as Commands,
|
ShowFileHistory: 'gitlens.showFileHistory' as Commands,
|
||||||
ShowLastQuickPick: 'gitlens.showLastQuickPick' as Commands,
|
ShowLastQuickPick: 'gitlens.showLastQuickPick' as Commands,
|
||||||
|
ShowLineBlame: 'gitlens.showLineBlame' as Commands,
|
||||||
ShowQuickCommitDetails: 'gitlens.showQuickCommitDetails' as Commands,
|
ShowQuickCommitDetails: 'gitlens.showQuickCommitDetails' as Commands,
|
||||||
ShowQuickCommitFileDetails: 'gitlens.showQuickCommitFileDetails' as Commands,
|
ShowQuickCommitFileDetails: 'gitlens.showQuickCommitFileDetails' as Commands,
|
||||||
ShowQuickFileHistory: 'gitlens.showQuickFileHistory' as Commands,
|
ShowQuickFileHistory: 'gitlens.showQuickFileHistory' as Commands,
|
||||||
@@ -47,9 +74,9 @@ export const Commands = {
|
|||||||
StashApply: 'gitlens.stashApply' as Commands,
|
StashApply: 'gitlens.stashApply' as Commands,
|
||||||
StashDelete: 'gitlens.stashDelete' as Commands,
|
StashDelete: 'gitlens.stashDelete' as Commands,
|
||||||
StashSave: 'gitlens.stashSave' as Commands,
|
StashSave: 'gitlens.stashSave' as Commands,
|
||||||
|
ToggleCodeLens: 'gitlens.toggleCodeLens' as Commands,
|
||||||
ToggleFileBlame: 'gitlens.toggleFileBlame' as Commands,
|
ToggleFileBlame: 'gitlens.toggleFileBlame' as Commands,
|
||||||
ToggleLineBlame: 'gitlens.toggleLineBlame' as Commands,
|
ToggleLineBlame: 'gitlens.toggleLineBlame' as Commands
|
||||||
ToggleCodeLens: 'gitlens.toggleCodeLens' as Commands
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getCommandUri(uri?: Uri, editor?: TextEditor): Uri | undefined {
|
export function getCommandUri(uri?: Uri, editor?: TextEditor): Uri | undefined {
|
||||||
@@ -58,7 +85,13 @@ export function getCommandUri(uri?: Uri, editor?: TextEditor): Uri | undefined {
|
|||||||
return editor.document.uri;
|
return editor.document.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandContext = 'gitlens:canToggleCodeLens' | 'gitlens:enabled' | 'gitlens:hasRemotes' | 'gitlens:isBlameable' | 'gitlens:isRepository' | 'gitlens:isTracked' | 'gitlens:key';
|
export type CommandContext = 'gitlens:canToggleCodeLens' |
|
||||||
|
'gitlens:enabled' |
|
||||||
|
'gitlens:hasRemotes' |
|
||||||
|
'gitlens:isBlameable' |
|
||||||
|
'gitlens:isRepository' |
|
||||||
|
'gitlens:isTracked' |
|
||||||
|
'gitlens:key';
|
||||||
export const CommandContext = {
|
export const CommandContext = {
|
||||||
CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext,
|
CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext,
|
||||||
Enabled: 'gitlens:enabled' as CommandContext,
|
Enabled: 'gitlens:enabled' as CommandContext,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
|||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
||||||
|
|
||||||
export interface DiffDirectoryCommandCommandArgs {
|
export interface DiffDirectoryCommandCommandArgs {
|
||||||
@@ -31,7 +32,7 @@ export class DiffDirectoryCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const repoPath = await this.git.getRepoPathFromUri(uri);
|
const repoPath = await this.git.getRepoPathFromUri(uri);
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to open directory compare`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open directory compare`);
|
||||||
|
|
||||||
if (!args.shaOrBranch1) {
|
if (!args.shaOrBranch1) {
|
||||||
const branches = await this.git.getBranches(repoPath);
|
const branches = await this.git.getBranches(repoPath);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { DiffWithPreviousCommandArgs } from './diffWithPrevious';
|
|||||||
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 * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface DiffLineWithPreviousCommandArgs {
|
export interface DiffLineWithPreviousCommandArgs {
|
||||||
@@ -35,7 +36,7 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
||||||
if (blame === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
|
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
|
|
||||||
args.commit = blame.commit;
|
args.commit = blame.commit;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vsco
|
|||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
|
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
|
||||||
import { GitCommit, GitService, GitUri } from '../gitService';
|
import { GitCommit, GitService, GitUri } from '../gitService';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
|
||||||
export interface DiffLineWithWorkingCommandArgs {
|
export interface DiffLineWithWorkingCommandArgs {
|
||||||
@@ -32,7 +33,7 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
||||||
if (blame === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
|
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
|
|
||||||
args.commit = blame.commit;
|
args.commit = blame.commit;
|
||||||
// If the line is uncommitted, find the previous commit
|
// If the line is uncommitted, find the previous commit
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
|||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
import { BranchesQuickPick, CommandQuickPickItem } from '../quickPicks';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ export class DiffWithBranchCommand extends ActiveEditorCommand {
|
|||||||
args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line);
|
args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line);
|
||||||
|
|
||||||
const gitUri = await GitUri.fromUri(uri, this.git);
|
const gitUri = await GitUri.fromUri(uri, this.git);
|
||||||
if (!gitUri.repoPath) return window.showWarningMessage(`Unable to open branch compare`);
|
if (!gitUri.repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open branch compare`);
|
||||||
|
|
||||||
const branches = await this.git.getBranches(gitUri.repoPath);
|
const branches = await this.git.getBranches(gitUri.repoPath);
|
||||||
const pick = await BranchesQuickPick.show(branches, `Compare ${path.basename(gitUri.fsPath)} to \u2026`, args.goBackCommand);
|
const pick = await BranchesQuickPick.show(branches, `Compare ${path.basename(gitUri.fsPath)} to \u2026`, args.goBackCommand);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
|||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
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 * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface DiffWithNextCommandArgs {
|
export interface DiffWithNextCommandArgs {
|
||||||
@@ -37,8 +38,8 @@ export class DiffWithNextCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
|
const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
|
||||||
|
|
||||||
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, args.range!);
|
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha !== undefined ? undefined : 2, args.range!);
|
||||||
if (log === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
|
if (log === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
|
|
||||||
args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
|
args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { BuiltInCommands } from '../constants';
|
|||||||
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 * as moment from 'moment';
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface DiffWithPreviousCommandArgs {
|
export interface DiffWithPreviousCommandArgs {
|
||||||
@@ -34,13 +34,13 @@ 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;
|
||||||
|
|
||||||
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, args.range!);
|
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha !== undefined ? undefined : 2, args.range!);
|
||||||
if (log === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
|
if (log === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
|
|
||||||
args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
|
args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
|
||||||
|
|
||||||
// If the sha is missing, treat it as a DiffWithWorking
|
// If the sha is missing and the file is uncommitted, then treat it as a DiffWithWorking
|
||||||
if (gitUri.sha === undefined) 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})`);
|
||||||
@@ -48,7 +48,7 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.commit.previousSha === undefined) return window.showInformationMessage(`Commit ${args.commit.shortSha} (${args.commit.author}, ${moment(args.commit.date).fromNow()}) has no previous commit`);
|
if (args.commit.previousSha === undefined) return Messages.showCommitHasNoPreviousCommitWarningMessage(args.commit);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [rhs, lhs] = await Promise.all([
|
const [rhs, lhs] = await Promise.all([
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
|||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
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 * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface DiffWithWorkingCommandArgs {
|
export interface DiffWithWorkingCommandArgs {
|
||||||
@@ -31,7 +32,7 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });
|
args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });
|
||||||
if (args.commit === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
|
if (args.commit === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
Logger.error(ex, 'DiffWithWorkingCommand', `getLogCommit(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`);
|
Logger.error(ex, 'DiffWithWorkingCommand', `getLogCommit(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
|
|||||||
import { ActiveEditorCommand, Commands, getCommandUri, openEditor } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri, openEditor } from './common';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
|
|
||||||
export interface OpenChangedFilesCommandArgs {
|
export interface OpenChangedFilesCommandArgs {
|
||||||
uris?: Uri[];
|
uris?: Uri[];
|
||||||
@@ -20,7 +21,7 @@ export class OpenChangedFilesCommand extends ActiveEditorCommand {
|
|||||||
try {
|
try {
|
||||||
if (args.uris === undefined) {
|
if (args.uris === undefined) {
|
||||||
const repoPath = await this.git.getRepoPathFromUri(uri);
|
const repoPath = await this.git.getRepoPathFromUri(uri);
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to open changed files`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open changed files`);
|
||||||
|
|
||||||
const status = await this.git.getStatusForRepo(repoPath);
|
const status = await this.git.getStatusForRepo(repoPath);
|
||||||
if (status === undefined) return window.showWarningMessage(`Unable to open changed files`);
|
if (status === undefined) return window.showWarningMessage(`Unable to open changed files`);
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
import { Arrays } from '../system';
|
import { Arrays } from '../system';
|
||||||
import { commands, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
|
import { commands, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitCommit, GitService, GitUri } from '../gitService';
|
import { GitBlameCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { OpenInRemoteCommandArgs } from './openInRemote';
|
import { OpenInRemoteCommandArgs } from './openInRemote';
|
||||||
|
|
||||||
export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
|
export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
|
||||||
@@ -27,12 +28,12 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
|
|||||||
if (blameline < 0) return undefined;
|
if (blameline < 0) return undefined;
|
||||||
|
|
||||||
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
||||||
if (blame === undefined) return window.showWarningMessage(`Unable to open commit in remote provider. File is probably not under source control`);
|
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open commit in remote provider');
|
||||||
|
|
||||||
let commit = blame.commit;
|
let commit = blame.commit;
|
||||||
// If the line is uncommitted, find the previous commit
|
// If the line is uncommitted, find the previous commit
|
||||||
if (commit.isUncommitted) {
|
if (commit.isUncommitted) {
|
||||||
commit = new GitCommit(commit.type, commit.repoPath, commit.previousSha!, commit.previousFileName!, commit.author, commit.date, commit.message);
|
commit = new GitBlameCommit(commit.repoPath, commit.previousSha!, commit.previousFileName!, commit.author, commit.date, commit.message, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider);
|
const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider);
|
||||||
|
|||||||
18
src/commands/resetSuppressedWarnings.ts
Normal file
18
src/commands/resetSuppressedWarnings.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
import { Objects } from '../system';
|
||||||
|
import { ExtensionContext } from 'vscode';
|
||||||
|
import { Command, Commands } from './common';
|
||||||
|
import { SuppressedKeys } from '../messages';
|
||||||
|
|
||||||
|
export class ResetSuppressedWarningsCommand extends Command {
|
||||||
|
|
||||||
|
constructor(private context: ExtensionContext) {
|
||||||
|
super(Commands.ResetSuppressedWarnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute() {
|
||||||
|
for (const key of Objects.values<string>(SuppressedKeys)) {
|
||||||
|
await this.context.globalState.update(key, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } fr
|
|||||||
import { Commands, EditorCommand, getCommandUri } from './common';
|
import { Commands, EditorCommand, getCommandUri } from './common';
|
||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
|
||||||
export interface ShowBlameHistoryCommandArgs {
|
export interface ShowBlameHistoryCommandArgs {
|
||||||
@@ -32,7 +33,7 @@ export class ShowBlameHistoryCommand extends EditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const locations = await this.git.getBlameLocations(gitUri, args.range, args.sha, args.line);
|
const locations = await this.git.getBlameLocations(gitUri, args.range, args.sha, args.line);
|
||||||
if (locations === undefined) return window.showWarningMessage(`Unable to show blame history. File is probably not under source control`);
|
if (locations === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show blame history');
|
||||||
|
|
||||||
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, args.position, locations);
|
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, args.position, locations);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { commands, InputBoxOptions, TextEditor, Uri, window } from 'vscode';
|
|||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitRepoSearchBy, GitService, GitUri } from '../gitService';
|
import { GitRepoSearchBy, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
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';
|
import { paste } from 'copy-paste';
|
||||||
@@ -33,7 +34,7 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
|
|||||||
const gitUri = uri === undefined ? undefined : await GitUri.fromUri(uri, this.git);
|
const gitUri = uri === undefined ? undefined : await GitUri.fromUri(uri, this.git);
|
||||||
|
|
||||||
const repoPath = gitUri === undefined ? this.git.repoPath : gitUri.repoPath;
|
const repoPath = gitUri === undefined ? this.git.repoPath : gitUri.repoPath;
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to show commit search`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show commit search`);
|
||||||
|
|
||||||
if (!args.search || args.searchBy == null) {
|
if (!args.search || args.searchBy == null) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } fr
|
|||||||
import { Commands, EditorCommand, getCommandUri } from './common';
|
import { Commands, EditorCommand, getCommandUri } from './common';
|
||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
|
||||||
export interface ShowFileHistoryCommandArgs {
|
export interface ShowFileHistoryCommandArgs {
|
||||||
@@ -30,7 +31,7 @@ export class ShowFileHistoryCommand extends EditorCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
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 window.showWarningMessage(`Unable to show file history. File is probably not under source control`);
|
if (locations === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show file history');
|
||||||
|
|
||||||
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, args.position, locations);
|
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, args.position, locations);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitService, GitUri, IGitLog } from '../gitService';
|
import { GitLog, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { BranchesQuickPick, BranchHistoryQuickPick, CommandQuickPickItem } from '../quickPicks';
|
import { BranchesQuickPick, BranchHistoryQuickPick, CommandQuickPickItem } from '../quickPicks';
|
||||||
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
||||||
|
|
||||||
export interface ShowQuickBranchHistoryCommandArgs {
|
export interface ShowQuickBranchHistoryCommandArgs {
|
||||||
branch?: string;
|
branch?: string;
|
||||||
log?: IGitLog;
|
log?: GitLog;
|
||||||
maxCount?: number;
|
maxCount?: number;
|
||||||
|
|
||||||
goBackCommand?: CommandQuickPickItem;
|
goBackCommand?: CommandQuickPickItem;
|
||||||
@@ -33,7 +34,7 @@ export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
|
|||||||
let progressCancellation = args.branch === undefined ? undefined : BranchHistoryQuickPick.showProgress(args.branch);
|
let progressCancellation = args.branch === undefined ? undefined : BranchHistoryQuickPick.showProgress(args.branch);
|
||||||
try {
|
try {
|
||||||
const repoPath = gitUri === undefined ? this.git.repoPath : gitUri.repoPath;
|
const repoPath = gitUri === undefined ? this.git.repoPath : gitUri.repoPath;
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to show branch history`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show branch history`);
|
||||||
|
|
||||||
if (args.branch === undefined) {
|
if (args.branch === undefined) {
|
||||||
const branches = await this.git.getBranches(repoPath);
|
const branches = await this.git.getBranches(repoPath);
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, TextEditor, Uri, window } from 'vscode';
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService';
|
import { GitCommit, GitLog, GitLogCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem, CommitDetailsQuickPick, CommitWithFileStatusQuickPickItem } from '../quickPicks';
|
import { CommandQuickPickItem, CommitDetailsQuickPick, CommitWithFileStatusQuickPickItem } from '../quickPicks';
|
||||||
import { ShowQuickCommitFileDetailsCommandArgs } from './showQuickCommitFileDetails';
|
import { ShowQuickCommitFileDetailsCommandArgs } from './showQuickCommitFileDetails';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface ShowQuickCommitDetailsCommandArgs {
|
export interface ShowQuickCommitDetailsCommandArgs {
|
||||||
sha?: string;
|
sha?: string;
|
||||||
commit?: GitCommit | GitLogCommit;
|
commit?: GitCommit | GitLogCommit;
|
||||||
repoLog?: IGitLog;
|
repoLog?: GitLog;
|
||||||
|
|
||||||
goBackCommand?: CommandQuickPickItem;
|
goBackCommand?: CommandQuickPickItem;
|
||||||
}
|
}
|
||||||
@@ -38,9 +39,12 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
||||||
if (blame === undefined) return window.showWarningMessage(`Unable to show commit details. File is probably not under source control`);
|
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show commit details');
|
||||||
|
|
||||||
args.sha = blame.commit.isUncommitted ? blame.commit.previousSha : blame.commit.sha;
|
// Because the previous sha of an uncommitted file isn't trust worthy we just have to kick out
|
||||||
|
if (blame.commit.isUncommitted) return Messages.showLineUncommittedWarningMessage('Unable to show commit details');
|
||||||
|
|
||||||
|
args.sha = blame.commit.sha;
|
||||||
repoPath = blame.commit.repoPath;
|
repoPath = blame.commit.repoPath;
|
||||||
workingFileName = blame.commit.fileName;
|
workingFileName = blame.commit.fileName;
|
||||||
|
|
||||||
@@ -64,13 +68,13 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
|
|||||||
|
|
||||||
if (args.repoLog === undefined) {
|
if (args.repoLog === undefined) {
|
||||||
const log = await this.git.getLogForRepo(repoPath!, args.sha, 2);
|
const log = await this.git.getLogForRepo(repoPath!, args.sha, 2);
|
||||||
if (log === undefined) return window.showWarningMessage(`Unable to show commit details`);
|
if (log === undefined) return Messages.showCommitNotFoundWarningMessage(`Unable to show commit details`);
|
||||||
|
|
||||||
args.commit = log.commits.get(args.sha!);
|
args.commit = log.commits.get(args.sha!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.commit === undefined) return window.showWarningMessage(`Unable to show commit details`);
|
if (args.commit === undefined) return Messages.showCommitNotFoundWarningMessage(`Unable to show commit details`);
|
||||||
|
|
||||||
if (args.commit.workingFileName === undefined) {
|
if (args.commit.workingFileName === undefined) {
|
||||||
args.commit.workingFileName = workingFileName;
|
args.commit.workingFileName = workingFileName;
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { TextEditor, Uri, window } from 'vscode';
|
import { TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService';
|
import { GitCommit, GitLog, GitLogCommit, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem, CommitFileDetailsQuickPick } from '../quickPicks';
|
import { CommandQuickPickItem, CommitFileDetailsQuickPick } from '../quickPicks';
|
||||||
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface ShowQuickCommitFileDetailsCommandArgs {
|
export interface ShowQuickCommitFileDetailsCommandArgs {
|
||||||
sha?: string;
|
sha?: string;
|
||||||
commit?: GitCommit | GitLogCommit;
|
commit?: GitCommit | GitLogCommit;
|
||||||
fileLog?: IGitLog;
|
fileLog?: GitLog;
|
||||||
|
|
||||||
goBackCommand?: CommandQuickPickItem;
|
goBackCommand?: CommandQuickPickItem;
|
||||||
}
|
}
|
||||||
@@ -37,9 +38,12 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
const blame = await this.git.getBlameForLine(gitUri, blameline);
|
||||||
if (blame === undefined) return window.showWarningMessage(`Unable to show commit file details. File is probably not under source control`);
|
if (blame === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show commit file details');
|
||||||
|
|
||||||
args.sha = blame.commit.isUncommitted ? blame.commit.previousSha : blame.commit.sha;
|
// Because the previous sha of an uncommitted file isn't trust worthy we just have to kick out
|
||||||
|
if (blame.commit.isUncommitted) return Messages.showLineUncommittedWarningMessage('Unable to show commit file details');
|
||||||
|
|
||||||
|
args.sha = blame.commit.sha;
|
||||||
|
|
||||||
args.commit = blame.commit;
|
args.commit = blame.commit;
|
||||||
workingFileName = path.relative(args.commit.repoPath, gitUri.fsPath);
|
workingFileName = path.relative(args.commit.repoPath, gitUri.fsPath);
|
||||||
@@ -65,12 +69,12 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args.fileLog === undefined) {
|
if (args.fileLog === undefined) {
|
||||||
args.commit = await this.git.getLogCommit(args.commit ? args.commit.repoPath : gitUri.repoPath, gitUri.fsPath, args.sha, { previous: true });
|
args.commit = await this.git.getLogCommit(args.commit === undefined ? gitUri.repoPath : args.commit.repoPath, gitUri.fsPath, args.sha, { previous: true });
|
||||||
if (args.commit === undefined) return window.showWarningMessage(`Unable to show commit file details`);
|
if (args.commit === undefined) return Messages.showCommitNotFoundWarningMessage(`Unable to show commit file details`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.commit === undefined) return window.showWarningMessage(`Unable to show commit file details`);
|
if (args.commit === undefined) return Messages.showCommitNotFoundWarningMessage(`Unable to show commit file details`);
|
||||||
|
|
||||||
// Attempt to the most recent commit -- so that we can find the real working filename if there was a rename
|
// Attempt to the most recent commit -- so that we can find the real working filename if there was a rename
|
||||||
args.commit.workingFileName = workingFileName;
|
args.commit.workingFileName = workingFileName;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
|||||||
import { ShowQuickBranchHistoryCommandArgs } from './showQuickBranchHistory';
|
import { ShowQuickBranchHistoryCommandArgs } from './showQuickBranchHistory';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { CommandQuickPickItem } from '../quickPicks';
|
import { CommandQuickPickItem } from '../quickPicks';
|
||||||
|
|
||||||
export interface ShowQuickCurrentBranchHistoryCommandArgs {
|
export interface ShowQuickCurrentBranchHistoryCommandArgs {
|
||||||
@@ -21,7 +22,7 @@ export class ShowQuickCurrentBranchHistoryCommand extends ActiveEditorCachedComm
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const repoPath = await this.git.getRepoPathFromUri(uri);
|
const repoPath = await this.git.getRepoPathFromUri(uri);
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to show branch history`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show branch history`);
|
||||||
|
|
||||||
const branch = await this.git.getBranch(repoPath);
|
const branch = await this.git.getBranch(repoPath);
|
||||||
if (branch === undefined) return undefined;
|
if (branch === undefined) return undefined;
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Range, TextEditor, Uri, window } from 'vscode';
|
import { commands, Range, TextEditor, Uri, window } from 'vscode';
|
||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitService, GitUri, IGitLog } from '../gitService';
|
import { GitLog, GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks';
|
import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks';
|
||||||
import { ShowQuickCommitFileDetailsCommandArgs } from './showQuickCommitFileDetails';
|
import { ShowQuickCommitFileDetailsCommandArgs } from './showQuickCommitFileDetails';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface ShowQuickFileHistoryCommandArgs {
|
export interface ShowQuickFileHistoryCommandArgs {
|
||||||
log?: IGitLog;
|
log?: GitLog;
|
||||||
maxCount?: number;
|
maxCount?: number;
|
||||||
range?: Range;
|
range?: Range;
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
|
|||||||
try {
|
try {
|
||||||
if (args.log === undefined) {
|
if (args.log === undefined) {
|
||||||
args.log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha, args.maxCount, args.range);
|
args.log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha, args.maxCount, args.range);
|
||||||
if (args.log === undefined) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`);
|
if (args.log === undefined) return Messages.showFileNotUnderSourceControlWarningMessage('Unable to show file history');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progressCancellation.token.isCancellationRequested) return undefined;
|
if (progressCancellation.token.isCancellationRequested) return undefined;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { TextEditor, Uri, window } from 'vscode';
|
|||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitService } from '../gitService';
|
import { GitService } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { CommandQuickPickItem, RepoStatusQuickPick } from '../quickPicks';
|
import { CommandQuickPickItem, RepoStatusQuickPick } from '../quickPicks';
|
||||||
|
|
||||||
export interface ShowQuickRepoStatusCommandArgs {
|
export interface ShowQuickRepoStatusCommandArgs {
|
||||||
@@ -20,7 +21,7 @@ export class ShowQuickRepoStatusCommand extends ActiveEditorCachedCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const repoPath = await this.git.getRepoPathFromUri(uri);
|
const repoPath = await this.git.getRepoPathFromUri(uri);
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to show repository status`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show repository status`);
|
||||||
|
|
||||||
const status = await this.git.getStatusForRepo(repoPath);
|
const status = await this.git.getStatusForRepo(repoPath);
|
||||||
if (status === undefined) return window.showWarningMessage(`Unable to show repository status`);
|
if (status === undefined) return window.showWarningMessage(`Unable to show repository status`);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { commands, TextEditor, Uri, window } from 'vscode';
|
|||||||
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
|
||||||
import { GitService, GitUri } from '../gitService';
|
import { GitService, GitUri } from '../gitService';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
import { Messages } from '../messages';
|
||||||
import { CommandQuickPickItem, StashListQuickPick } from '../quickPicks';
|
import { CommandQuickPickItem, StashListQuickPick } from '../quickPicks';
|
||||||
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const repoPath = await this.git.getRepoPathFromUri(uri);
|
const repoPath = await this.git.getRepoPathFromUri(uri);
|
||||||
if (!repoPath) return window.showWarningMessage(`Unable to show stashed changes`);
|
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show stashed changes`);
|
||||||
|
|
||||||
const stash = await this.git.getStashList(repoPath);
|
const stash = await this.git.getStashList(repoPath);
|
||||||
if (stash === undefined) return window.showWarningMessage(`Unable to show stashed changes`);
|
if (stash === undefined) return window.showWarningMessage(`Unable to show stashed changes`);
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ export const BlameLineHighlightLocations = {
|
|||||||
OverviewRuler: 'overviewRuler' as BlameLineHighlightLocations
|
OverviewRuler: 'overviewRuler' as BlameLineHighlightLocations
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CodeLensCommand = 'gitlens.toggleFileBlame' | 'gitlens.showBlameHistory' | 'gitlens.showFileHistory' | 'gitlens.diffWithPrevious' | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory';
|
export type CodeLensCommand = 'gitlens.toggleFileBlame' |
|
||||||
|
'gitlens.showBlameHistory' |
|
||||||
|
'gitlens.showFileHistory' |
|
||||||
|
'gitlens.diffWithPrevious' |
|
||||||
|
'gitlens.showQuickCommitDetails' |
|
||||||
|
'gitlens.showQuickCommitFileDetails' |
|
||||||
|
'gitlens.showQuickFileHistory' |
|
||||||
|
'gitlens.showQuickRepoHistory';
|
||||||
export const CodeLensCommand = {
|
export const CodeLensCommand = {
|
||||||
BlameAnnotate: Commands.ToggleFileBlame as CodeLensCommand,
|
BlameAnnotate: Commands.ToggleFileBlame as CodeLensCommand,
|
||||||
ShowBlameHistory: Commands.ShowBlameHistory as CodeLensCommand,
|
ShowBlameHistory: Commands.ShowBlameHistory as CodeLensCommand,
|
||||||
@@ -43,7 +50,16 @@ export const LineAnnotationType = {
|
|||||||
Hover: 'hover' as LineAnnotationType
|
Hover: 'hover' as LineAnnotationType
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StatusBarCommand = 'gitlens.toggleFileBlame' | 'gitlens.showBlameHistory' | 'gitlens.showFileHistory' | 'gitlens.toggleCodeLens' | 'gitlens.diffWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory';
|
export type StatusBarCommand = 'gitlens.toggleFileBlame' |
|
||||||
|
'gitlens.showBlameHistory' |
|
||||||
|
'gitlens.showFileHistory' |
|
||||||
|
'gitlens.toggleCodeLens' |
|
||||||
|
'gitlens.diffWithPrevious' |
|
||||||
|
'gitlens.diffWithWorking' |
|
||||||
|
'gitlens.showQuickCommitDetails' |
|
||||||
|
'gitlens.showQuickCommitFileDetails' |
|
||||||
|
'gitlens.showQuickFileHistory' |
|
||||||
|
'gitlens.showQuickRepoHistory';
|
||||||
export const StatusBarCommand = {
|
export const StatusBarCommand = {
|
||||||
BlameAnnotate: Commands.ToggleFileBlame as StatusBarCommand,
|
BlameAnnotate: Commands.ToggleFileBlame as StatusBarCommand,
|
||||||
ShowBlameHistory: Commands.ShowBlameHistory as StatusBarCommand,
|
ShowBlameHistory: Commands.ShowBlameHistory as StatusBarCommand,
|
||||||
|
|||||||
@@ -7,9 +7,23 @@ export const QualifiedExtensionId = `eamodio.${ExtensionId}`;
|
|||||||
|
|
||||||
export const ApplicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
|
export const ApplicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
|
||||||
|
|
||||||
export type BuiltInCommands = 'cursorMove' | 'editor.action.showReferences' | 'editor.action.toggleRenderWhitespace' | 'editorScroll' | 'revealLine' | 'setContext' | 'vscode.diff' | 'vscode.executeDocumentSymbolProvider' | 'vscode.executeCodeLensProvider' | 'vscode.open' | 'vscode.previewHtml' | 'workbench.action.closeActiveEditor' | 'workbench.action.nextEditor';
|
export type BuiltInCommands = 'cursorMove' |
|
||||||
|
'editor.action.showReferences' |
|
||||||
|
'editor.action.toggleRenderWhitespace' |
|
||||||
|
'editorScroll' |
|
||||||
|
'revealLine' |
|
||||||
|
'setContext' |
|
||||||
|
'vscode.diff' |
|
||||||
|
'vscode.executeDocumentSymbolProvider' |
|
||||||
|
'vscode.executeCodeLensProvider' |
|
||||||
|
'vscode.open' |
|
||||||
|
'vscode.previewHtml' |
|
||||||
|
'workbench.action.closeActiveEditor' |
|
||||||
|
'workbench.action.closeAllEditors' |
|
||||||
|
'workbench.action.nextEditor';
|
||||||
export const BuiltInCommands = {
|
export const BuiltInCommands = {
|
||||||
CloseActiveEditor: 'workbench.action.closeActiveEditor' as BuiltInCommands,
|
CloseActiveEditor: 'workbench.action.closeActiveEditor' as BuiltInCommands,
|
||||||
|
CloseAllEditors: 'workbench.action.closeAllEditors' as BuiltInCommands,
|
||||||
CursorMove: 'cursorMove' as BuiltInCommands,
|
CursorMove: 'cursorMove' as BuiltInCommands,
|
||||||
Diff: 'vscode.diff' as BuiltInCommands,
|
Diff: 'vscode.diff' as BuiltInCommands,
|
||||||
EditorScroll: 'editorScroll' as BuiltInCommands,
|
EditorScroll: 'editorScroll' as BuiltInCommands,
|
||||||
@@ -31,10 +45,7 @@ export const DocumentSchemes = {
|
|||||||
GitLensGit: 'gitlens-git' as DocumentSchemes
|
GitLensGit: 'gitlens-git' as DocumentSchemes
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WorkspaceState = 'repoPath' | 'suppressGitVersionWarning' | 'suppressUpdateNotice' | 'suppressWelcomeNotice';
|
export type WorkspaceState = 'gitlensVersion';
|
||||||
export const WorkspaceState = {
|
export const WorkspaceState = {
|
||||||
GitLensVersion: 'gitlensVersion' as WorkspaceState,
|
GitLensVersion: 'gitlensVersion' as WorkspaceState
|
||||||
SuppressGitVersionWarning: 'suppressGitVersionWarning' as WorkspaceState,
|
|
||||||
SuppressUpdateNotice: 'suppressUpdateNotice' as WorkspaceState,
|
|
||||||
SuppressWelcomeNotice: 'suppressWelcomeNotice' as WorkspaceState
|
|
||||||
};
|
};
|
||||||
@@ -7,7 +7,7 @@ import { Commands } from './commands';
|
|||||||
import { TextEditorComparer } from './comparers';
|
import { TextEditorComparer } from './comparers';
|
||||||
import { FileAnnotationType, IConfig, LineAnnotationType, StatusBarCommand } from './configuration';
|
import { FileAnnotationType, IConfig, LineAnnotationType, StatusBarCommand } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey } from './constants';
|
import { DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { BlameabilityChangeEvent, CommitFormatter, GitCommit, GitContextTracker, GitService, GitUri, IGitCommitLine } from './gitService';
|
import { BlameabilityChangeEvent, CommitFormatter, GitCommit, GitCommitLine, GitContextTracker, GitService, GitUri } from './gitService';
|
||||||
|
|
||||||
const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
||||||
after: {
|
after: {
|
||||||
@@ -181,7 +181,7 @@ export class CurrentLineController extends Disposable {
|
|||||||
line = line - this._uri.offset;
|
line = line - this._uri.offset;
|
||||||
|
|
||||||
let commit: GitCommit | undefined = undefined;
|
let commit: GitCommit | undefined = undefined;
|
||||||
let commitLine: IGitCommitLine | undefined = undefined;
|
let commitLine: GitCommitLine | undefined = undefined;
|
||||||
// Since blame information isn't valid when there are unsaved changes -- don't show any status
|
// Since blame information isn't valid when there are unsaved changes -- don't show any status
|
||||||
if (this._blameable && line >= 0) {
|
if (this._blameable && line >= 0) {
|
||||||
const blameLine = await this.git.getBlameForLine(this._uri, line);
|
const blameLine = await this.git.getBlameForLine(this._uri, line);
|
||||||
@@ -190,7 +190,7 @@ export class CurrentLineController extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (commit !== undefined && commitLine !== undefined) {
|
if (commit !== undefined && commitLine !== undefined) {
|
||||||
this.show(commit, commitLine, editor);
|
this.show(commit, commitLine, editor, line);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.clear(editor);
|
this.clear(editor);
|
||||||
@@ -215,12 +215,12 @@ export class CurrentLineController extends Disposable {
|
|||||||
editor.setDecorations(annotationDecoration, []);
|
editor.setDecorations(annotationDecoration, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
async show(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
|
async show(commit: GitCommit, blameLine: GitCommitLine, editor: TextEditor, line: number) {
|
||||||
// I have no idea why I need this protection -- but it happens
|
// I have no idea why I need this protection -- but it happens
|
||||||
if (editor.document === undefined) return;
|
if (editor.document === undefined) return;
|
||||||
|
|
||||||
this._updateStatusBar(commit);
|
this._updateStatusBar(commit);
|
||||||
await this._updateAnnotations(commit, blameLine, editor);
|
await this._updateAnnotations(commit, blameLine, editor, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
async showAnnotations(editor: TextEditor, type: LineAnnotationType) {
|
async showAnnotations(editor: TextEditor, type: LineAnnotationType) {
|
||||||
@@ -247,11 +247,11 @@ export class CurrentLineController extends Disposable {
|
|||||||
await this._updateBlame(editor.selection.active.line, editor);
|
await this._updateBlame(editor.selection.active.line, editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateAnnotations(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
|
private async _updateAnnotations(commit: GitCommit, blameLine: GitCommitLine, editor: TextEditor, line?: number) {
|
||||||
const cfg = this._config.blame.line;
|
const cfg = this._config.blame.line;
|
||||||
if (!cfg.enabled) return;
|
if (!cfg.enabled) return;
|
||||||
|
|
||||||
const line = blameLine.line + this._uri.offset;
|
line = line === undefined ? blameLine.line + this._uri.offset : line;
|
||||||
|
|
||||||
const decorationOptions: DecorationOptions[] = [];
|
const decorationOptions: DecorationOptions[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Objects } from './system';
|
// import { Objects } from './system';
|
||||||
import { commands, ExtensionContext, extensions, languages, Uri, window, workspace } from 'vscode';
|
import { ExtensionContext, extensions, languages, window, workspace } from 'vscode';
|
||||||
import { AnnotationController } from './annotations/annotationController';
|
import { AnnotationController } from './annotations/annotationController';
|
||||||
import { CommandContext, setCommandContext } from './commands';
|
import { CommandContext, setCommandContext } from './commands';
|
||||||
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
|
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
|
||||||
import { OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands';
|
import { OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands';
|
||||||
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
|
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
|
||||||
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithWorkingCommand} from './commands';
|
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithWorkingCommand} from './commands';
|
||||||
|
import { ResetSuppressedWarningsCommand } from './commands';
|
||||||
import { ShowFileBlameCommand, ShowLineBlameCommand, ToggleFileBlameCommand, ToggleLineBlameCommand } from './commands';
|
import { ShowFileBlameCommand, ShowLineBlameCommand, ToggleFileBlameCommand, ToggleLineBlameCommand } from './commands';
|
||||||
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
||||||
import { ShowLastQuickPickCommand } from './commands';
|
import { ShowLastQuickPickCommand } from './commands';
|
||||||
@@ -17,17 +18,19 @@ import { StashApplyCommand, StashDeleteCommand, StashSaveCommand } from './comma
|
|||||||
import { ToggleCodeLensCommand } from './commands';
|
import { ToggleCodeLensCommand } from './commands';
|
||||||
import { Keyboard } from './commands';
|
import { Keyboard } from './commands';
|
||||||
import { BlameLineHighlightLocations, CodeLensLocations, IConfig, LineAnnotationType } from './configuration';
|
import { BlameLineHighlightLocations, CodeLensLocations, IConfig, LineAnnotationType } from './configuration';
|
||||||
import { ApplicationInsightsKey, BuiltInCommands, ExtensionKey, QualifiedExtensionId, WorkspaceState } from './constants';
|
import { ApplicationInsightsKey, ExtensionKey, QualifiedExtensionId, WorkspaceState } from './constants';
|
||||||
import { CurrentLineController } from './currentLineController';
|
import { CurrentLineController } from './currentLineController';
|
||||||
import { GitContentProvider } from './gitContentProvider';
|
import { GitContentProvider } from './gitContentProvider';
|
||||||
import { GitContextTracker, GitService } from './gitService';
|
import { GitContextTracker, GitService } from './gitService';
|
||||||
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
|
import { Messages, SuppressedKeys } from './messages';
|
||||||
import { Telemetry } from './telemetry';
|
import { Telemetry } from './telemetry';
|
||||||
|
|
||||||
// this method is called when your extension is activated
|
// this method is called when your extension is activated
|
||||||
export async function activate(context: ExtensionContext) {
|
export async function activate(context: ExtensionContext) {
|
||||||
Logger.configure(context);
|
Logger.configure(context);
|
||||||
|
Messages.configure(context);
|
||||||
Telemetry.configure(ApplicationInsightsKey);
|
Telemetry.configure(ApplicationInsightsKey);
|
||||||
|
|
||||||
const gitlens = extensions.getExtension(QualifiedExtensionId)!;
|
const gitlens = extensions.getExtension(QualifiedExtensionId)!;
|
||||||
@@ -105,6 +108,7 @@ export async function activate(context: ExtensionContext) {
|
|||||||
context.subscriptions.push(new ShowLineBlameCommand(currentLineController));
|
context.subscriptions.push(new ShowLineBlameCommand(currentLineController));
|
||||||
context.subscriptions.push(new ToggleFileBlameCommand(annotationController));
|
context.subscriptions.push(new ToggleFileBlameCommand(annotationController));
|
||||||
context.subscriptions.push(new ToggleLineBlameCommand(currentLineController));
|
context.subscriptions.push(new ToggleLineBlameCommand(currentLineController));
|
||||||
|
context.subscriptions.push(new ResetSuppressedWarningsCommand(context));
|
||||||
context.subscriptions.push(new ShowBlameHistoryCommand(git));
|
context.subscriptions.push(new ShowBlameHistoryCommand(git));
|
||||||
context.subscriptions.push(new ShowFileHistoryCommand(git));
|
context.subscriptions.push(new ShowFileHistoryCommand(git));
|
||||||
context.subscriptions.push(new ShowLastQuickPickCommand());
|
context.subscriptions.push(new ShowLastQuickPickCommand());
|
||||||
@@ -121,7 +125,8 @@ export async function activate(context: ExtensionContext) {
|
|||||||
context.subscriptions.push(new StashSaveCommand(git));
|
context.subscriptions.push(new StashSaveCommand(git));
|
||||||
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
||||||
|
|
||||||
Telemetry.trackEvent('initialized', Objects.flatten(cfg, 'config', true));
|
// Constantly over my data cap so stop collecting initialized event
|
||||||
|
// Telemetry.trackEvent('initialized', Objects.flatten(cfg, 'config', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method is called when your extension is deactivated
|
// this method is called when your extension is deactivated
|
||||||
@@ -252,49 +257,25 @@ async function migrateSettings(context: ExtensionContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function notifyOnNewGitLensVersion(context: ExtensionContext, version: string) {
|
async function notifyOnNewGitLensVersion(context: ExtensionContext, version: string) {
|
||||||
if (context.globalState.get(WorkspaceState.SuppressUpdateNotice, false)) return;
|
if (context.globalState.get(SuppressedKeys.UpdateNotice, false)) return;
|
||||||
|
|
||||||
const previousVersion = context.globalState.get<string>(WorkspaceState.GitLensVersion);
|
const previousVersion = context.globalState.get<string>(WorkspaceState.GitLensVersion);
|
||||||
|
|
||||||
if (!context.globalState.get(WorkspaceState.SuppressWelcomeNotice, false)) {
|
if (previousVersion === undefined) {
|
||||||
await context.globalState.update(WorkspaceState.SuppressWelcomeNotice, true);
|
await Messages.showWelcomeMessage();
|
||||||
|
return;
|
||||||
if (previousVersion === undefined) {
|
|
||||||
const result = await window.showInformationMessage(`Thank you for choosing GitLens! GitLens is powerful, feature rich, and highly configurable, so please be sure to view the docs and tailor it to suit your needs.`, 'View Docs');
|
|
||||||
if (result === 'View Docs') {
|
|
||||||
// TODO: Reset before release
|
|
||||||
// commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens'));
|
|
||||||
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://github.com/eamodio/vscode-gitlens/blob/develop/README.md'));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousVersion) {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await window.showInformationMessage(`GitLens has been updated to v${version}`, 'View Release Notes', `Don't Show Again`);
|
await Messages.showUpdateMessage(version);
|
||||||
if (result === 'View Release Notes') {
|
|
||||||
// TODO: Reset before release
|
|
||||||
// commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens/changelog'));
|
|
||||||
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://github.com/eamodio/vscode-gitlens/blob/develop/CHANGELOG.md'));
|
|
||||||
}
|
|
||||||
else if (result === `Don't Show Again`) {
|
|
||||||
context.globalState.update(WorkspaceState.SuppressUpdateNotice, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function notifyOnUnsupportedGitVersion(context: ExtensionContext, version: string) {
|
async function notifyOnUnsupportedGitVersion(context: ExtensionContext, version: string) {
|
||||||
if (context.globalState.get(WorkspaceState.SuppressGitVersionWarning, false)) return;
|
if (GitService.validateGitVersion(2, 2)) return;
|
||||||
|
|
||||||
// If git is less than v2.2.0
|
// If git is less than v2.2.0
|
||||||
if (!GitService.validateGitVersion(2, 2)) {
|
await Messages.showUnsupportedGitVersionErrorMessage(version);
|
||||||
const result = await window.showErrorMessage(`GitLens requires a newer version of Git (>= 2.2.0) than is currently installed (${version}). Please install a more recent version of Git.`, `Don't Show Again`);
|
|
||||||
if (result === `Don't Show Again`) {
|
|
||||||
context.globalState.update(WorkspaceState.SuppressGitVersionWarning, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Strings } from '../../system';
|
import { Strings } from '../../system';
|
||||||
import { GitCommit } from '../models/commit';
|
import { GitCommit } from '../models/commit';
|
||||||
import { IGitDiffLine } from '../models/diff';
|
import { GitDiffLine } from '../models/diff';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
export interface ICommitFormatOptions {
|
export interface ICommitFormatOptions {
|
||||||
@@ -142,7 +142,7 @@ export class CommitFormatter {
|
|||||||
return `\`${commit.shortSha}\` __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format(dateFormat)})_${message}`;
|
return `\`${commit.shortSha}\` __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format(dateFormat)})_${message}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static toHoverDiff(commit: GitCommit, previous: IGitDiffLine | undefined, current: IGitDiffLine | undefined): string | undefined {
|
static toHoverDiff(commit: GitCommit, previous: GitDiffLine | undefined, current: GitDiffLine | undefined): string | undefined {
|
||||||
if (previous === undefined && current === undefined) return undefined;
|
if (previous === undefined && current === undefined) return undefined;
|
||||||
|
|
||||||
const codeDiff = this._getCodeDiff(previous, current);
|
const codeDiff = this._getCodeDiff(previous, current);
|
||||||
@@ -151,7 +151,7 @@ export class CommitFormatter {
|
|||||||
: `\`Changes\` \u2014 \`${commit.previousShortSha}\` \u2194 \`${commit.shortSha}\`\n${codeDiff}`;
|
: `\`Changes\` \u2014 \`${commit.previousShortSha}\` \u2194 \`${commit.shortSha}\`\n${codeDiff}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _getCodeDiff(previous: IGitDiffLine | undefined, current: IGitDiffLine | undefined): string {
|
private static _getCodeDiff(previous: GitDiffLine | undefined, current: GitDiffLine | undefined): string {
|
||||||
return `\`\`\`
|
return `\`\`\`
|
||||||
- ${previous === undefined ? '' : previous.line.trim()}
|
- ${previous === undefined ? '' : previous.line.trim()}
|
||||||
+ ${current === undefined ? '' : current.line.trim()}
|
+ ${current === undefined ? '' : current.line.trim()}
|
||||||
|
|||||||
@@ -114,13 +114,15 @@ export class GitContextTracker extends Disposable {
|
|||||||
|
|
||||||
private async _updateContextHasRemotes(uri: GitUri | undefined) {
|
private async _updateContextHasRemotes(uri: GitUri | undefined) {
|
||||||
try {
|
try {
|
||||||
|
let repoPath = this.git.repoPath;
|
||||||
|
if (uri !== undefined && this.git.isTrackable(uri)) {
|
||||||
|
repoPath = uri.repoPath || this.git.repoPath;
|
||||||
|
}
|
||||||
|
|
||||||
let hasRemotes = false;
|
let hasRemotes = false;
|
||||||
if (uri && this.git.isTrackable(uri)) {
|
if (repoPath) {
|
||||||
const repoPath = uri.repoPath || this.git.repoPath;
|
const remotes = await this.git.getRemotes(repoPath);
|
||||||
if (repoPath) {
|
hasRemotes = remotes.length !== 0;
|
||||||
const remotes = await this.git.getRemotes(repoPath);
|
|
||||||
hasRemotes = remotes.length !== 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setCommandContext(CommandContext.HasRemotes, hasRemotes);
|
setCommandContext(CommandContext.HasRemotes, hasRemotes);
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { GitCommit, IGitAuthor, IGitCommitLine } from './commit';
|
import { GitAuthor, GitCommitLine } from './commit';
|
||||||
|
import { GitBlameCommit } from './blameCommit';
|
||||||
|
|
||||||
export interface IGitBlame {
|
export interface GitBlame {
|
||||||
repoPath: string;
|
repoPath: string;
|
||||||
authors: Map<string, IGitAuthor>;
|
authors: Map<string, GitAuthor>;
|
||||||
commits: Map<string, GitCommit>;
|
commits: Map<string, GitBlameCommit>;
|
||||||
lines: IGitCommitLine[];
|
lines: GitCommitLine[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitBlameLine {
|
export interface GitBlameLine {
|
||||||
author: IGitAuthor;
|
author: GitAuthor;
|
||||||
commit: GitCommit;
|
commit: GitBlameCommit;
|
||||||
line: IGitCommitLine;
|
line: GitCommitLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitBlameLines extends IGitBlame {
|
export interface GitBlameLines extends GitBlame {
|
||||||
allLines: IGitCommitLine[];
|
allLines: GitCommitLine[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitBlameCommitLines {
|
export interface GitBlameCommitLines {
|
||||||
author: IGitAuthor;
|
author: GitAuthor;
|
||||||
commit: GitCommit;
|
commit: GitBlameCommit;
|
||||||
lines: IGitCommitLine[];
|
lines: GitCommitLine[];
|
||||||
}
|
}
|
||||||
20
src/git/models/blameCommit.ts
Normal file
20
src/git/models/blameCommit.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
import { GitCommit, GitCommitLine } from './commit';
|
||||||
|
|
||||||
|
export class GitBlameCommit extends GitCommit {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
repoPath: string,
|
||||||
|
sha: string,
|
||||||
|
fileName: string,
|
||||||
|
author: string,
|
||||||
|
date: Date,
|
||||||
|
message: string,
|
||||||
|
public lines: GitCommitLine[],
|
||||||
|
originalFileName?: string,
|
||||||
|
previousSha?: string,
|
||||||
|
previousFileName?: string
|
||||||
|
) {
|
||||||
|
super('blame', repoPath, sha, fileName, author, date, message, originalFileName, previousSha, previousFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,30 +3,12 @@ import { Uri } from 'vscode';
|
|||||||
import { Git } from '../git';
|
import { Git } from '../git';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface IGitAuthor {
|
export interface GitAuthor {
|
||||||
name: string;
|
name: string;
|
||||||
lineCount: number;
|
lineCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitCommit {
|
export interface GitCommitLine {
|
||||||
type: GitCommitType;
|
|
||||||
repoPath: string;
|
|
||||||
sha: string;
|
|
||||||
fileName: string;
|
|
||||||
author?: string;
|
|
||||||
date: Date;
|
|
||||||
message: string;
|
|
||||||
lines: IGitCommitLine[];
|
|
||||||
originalFileName?: string;
|
|
||||||
previousSha?: string;
|
|
||||||
previousFileName?: string;
|
|
||||||
|
|
||||||
readonly isUncommitted: boolean;
|
|
||||||
previousUri: Uri;
|
|
||||||
uri: Uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IGitCommitLine {
|
|
||||||
sha: string;
|
sha: string;
|
||||||
previousSha?: string;
|
previousSha?: string;
|
||||||
line: number;
|
line: number;
|
||||||
@@ -36,10 +18,10 @@ export interface IGitCommitLine {
|
|||||||
|
|
||||||
export type GitCommitType = 'blame' | 'branch' | 'file' | 'stash';
|
export type GitCommitType = 'blame' | 'branch' | 'file' | 'stash';
|
||||||
|
|
||||||
export class GitCommit implements IGitCommit {
|
export class GitCommit {
|
||||||
|
|
||||||
type: GitCommitType;
|
type: GitCommitType;
|
||||||
lines: IGitCommitLine[];
|
// lines: GitCommitLine[];
|
||||||
originalFileName?: string;
|
originalFileName?: string;
|
||||||
previousSha?: string;
|
previousSha?: string;
|
||||||
previousFileName?: string;
|
previousFileName?: string;
|
||||||
@@ -54,7 +36,7 @@ export class GitCommit implements IGitCommit {
|
|||||||
public author: string,
|
public author: string,
|
||||||
public date: Date,
|
public date: Date,
|
||||||
public message: string,
|
public message: string,
|
||||||
lines?: IGitCommitLine[],
|
// lines?: GitCommitLine[],
|
||||||
originalFileName?: string,
|
originalFileName?: string,
|
||||||
previousSha?: string,
|
previousSha?: string,
|
||||||
previousFileName?: string
|
previousFileName?: string
|
||||||
@@ -62,7 +44,7 @@ export class GitCommit implements IGitCommit {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
this.fileName = this.fileName && this.fileName.replace(/, ?$/, '');
|
this.fileName = this.fileName && this.fileName.replace(/, ?$/, '');
|
||||||
|
|
||||||
this.lines = lines || [];
|
// this.lines = lines || [];
|
||||||
this.originalFileName = originalFileName;
|
this.originalFileName = originalFileName;
|
||||||
this.previousSha = previousSha;
|
this.previousSha = previousSha;
|
||||||
this.previousFileName = previousFileName;
|
this.previousFileName = previousFileName;
|
||||||
|
|||||||
@@ -1,24 +1,45 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
import { GitDiffParser } from '../parsers/diffParser';
|
||||||
|
|
||||||
export interface IGitDiffLine {
|
export interface GitDiffLine {
|
||||||
line: string;
|
line: string;
|
||||||
state: 'added' | 'removed' | 'unchanged';
|
state: 'added' | 'removed' | 'unchanged';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitDiffChunk {
|
export class GitDiffChunk {
|
||||||
current: (IGitDiffLine | undefined)[];
|
|
||||||
currentStart: number;
|
|
||||||
currentEnd: number;
|
|
||||||
|
|
||||||
previous: (IGitDiffLine | undefined)[];
|
private _chunk: string | undefined;
|
||||||
previousStart: number;
|
private _current: (GitDiffLine | undefined)[] | undefined;
|
||||||
previousEnd: number;
|
private _previous: (GitDiffLine | undefined)[] | undefined;
|
||||||
|
|
||||||
chunk?: string;
|
constructor(chunk: string, public currentPosition: { start: number, end: number }, public previousPosition: { start: number, end: number }) {
|
||||||
|
this._chunk = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
get current(): (GitDiffLine | undefined)[] {
|
||||||
|
if (this._chunk !== undefined) {
|
||||||
|
this.parseChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._current!;
|
||||||
|
}
|
||||||
|
|
||||||
|
get previous(): (GitDiffLine | undefined)[] {
|
||||||
|
if (this._chunk !== undefined) {
|
||||||
|
this.parseChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._previous!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseChunk() {
|
||||||
|
[this._current, this._previous] = GitDiffParser.parseChunk(this._chunk!);
|
||||||
|
this._chunk = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGitDiff {
|
export interface GitDiff {
|
||||||
chunks: IGitDiffChunk[];
|
chunks: GitDiffChunk[];
|
||||||
|
|
||||||
diff?: string;
|
diff?: string;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Range } from 'vscode';
|
import { Range } from 'vscode';
|
||||||
import { IGitAuthor } from './commit';
|
import { GitAuthor } from './commit';
|
||||||
import { GitLogCommit } from './logCommit';
|
import { GitLogCommit } from './logCommit';
|
||||||
|
|
||||||
export interface IGitLog {
|
export interface GitLog {
|
||||||
repoPath: string;
|
repoPath: string;
|
||||||
authors: Map<string, IGitAuthor>;
|
authors: Map<string, GitAuthor>;
|
||||||
commits: Map<string, GitLogCommit>;
|
commits: Map<string, GitLogCommit>;
|
||||||
|
|
||||||
sha: string | undefined;
|
sha: string | undefined;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Uri } from 'vscode';
|
import { Uri } from 'vscode';
|
||||||
import { GitCommit, GitCommitType, IGitCommitLine } from './commit';
|
import { GitCommit, GitCommitType } from './commit';
|
||||||
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
@@ -23,12 +23,11 @@ export class GitLogCommit extends GitCommit {
|
|||||||
message: string,
|
message: string,
|
||||||
status?: GitStatusFileStatus,
|
status?: GitStatusFileStatus,
|
||||||
fileStatuses?: IGitStatusFile[],
|
fileStatuses?: IGitStatusFile[],
|
||||||
lines?: IGitCommitLine[],
|
|
||||||
originalFileName?: string,
|
originalFileName?: string,
|
||||||
previousSha?: string,
|
previousSha?: string,
|
||||||
previousFileName?: string
|
previousFileName?: string
|
||||||
) {
|
) {
|
||||||
super(type, repoPath, sha, fileName, author, date, message, lines, originalFileName, previousSha, previousFileName);
|
super(type, repoPath, sha, fileName, author, date, message, originalFileName, previousSha, previousFileName);
|
||||||
|
|
||||||
this.fileNames = this.fileName;
|
this.fileNames = this.fileName;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
export * from './blame';
|
export * from './blame';
|
||||||
|
export * from './blameCommit';
|
||||||
export * from './branch';
|
export * from './branch';
|
||||||
export * from './commit';
|
export * from './commit';
|
||||||
export * from './diff';
|
export * from './diff';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { GitStashCommit } from './stashCommit';
|
import { GitStashCommit } from './stashCommit';
|
||||||
|
|
||||||
export interface IGitStash {
|
export interface GitStash {
|
||||||
repoPath: string;
|
repoPath: string;
|
||||||
commits: Map<string, GitStashCommit>;
|
commits: Map<string, GitStashCommit>;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { IGitCommitLine } from './commit';
|
|
||||||
import { GitLogCommit } from './logCommit';
|
import { GitLogCommit } from './logCommit';
|
||||||
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
import { GitStatusFileStatus, IGitStatusFile } from './status';
|
||||||
|
|
||||||
@@ -14,12 +13,11 @@ export class GitStashCommit extends GitLogCommit {
|
|||||||
message: string,
|
message: string,
|
||||||
status?: GitStatusFileStatus,
|
status?: GitStatusFileStatus,
|
||||||
fileStatuses?: IGitStatusFile[],
|
fileStatuses?: IGitStatusFile[],
|
||||||
lines?: IGitCommitLine[],
|
|
||||||
originalFileName?: string,
|
originalFileName?: string,
|
||||||
previousSha?: string,
|
previousSha?: string,
|
||||||
previousFileName?: string
|
previousFileName?: string
|
||||||
) {
|
) {
|
||||||
super('stash', repoPath, sha, fileName, 'You', date, message, status, fileStatuses, lines, originalFileName, previousSha, previousFileName);
|
super('stash', repoPath, sha, fileName, 'You', date, message, status, fileStatuses, originalFileName, previousSha, previousFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
get shortSha() {
|
get shortSha() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { Uri } from 'vscode';
|
import { Uri } from 'vscode';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export interface IGitStatus {
|
export interface GitStatus {
|
||||||
|
|
||||||
branch: string;
|
branch: string;
|
||||||
repoPath: string;
|
repoPath: string;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Git, GitCommit, IGitAuthor, IGitBlame, IGitCommitLine } from './../git';
|
import { Strings } from '../../system';
|
||||||
|
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitCommitLine } from './../git';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
interface IBlameEntry {
|
interface BlameEntry {
|
||||||
sha: string;
|
sha: string;
|
||||||
|
|
||||||
line: number;
|
line: number;
|
||||||
@@ -11,15 +12,9 @@ interface IBlameEntry {
|
|||||||
lineCount: number;
|
lineCount: number;
|
||||||
|
|
||||||
author: string;
|
author: string;
|
||||||
// authorEmail?: string;
|
|
||||||
authorDate?: string;
|
authorDate?: string;
|
||||||
authorTimeZone?: string;
|
authorTimeZone?: string;
|
||||||
|
|
||||||
// committer?: string;
|
|
||||||
// committerEmail?: string;
|
|
||||||
// committerDate?: string;
|
|
||||||
// committerTimeZone?: string;
|
|
||||||
|
|
||||||
previousSha?: string;
|
previousSha?: string;
|
||||||
previousFileName?: string;
|
previousFileName?: string;
|
||||||
|
|
||||||
@@ -30,21 +25,26 @@ interface IBlameEntry {
|
|||||||
|
|
||||||
export class GitBlameParser {
|
export class GitBlameParser {
|
||||||
|
|
||||||
private static _parseEntries(data: string): IBlameEntry[] | undefined {
|
static parse(data: string, repoPath: string | undefined, fileName: string): GitBlame | undefined {
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
|
|
||||||
const lines = data.split('\n');
|
const authors: Map<string, GitAuthor> = new Map();
|
||||||
if (!lines.length) return undefined;
|
const commits: Map<string, GitBlameCommit> = new Map();
|
||||||
|
const lines: GitCommitLine[] = [];
|
||||||
|
|
||||||
const entries: IBlameEntry[] = [];
|
let relativeFileName = repoPath && fileName;
|
||||||
|
|
||||||
let entry: IBlameEntry | undefined = undefined;
|
let entry: BlameEntry | undefined = undefined;
|
||||||
let position = -1;
|
let line: string;
|
||||||
while (++position < lines.length) {
|
let lineParts: string[];
|
||||||
const lineParts = lines[position].split(' ');
|
|
||||||
if (lineParts.length < 2) {
|
let i = -1;
|
||||||
continue;
|
let first = true;
|
||||||
}
|
|
||||||
|
for (line of Strings.lines(data)) {
|
||||||
|
i++;
|
||||||
|
lineParts = line.split(' ');
|
||||||
|
if (lineParts.length < 2) continue;
|
||||||
|
|
||||||
if (entry === undefined) {
|
if (entry === undefined) {
|
||||||
entry = {
|
entry = {
|
||||||
@@ -52,7 +52,7 @@ export class GitBlameParser {
|
|||||||
originalLine: parseInt(lineParts[1], 10) - 1,
|
originalLine: parseInt(lineParts[1], 10) - 1,
|
||||||
line: parseInt(lineParts[2], 10) - 1,
|
line: parseInt(lineParts[2], 10) - 1,
|
||||||
lineCount: parseInt(lineParts[3], 10)
|
lineCount: parseInt(lineParts[3], 10)
|
||||||
} as IBlameEntry;
|
} as BlameEntry;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -64,10 +64,6 @@ export class GitBlameParser {
|
|||||||
: lineParts.slice(1).join(' ').trim();
|
: lineParts.slice(1).join(' ').trim();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case 'author-mail':
|
|
||||||
// entry.authorEmail = lineParts[1].trim();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
case 'author-time':
|
case 'author-time':
|
||||||
entry.authorDate = lineParts[1];
|
entry.authorDate = lineParts[1];
|
||||||
break;
|
break;
|
||||||
@@ -76,22 +72,6 @@ export class GitBlameParser {
|
|||||||
entry.authorTimeZone = lineParts[1];
|
entry.authorTimeZone = lineParts[1];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case 'committer':
|
|
||||||
// entry.committer = lineParts.slice(1).join(' ').trim();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case 'committer-mail':
|
|
||||||
// entry.committerEmail = lineParts[1].trim();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case 'committer-time':
|
|
||||||
// entry.committerDate = lineParts[1];
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case 'committer-tz':
|
|
||||||
// entry.committerTimeZone = lineParts[1];
|
|
||||||
// break;
|
|
||||||
|
|
||||||
case 'summary':
|
case 'summary':
|
||||||
entry.summary = lineParts.slice(1).join(' ').trim();
|
entry.summary = lineParts.slice(1).join(' ').trim();
|
||||||
break;
|
break;
|
||||||
@@ -104,7 +84,15 @@ export class GitBlameParser {
|
|||||||
case 'filename':
|
case 'filename':
|
||||||
entry.fileName = lineParts.slice(1).join(' ');
|
entry.fileName = lineParts.slice(1).join(' ');
|
||||||
|
|
||||||
entries.push(entry);
|
if (first && repoPath === undefined) {
|
||||||
|
// Try to get the repoPath from the most recent commit
|
||||||
|
repoPath = Git.normalizePath(fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName!, ''));
|
||||||
|
relativeFileName = Git.normalizePath(path.relative(repoPath, fileName));
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
GitBlameParser._parseEntry(entry, repoPath, relativeFileName, commits, authors, lines);
|
||||||
|
|
||||||
entry = undefined;
|
entry = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -113,71 +101,6 @@ export class GitBlameParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
static parse(data: string, repoPath: string | undefined, fileName: string): IGitBlame | undefined {
|
|
||||||
const entries = this._parseEntries(data);
|
|
||||||
if (!entries) return undefined;
|
|
||||||
|
|
||||||
const authors: Map<string, IGitAuthor> = new Map();
|
|
||||||
const commits: Map<string, GitCommit> = new Map();
|
|
||||||
const lines: IGitCommitLine[] = [];
|
|
||||||
|
|
||||||
let relativeFileName = repoPath && fileName;
|
|
||||||
|
|
||||||
for (let i = 0, len = entries.length; i < len; i++) {
|
|
||||||
const entry = entries[i];
|
|
||||||
|
|
||||||
if (i === 0 && repoPath === undefined) {
|
|
||||||
// Try to get the repoPath from the most recent commit
|
|
||||||
repoPath = Git.normalizePath(fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName!, ''));
|
|
||||||
relativeFileName = Git.normalizePath(path.relative(repoPath, fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
let commit = commits.get(entry.sha);
|
|
||||||
if (commit === undefined) {
|
|
||||||
if (entry.author !== undefined) {
|
|
||||||
let author = authors.get(entry.author);
|
|
||||||
if (author === undefined) {
|
|
||||||
author = {
|
|
||||||
name: entry.author,
|
|
||||||
lineCount: 0
|
|
||||||
};
|
|
||||||
authors.set(entry.author, author);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commit = new GitCommit('blame', repoPath!, entry.sha, relativeFileName!, entry.author, moment(`${entry.authorDate} ${entry.authorTimeZone}`, 'X +-HHmm').toDate(), entry.summary!);
|
|
||||||
|
|
||||||
if (relativeFileName !== entry.fileName) {
|
|
||||||
commit.originalFileName = entry.fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.previousSha) {
|
|
||||||
commit.previousSha = entry.previousSha;
|
|
||||||
commit.previousFileName = entry.previousFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
commits.set(entry.sha, commit);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = 0, len = entry.lineCount; j < len; j++) {
|
|
||||||
const line: IGitCommitLine = {
|
|
||||||
sha: entry.sha,
|
|
||||||
line: entry.line + j,
|
|
||||||
originalLine: entry.originalLine + j
|
|
||||||
};
|
|
||||||
|
|
||||||
if (commit.previousSha) {
|
|
||||||
line.previousSha = commit.previousSha;
|
|
||||||
}
|
|
||||||
|
|
||||||
commit.lines.push(line);
|
|
||||||
lines[line.line] = line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commits.forEach(c => {
|
commits.forEach(c => {
|
||||||
if (c.author === undefined) return;
|
if (c.author === undefined) return;
|
||||||
|
|
||||||
@@ -187,23 +110,57 @@ export class GitBlameParser {
|
|||||||
author.lineCount += c.lines.length;
|
author.lineCount += c.lines.length;
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedAuthors: Map<string, IGitAuthor> = new Map();
|
const sortedAuthors = new Map([...authors.entries()].sort((a, b) => b[1].lineCount - a[1].lineCount));
|
||||||
// const values =
|
|
||||||
Array.from(authors.values())
|
|
||||||
.sort((a, b) => b.lineCount - a.lineCount)
|
|
||||||
.forEach(a => sortedAuthors.set(a.name, a));
|
|
||||||
|
|
||||||
// const sortedCommits: Map<string, IGitCommit> = new Map();
|
|
||||||
// Array.from(commits.values())
|
|
||||||
// .sort((a, b) => b.date.getTime() - a.date.getTime())
|
|
||||||
// .forEach(c => sortedCommits.set(c.sha, c));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
repoPath: repoPath,
|
repoPath: repoPath,
|
||||||
authors: sortedAuthors,
|
authors: sortedAuthors,
|
||||||
// commits: sortedCommits,
|
|
||||||
commits: commits,
|
commits: commits,
|
||||||
lines: lines
|
lines: lines
|
||||||
} as IGitBlame;
|
} as GitBlame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _parseEntry(entry: BlameEntry, repoPath: string | undefined, fileName: string | undefined, commits: Map<string, GitBlameCommit>, authors: Map<string, GitAuthor>, lines: GitCommitLine[]) {
|
||||||
|
let commit = commits.get(entry.sha);
|
||||||
|
if (commit === undefined) {
|
||||||
|
if (entry.author !== undefined) {
|
||||||
|
let author = authors.get(entry.author);
|
||||||
|
if (author === undefined) {
|
||||||
|
author = {
|
||||||
|
name: entry.author,
|
||||||
|
lineCount: 0
|
||||||
|
};
|
||||||
|
authors.set(entry.author, author);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commit = new GitBlameCommit(repoPath!, entry.sha, fileName!, entry.author, moment(`${entry.authorDate} ${entry.authorTimeZone}`, 'X +-HHmm').toDate(), entry.summary!, []);
|
||||||
|
|
||||||
|
if (fileName !== entry.fileName) {
|
||||||
|
commit.originalFileName = entry.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.previousSha) {
|
||||||
|
commit.previousSha = entry.previousSha;
|
||||||
|
commit.previousFileName = entry.previousFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
commits.set(entry.sha, commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0, len = entry.lineCount; i < len; i++) {
|
||||||
|
const line: GitCommitLine = {
|
||||||
|
sha: entry.sha,
|
||||||
|
line: entry.line + i,
|
||||||
|
originalLine: entry.originalLine + i
|
||||||
|
};
|
||||||
|
|
||||||
|
if (commit.previousSha) {
|
||||||
|
line.previousSha = commit.previousSha;
|
||||||
|
}
|
||||||
|
|
||||||
|
commit.lines.push(line);
|
||||||
|
lines[line.line] = line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,62 +1,33 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { IGitDiff, IGitDiffChunk, IGitDiffLine } from './../git';
|
import { Iterables, Strings } from '../../system';
|
||||||
|
import { GitDiff, GitDiffChunk, GitDiffLine } from './../git';
|
||||||
|
|
||||||
const unifiedDiffRegex = /^@@ -([\d]+),([\d]+) [+]([\d]+),([\d]+) @@([\s\S]*?)(?=^@@)/gm;
|
const unifiedDiffRegex = /^@@ -([\d]+),([\d]+) [+]([\d]+),([\d]+) @@([\s\S]*?)(?=^@@)/gm;
|
||||||
|
|
||||||
export class GitDiffParser {
|
export class GitDiffParser {
|
||||||
|
|
||||||
static parse(data: string, debug: boolean = false): IGitDiff | undefined {
|
static parse(data: string, debug: boolean = false): GitDiff | undefined {
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
|
|
||||||
const chunks: IGitDiffChunk[] = [];
|
const chunks: GitDiffChunk[] = [];
|
||||||
|
|
||||||
let match: RegExpExecArray | null = null;
|
let match: RegExpExecArray | null = null;
|
||||||
|
|
||||||
|
let chunk: string;
|
||||||
|
let currentStart: number;
|
||||||
|
let previousStart: number;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
match = unifiedDiffRegex.exec(`${data}\n@@`);
|
match = unifiedDiffRegex.exec(`${data}\n@@`);
|
||||||
if (match == null) break;
|
if (match == null) break;
|
||||||
|
|
||||||
const previousStart = +match[1];
|
// Stops excessive memory usage
|
||||||
const currentStart = +match[3];
|
// https://bugs.chromium.org/p/v8/issues/detail?id=2869
|
||||||
|
chunk = (' ' + match[5]).substr(1);
|
||||||
|
currentStart = parseInt(match[3], 10);
|
||||||
|
previousStart = parseInt(match[1], 10);
|
||||||
|
|
||||||
const chunk = match[5];
|
chunks.push(new GitDiffChunk(chunk, { start: currentStart, end: currentStart + parseInt(match[4], 10) }, { start: previousStart, end: previousStart + parseInt(match[2], 10) }));
|
||||||
const lines = chunk.split('\n').slice(1);
|
|
||||||
|
|
||||||
const current: (IGitDiffLine | undefined)[] = [];
|
|
||||||
const previous: (IGitDiffLine | undefined)[] = [];
|
|
||||||
for (const l of lines) {
|
|
||||||
switch (l[0]) {
|
|
||||||
case '+':
|
|
||||||
current.push({
|
|
||||||
line: ` ${l.substring(1)}`,
|
|
||||||
state: 'added'
|
|
||||||
});
|
|
||||||
previous.push(undefined);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '-':
|
|
||||||
current.push(undefined);
|
|
||||||
previous.push({
|
|
||||||
line: ` ${l.substring(1)}`,
|
|
||||||
state: 'removed'
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
current.push({ line: l, state: 'unchanged' });
|
|
||||||
previous.push({ line: l, state: 'unchanged' });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
chunks.push({
|
|
||||||
chunk: debug ? chunk : undefined,
|
|
||||||
current: current,
|
|
||||||
currentStart: currentStart,
|
|
||||||
currentEnd: currentStart + +match[4],
|
|
||||||
previous: previous,
|
|
||||||
previousStart: previousStart,
|
|
||||||
previousEnd: previousStart + +match[2]
|
|
||||||
});
|
|
||||||
} while (match != null);
|
} while (match != null);
|
||||||
|
|
||||||
if (!chunks.length) return undefined;
|
if (!chunks.length) return undefined;
|
||||||
@@ -64,7 +35,40 @@ export class GitDiffParser {
|
|||||||
const diff = {
|
const diff = {
|
||||||
diff: debug ? data : undefined,
|
diff: debug ? data : undefined,
|
||||||
chunks: chunks
|
chunks: chunks
|
||||||
} as IGitDiff;
|
} as GitDiff;
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static parseChunk(chunk: string): [(GitDiffLine | undefined)[], (GitDiffLine | undefined)[]] {
|
||||||
|
const lines = Iterables.skip(Strings.lines(chunk), 1);
|
||||||
|
|
||||||
|
const current: (GitDiffLine | undefined)[] = [];
|
||||||
|
const previous: (GitDiffLine | undefined)[] = [];
|
||||||
|
for (const l of lines) {
|
||||||
|
switch (l[0]) {
|
||||||
|
case '+':
|
||||||
|
current.push({
|
||||||
|
line: ` ${l.substring(1)}`,
|
||||||
|
state: 'added'
|
||||||
|
});
|
||||||
|
previous.push(undefined);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
current.push(undefined);
|
||||||
|
previous.push({
|
||||||
|
line: ` ${l.substring(1)}`,
|
||||||
|
state: 'removed'
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
current.push({ line: l, state: 'unchanged' });
|
||||||
|
previous.push({ line: l, state: 'unchanged' });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [current, previous];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
import { Strings } from '../../system';
|
||||||
import { Range } from 'vscode';
|
import { Range } from 'vscode';
|
||||||
import { Git, GitCommitType, GitLogCommit, GitStatusFileStatus, IGitAuthor, IGitLog, IGitStatusFile } from './../git';
|
import { Git, GitAuthor, GitCommitType, GitLog, GitLogCommit, GitStatusFileStatus, IGitStatusFile } from './../git';
|
||||||
// import { Logger } from '../../logger';
|
// import { Logger } from '../../logger';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
interface ILogEntry {
|
interface LogEntry {
|
||||||
sha: string;
|
sha: string;
|
||||||
|
|
||||||
author: string;
|
author: string;
|
||||||
authorDate?: string;
|
authorDate?: string;
|
||||||
|
|
||||||
// committer?: string;
|
|
||||||
// committerDate?: string;
|
|
||||||
|
|
||||||
parentShas?: string[];
|
parentShas?: string[];
|
||||||
|
|
||||||
fileName?: string;
|
fileName?: string;
|
||||||
@@ -29,31 +27,54 @@ const diffRegex = /diff --git a\/(.*) b\/(.*)/;
|
|||||||
|
|
||||||
export class GitLogParser {
|
export class GitLogParser {
|
||||||
|
|
||||||
private static _parseEntries(data: string, type: GitCommitType, maxCount: number | undefined, reverse: boolean): ILogEntry[] | undefined {
|
static parse(data: string, type: GitCommitType, repoPath: string | undefined, fileName: string | undefined, sha: string | undefined, maxCount: number | undefined, reverse: boolean, range: Range | undefined): GitLog | undefined {
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
|
|
||||||
const lines = data.split('\n');
|
const authors: Map<string, GitAuthor> = new Map();
|
||||||
if (!lines.length) return undefined;
|
const commits: Map<string, GitLogCommit> = new Map();
|
||||||
|
|
||||||
const entries: ILogEntry[] = [];
|
let relativeFileName: string;
|
||||||
|
let recentCommit: GitLogCommit | undefined = undefined;
|
||||||
|
|
||||||
let entry: ILogEntry | undefined = undefined;
|
if (repoPath !== undefined) {
|
||||||
let position = -1;
|
repoPath = Git.normalizePath(repoPath);
|
||||||
while (++position < lines.length) {
|
}
|
||||||
// Since log --reverse doesn't properly honor a max count -- enforce it here
|
|
||||||
if (reverse && maxCount && (entries.length >= maxCount)) break;
|
|
||||||
|
|
||||||
let lineParts = lines[position].split(' ');
|
let entry: LogEntry | undefined = undefined;
|
||||||
if (lineParts.length < 2) {
|
let line: string | undefined = undefined;
|
||||||
continue;
|
let lineParts: string[];
|
||||||
|
let next: IteratorResult<string> | undefined = undefined;
|
||||||
|
|
||||||
|
let i = -1;
|
||||||
|
let first = true;
|
||||||
|
let skip = false;
|
||||||
|
|
||||||
|
const lines = Strings.lines(data);
|
||||||
|
// for (line of lines) {
|
||||||
|
while (true) {
|
||||||
|
if (!skip) {
|
||||||
|
next = lines.next();
|
||||||
|
if (next.done) break;
|
||||||
|
|
||||||
|
line = next.value;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
skip = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since log --reverse doesn't properly honor a max count -- enforce it here
|
||||||
|
if (reverse && maxCount && (i >= maxCount)) break;
|
||||||
|
|
||||||
|
lineParts = line!.split(' ');
|
||||||
|
if (lineParts.length < 2) continue;
|
||||||
|
|
||||||
if (entry === undefined) {
|
if (entry === undefined) {
|
||||||
if (!Git.shaRegex.test(lineParts[0])) continue;
|
if (!Git.shaRegex.test(lineParts[0])) continue;
|
||||||
|
|
||||||
entry = {
|
entry = {
|
||||||
sha: lineParts[0]
|
sha: lineParts[0]
|
||||||
} as ILogEntry;
|
} as LogEntry;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -69,47 +90,54 @@ export class GitLogParser {
|
|||||||
entry.authorDate = `${lineParts[1]}T${lineParts[2]}${lineParts[3]}`;
|
entry.authorDate = `${lineParts[1]}T${lineParts[2]}${lineParts[3]}`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case 'committer':
|
|
||||||
// entry.committer = lineParts.slice(1).join(' ').trim();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// case 'committer-date':
|
|
||||||
// entry.committerDate = lineParts.slice(1).join(' ').trim();
|
|
||||||
// break;
|
|
||||||
|
|
||||||
case 'parents':
|
case 'parents':
|
||||||
entry.parentShas = lineParts.slice(1);
|
entry.parentShas = lineParts.slice(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'summary':
|
case 'summary':
|
||||||
entry.summary = lineParts.slice(1).join(' ').trim();
|
entry.summary = lineParts.slice(1).join(' ').trim();
|
||||||
while (++position < lines.length) {
|
while (true) {
|
||||||
const next = lines[position];
|
next = lines.next();
|
||||||
if (!next) break;
|
if (next.done) break;
|
||||||
if (next === 'filename ?') {
|
|
||||||
position--;
|
i++;
|
||||||
|
line = next.value;
|
||||||
|
if (!line) break;
|
||||||
|
|
||||||
|
if (line === 'filename ?') {
|
||||||
|
skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.summary += `\n${lines[position]}`;
|
entry.summary += `\n${line}`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'filename':
|
case 'filename':
|
||||||
if (type === 'branch') {
|
if (type === 'branch') {
|
||||||
const nextLine = lines[position + 1];
|
next = lines.next();
|
||||||
// If the next line isn't blank, make sure it isn't starting a new commit
|
if (next.done) break;
|
||||||
if (nextLine && Git.shaRegex.test(nextLine)) continue;
|
|
||||||
|
|
||||||
position++;
|
i++;
|
||||||
|
line = next.value;
|
||||||
|
|
||||||
|
// If the next line isn't blank, make sure it isn't starting a new commit
|
||||||
|
if (line && Git.shaRegex.test(line)) {
|
||||||
|
skip = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let diff = false;
|
let diff = false;
|
||||||
while (++position < lines.length) {
|
while (true) {
|
||||||
const line = lines[position];
|
next = lines.next();
|
||||||
|
if (next.done) break;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
line = next.value;
|
||||||
lineParts = line.split(' ');
|
lineParts = line.split(' ');
|
||||||
|
|
||||||
if (Git.shaRegex.test(lineParts[0])) {
|
if (Git.shaRegex.test(lineParts[0])) {
|
||||||
position--;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,125 +175,88 @@ export class GitLogParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
position += 2;
|
next = lines.next();
|
||||||
const line = lines[position];
|
next = lines.next();
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
line = next.value;
|
||||||
|
|
||||||
entry.status = line[0] as GitStatusFileStatus;
|
entry.status = line[0] as GitStatusFileStatus;
|
||||||
entry.fileName = line.substring(1);
|
entry.fileName = line.substring(1);
|
||||||
this._parseFileName(entry);
|
this._parseFileName(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.push(entry);
|
if (first && repoPath === undefined && type === 'file' && fileName !== undefined) {
|
||||||
|
// Try to get the repoPath from the most recent commit
|
||||||
|
repoPath = Git.normalizePath(fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName!, ''));
|
||||||
|
relativeFileName = Git.normalizePath(path.relative(repoPath, fileName));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
relativeFileName = entry.fileName!;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
recentCommit = GitLogParser._parseEntry(entry, type, repoPath, relativeFileName, commits, authors, recentCommit);
|
||||||
|
|
||||||
entry = undefined;
|
entry = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (next!.done) break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
static parse(data: string, type: GitCommitType, repoPath: string | undefined, fileName: string | undefined, sha: string | undefined, maxCount: number | undefined, reverse: boolean, range: Range | undefined): IGitLog | undefined {
|
|
||||||
const entries = this._parseEntries(data, type, maxCount, reverse);
|
|
||||||
if (!entries) return undefined;
|
|
||||||
|
|
||||||
const authors: Map<string, IGitAuthor> = new Map();
|
|
||||||
const commits: Map<string, GitLogCommit> = new Map();
|
|
||||||
|
|
||||||
let relativeFileName: string;
|
|
||||||
let recentCommit: GitLogCommit | undefined = undefined;
|
|
||||||
|
|
||||||
if (repoPath !== undefined) {
|
|
||||||
repoPath = Git.normalizePath(repoPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0, len = entries.length; i < len; i++) {
|
|
||||||
// Since log --reverse doesn't properly honor a max count -- enforce it here
|
|
||||||
if (reverse && maxCount && (i >= maxCount)) break;
|
|
||||||
|
|
||||||
const entry = entries[i];
|
|
||||||
|
|
||||||
if (i === 0 && repoPath === undefined && type === 'file' && fileName !== undefined) {
|
|
||||||
// Try to get the repoPath from the most recent commit
|
|
||||||
repoPath = Git.normalizePath(fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName!, ''));
|
|
||||||
relativeFileName = Git.normalizePath(path.relative(repoPath, fileName));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
relativeFileName = entry.fileName!;
|
|
||||||
}
|
|
||||||
|
|
||||||
let commit = commits.get(entry.sha);
|
|
||||||
if (commit === undefined) {
|
|
||||||
if (entry.author !== undefined) {
|
|
||||||
let author = authors.get(entry.author);
|
|
||||||
if (author === undefined) {
|
|
||||||
author = {
|
|
||||||
name: entry.author,
|
|
||||||
lineCount: 0
|
|
||||||
};
|
|
||||||
authors.set(entry.author, author);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commit = new GitLogCommit(type, repoPath!, entry.sha, relativeFileName, entry.author, moment(entry.authorDate).toDate(), entry.summary!, entry.status, entry.fileStatuses, undefined, entry.originalFileName);
|
|
||||||
commit.parentShas = entry.parentShas!;
|
|
||||||
|
|
||||||
if (relativeFileName !== entry.fileName) {
|
|
||||||
commit.originalFileName = entry.fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
commits.set(entry.sha, commit);
|
|
||||||
}
|
|
||||||
// else {
|
|
||||||
// Logger.log(`merge commit? ${entry.sha}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (recentCommit !== undefined) {
|
|
||||||
recentCommit.previousSha = commit.sha;
|
|
||||||
|
|
||||||
// If the commit sha's match (merge commit), just forward it along
|
|
||||||
commit.nextSha = commit.sha !== recentCommit.sha ? recentCommit.sha : recentCommit.nextSha;
|
|
||||||
|
|
||||||
// Only add a filename if this is a file log
|
|
||||||
if (type === 'file') {
|
|
||||||
recentCommit.previousFileName = commit.originalFileName || commit.fileName;
|
|
||||||
commit.nextFileName = recentCommit.originalFileName || recentCommit.fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recentCommit = commit;
|
|
||||||
}
|
|
||||||
|
|
||||||
commits.forEach(c => {
|
|
||||||
if (c.author === undefined) return;
|
|
||||||
|
|
||||||
const author = authors.get(c.author);
|
|
||||||
if (author === undefined) return;
|
|
||||||
|
|
||||||
author.lineCount += c.lines.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortedAuthors: Map<string, IGitAuthor> = new Map();
|
|
||||||
// const values =
|
|
||||||
Array.from(authors.values())
|
|
||||||
.sort((a, b) => b.lineCount - a.lineCount)
|
|
||||||
.forEach(a => sortedAuthors.set(a.name, a));
|
|
||||||
|
|
||||||
// const sortedCommits: Map<string, IGitCommit> = new Map();
|
|
||||||
// Array.from(commits.values())
|
|
||||||
// .sort((a, b) => b.date.getTime() - a.date.getTime())
|
|
||||||
// .forEach(c => sortedCommits.set(c.sha, c));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
repoPath: repoPath,
|
repoPath: repoPath,
|
||||||
authors: sortedAuthors,
|
authors: authors,
|
||||||
// commits: sortedCommits,
|
|
||||||
commits: commits,
|
commits: commits,
|
||||||
sha: sha,
|
sha: sha,
|
||||||
maxCount: maxCount,
|
maxCount: maxCount,
|
||||||
range: range,
|
range: range,
|
||||||
truncated: !!(maxCount && entries.length >= maxCount)
|
truncated: !!(maxCount && i >= maxCount)
|
||||||
} as IGitLog;
|
} as GitLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _parseEntry(entry: LogEntry, type: GitCommitType, repoPath: string | undefined, relativeFileName: string, commits: Map<string, GitLogCommit>, authors: Map<string, GitAuthor>, recentCommit: GitLogCommit | undefined): GitLogCommit | undefined {
|
||||||
|
let commit = commits.get(entry.sha);
|
||||||
|
if (commit === undefined) {
|
||||||
|
if (entry.author !== undefined) {
|
||||||
|
let author = authors.get(entry.author);
|
||||||
|
if (author === undefined) {
|
||||||
|
author = {
|
||||||
|
name: entry.author,
|
||||||
|
lineCount: 0
|
||||||
|
};
|
||||||
|
authors.set(entry.author, author);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commit = new GitLogCommit(type, repoPath!, entry.sha, relativeFileName, entry.author, moment(entry.authorDate).toDate(), entry.summary!, entry.status, entry.fileStatuses, undefined, entry.originalFileName);
|
||||||
|
commit.parentShas = entry.parentShas!;
|
||||||
|
|
||||||
|
if (relativeFileName !== entry.fileName) {
|
||||||
|
commit.originalFileName = entry.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
commits.set(entry.sha, commit);
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// Logger.log(`merge commit? ${entry.sha}`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (recentCommit !== undefined) {
|
||||||
|
recentCommit.previousSha = commit.sha;
|
||||||
|
|
||||||
|
// If the commit sha's match (merge commit), just forward it along
|
||||||
|
commit.nextSha = commit.sha !== recentCommit.sha ? recentCommit.sha : recentCommit.nextSha;
|
||||||
|
|
||||||
|
// Only add a filename if this is a file log
|
||||||
|
if (type === 'file') {
|
||||||
|
recentCommit.previousFileName = commit.originalFileName || commit.fileName;
|
||||||
|
commit.nextFileName = recentCommit.originalFileName || recentCommit.fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _parseFileName(entry: { fileName?: string, originalFileName?: string }) {
|
private static _parseFileName(entry: { fileName?: string, originalFileName?: string }) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Git, GitStashCommit, GitStatusFileStatus, IGitStash, IGitStatusFile } from './../git';
|
import { Git, GitStash, GitStashCommit, GitStatusFileStatus, IGitStatusFile } from './../git';
|
||||||
// import { Logger } from '../../logger';
|
// import { Logger } from '../../logger';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
interface IStashEntry {
|
interface StashEntry {
|
||||||
sha: string;
|
sha: string;
|
||||||
date?: string;
|
date?: string;
|
||||||
fileNames: string;
|
fileNames: string;
|
||||||
@@ -14,15 +14,15 @@ interface IStashEntry {
|
|||||||
|
|
||||||
export class GitStashParser {
|
export class GitStashParser {
|
||||||
|
|
||||||
private static _parseEntries(data: string): IStashEntry[] | undefined {
|
private static _parseEntries(data: string): StashEntry[] | undefined {
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
|
|
||||||
const lines = data.split('\n');
|
const lines = data.split('\n');
|
||||||
if (!lines.length) return undefined;
|
if (!lines.length) return undefined;
|
||||||
|
|
||||||
const entries: IStashEntry[] = [];
|
const entries: StashEntry[] = [];
|
||||||
|
|
||||||
let entry: IStashEntry | undefined = undefined;
|
let entry: StashEntry | undefined = undefined;
|
||||||
let position = -1;
|
let position = -1;
|
||||||
while (++position < lines.length) {
|
while (++position < lines.length) {
|
||||||
let lineParts = lines[position].split(' ');
|
let lineParts = lines[position].split(' ');
|
||||||
@@ -35,7 +35,7 @@ export class GitStashParser {
|
|||||||
|
|
||||||
entry = {
|
entry = {
|
||||||
sha: lineParts[0]
|
sha: lineParts[0]
|
||||||
} as IStashEntry;
|
} as StashEntry;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ export class GitStashParser {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
static parse(data: string, repoPath: string): IGitStash | undefined {
|
static parse(data: string, repoPath: string): GitStash | undefined {
|
||||||
const entries = this._parseEntries(data);
|
const entries = this._parseEntries(data);
|
||||||
if (entries === undefined) return undefined;
|
if (entries === undefined) return undefined;
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ export class GitStashParser {
|
|||||||
return {
|
return {
|
||||||
repoPath: repoPath,
|
repoPath: repoPath,
|
||||||
commits: commits
|
commits: commits
|
||||||
} as IGitStash;
|
} as GitStash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _parseFileName(entry: { fileName?: string, originalFileName?: string }) {
|
private static _parseFileName(entry: { fileName?: string, originalFileName?: string }) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Git, GitStatusFile, GitStatusFileStatus, IGitStatus } from './../git';
|
import { Git, GitStatus, GitStatusFile, GitStatusFileStatus } from './../git';
|
||||||
|
|
||||||
interface IFileStatusEntry {
|
interface FileStatusEntry {
|
||||||
staged: boolean;
|
staged: boolean;
|
||||||
status: GitStatusFileStatus;
|
status: GitStatusFileStatus;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@@ -13,7 +13,7 @@ const behindStatusV1Regex = /(?:behind ([0-9]+))/;
|
|||||||
|
|
||||||
export class GitStatusParser {
|
export class GitStatusParser {
|
||||||
|
|
||||||
static parse(data: string, repoPath: string, porcelainVersion: number): IGitStatus | undefined {
|
static parse(data: string, repoPath: string, porcelainVersion: number): GitStatus | undefined {
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
|
|
||||||
const lines = data.split('\n').filter(_ => !!_);
|
const lines = data.split('\n').filter(_ => !!_);
|
||||||
@@ -40,7 +40,7 @@ export class GitStatusParser {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _parseV1(lines: string[], repoPath: string, status: IGitStatus) {
|
private static _parseV1(lines: string[], repoPath: string, status: GitStatus) {
|
||||||
let position = -1;
|
let position = -1;
|
||||||
while (++position < lines.length) {
|
while (++position < lines.length) {
|
||||||
const line = lines[position];
|
const line = lines[position];
|
||||||
@@ -59,7 +59,7 @@ export class GitStatusParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let entry: IFileStatusEntry;
|
let entry: FileStatusEntry;
|
||||||
const rawStatus = line.substring(0, 2);
|
const rawStatus = line.substring(0, 2);
|
||||||
const fileName = line.substring(3);
|
const fileName = line.substring(3);
|
||||||
if (rawStatus[0] === 'R') {
|
if (rawStatus[0] === 'R') {
|
||||||
@@ -74,7 +74,7 @@ export class GitStatusParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _parseV2(lines: string[], repoPath: string, status: IGitStatus) {
|
private static _parseV2(lines: string[], repoPath: string, status: GitStatus) {
|
||||||
let position = -1;
|
let position = -1;
|
||||||
while (++position < lines.length) {
|
while (++position < lines.length) {
|
||||||
const line = lines[position];
|
const line = lines[position];
|
||||||
@@ -99,7 +99,7 @@ export class GitStatusParser {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const lineParts = line.split(' ');
|
const lineParts = line.split(' ');
|
||||||
let entry: IFileStatusEntry | undefined = undefined;
|
let entry: FileStatusEntry | undefined = undefined;
|
||||||
switch (lineParts[0][0]) {
|
switch (lineParts[0][0]) {
|
||||||
case '1': // normal
|
case '1': // normal
|
||||||
entry = this._parseFileEntry(lineParts[1], lineParts.slice(8).join(' '));
|
entry = this._parseFileEntry(lineParts[1], lineParts.slice(8).join(' '));
|
||||||
@@ -123,7 +123,7 @@ export class GitStatusParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _parseFileEntry(rawStatus: string, fileName: string, originalFileName?: string): IFileStatusEntry {
|
private static _parseFileEntry(rawStatus: string, fileName: string, originalFileName?: string): FileStatusEntry {
|
||||||
const indexStatus = rawStatus[0] !== '.' ? rawStatus[0].trim() : undefined;
|
const indexStatus = rawStatus[0] !== '.' ? rawStatus[0].trim() : undefined;
|
||||||
const workTreeStatus = rawStatus[1] !== '.' ? rawStatus[1].trim() : undefined;
|
const workTreeStatus = rawStatus[1] !== '.' ? rawStatus[1].trim() : undefined;
|
||||||
|
|
||||||
@@ -132,6 +132,6 @@ export class GitStatusParser {
|
|||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
originalFileName: originalFileName,
|
originalFileName: originalFileName,
|
||||||
staged: !!indexStatus
|
staged: !!indexStatus
|
||||||
} as IFileStatusEntry;
|
} as FileStatusEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ const providerMap = new Map<string, (domain: string, path: string) => RemoteProv
|
|||||||
['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:\/\/git@(.*?)\/)(.*)$/;
|
const UrlRegex = /^(?:git:\/\/(.*?)\/|https:\/\/(.*?)\/|http:\/\/(.*?)\/|git@(.*):|ssh:\/\/(?:.*@)?(.*?)(?::.*?)?\/)(.*)$/;
|
||||||
|
|
||||||
export class RemoteProviderFactory {
|
export class RemoteProviderFactory {
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export class RemoteProviderFactory {
|
|||||||
if (match == null) return undefined;
|
if (match == null) return undefined;
|
||||||
|
|
||||||
const domain = match[1] || match[2] || match[3] || match[4] || match[5];
|
const domain = match[1] || match[2] || match[3] || match[4] || match[5];
|
||||||
const path = match[6].replace(/\.git/, '');
|
const path = match[6].replace(/\.git\/?$/, '');
|
||||||
|
|
||||||
const key = domain.toLowerCase().endsWith('visualstudio.com')
|
const key = domain.toLowerCase().endsWith('visualstudio.com')
|
||||||
? 'visualstudio.com'
|
? 'visualstudio.com'
|
||||||
|
|||||||
@@ -4,28 +4,28 @@ import { CancellationToken, CodeLens, CodeLensProvider, Command, commands, Docum
|
|||||||
import { Commands, DiffWithPreviousCommandArgs, ShowBlameHistoryCommandArgs, ShowFileHistoryCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from './commands';
|
import { Commands, DiffWithPreviousCommandArgs, ShowBlameHistoryCommandArgs, ShowFileHistoryCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from './commands';
|
||||||
import { BuiltInCommands, DocumentSchemes, ExtensionKey } from './constants';
|
import { BuiltInCommands, DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { CodeLensCommand, CodeLensLocations, ICodeLensLanguageLocation, IConfig } from './configuration';
|
import { CodeLensCommand, CodeLensLocations, ICodeLensLanguageLocation, IConfig } from './configuration';
|
||||||
import { GitCommit, GitService, GitUri, IGitBlame, IGitBlameLines } from './gitService';
|
import { GitBlame, GitBlameCommit, GitBlameLines, GitService, GitUri } from './gitService';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
export class GitRecentChangeCodeLens extends CodeLens {
|
export class GitRecentChangeCodeLens extends CodeLens {
|
||||||
|
|
||||||
constructor(private blame: () => IGitBlameLines | undefined, public uri: GitUri, public symbolKind: SymbolKind, public blameRange: Range, public isFullRange: boolean, range: Range) {
|
constructor(private blame: () => GitBlameLines | undefined, public uri: GitUri, public symbolKind: SymbolKind, public blameRange: Range, public isFullRange: boolean, range: Range) {
|
||||||
super(range);
|
super(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBlame(): IGitBlameLines | undefined {
|
getBlame(): GitBlameLines | undefined {
|
||||||
return this.blame();
|
return this.blame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GitAuthorsCodeLens extends CodeLens {
|
export class GitAuthorsCodeLens extends CodeLens {
|
||||||
|
|
||||||
constructor(private blame: () => IGitBlameLines | undefined, public uri: GitUri, public symbolKind: SymbolKind, public blameRange: Range, public isFullRange: boolean, range: Range) {
|
constructor(private blame: () => GitBlameLines | undefined, public uri: GitUri, public symbolKind: SymbolKind, public blameRange: Range, public isFullRange: boolean, range: Range) {
|
||||||
super(range);
|
super(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBlame(): IGitBlameLines | undefined {
|
getBlame(): GitBlameLines | undefined {
|
||||||
return this.blame();
|
return this.blame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
const gitUri = await GitUri.fromUri(document.uri, this.git);
|
const gitUri = await GitUri.fromUri(document.uri, this.git);
|
||||||
|
|
||||||
const blamePromise = this.git.getBlameForFile(gitUri);
|
const blamePromise = this.git.getBlameForFile(gitUri);
|
||||||
let blame: IGitBlame | undefined;
|
let blame: GitBlame | undefined;
|
||||||
if (languageLocations.locations.length === 1 && languageLocations.locations.includes(CodeLensLocations.Document)) {
|
if (languageLocations.locations.length === 1 && languageLocations.locations.includes(CodeLensLocations.Document)) {
|
||||||
blame = await blamePromise;
|
blame = await blamePromise;
|
||||||
if (blame === undefined || !blame.lines.length) return lenses;
|
if (blame === undefined || !blame.lines.length) return lenses;
|
||||||
@@ -81,7 +81,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
commands.executeCommand(BuiltInCommands.ExecuteDocumentSymbolProvider, document.uri) as Promise<any>
|
commands.executeCommand(BuiltInCommands.ExecuteDocumentSymbolProvider, document.uri) as Promise<any>
|
||||||
]);
|
]);
|
||||||
|
|
||||||
blame = values[0] as IGitBlame;
|
blame = values[0] as GitBlame;
|
||||||
if (blame === undefined || !blame.lines.length) return lenses;
|
if (blame === undefined || !blame.lines.length) return lenses;
|
||||||
|
|
||||||
const symbols = values[1] as SymbolInformation[];
|
const symbols = values[1] as SymbolInformation[];
|
||||||
@@ -94,7 +94,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
// Check if we have a lens for the whole document -- if not add one
|
// Check if we have a lens for the whole document -- if not add one
|
||||||
if (!lenses.find(l => l.range.start.line === 0 && l.range.end.line === 0)) {
|
if (!lenses.find(l => l.range.start.line === 0 && l.range.end.line === 0)) {
|
||||||
const blameRange = document.validateRange(new Range(0, 1000000, 1000000, 1000000));
|
const blameRange = document.validateRange(new Range(0, 1000000, 1000000, 1000000));
|
||||||
let blameForRangeFn: (() => IGitBlameLines | undefined) | undefined = undefined;
|
let blameForRangeFn: (() => GitBlameLines | undefined) | undefined = undefined;
|
||||||
if (this._documentIsDirty || this._config.codeLens.recentChange.enabled) {
|
if (this._documentIsDirty || this._config.codeLens.recentChange.enabled) {
|
||||||
blameForRangeFn = Functions.once(() => this.git.getBlameForRangeSync(blame!, gitUri, blameRange));
|
blameForRangeFn = Functions.once(() => this.git.getBlameForRangeSync(blame!, gitUri, blameRange));
|
||||||
lenses.push(new GitRecentChangeCodeLens(blameForRangeFn, gitUri, SymbolKind.File, blameRange, true, new Range(0, 0, 0, blameRange.start.character)));
|
lenses.push(new GitRecentChangeCodeLens(blameForRangeFn, gitUri, SymbolKind.File, blameRange, true, new Range(0, 0, 0, blameRange.start.character)));
|
||||||
@@ -176,7 +176,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return valid ? range || symbol.location.range : undefined;
|
return valid ? range || symbol.location.range : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _provideCodeLens(gitUri: GitUri, document: TextDocument, symbol: SymbolInformation, languageLocation: ICodeLensLanguageLocation, blame: IGitBlame, lenses: CodeLens[]): void {
|
private _provideCodeLens(gitUri: GitUri, document: TextDocument, symbol: SymbolInformation, languageLocation: ICodeLensLanguageLocation, blame: GitBlame, lenses: CodeLens[]): void {
|
||||||
const blameRange = this._validateSymbolAndGetBlameRange(document, symbol, languageLocation);
|
const blameRange = this._validateSymbolAndGetBlameRange(document, symbol, languageLocation);
|
||||||
if (!blameRange) return;
|
if (!blameRange) return;
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
// Anchor the code lens to the end of the line -- so they are somewhat consistenly placed
|
// Anchor the code lens to the end of the line -- so they are somewhat consistenly placed
|
||||||
let startChar = line.range.end.character - 1;
|
let startChar = line.range.end.character - 1;
|
||||||
|
|
||||||
let blameForRangeFn: (() => IGitBlameLines | undefined) | undefined = undefined;
|
let blameForRangeFn: (() => GitBlameLines | undefined) | undefined = undefined;
|
||||||
if (this._documentIsDirty || this._config.codeLens.recentChange.enabled) {
|
if (this._documentIsDirty || this._config.codeLens.recentChange.enabled) {
|
||||||
blameForRangeFn = Functions.once(() => this.git.getBlameForRangeSync(blame, gitUri, blameRange));
|
blameForRangeFn = Functions.once(() => this.git.getBlameForRangeSync(blame, gitUri, blameRange));
|
||||||
lenses.push(new GitRecentChangeCodeLens(blameForRangeFn, gitUri, symbol.kind, blameRange, false, line.range.with(new Position(line.range.start.line, startChar))));
|
lenses.push(new GitRecentChangeCodeLens(blameForRangeFn, gitUri, symbol.kind, blameRange, false, line.range.with(new Position(line.range.start.line, startChar))));
|
||||||
@@ -295,7 +295,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyBlameAnnotateCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines): T {
|
_applyBlameAnnotateCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: Commands.ToggleFileBlame,
|
command: Commands.ToggleFileBlame,
|
||||||
@@ -304,7 +304,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyShowBlameHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyShowBlameHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
let line = lens.range.start.line;
|
let line = lens.range.start.line;
|
||||||
if (commit) {
|
if (commit) {
|
||||||
const blameLine = commit.lines.find(_ => _.line === line);
|
const blameLine = commit.lines.find(_ => _.line === line);
|
||||||
@@ -330,7 +330,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyShowFileHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyShowFileHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
let line = lens.range.start.line;
|
let line = lens.range.start.line;
|
||||||
if (commit) {
|
if (commit) {
|
||||||
const blameLine = commit.lines.find(_ => _.line === line);
|
const blameLine = commit.lines.find(_ => _.line === line);
|
||||||
@@ -355,7 +355,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyDiffWithPreviousCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyDiffWithPreviousCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
if (commit === undefined) {
|
if (commit === undefined) {
|
||||||
const blameLine = blame.allLines[lens.range.start.line];
|
const blameLine = blame.allLines[lens.range.start.line];
|
||||||
commit = blame.commits.get(blameLine.sha);
|
commit = blame.commits.get(blameLine.sha);
|
||||||
@@ -375,7 +375,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyShowQuickCommitDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyShowQuickCommitDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitDetails,
|
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitDetails,
|
||||||
@@ -389,7 +389,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyShowQuickCommitFileDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyShowQuickCommitFileDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitFileDetails,
|
command: commit !== undefined && commit.isUncommitted ? '' : CodeLensCommand.ShowQuickCommitFileDetails,
|
||||||
@@ -403,7 +403,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyShowQuickFileHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyShowQuickFileHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: CodeLensCommand.ShowQuickFileHistory,
|
command: CodeLensCommand.ShowQuickFileHistory,
|
||||||
@@ -417,7 +417,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
return lens;
|
return lens;
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyShowQuickBranchHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, commit?: GitCommit): T {
|
_applyShowQuickBranchHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: GitBlameLines, commit?: GitBlameCommit): T {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: title,
|
title: title,
|
||||||
command: CodeLensCommand.ShowQuickCurrentBranchHistory,
|
command: CodeLensCommand.ShowQuickCurrentBranchHistory,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Disposable, Event, EventEmitter, ExtensionContext, FileSystemWatcher, l
|
|||||||
import { CommandContext, setCommandContext } from './commands';
|
import { CommandContext, setCommandContext } from './commands';
|
||||||
import { IConfig } from './configuration';
|
import { IConfig } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey } from './constants';
|
import { DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { Git, GitBlameParser, GitBranch, GitCommit, GitDiffParser, GitLogCommit, GitLogParser, GitRemote, GitStashParser, GitStatusFile, GitStatusParser, IGit, IGitAuthor, IGitBlame, IGitBlameLine, IGitBlameLines, IGitDiff, IGitDiffLine, IGitLog, IGitStash, IGitStatus, setDefaultEncoding } from './git/git';
|
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitCommit, GitDiff, GitDiffLine, GitDiffParser, GitLog, GitLogCommit, GitLogParser, GitRemote, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, IGit, setDefaultEncoding } from './git/git';
|
||||||
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
|
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
|
||||||
import { GitCodeLensProvider } from './gitCodeLensProvider';
|
import { GitCodeLensProvider } from './gitCodeLensProvider';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
@@ -26,7 +26,7 @@ class UriCacheEntry {
|
|||||||
|
|
||||||
class GitCacheEntry {
|
class GitCacheEntry {
|
||||||
|
|
||||||
private cache: Map<string, ICachedBlame | ICachedDiff | ICachedLog> = new Map();
|
private cache: Map<string, CachedBlame | CachedDiff | CachedLog> = new Map();
|
||||||
|
|
||||||
constructor(public key: string) { }
|
constructor(public key: string) { }
|
||||||
|
|
||||||
@@ -34,23 +34,23 @@ class GitCacheEntry {
|
|||||||
return Iterables.every(this.cache.values(), _ => _.errorMessage !== undefined);
|
return Iterables.every(this.cache.values(), _ => _.errorMessage !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
get<T extends ICachedBlame | ICachedDiff | ICachedLog>(key: string): T | undefined {
|
get<T extends CachedBlame | CachedDiff | CachedLog>(key: string): T | undefined {
|
||||||
return this.cache.get(key) as T;
|
return this.cache.get(key) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
set<T extends ICachedBlame | ICachedDiff | ICachedLog>(key: string, value: T) {
|
set<T extends CachedBlame | CachedDiff | CachedLog>(key: string, value: T) {
|
||||||
this.cache.set(key, value);
|
this.cache.set(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICachedItem<T> {
|
interface CachedItem<T> {
|
||||||
item: Promise<T>;
|
item: Promise<T>;
|
||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICachedBlame extends ICachedItem<IGitBlame> { }
|
interface CachedBlame extends CachedItem<GitBlame> { }
|
||||||
interface ICachedDiff extends ICachedItem<IGitDiff> { }
|
interface CachedDiff extends CachedItem<GitDiff> { }
|
||||||
interface ICachedLog extends ICachedItem<IGitLog> { }
|
interface CachedLog extends CachedItem<GitLog> { }
|
||||||
|
|
||||||
enum RemoveCacheReason {
|
enum RemoveCacheReason {
|
||||||
DocumentClosed,
|
DocumentClosed,
|
||||||
@@ -89,7 +89,7 @@ export class GitService extends Disposable {
|
|||||||
private _fsWatcher: FileSystemWatcher | undefined;
|
private _fsWatcher: FileSystemWatcher | undefined;
|
||||||
private _gitignore: Promise<ignore.Ignore>;
|
private _gitignore: Promise<ignore.Ignore>;
|
||||||
|
|
||||||
static EmptyPromise: Promise<IGitBlame | IGitDiff | IGitLog | undefined> = Promise.resolve(undefined);
|
static EmptyPromise: Promise<GitBlame | GitDiff | GitLog | undefined> = Promise.resolve(undefined);
|
||||||
|
|
||||||
constructor(private context: ExtensionContext, public repoPath: string) {
|
constructor(private context: ExtensionContext, public repoPath: string) {
|
||||||
super(() => this.dispose());
|
super(() => this.dispose());
|
||||||
@@ -287,18 +287,18 @@ export class GitService extends Disposable {
|
|||||||
if (sha === undefined) {
|
if (sha === undefined) {
|
||||||
// Get the most recent commit for this file name
|
// Get the most recent commit for this file name
|
||||||
const c = await this.getLogCommit(repoPath, fileName);
|
const c = await this.getLogCommit(repoPath, fileName);
|
||||||
if (!c) return undefined;
|
if (c === undefined) return undefined;
|
||||||
|
|
||||||
sha = c.sha;
|
sha = c.sha;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the full commit (so we can see if there are any matching renames in the file statuses)
|
// Get the full commit (so we can see if there are any matching renames in the file statuses)
|
||||||
const log = await this.getLogForRepo(repoPath, sha, 1);
|
const log = await this.getLogForRepo(repoPath, sha, 1);
|
||||||
if (!log) return undefined;
|
if (log === undefined) return undefined;
|
||||||
|
|
||||||
const c = Iterables.first(log.commits.values());
|
const c = Iterables.first(log.commits.values());
|
||||||
const status = c.fileStatuses.find(_ => _.originalFileName === fileName);
|
const status = c.fileStatuses.find(_ => _.originalFileName === fileName);
|
||||||
if (!status) return undefined;
|
if (status === undefined) return undefined;
|
||||||
|
|
||||||
return status.fileName;
|
return status.fileName;
|
||||||
}
|
}
|
||||||
@@ -338,7 +338,7 @@ export class GitService extends Disposable {
|
|||||||
return !entry.hasErrors;
|
return !entry.hasErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBlameForFile(uri: GitUri): Promise<IGitBlame | undefined> {
|
async getBlameForFile(uri: GitUri): Promise<GitBlame | undefined> {
|
||||||
let key = 'blame';
|
let key = 'blame';
|
||||||
if (uri.sha !== undefined) {
|
if (uri.sha !== undefined) {
|
||||||
key += `:${uri.sha}`;
|
key += `:${uri.sha}`;
|
||||||
@@ -350,7 +350,7 @@ export class GitService extends Disposable {
|
|||||||
entry = this._gitCache.get(cacheKey);
|
entry = this._gitCache.get(cacheKey);
|
||||||
|
|
||||||
if (entry !== undefined) {
|
if (entry !== undefined) {
|
||||||
const cachedBlame = entry.get<ICachedBlame>(key);
|
const cachedBlame = entry.get<CachedBlame>(key);
|
||||||
if (cachedBlame !== undefined) {
|
if (cachedBlame !== undefined) {
|
||||||
Logger.log(`Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
|
Logger.log(`Cached(${key}): getBlameForFile('${uri.repoPath}', '${uri.fsPath}', ${uri.sha})`);
|
||||||
return cachedBlame.item;
|
return cachedBlame.item;
|
||||||
@@ -373,15 +373,15 @@ export class GitService extends Disposable {
|
|||||||
if (entry) {
|
if (entry) {
|
||||||
Logger.log(`Add blame cache for '${entry.key}:${key}'`);
|
Logger.log(`Add blame cache for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedBlame>(key, {
|
entry.set<CachedBlame>(key, {
|
||||||
item: promise
|
item: promise
|
||||||
} as ICachedBlame);
|
} as CachedBlame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getBlameForFile(uri: GitUri, entry: GitCacheEntry | undefined, key: string): Promise<IGitBlame | undefined> {
|
private async _getBlameForFile(uri: GitUri, entry: GitCacheEntry | undefined, key: string): Promise<GitBlame | undefined> {
|
||||||
const [file, root] = Git.splitPath(uri.fsPath, uri.repoPath, false);
|
const [file, root] = Git.splitPath(uri.fsPath, uri.repoPath, false);
|
||||||
|
|
||||||
const ignore = await this._gitignore;
|
const ignore = await this._gitignore;
|
||||||
@@ -390,12 +390,13 @@ export class GitService extends Disposable {
|
|||||||
if (entry && entry.key) {
|
if (entry && entry.key) {
|
||||||
this._onDidBlameFail.fire(entry.key);
|
this._onDidBlameFail.fire(entry.key);
|
||||||
}
|
}
|
||||||
return await GitService.EmptyPromise as IGitBlame;
|
return await GitService.EmptyPromise as GitBlame;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.blame(root, file, uri.sha);
|
const data = await Git.blame(root, file, uri.sha);
|
||||||
return GitBlameParser.parse(data, root, file);
|
const blame = GitBlameParser.parse(data, root, file);
|
||||||
|
return blame;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
// Trap and cache expected blame errors
|
// Trap and cache expected blame errors
|
||||||
@@ -403,28 +404,31 @@ export class GitService extends Disposable {
|
|||||||
const msg = ex && ex.toString();
|
const msg = ex && ex.toString();
|
||||||
Logger.log(`Replace blame cache with empty promise for '${entry.key}:${key}'`);
|
Logger.log(`Replace blame cache with empty promise for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedBlame>(key, {
|
entry.set<CachedBlame>(key, {
|
||||||
item: GitService.EmptyPromise,
|
item: GitService.EmptyPromise,
|
||||||
errorMessage: msg
|
errorMessage: msg
|
||||||
} as ICachedBlame);
|
} as CachedBlame);
|
||||||
|
|
||||||
this._onDidBlameFail.fire(entry.key);
|
this._onDidBlameFail.fire(entry.key);
|
||||||
return await GitService.EmptyPromise as IGitBlame;
|
return await GitService.EmptyPromise as GitBlame;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBlameForLine(uri: GitUri, line: number): Promise<IGitBlameLine | undefined> {
|
async getBlameForLine(uri: GitUri, line: number): Promise<GitBlameLine | undefined> {
|
||||||
Logger.log(`getBlameForLine('${uri.repoPath}', '${uri.fsPath}', ${line}, ${uri.sha})`);
|
Logger.log(`getBlameForLine('${uri.repoPath}', '${uri.fsPath}', ${line}, ${uri.sha})`);
|
||||||
|
|
||||||
if (this.UseCaching) {
|
if (this.UseCaching) {
|
||||||
const blame = await this.getBlameForFile(uri);
|
const blame = await this.getBlameForFile(uri);
|
||||||
if (blame === undefined) return undefined;
|
if (blame === undefined) return undefined;
|
||||||
|
|
||||||
const blameLine = blame.lines[line];
|
let blameLine = blame.lines[line];
|
||||||
if (blameLine === undefined) return undefined;
|
if (blameLine === undefined) {
|
||||||
|
if (blame.lines.length !== line) return undefined;
|
||||||
|
blameLine = blame.lines[line - 1];
|
||||||
|
}
|
||||||
|
|
||||||
const commit = blame.commits.get(blameLine.sha);
|
const commit = blame.commits.get(blameLine.sha);
|
||||||
if (commit === undefined) return undefined;
|
if (commit === undefined) return undefined;
|
||||||
@@ -433,7 +437,7 @@ export class GitService extends Disposable {
|
|||||||
author: Object.assign({}, blame.authors.get(commit.author), { lineCount: commit.lines.length }),
|
author: Object.assign({}, blame.authors.get(commit.author), { lineCount: commit.lines.length }),
|
||||||
commit: commit,
|
commit: commit,
|
||||||
line: blameLine
|
line: blameLine
|
||||||
} as IGitBlameLine;
|
} as GitBlameLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = uri.fsPath;
|
const fileName = uri.fsPath;
|
||||||
@@ -441,7 +445,7 @@ export class GitService extends Disposable {
|
|||||||
try {
|
try {
|
||||||
const data = await Git.blame(uri.repoPath, fileName, uri.sha, line + 1, line + 1);
|
const data = await Git.blame(uri.repoPath, fileName, uri.sha, line + 1, line + 1);
|
||||||
const blame = GitBlameParser.parse(data, uri.repoPath, fileName);
|
const blame = GitBlameParser.parse(data, uri.repoPath, fileName);
|
||||||
if (!blame) return undefined;
|
if (blame === undefined) return undefined;
|
||||||
|
|
||||||
const commit = Iterables.first(blame.commits.values());
|
const commit = Iterables.first(blame.commits.values());
|
||||||
if (uri.repoPath) {
|
if (uri.repoPath) {
|
||||||
@@ -451,41 +455,40 @@ export class GitService extends Disposable {
|
|||||||
author: Iterables.first(blame.authors.values()),
|
author: Iterables.first(blame.authors.values()),
|
||||||
commit: commit,
|
commit: commit,
|
||||||
line: blame.lines[line]
|
line: blame.lines[line]
|
||||||
} as IGitBlameLine;
|
} as GitBlameLine;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBlameForRange(uri: GitUri, range: Range): Promise<IGitBlameLines | undefined> {
|
async getBlameForRange(uri: GitUri, range: Range): Promise<GitBlameLines | undefined> {
|
||||||
Logger.log(`getBlameForRange('${uri.repoPath}', '${uri.fsPath}', [${range.start.line}, ${range.end.line}], ${uri.sha})`);
|
Logger.log(`getBlameForRange('${uri.repoPath}', '${uri.fsPath}', [${range.start.line}, ${range.end.line}], ${uri.sha})`);
|
||||||
|
|
||||||
const blame = await this.getBlameForFile(uri);
|
const blame = await this.getBlameForFile(uri);
|
||||||
if (!blame) return undefined;
|
if (blame === undefined) return undefined;
|
||||||
|
|
||||||
return this.getBlameForRangeSync(blame, uri, range);
|
return this.getBlameForRangeSync(blame, uri, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBlameForRangeSync(blame: IGitBlame, uri: GitUri, range: Range): IGitBlameLines | undefined {
|
getBlameForRangeSync(blame: GitBlame, uri: GitUri, range: Range): GitBlameLines | undefined {
|
||||||
Logger.log(`getBlameForRangeSync('${uri.repoPath}', '${uri.fsPath}', [${range.start.line}, ${range.end.line}], ${uri.sha})`);
|
Logger.log(`getBlameForRangeSync('${uri.repoPath}', '${uri.fsPath}', [${range.start.line}, ${range.end.line}], ${uri.sha})`);
|
||||||
|
|
||||||
if (!blame.lines.length) return Object.assign({ allLines: blame.lines }, blame);
|
if (blame.lines.length === 0) return Object.assign({ allLines: blame.lines }, blame);
|
||||||
|
|
||||||
if (range.start.line === 0 && range.end.line === blame.lines.length - 1) {
|
if (range.start.line === 0 && range.end.line === blame.lines.length - 1) {
|
||||||
return Object.assign({ allLines: blame.lines }, blame);
|
return Object.assign({ allLines: blame.lines }, blame);
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = blame.lines.slice(range.start.line, range.end.line + 1);
|
const lines = blame.lines.slice(range.start.line, range.end.line + 1);
|
||||||
const shas: Set<string> = new Set();
|
const shas = new Set(lines.map(l => l.sha));
|
||||||
lines.forEach(l => shas.add(l.sha));
|
|
||||||
|
|
||||||
const authors: Map<string, IGitAuthor> = new Map();
|
const authors: Map<string, GitAuthor> = new Map();
|
||||||
const commits: Map<string, GitCommit> = new Map();
|
const commits: Map<string, GitBlameCommit> = new Map();
|
||||||
blame.commits.forEach(c => {
|
for (const c of blame.commits.values()) {
|
||||||
if (!shas.has(c.sha)) return;
|
if (!shas.has(c.sha)) return;
|
||||||
|
|
||||||
const commit: GitCommit = new GitCommit('blame', c.repoPath, c.sha, c.fileName, c.author, c.date, c.message,
|
const commit = new GitBlameCommit(c.repoPath, c.sha, c.fileName, c.author, c.date, c.message,
|
||||||
c.lines.filter(l => l.line >= range.start.line && l.line <= range.end.line), c.originalFileName, c.previousSha, c.previousFileName);
|
c.lines.filter(l => l.line >= range.start.line && l.line <= range.end.line), c.originalFileName, c.previousSha, c.previousFileName);
|
||||||
commits.set(c.sha, commit);
|
commits.set(c.sha, commit);
|
||||||
|
|
||||||
@@ -499,26 +502,23 @@ export class GitService extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
author.lineCount += commit.lines.length;
|
author.lineCount += commit.lines.length;
|
||||||
});
|
}
|
||||||
|
|
||||||
const sortedAuthors: Map<string, IGitAuthor> = new Map();
|
const sortedAuthors = new Map([...authors.entries()].sort((a, b) => b[1].lineCount - a[1].lineCount));
|
||||||
Array.from(authors.values())
|
|
||||||
.sort((a, b) => b.lineCount - a.lineCount)
|
|
||||||
.forEach(a => sortedAuthors.set(a.name, a));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authors: sortedAuthors,
|
authors: sortedAuthors,
|
||||||
commits: commits,
|
commits: commits,
|
||||||
lines: lines,
|
lines: lines,
|
||||||
allLines: blame.lines
|
allLines: blame.lines
|
||||||
} as IGitBlameLines;
|
} as GitBlameLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBlameLocations(uri: GitUri, range: Range, selectedSha?: string, line?: number): Promise<Location[] | undefined> {
|
async getBlameLocations(uri: GitUri, range: Range, selectedSha?: string, line?: number): Promise<Location[] | undefined> {
|
||||||
Logger.log(`getBlameLocations('${uri.repoPath}', '${uri.fsPath}', [${range.start.line}, ${range.end.line}], ${uri.sha})`);
|
Logger.log(`getBlameLocations('${uri.repoPath}', '${uri.fsPath}', [${range.start.line}, ${range.end.line}], ${uri.sha})`);
|
||||||
|
|
||||||
const blame = await this.getBlameForRange(uri, range);
|
const blame = await this.getBlameForRange(uri, range);
|
||||||
if (!blame) return undefined;
|
if (blame === undefined) return undefined;
|
||||||
|
|
||||||
const commitCount = blame.commits.size;
|
const commitCount = blame.commits.size;
|
||||||
|
|
||||||
@@ -571,7 +571,7 @@ export class GitService extends Disposable {
|
|||||||
return entry && entry.uri;
|
return entry && entry.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDiffForFile(uri: GitUri, sha1?: string, sha2?: string): Promise<IGitDiff | undefined> {
|
async getDiffForFile(uri: GitUri, sha1?: string, sha2?: string): Promise<GitDiff | undefined> {
|
||||||
if (sha1 !== undefined && sha2 === undefined && uri.sha !== undefined) {
|
if (sha1 !== undefined && sha2 === undefined && uri.sha !== undefined) {
|
||||||
sha2 = uri.sha;
|
sha2 = uri.sha;
|
||||||
}
|
}
|
||||||
@@ -590,7 +590,7 @@ export class GitService extends Disposable {
|
|||||||
entry = this._gitCache.get(cacheKey);
|
entry = this._gitCache.get(cacheKey);
|
||||||
|
|
||||||
if (entry !== undefined) {
|
if (entry !== undefined) {
|
||||||
const cachedDiff = entry.get<ICachedDiff>(key);
|
const cachedDiff = entry.get<CachedDiff>(key);
|
||||||
if (cachedDiff !== undefined) {
|
if (cachedDiff !== undefined) {
|
||||||
Logger.log(`Cached(${key}): getDiffForFile('${uri.repoPath}', '${uri.fsPath}', ${sha1}, ${sha2})`);
|
Logger.log(`Cached(${key}): getDiffForFile('${uri.repoPath}', '${uri.fsPath}', ${sha1}, ${sha2})`);
|
||||||
return cachedDiff.item;
|
return cachedDiff.item;
|
||||||
@@ -613,20 +613,21 @@ export class GitService extends Disposable {
|
|||||||
if (entry) {
|
if (entry) {
|
||||||
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedDiff>(key, {
|
entry.set<CachedDiff>(key, {
|
||||||
item: promise
|
item: promise
|
||||||
} as ICachedDiff);
|
} as CachedDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getDiffForFile(repoPath: string | undefined, fileName: string, sha1: string | undefined, sha2: string | undefined, entry: GitCacheEntry | undefined, key: string): Promise<IGitDiff | undefined> {
|
private async _getDiffForFile(repoPath: string | undefined, fileName: string, sha1: string | undefined, sha2: string | undefined, entry: GitCacheEntry | undefined, key: string): Promise<GitDiff | undefined> {
|
||||||
const [file, root] = Git.splitPath(fileName, repoPath, false);
|
const [file, root] = Git.splitPath(fileName, repoPath, false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.diff(root, file, sha1, sha2);
|
const data = await Git.diff(root, file, sha1, sha2);
|
||||||
return GitDiffParser.parse(data);
|
const diff = GitDiffParser.parse(data);
|
||||||
|
return diff;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
// Trap and cache expected diff errors
|
// Trap and cache expected diff errors
|
||||||
@@ -634,29 +635,29 @@ export class GitService extends Disposable {
|
|||||||
const msg = ex && ex.toString();
|
const msg = ex && ex.toString();
|
||||||
Logger.log(`Replace diff cache with empty promise for '${entry.key}:${key}'`);
|
Logger.log(`Replace diff cache with empty promise for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedDiff>(key, {
|
entry.set<CachedDiff>(key, {
|
||||||
item: GitService.EmptyPromise,
|
item: GitService.EmptyPromise,
|
||||||
errorMessage: msg
|
errorMessage: msg
|
||||||
} as ICachedDiff);
|
} as CachedDiff);
|
||||||
|
|
||||||
return await GitService.EmptyPromise as IGitDiff;
|
return await GitService.EmptyPromise as GitDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDiffForLine(uri: GitUri, line: number, sha1?: string, sha2?: string): Promise<[IGitDiffLine | undefined, IGitDiffLine | undefined]> {
|
async getDiffForLine(uri: GitUri, line: number, sha1?: string, sha2?: string): Promise<[GitDiffLine | undefined, GitDiffLine | undefined]> {
|
||||||
try {
|
try {
|
||||||
const diff = await this.getDiffForFile(uri, sha1, sha2);
|
const diff = await this.getDiffForFile(uri, sha1, sha2);
|
||||||
if (diff === undefined) return [undefined, undefined];
|
if (diff === undefined) return [undefined, undefined];
|
||||||
|
|
||||||
const chunk = diff.chunks.find(_ => _.currentStart <= line && _.currentEnd >= line);
|
const chunk = diff.chunks.find(_ => _.currentPosition.start <= line && _.currentPosition.end >= line);
|
||||||
if (chunk === undefined) return [undefined, undefined];
|
if (chunk === undefined) return [undefined, undefined];
|
||||||
|
|
||||||
// Search for the line (skipping deleted lines -- since they don't currently exist in the editor)
|
// Search for the line (skipping deleted lines -- since they don't currently exist in the editor)
|
||||||
// Keep track of the deleted lines for the original version
|
// Keep track of the deleted lines for the original version
|
||||||
line = line - chunk.currentStart + 1;
|
line = line - chunk.currentPosition.start + 1;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
let deleted = 0;
|
let deleted = 0;
|
||||||
for (const l of chunk.current) {
|
for (const l of chunk.current) {
|
||||||
@@ -673,7 +674,7 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
chunk.previous[line + deleted - 1],
|
chunk.previous[line + deleted - 1],
|
||||||
chunk.current[line + deleted + (chunk.currentStart - chunk.previousStart)]
|
chunk.current[line + deleted + (chunk.currentPosition.start - chunk.previousPosition.start)]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
@@ -688,22 +689,22 @@ export class GitService extends Disposable {
|
|||||||
if (typeof shaOrOptions === 'string') {
|
if (typeof shaOrOptions === 'string') {
|
||||||
sha = shaOrOptions;
|
sha = shaOrOptions;
|
||||||
}
|
}
|
||||||
else if (!options) {
|
else if (options === undefined) {
|
||||||
options = shaOrOptions;
|
options = shaOrOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
const log = await this.getLogForFile(repoPath, fileName, sha, options.previous ? 2 : 1);
|
const log = await this.getLogForFile(repoPath, fileName, sha, options.previous ? 2 : 1);
|
||||||
if (!log) return undefined;
|
if (log === undefined) return undefined;
|
||||||
|
|
||||||
const commit = sha && log.commits.get(sha);
|
const commit = sha && log.commits.get(sha);
|
||||||
if (!commit && sha && !options.firstIfMissing) return undefined;
|
if (commit === undefined && sha && !options.firstIfMissing) return undefined;
|
||||||
|
|
||||||
return commit || Iterables.first(log.commits.values());
|
return commit || Iterables.first(log.commits.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLogForRepo(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false): Promise<IGitLog | undefined> {
|
async getLogForRepo(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false): Promise<GitLog | undefined> {
|
||||||
Logger.log(`getLogForRepo('${repoPath}', ${sha}, ${maxCount})`);
|
Logger.log(`getLogForRepo('${repoPath}', ${sha}, ${maxCount})`);
|
||||||
|
|
||||||
if (maxCount == null) {
|
if (maxCount == null) {
|
||||||
@@ -712,14 +713,15 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.log(repoPath, sha, maxCount, reverse);
|
const data = await Git.log(repoPath, sha, maxCount, reverse);
|
||||||
return GitLogParser.parse(data, 'branch', repoPath, undefined, sha, maxCount, reverse, undefined);
|
const log = GitLogParser.parse(data, 'branch', repoPath, undefined, sha, maxCount, reverse, undefined);
|
||||||
|
return log;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLogForRepoSearch(repoPath: string, search: string, searchBy: GitRepoSearchBy, maxCount?: number): Promise<IGitLog | undefined> {
|
async getLogForRepoSearch(repoPath: string, search: string, searchBy: GitRepoSearchBy, maxCount?: number): Promise<GitLog | undefined> {
|
||||||
Logger.log(`getLogForRepoSearch('${repoPath}', ${search}, ${searchBy}, ${maxCount})`);
|
Logger.log(`getLogForRepoSearch('${repoPath}', ${search}, ${searchBy}, ${maxCount})`);
|
||||||
|
|
||||||
if (maxCount == null) {
|
if (maxCount == null) {
|
||||||
@@ -745,14 +747,15 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.log_search(repoPath, searchArgs, maxCount);
|
const data = await Git.log_search(repoPath, searchArgs, maxCount);
|
||||||
return GitLogParser.parse(data, 'branch', repoPath, undefined, undefined, maxCount, false, undefined);
|
const log = GitLogParser.parse(data, 'branch', repoPath, undefined, undefined, maxCount, false, undefined);
|
||||||
|
return log;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLogForFile(repoPath: string | undefined, fileName: string, sha?: string, maxCount?: number, range?: Range, reverse: boolean = false): Promise<IGitLog | undefined> {
|
async getLogForFile(repoPath: string | undefined, fileName: string, sha?: string, maxCount?: number, range?: Range, reverse: boolean = false): Promise<GitLog | undefined> {
|
||||||
let key = 'log';
|
let key = 'log';
|
||||||
if (sha !== undefined) {
|
if (sha !== undefined) {
|
||||||
key += `:${sha}`;
|
key += `:${sha}`;
|
||||||
@@ -767,7 +770,7 @@ export class GitService extends Disposable {
|
|||||||
entry = this._gitCache.get(cacheKey);
|
entry = this._gitCache.get(cacheKey);
|
||||||
|
|
||||||
if (entry !== undefined) {
|
if (entry !== undefined) {
|
||||||
const cachedLog = entry.get<ICachedLog>(key);
|
const cachedLog = entry.get<CachedLog>(key);
|
||||||
if (cachedLog !== undefined) {
|
if (cachedLog !== undefined) {
|
||||||
Logger.log(`Cached(${key}): getLogForFile('${repoPath}', '${fileName}', ${sha}, ${maxCount}, undefined, false)`);
|
Logger.log(`Cached(${key}): getLogForFile('${repoPath}', '${fileName}', ${sha}, ${maxCount}, undefined, false)`);
|
||||||
return cachedLog.item;
|
return cachedLog.item;
|
||||||
@@ -775,7 +778,7 @@ export class GitService extends Disposable {
|
|||||||
|
|
||||||
if (key !== 'log') {
|
if (key !== 'log') {
|
||||||
// Since we are looking for partial log, see if we have the log of the whole file
|
// Since we are looking for partial log, see if we have the log of the whole file
|
||||||
const cachedLog = entry.get<ICachedLog>('log');
|
const cachedLog = entry.get<CachedLog>('log');
|
||||||
if (cachedLog !== undefined) {
|
if (cachedLog !== undefined) {
|
||||||
if (sha === undefined) {
|
if (sha === undefined) {
|
||||||
Logger.log(`Cached(~${key}): getLogForFile('${repoPath}', '${fileName}', ${sha}, ${maxCount}, undefined, false)`);
|
Logger.log(`Cached(~${key}): getLogForFile('${repoPath}', '${fileName}', ${sha}, ${maxCount}, undefined, false)`);
|
||||||
@@ -808,26 +811,27 @@ export class GitService extends Disposable {
|
|||||||
if (entry) {
|
if (entry) {
|
||||||
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
Logger.log(`Add log cache for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedLog>(key, {
|
entry.set<CachedLog>(key, {
|
||||||
item: promise
|
item: promise
|
||||||
} as ICachedLog);
|
} as CachedLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getLogForFile(repoPath: string | undefined, fileName: string, sha: string | undefined, range: Range | undefined, maxCount: number | undefined, reverse: boolean, entry: GitCacheEntry | undefined, key: string): Promise<IGitLog | undefined> {
|
private async _getLogForFile(repoPath: string | undefined, fileName: string, sha: string | undefined, range: Range | undefined, maxCount: number | undefined, reverse: boolean, entry: GitCacheEntry | undefined, key: string): Promise<GitLog | undefined> {
|
||||||
const [file, root] = Git.splitPath(fileName, repoPath, false);
|
const [file, root] = Git.splitPath(fileName, repoPath, false);
|
||||||
|
|
||||||
const ignore = await this._gitignore;
|
const ignore = await this._gitignore;
|
||||||
if (ignore && !ignore.filter([file]).length) {
|
if (ignore && !ignore.filter([file]).length) {
|
||||||
Logger.log(`Skipping log; '${fileName}' is gitignored`);
|
Logger.log(`Skipping log; '${fileName}' is gitignored`);
|
||||||
return await GitService.EmptyPromise as IGitLog;
|
return await GitService.EmptyPromise as GitLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await Git.log_file(root, file, sha, maxCount, reverse, range && range.start.line + 1, range && range.end.line + 1);
|
const data = await Git.log_file(root, file, sha, maxCount, reverse, range && range.start.line + 1, range && range.end.line + 1);
|
||||||
return GitLogParser.parse(data, 'file', root, file, sha, maxCount, reverse, range);
|
const log = GitLogParser.parse(data, 'file', root, file, sha, maxCount, reverse, range);
|
||||||
|
return log;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
// Trap and cache expected log errors
|
// Trap and cache expected log errors
|
||||||
@@ -835,12 +839,12 @@ export class GitService extends Disposable {
|
|||||||
const msg = ex && ex.toString();
|
const msg = ex && ex.toString();
|
||||||
Logger.log(`Replace log cache with empty promise for '${entry.key}:${key}'`);
|
Logger.log(`Replace log cache with empty promise for '${entry.key}:${key}'`);
|
||||||
|
|
||||||
entry.set<ICachedLog>(key, {
|
entry.set<CachedLog>(key, {
|
||||||
item: GitService.EmptyPromise,
|
item: GitService.EmptyPromise,
|
||||||
errorMessage: msg
|
errorMessage: msg
|
||||||
} as ICachedLog);
|
} as CachedLog);
|
||||||
|
|
||||||
return await GitService.EmptyPromise as IGitLog;
|
return await GitService.EmptyPromise as GitLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -851,7 +855,7 @@ export class GitService extends Disposable {
|
|||||||
Logger.log(`getLogLocations('${uri.repoPath}', '${uri.fsPath}', ${uri.sha}, ${selectedSha}, ${line})`);
|
Logger.log(`getLogLocations('${uri.repoPath}', '${uri.fsPath}', ${uri.sha}, ${selectedSha}, ${line})`);
|
||||||
|
|
||||||
const log = await this.getLogForFile(uri.repoPath, uri.fsPath, uri.sha);
|
const log = await this.getLogForFile(uri.repoPath, uri.fsPath, uri.sha);
|
||||||
if (!log) return undefined;
|
if (log === undefined) return undefined;
|
||||||
|
|
||||||
const commitCount = log.commits.size;
|
const commitCount = log.commits.size;
|
||||||
|
|
||||||
@@ -908,11 +912,12 @@ export class GitService extends Disposable {
|
|||||||
return repoPath;
|
return repoPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStashList(repoPath: string): Promise<IGitStash | undefined> {
|
async getStashList(repoPath: string): Promise<GitStash | undefined> {
|
||||||
Logger.log(`getStash('${repoPath}')`);
|
Logger.log(`getStash('${repoPath}')`);
|
||||||
|
|
||||||
const data = await Git.stash_list(repoPath);
|
const data = await Git.stash_list(repoPath);
|
||||||
return GitStashParser.parse(data, repoPath);
|
const stash = GitStashParser.parse(data, repoPath);
|
||||||
|
return stash;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStatusForFile(repoPath: string, fileName: string): Promise<GitStatusFile | undefined> {
|
async getStatusForFile(repoPath: string, fileName: string): Promise<GitStatusFile | undefined> {
|
||||||
@@ -927,13 +932,14 @@ export class GitService extends Disposable {
|
|||||||
return status.files[0];
|
return status.files[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStatusForRepo(repoPath: string): Promise<IGitStatus | undefined> {
|
async getStatusForRepo(repoPath: string): Promise<GitStatus | undefined> {
|
||||||
Logger.log(`getStatusForRepo('${repoPath}')`);
|
Logger.log(`getStatusForRepo('${repoPath}')`);
|
||||||
|
|
||||||
const porcelainVersion = Git.validateVersion(2, 11) ? 2 : 1;
|
const porcelainVersion = Git.validateVersion(2, 11) ? 2 : 1;
|
||||||
|
|
||||||
const data = await Git.status(repoPath, porcelainVersion);
|
const data = await Git.status(repoPath, porcelainVersion);
|
||||||
return GitStatusParser.parse(data, repoPath, porcelainVersion);
|
const status = GitStatusParser.parse(data, repoPath, porcelainVersion);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVersionedFile(repoPath: string | undefined, fileName: string, sha: string) {
|
async getVersionedFile(repoPath: string | undefined, fileName: string, sha: string) {
|
||||||
|
|||||||
103
src/messages.ts
Normal file
103
src/messages.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
'use strict';
|
||||||
|
import { commands, ExtensionContext, Uri, window } from 'vscode';
|
||||||
|
import { BuiltInCommands } from './constants';
|
||||||
|
import { GitCommit } from './gitService';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
|
export type SuppressedKeys = 'suppressCommitHasNoPreviousCommitWarning' |
|
||||||
|
'suppressCommitNotFoundWarning' |
|
||||||
|
'suppressFileNotUnderSourceControlWarning' |
|
||||||
|
'suppressGitVersionWarning' |
|
||||||
|
'suppressLineUncommittedWarning' |
|
||||||
|
'suppressNoRepositoryWarning' |
|
||||||
|
'suppressUpdateNotice';
|
||||||
|
export const SuppressedKeys = {
|
||||||
|
CommitHasNoPreviousCommitWarning: 'suppressCommitHasNoPreviousCommitWarning' as SuppressedKeys,
|
||||||
|
CommitNotFoundWarning: 'suppressCommitNotFoundWarning' as SuppressedKeys,
|
||||||
|
FileNotUnderSourceControlWarning: 'suppressFileNotUnderSourceControlWarning' as SuppressedKeys,
|
||||||
|
GitVersionWarning: 'suppressGitVersionWarning' as SuppressedKeys,
|
||||||
|
LineUncommittedWarning: 'suppressLineUncommittedWarning' as SuppressedKeys,
|
||||||
|
NoRepositoryWarning: 'suppressNoRepositoryWarning' as SuppressedKeys,
|
||||||
|
UpdateNotice: 'suppressUpdateNotice' as SuppressedKeys
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Messages {
|
||||||
|
|
||||||
|
static context: ExtensionContext;
|
||||||
|
|
||||||
|
static configure(context: ExtensionContext) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static showCommitHasNoPreviousCommitWarningMessage(commit: GitCommit): Promise<string | undefined> {
|
||||||
|
return Messages._showMessage('info', `Commit ${commit.shortSha} (${commit.author}, ${moment(commit.date).fromNow()}) has no previous commit`, SuppressedKeys.CommitHasNoPreviousCommitWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showCommitNotFoundWarningMessage(message: string): Promise<string | undefined> {
|
||||||
|
return Messages._showMessage('warn', `${message}. The commit could not be found`, SuppressedKeys.CommitNotFoundWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showFileNotUnderSourceControlWarningMessage(message: string): Promise<string | undefined> {
|
||||||
|
return Messages._showMessage('warn', `${message}. The file is probably not under source control`, SuppressedKeys.FileNotUnderSourceControlWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showLineUncommittedWarningMessage(message: string): Promise<string | undefined> {
|
||||||
|
return Messages._showMessage('warn', `${message}. The line has uncommitted changes`, SuppressedKeys.LineUncommittedWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showNoRepositoryWarningMessage(message: string): Promise<string | undefined> {
|
||||||
|
return Messages._showMessage('warn', `${message}. No repository could be found`, SuppressedKeys.NoRepositoryWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showUnsupportedGitVersionErrorMessage(version: string): Promise<string | undefined> {
|
||||||
|
return Messages._showMessage('error', `GitLens requires a newer version of Git (>= 2.2.0) than is currently installed (${version}). Please install a more recent version of Git.`, SuppressedKeys.GitVersionWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async showUpdateMessage(version: string): Promise<string | undefined> {
|
||||||
|
const viewReleaseNotes = 'View Release Notes';
|
||||||
|
const result = await Messages._showMessage('info', `GitLens has been updated to v${version}`, SuppressedKeys.UpdateNotice, undefined, viewReleaseNotes);
|
||||||
|
if (result === viewReleaseNotes) {
|
||||||
|
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens/changelog'));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async showWelcomeMessage(): Promise<string | undefined> {
|
||||||
|
const viewDocs = 'View Docs';
|
||||||
|
const result = await window.showInformationMessage(`Thank you for choosing GitLens! GitLens is powerful, feature rich, and highly configurable, so please be sure to view the docs and tailor it to suit your needs.`, viewDocs);
|
||||||
|
if (result === viewDocs) {
|
||||||
|
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens'));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async _showMessage(type: 'info' | 'warn' | 'error', message: string, suppressionKey: SuppressedKeys, dontShowAgain: string | null = 'Don\'t Show Again', ...actions: any[]): Promise<string | undefined> {
|
||||||
|
if (Messages.context.globalState.get(suppressionKey, false)) return undefined;
|
||||||
|
|
||||||
|
if (dontShowAgain !== null) {
|
||||||
|
actions.push(dontShowAgain);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result: string | undefined = undefined;
|
||||||
|
switch (type) {
|
||||||
|
case 'info':
|
||||||
|
result = await window.showInformationMessage(message, ...actions);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'warn':
|
||||||
|
result = await window.showWarningMessage(message, ...actions);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'error':
|
||||||
|
result = await window.showErrorMessage(message, ...actions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dontShowAgain === null || result === dontShowAgain) {
|
||||||
|
await Messages.context.globalState.update(suppressionKey, true);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { Arrays, Iterables } from '../system';
|
|||||||
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, Keyboard, KeyNoopCommand, ShowCommitSearchCommandArgs, ShowQuickBranchHistoryCommandArgs } from '../commands';
|
import { Commands, Keyboard, KeyNoopCommand, ShowCommitSearchCommandArgs, ShowQuickBranchHistoryCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
||||||
import { GitService, GitUri, IGitLog, RemoteResource } from '../gitService';
|
import { GitLog, GitService, GitUri, RemoteResource } from '../gitService';
|
||||||
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
||||||
|
|
||||||
export class BranchHistoryQuickPick {
|
export class BranchHistoryQuickPick {
|
||||||
@@ -17,7 +17,7 @@ export class BranchHistoryQuickPick {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static async show(git: GitService, log: IGitLog, uri: GitUri | undefined, branch: string, progressCancellation: CancellationTokenSource, goBackCommand?: CommandQuickPickItem, nextPageCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
static async show(git: GitService, log: GitLog, uri: GitUri | undefined, branch: string, progressCancellation: CancellationTokenSource, goBackCommand?: CommandQuickPickItem, nextPageCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c))) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c))) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
||||||
|
|
||||||
const currentCommand = new CommandQuickPickItem({
|
const currentCommand = new CommandQuickPickItem({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Arrays, Iterables } from '../system';
|
|||||||
import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from 'vscode';
|
import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffDirectoryCommandCommandArgs, DiffWithPreviousCommandArgs, Keyboard, KeyNoopCommand, Keys, ShowQuickCommitDetailsCommandArgs, StashApplyCommandArgs, StashDeleteCommandArgs } from '../commands';
|
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffDirectoryCommandCommandArgs, DiffWithPreviousCommandArgs, Keyboard, KeyNoopCommand, Keys, ShowQuickCommitDetailsCommandArgs, StashApplyCommandArgs, StashDeleteCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem, QuickPickItem } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem, QuickPickItem } from './common';
|
||||||
import { getGitStatusIcon, GitCommit, GitLogCommit, GitService, GitStashCommit, GitStatusFileStatus, GitUri, IGitCommitInfo, IGitLog, IGitStatusFile, RemoteResource } from '../gitService';
|
import { getGitStatusIcon, GitCommit, GitLog, GitLogCommit, GitService, GitStashCommit, GitStatusFileStatus, GitUri, IGitCommitInfo, IGitStatusFile, RemoteResource } from '../gitService';
|
||||||
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@@ -103,7 +103,7 @@ export class OpenCommitWorkingTreeFilesCommandQuickPickItem extends OpenFilesCom
|
|||||||
|
|
||||||
export class CommitDetailsQuickPick {
|
export class CommitDetailsQuickPick {
|
||||||
|
|
||||||
static async show(git: GitService, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, repoLog?: IGitLog): Promise<CommitWithFileStatusQuickPickItem | CommandQuickPickItem | undefined> {
|
static async show(git: GitService, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, repoLog?: GitLog): Promise<CommitWithFileStatusQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
const items: (CommitWithFileStatusQuickPickItem | CommandQuickPickItem)[] = commit.fileStatuses.map(fs => new CommitWithFileStatusQuickPickItem(commit, fs));
|
const items: (CommitWithFileStatusQuickPickItem | CommandQuickPickItem)[] = commit.fileStatuses.map(fs => new CommitWithFileStatusQuickPickItem(commit, fs));
|
||||||
|
|
||||||
const stash = commit.type === 'stash';
|
const stash = commit.type === 'stash';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Arrays, Iterables } from '../system';
|
|||||||
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
|
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, Keyboard, KeyNoopCommand, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, Keyboard, KeyNoopCommand, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './common';
|
||||||
import { GitBranch, GitLogCommit, GitService, GitUri, IGitLog, RemoteResource } from '../gitService';
|
import { GitBranch, GitLog, GitLogCommit, GitService, GitUri, RemoteResource } from '../gitService';
|
||||||
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@@ -41,7 +41,7 @@ export class OpenCommitWorkingTreeFileCommandQuickPickItem extends OpenFileComma
|
|||||||
|
|
||||||
export class CommitFileDetailsQuickPick {
|
export class CommitFileDetailsQuickPick {
|
||||||
|
|
||||||
static async show(git: GitService, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, fileLog?: IGitLog): Promise<CommandQuickPickItem | undefined> {
|
static async show(git: GitService, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, fileLog?: GitLog): Promise<CommandQuickPickItem | undefined> {
|
||||||
const items: CommandQuickPickItem[] = [];
|
const items: CommandQuickPickItem[] = [];
|
||||||
|
|
||||||
const stash = commit.type === 'stash';
|
const stash = commit.type === 'stash';
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
import { Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { QuickPickOptions, window } from 'vscode';
|
import { QuickPickOptions, window } from 'vscode';
|
||||||
import { Keyboard } from '../commands';
|
import { Keyboard } from '../commands';
|
||||||
import { GitService, IGitLog } from '../gitService';
|
import { GitLog, GitService } from '../gitService';
|
||||||
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut } from '../quickPicks';
|
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut } from '../quickPicks';
|
||||||
|
|
||||||
export class CommitsQuickPick {
|
export class CommitsQuickPick {
|
||||||
|
|
||||||
static async show(git: GitService, log: IGitLog, placeHolder: string, goBackCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
static async show(git: GitService, log: GitLog, placeHolder: string, goBackCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
const items = ((log && Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c)))) || []) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
const items = ((log && Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c)))) || []) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
||||||
|
|
||||||
if (goBackCommand) {
|
if (goBackCommand) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Arrays, Iterables } from '../system';
|
|||||||
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, Keyboard, KeyNoopCommand, ShowQuickCurrentBranchHistoryCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
import { Commands, Keyboard, KeyNoopCommand, ShowQuickCurrentBranchHistoryCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
|
||||||
import { GitService, GitUri, IGitLog, RemoteResource } from '../gitService';
|
import { GitLog, GitService, GitUri, RemoteResource } from '../gitService';
|
||||||
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
import { OpenRemotesCommandQuickPickItem } from './remotes';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export class FileHistoryQuickPick {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static async show(git: GitService, log: IGitLog, uri: GitUri, progressCancellation: CancellationTokenSource, goBackCommand?: CommandQuickPickItem, nextPageCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
static async show(git: GitService, log: GitLog, uri: GitUri, progressCancellation: CancellationTokenSource, goBackCommand?: CommandQuickPickItem, nextPageCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c))) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c))) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
||||||
|
|
||||||
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
|
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Iterables } from '../system';
|
|||||||
import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from 'vscode';
|
import { commands, QuickPickOptions, TextDocumentShowOptions, Uri, window } from 'vscode';
|
||||||
import { Commands, DiffWithWorkingCommandArgs, Keyboard, Keys, OpenChangedFilesCommandArgs, ShowQuickBranchHistoryCommandArgs, ShowQuickRepoStatusCommandArgs, ShowQuickStashListCommandArgs } from '../commands';
|
import { Commands, DiffWithWorkingCommandArgs, Keyboard, Keys, OpenChangedFilesCommandArgs, ShowQuickBranchHistoryCommandArgs, ShowQuickRepoStatusCommandArgs, ShowQuickStashListCommandArgs } from '../commands';
|
||||||
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem, QuickPickItem } from './common';
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem, QuickPickItem } from './common';
|
||||||
import { GitService, GitStatusFile, GitUri, IGitStatus } from '../gitService';
|
import { GitService, GitStatus, GitStatusFile, GitUri } from '../gitService';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export class OpenStatusFileCommandQuickPickItem extends OpenFileCommandQuickPickItem {
|
export class OpenStatusFileCommandQuickPickItem extends OpenFileCommandQuickPickItem {
|
||||||
@@ -58,7 +58,7 @@ export class OpenStatusFilesCommandQuickPickItem extends CommandQuickPickItem {
|
|||||||
|
|
||||||
export class RepoStatusQuickPick {
|
export class RepoStatusQuickPick {
|
||||||
|
|
||||||
static async show(status: IGitStatus, goBackCommand?: CommandQuickPickItem): Promise<OpenStatusFileCommandQuickPickItem | OpenStatusFilesCommandQuickPickItem | CommandQuickPickItem | undefined> {
|
static async show(status: GitStatus, goBackCommand?: CommandQuickPickItem): Promise<OpenStatusFileCommandQuickPickItem | OpenStatusFilesCommandQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
// Sort the status by staged and then filename
|
// Sort the status by staged and then filename
|
||||||
const files = status.files;
|
const files = status.files;
|
||||||
files.sort((a, b) => (a.staged ? -1 : 1) - (b.staged ? -1 : 1) || a.fileName.localeCompare(b.fileName));
|
files.sort((a, b) => (a.staged ? -1 : 1) - (b.staged ? -1 : 1) || a.fileName.localeCompare(b.fileName));
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
import { Iterables } from '../system';
|
import { Iterables } from '../system';
|
||||||
import { QuickPickOptions, window } from 'vscode';
|
import { QuickPickOptions, window } from 'vscode';
|
||||||
import { Commands, Keyboard, StashSaveCommandArgs } from '../commands';
|
import { Commands, Keyboard, StashSaveCommandArgs } from '../commands';
|
||||||
import { GitService, IGitStash } from '../gitService';
|
import { GitService, GitStash } from '../gitService';
|
||||||
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut } from '../quickPicks';
|
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut } from '../quickPicks';
|
||||||
|
|
||||||
export class StashListQuickPick {
|
export class StashListQuickPick {
|
||||||
|
|
||||||
static async show(git: GitService, stash: IGitStash, mode: 'list' | 'apply', goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
static async show(git: GitService, stash: GitStash, mode: 'list' | 'apply', goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
const items = ((stash && Array.from(Iterables.map(stash.commits.values(), c => new CommitQuickPickItem(c)))) || []) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
const items = ((stash && Array.from(Iterables.map(stash.commits.values(), c => new CommitQuickPickItem(c)))) || []) as (CommitQuickPickItem | CommandQuickPickItem)[];
|
||||||
|
|
||||||
if (mode === 'list') {
|
if (mode === 'list') {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export namespace Iterables {
|
|||||||
return source.next().value;
|
return source.next().value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* skip<T>(source: Iterable<T> | IterableIterator<T>, count: number): Iterable<T> {
|
export function* skip<T>(source: Iterable<T> | IterableIterator<T>, count: number): Iterable<T> | IterableIterator<T> {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const item of source) {
|
for (const item of source) {
|
||||||
if (i >= count) yield item;
|
if (i >= count) yield item;
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ export namespace Objects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* values(o: any): IterableIterator<[any]> {
|
export function* values<T>(o: any): IterableIterator<T> {
|
||||||
for (const key in o) {
|
for (const key in o) {
|
||||||
yield [o[key]];
|
yield o[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,19 @@ export namespace Strings {
|
|||||||
return new Function(`return \`${template}\`;`).call(context);
|
return new Function(`return \`${template}\`;`).call(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* lines(s: string): IterableIterator<string> {
|
||||||
|
let i = 0;
|
||||||
|
while (i < s.length) {
|
||||||
|
let j = s.indexOf('\n', i);
|
||||||
|
if (j === -1) {
|
||||||
|
j = s.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield s.substring(i, j);
|
||||||
|
i = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function padLeft(s: string, padTo: number, padding: string = '\u00a0') {
|
export function padLeft(s: string, padTo: number, padding: string = '\u00a0') {
|
||||||
const diff = padTo - s.length;
|
const diff = padTo - s.length;
|
||||||
return (diff <= 0) ? s : '\u00a0'.repeat(diff) + s;
|
return (diff <= 0) ? s : '\u00a0'.repeat(diff) + s;
|
||||||
|
|||||||
Reference in New Issue
Block a user