diff --git a/CHANGELOG.md b/CHANGELOG.md index 704d039..661093c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [8.2.0-beta] - 2018-03-26 ### Added +- Adds new *GitLens History* explorer to explore the history of the current file — same as the history view in the *GitLens* explorer when undocked + + ![GitLens History explorer](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/ss-gitlens-history-explorer.png) + - Adds rich tooltip details to the *GitLens* explorer and *GitLens Results* view - Adds richer working tree and upstream status information to branches in the *GitLens* explorer - Adds an indicator to the *GitLens* explorer's branch history to mark the synchronization point between the local and remote branch (if available) diff --git a/README.md b/README.md index 6ad3ddf..65adacc 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,18 @@ # What's new in GitLens 8 ## 8.2 — April 2018 -- Adds rich tooltip details to the *GitLens* explorer and *GitLens Results* view - - Adds richer working tree and upstream status information to branches in the *GitLens* explorer +- Adds new *GitLens History* explorer to explore the history of the current file — same as the history view in the *GitLens* explorer when undocked +- Adds richer tooltips to the *GitLens* explorer and *GitLens Results* view, and richer working tree and upstream status to the *GitLens* explorer - Adds an indicator to the *GitLens* explorer's branch history to mark the synchronization point between the local and remote branch (if available) - Adds ability to easily switch between relative and absolute dates via the `gitlens.defaultDateStyle` settings — closes [#312](https://github.com/eamodio/vscode-gitlens/issues/312) + - Adds `${agoOrDate}` and `${authorAgoOrDate}` tokens to `gitlens.blame.format`, `gitlens.currentLine.format`, `gitlens.explorers.commitFormat`, `gitlens.explorers.stashFormat`, and `gitlens.statusBar.format` settings which will honor the `gitlens.defaultDateStyle` setting +- Adds annotation format settings (`gitlens.*.format`) to the interactive settings editor - Adds `gitlens.currentLine.scrollable` setting to specify whether the current line blame annotation can be scrolled into view when it is outside the viewport — closes [#149](https://github.com/eamodio/vscode-gitlens/issues/149), [#290](https://github.com/eamodio/vscode-gitlens/issues/290), [#265](https://github.com/eamodio/vscode-gitlens/issues/265) +- Adds `gitlens.statusBar.reduceFlicker` setting to the interactive settings editor +- Adds a one-time notification on startup if the `alt-based` keyboard shortcuts are in use, with options to easily switch to another set - Adds *Copy Commit ID to Clipboard* (`gitlens.copyShaToClipboard`) command to changed file nodes in the *GitLens* explorer and *GitLens Results* view - Adds *Copy Commit Message to Clipboard* (`gitlens.copyMessageToClipboard`) command to changed file nodes in the *GitLens* explorer and *GitLens Results* view +- Moves *Keyboard Settings* to the *General* section of the interactive settings editor - Renames *Compare with Index (HEAD)* (`gitlens.explorers.compareWithHead`) command to *Compare with HEAD* — closes [#309](https://github.com/eamodio/vscode-gitlens/issues/309) - Renames *Compare Index (HEAD) with Branch or Tag...* (`gitlens.diffHeadWithBranch`) command to *Compare HEAD with Branch or Tag...* — closes [#309](https://github.com/eamodio/vscode-gitlens/issues/309) - Removes the unnecessary *Show File Blame Annotations* (`gitlens.showFileBlame`) command — *Toggle File Blame Annotations* (`gitlens.toggleFileBlame`) provides similar functionality @@ -95,7 +100,7 @@ For more advanced customizations, refer to the [settings documentation](#gitlens ## Features ### GitLens Explorer -A [customizable](#gitlens-explorer-settings "Jump to the GitLens Explorer settings") explorer to navigate and explore repositories or file histories. The GitLens explorer provides two views (modes) — a Repository view and a History view. +A [customizable](#gitlens-explorer-settings "Jump to the GitLens Explorer settings") explorer to navigate and explore repositories or file histories. The *GitLens* explorer provides two views (modes) — a Repository view and a History view. - A toolbar provides *Search Commits*, *Switch to Repository View* or *Switch to History View*, and *Refresh* commands - Quickly switch between views using the *Switch to Repository View* or *Switch to History View* commands - A context menu provides *Automatic Layout*, *List Layout*, *Tree Layout*, *Enable Automatic Refresh* or *Disable Automatic Refresh*, and *Follow Renames* or *Don't Follow Renames* commands @@ -169,8 +174,21 @@ The repository view provides a full Git repository explorer, which has the follo GitLens Explorer History view

-The history view provides the revision history of the active file, which has the following features, -- Automatically updates to track the active editor +The history view provides the revision history of the current file, which has the following features, +- Automatically updates to track the current editor +- A context menu provides *Open File*, *Open File in Remote* (if available), and *Refresh* commands +- An inline toolbar provides an *Open File* command +- Context menus for each revision (commit) provides + - *Open Changes*, *Open Changes with Working File*, *Open File*, *Open Revision*, *Open File in Remote* (if available), *Open Revision in Remote* (if available), *Apply Changes*, and *Show Commit File Details* commands + +--- +### GitLens History Explorer +

+ GitLens History Explorer +

+ +A [customizable](#gitlens-history-explorer-settings "Jump to the GitLens History Explorer settings") explorer to explore the history of the current file. This is same as the history view in the *GitLens* Explorer when undocked +- Automatically updates to track the current editor - A context menu provides *Open File*, *Open File in Remote* (if available), and *Refresh* commands - An inline toolbar provides an *Open File* command - Context menus for each revision (commit) provides @@ -383,8 +401,8 @@ An on-demand, [customizable](#gitlens-results-view-settings "Jump to the GitLens - Also supports [remote services with custom domains](#custom-remotes-settings "Jump to Custom Remotes settings"), such as **Bitbucket, Bitbucket Server (previously called Stash), GitHub, GitHub Enterprise, GitLab** - *Open Branches in Remote* command (`gitlens.openBranchesInRemote`) — opens the branches in the supported remote service - *Open Branch in Remote* command (`gitlens.openBranchInRemote`) — opens the current branch commits in the supported remote service - - *Open Commit in Remote* command (`gitlens.openCommitInRemote`) — opens the commit revision of the active line in the supported remote service - - *Open File in Remote* command (`gitlens.openFileInRemote`) — opens the active file/revision in the supported remote service + - *Open Commit in Remote* command (`gitlens.openCommitInRemote`) — opens the commit revision of the current line in the supported remote service + - *Open File in Remote* command (`gitlens.openFileInRemote`) — opens the current file/revision in the supported remote service - *Open Repository in Remote* command (`gitlens.openRepoInRemote`) — opens the repository in the supported remote service #### Branch History @@ -405,7 +423,7 @@ An on-demand, [customizable](#gitlens-results-view-settings "Jump to the GitLens File History Quick Pick Menu

-- 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 current file for exploring its commit history - Provides additional entries to *Show in Results*, *Show Branch History*, and *Open File in \* when available - Navigate back to the previous quick pick menu via `alt+left arrow`, if available - Navigate pages via `alt+,` and `alt+.` to go backward and forward respectively @@ -415,7 +433,7 @@ An on-demand, [customizable](#gitlens-results-view-settings "Jump to the GitLens Commit Details Quick Pick Menu

-- 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 current file - Quickly see the set of files changed in the commit, complete with status indicators for adds, changes, renames, and deletes - Provides additional entries to *Show in Results*, *Open Commit in \* when available, *Open Files*, *Open Revisions*, *Open Directory Compare with Previous Revision*, *Open Directory Compare with Working Tree*, *Copy Commit ID to Clipboard*, *Copy Commit Message to Clipboard* - Navigate back to the previous quick pick menu via `alt+left arrow`, if available @@ -426,7 +444,7 @@ An on-demand, [customizable](#gitlens-results-view-settings "Jump to the GitLens Commit File Details Quick Pick Menu

-- Adds a *Show Commit File 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 Commit File 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 current file - Provides entries to *Open Changes*, *Open Changes with Working File*, *Open File*, *Open Revision*, *Open File in \* when available, *Open Revision in \* when available, *Copy Commit ID to Clipboard*, *Copy Commit Message to Clipboard*, *Show Commit Details*, *Show File History*, and *Show Previous File History* - Navigate back to the previous quick pick menu via `alt+left arrow`, if available - Use the `alt+right arrow` shortcut on an entry to execute it without closing the quick pick menu, if possible — commands that open windows outside of VS Code will still close the quick pick menu unless [`"gitlens.advanced.quickPick.closeOnFocusOut": false`](#advanced-settings "Jump to Advanced settings") is set @@ -484,30 +502,30 @@ An on-demand, [customizable](#gitlens-results-view-settings "Jump to the GitLens - Adds a *Compare Working Tree with Branch or Tag...* command (`gitlens.diffWorkingWithBranch`) to compare the working tree with the selected branch or tag -- Adds a *Compare File with Branch or Tag...* command (`gitlens.diffWithBranch`) to compare the active file with the same file on the selected branch or tag +- Adds a *Compare File with Branch or Tag...* command (`gitlens.diffWithBranch`) to compare the current file with the same file on the selected branch or tag -- Adds a *Compare File with Next Revision* command (`gitlens.diffWithNext`) with a shortcut of `alt+.` to compare the active file/diff with the next commit revision +- Adds a *Compare File with Next Revision* command (`gitlens.diffWithNext`) with a shortcut of `alt+.` to compare the current file/diff with the next commit revision -- Adds a *Compare File with Previous Revision* command (`gitlens.diffWithPrevious`) with a shortcut of `alt+,` to compare the active file/diff with the previous commit revision +- Adds a *Compare File with Previous Revision* command (`gitlens.diffWithPrevious`) with a shortcut of `alt+,` to compare the current file/diff with the previous commit revision -- Adds a *Compare Line Revision with Previous* command (`gitlens.diffLineWithPrevious`) with a shortcut of `shift+alt+,` to compare the active file/diff with the previous line commit revision +- Adds a *Compare Line Revision with Previous* command (`gitlens.diffLineWithPrevious`) with a shortcut of `shift+alt+,` to compare the current file/diff with the previous line commit revision -- Adds a *Compare File with Revision...* command (`gitlens.diffWithRevision`) to compare the active file with the selected revision of the same file +- Adds a *Compare File with Revision...* command (`gitlens.diffWithRevision`) to compare the current file with the selected revision of the same file -- Adds a *Compare File with Working Revision* command (`gitlens.diffWithWorking`) with a shortcut of `shift+alt+w` to compare the most recent commit revision of the active file/diff with the working tree +- Adds a *Compare File with Working Revision* command (`gitlens.diffWithWorking`) with a shortcut of `shift+alt+w` to compare the most recent commit revision of the current file/diff with the working tree -- Adds a *Compare Line Revision with Working File* command (`gitlens.diffLineWithWorking`) with a shortcut of `alt+w` to compare the commit revision of the active line with the working tree +- Adds a *Compare Line Revision with Working File* command (`gitlens.diffLineWithWorking`) with a shortcut of `alt+w` to compare the commit revision of the current line with the working tree --- ### 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 or from the most recent commit to the current branch, if there is no active editor +- Adds a *Copy Commit ID to Clipboard* command (`gitlens.copyShaToClipboard`) to copy the commit id (sha) of the current line to the clipboard or from the most recent commit to the current branch, if there is no current editor -- Adds a *Copy Commit Message to Clipboard* command (`gitlens.copyMessageToClipboard`) to copy the commit message of the active line to the clipboard or from the most recent commit to the current branch, if there is no active editor +- Adds a *Copy Commit Message to Clipboard* command (`gitlens.copyMessageToClipboard`) to copy the commit message of the current line to the clipboard or from the most recent commit to the current branch, if there is no current editor -- Adds a *Open Working File"* command (`gitlens.openWorkingFile`) to open the working file for the active file revision +- Adds a *Open Working File"* command (`gitlens.openWorkingFile`) to open the working file for the current file revision -- Adds a *Open Revision...* command (`gitlens.openFileRevision`) to open the selected revision for the active file +- Adds a *Open Revision...* command (`gitlens.openFileRevision`) to open the selected revision for the current file - Adds a *Open Changes (with difftool)* command (`gitlens.externalDiff`) to the source control group and source control resource context menus to open the changes of a file or set of files with the configured git difftool @@ -549,7 +567,15 @@ See also [Explorer Settings](#explorer-settings "Jump to the Explorer settings") |`gitlens.gitExplorer.files.threshold`|Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the *GitLens* explorer
Only applies when displaying files as `auto` |`gitlens.gitExplorer.includeWorkingTree`|Specifies whether to include working tree files inside the `Repository Status` node of the *GitLens* explorer |`gitlens.gitExplorer.showTrackingBranch`|Specifies whether to show the tracking branch when displaying local branches in the *GitLens* explorer" -|`gitlens.gitExplorer.view`|Specifies the starting view (mode) of the *GitLens* explorer
`auto` - shows the last selected view, defaults to `repository`
`history` - shows the commit history of the active file
`repository` - shows a repository explorer" +|`gitlens.gitExplorer.view`|Specifies the starting view of the *GitLens* explorer
`auto` - shows the last selected view, defaults to `repository`
`history` - shows the commit history of the current file
`repository` - shows a repository explorer" + +### GitLens History Explorer Settings + +See also [Explorer Settings](#explorer-settings "Jump to the Explorer settings") + +|Name | Description +|-----|------------ +|`gitlens.historyExplorer.enabled`|Specifies whether to show the current file history undocked in a *GitLens History* explorer ### GitLens Results View Settings diff --git a/images/cl-history-explorer.png b/images/cl-history-explorer.png new file mode 100644 index 0000000..70ce7aa Binary files /dev/null and b/images/cl-history-explorer.png differ diff --git a/images/dark/icon-dock.svg b/images/dark/icon-dock.svg new file mode 100644 index 0000000..60f3e91 --- /dev/null +++ b/images/dark/icon-dock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/images/dark/icon-undock.svg b/images/dark/icon-undock.svg new file mode 100644 index 0000000..6852772 --- /dev/null +++ b/images/dark/icon-undock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/images/light/icon-dock.svg b/images/light/icon-dock.svg new file mode 100644 index 0000000..1971de2 --- /dev/null +++ b/images/light/icon-dock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/images/light/icon-undock.svg b/images/light/icon-undock.svg new file mode 100644 index 0000000..85d758d --- /dev/null +++ b/images/light/icon-undock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/images/ss-gitlens-explorer-history.png b/images/ss-gitlens-explorer-history.png index 385b30d..e4db7d4 100644 Binary files a/images/ss-gitlens-explorer-history.png and b/images/ss-gitlens-explorer-history.png differ diff --git a/images/ss-gitlens-history-explorer.png b/images/ss-gitlens-history-explorer.png new file mode 100644 index 0000000..70ce7aa Binary files /dev/null and b/images/ss-gitlens-history-explorer.png differ diff --git a/package.json b/package.json index daf5446..25c0cd7 100644 --- a/package.json +++ b/package.json @@ -472,7 +472,7 @@ "history", "repository" ], - "description": "Specifies the starting view (mode) of the `GitLens` explorer\n `auto` - shows the last selected view, defaults to `repository`\n `history` - shows the commit history of the active file\n `repository` - shows a repository explorer", + "description": "Specifies the starting view of the `GitLens` explorer\n `auto` - shows the last selected view, defaults to `repository`\n `history` - shows the commit history of the current file\n `repository` - shows a repository explorer", "scope": "window" }, "gitlens.heatmap.toggleMode": { @@ -485,6 +485,12 @@ "description": "Specifies how the gutter heatmap annotations will be toggled\n `file` - toggle each file individually\n `window` - toggle the window, i.e. all files at once", "scope": "window" }, + "gitlens.historyExplorer.enabled": { + "type": "boolean", + "default": false, + "description": "Specifies whether to show the current file history undocked in a `GitLens History` explorer", + "scope": "window" + }, "gitlens.hovers.annotations.changes": { "type": "boolean", "default": true, @@ -1555,6 +1561,15 @@ "category": "GitLens" }, { + "command": "gitlens.gitExplorer.undockHistory", + "title": "Undock History from GitLens Explorer", + "category": "GitLens", + "icon": { + "dark": "images/dark/icon-undock.svg", + "light": "images/light/icon-undock.svg" + } + }, + { "command": "gitlens.gitExplorer.refresh", "title": "Refresh", "category": "GitLens", @@ -1622,6 +1637,48 @@ } }, { + "command": "gitlens.historyExplorer.close", + "title": "Close", + "category": "GitLens", + "icon": { + "dark": "images/dark/icon-close.svg", + "light": "images/light/icon-close.svg" + } + }, + { + "command": "gitlens.historyExplorer.dock", + "title": "Dock History to GitLens Explorer", + "category": "GitLens", + "icon": { + "dark": "images/dark/icon-dock.svg", + "light": "images/light/icon-dock.svg" + } + }, + { + "command": "gitlens.historyExplorer.refresh", + "title": "Refresh", + "category": "GitLens", + "icon": { + "dark": "images/dark/icon-refresh.svg", + "light": "images/light/icon-refresh.svg" + } + }, + { + "command": "gitlens.historyExplorer.refreshNode", + "title": "Refresh", + "category": "GitLens" + }, + { + "command": "gitlens.historyExplorer.setRenameFollowingOn", + "title": "Follow Renames", + "category": "GitLens" + }, + { + "command": "gitlens.historyExplorer.setRenameFollowingOff", + "title": "Don't Follow Renames", + "category": "GitLens" + }, + { "command": "gitlens.resultsExplorer.clearResultsNode", "title": "Clear Results", "category": "GitLens", @@ -2044,11 +2101,39 @@ }, { "command": "gitlens.gitExplorer.switchToHistoryView", - "when": "gitlens:enabled && gitlens:gitExplorer:view == repository" + "when": "gitlens:enabled && !gitlens:historyExplorer && gitlens:gitExplorer:view == repository" }, { "command": "gitlens.gitExplorer.switchToRepositoryView", - "when": "gitlens:enabled && gitlens:gitExplorer:view == history" + "when": "gitlens:enabled && !gitlens:historyExplorer && gitlens:gitExplorer:view == history" + }, + { + "command": "gitlens.gitExplorer.undockHistory", + "when": "gitlens:enabled && !gitlens:historyExplorer" + }, + { + "command": "gitlens.historyExplorer.close", + "when": "false" + }, + { + "command": "gitlens.historyExplorer.dock", + "when": "gitlens:enabled && gitlens:historyExplorer" + }, + { + "command": "gitlens.historyExplorer.refresh", + "when": "false" + }, + { + "command": "gitlens.historyExplorer.refreshNode", + "when": "false" + }, + { + "command": "gitlens.historyExplorer.setRenameFollowingOn", + "when": "false" + }, + { + "command": "gitlens.historyExplorer.setRenameFollowingOff", + "when": "false" }, { "command": "gitlens.resultsExplorer.clearResultsNode", @@ -2321,19 +2406,24 @@ "group": "navigation@1" }, { - "command": "gitlens.gitExplorer.switchToHistoryView", - "when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == repository", + "command": "gitlens.gitExplorer.undockHistory", + "when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == history && !gitlens:historyExplorer", "group": "navigation@2" }, { + "command": "gitlens.gitExplorer.switchToHistoryView", + "when": "view == gitlens.gitExplorer && !gitlens:historyExplorer && gitlens:gitExplorer:view == repository", + "group": "navigation@3" + }, + { "command": "gitlens.gitExplorer.switchToRepositoryView", - "when": "view == gitlens.gitExplorer && gitlens:gitExplorer:view == history", + "when": "view == gitlens.gitExplorer && !gitlens:historyExplorer && gitlens:gitExplorer:view == history", "group": "navigation@3" }, { "command": "gitlens.gitExplorer.refresh", "when": "view == gitlens.gitExplorer", - "group": "navigation@4" + "group": "navigation@8" }, { "command": "gitlens.gitExplorer.setFilesLayoutToAuto", @@ -2371,6 +2461,31 @@ "group": "2_gitlens_1" }, { + "command": "gitlens.historyExplorer.refresh", + "when": "view == gitlens.historyExplorer", + "group": "navigation@1" + }, + { + "command": "gitlens.historyExplorer.dock", + "when": "view == gitlens.historyExplorer && gitlens:gitExplorer", + "group": "navigation@9" + }, + { + "command": "gitlens.historyExplorer.close", + "when": "view == gitlens.historyExplorer && !gitlens:gitExplorer", + "group": "navigation@9" + }, + { + "command": "gitlens.historyExplorer.setRenameFollowingOn", + "when": "view == gitlens.historyExplorer && !config.gitlens.advanced.fileHistoryFollowsRenames", + "group": "1_gitlens" + }, + { + "command": "gitlens.historyExplorer.setRenameFollowingOff", + "when": "view == gitlens.historyExplorer && config.gitlens.advanced.fileHistoryFollowsRenames", + "group": "1_gitlens" + }, + { "command": "gitlens.showCommitSearch", "when": "view == gitlens.resultsExplorer", "group": "navigation@1" @@ -2694,12 +2809,17 @@ }, { "command": "gitlens.gitExplorer.refreshNode", - "when": "view =~ /gitlens\\.gitExplorer/ && viewItem =~ /gitlens:(?!file\\b)/", + "when": "view == gitlens.gitExplorer && viewItem =~ /gitlens:(?!file\\b)/", "group": "9_gitlens@1" }, { "command": "gitlens.resultsExplorer.refreshNode", - "when": "view =~ /gitlens\\.resultsExplorer/ && viewItem =~ /gitlens:(?!file\\b)/", + "when": "view == gitlens.resultsExplorer && viewItem =~ /gitlens:(?!file\\b)/", + "group": "9_gitlens@1" + }, + { + "command": "gitlens.historyExplorer.refreshNode", + "when": "view == gitlens.historyExplorer && viewItem =~ /gitlens:(?!file\\b)/", "group": "9_gitlens@1" } ] @@ -2887,6 +3007,11 @@ "when": "gitlens:enabled && gitlens:gitExplorer" }, { + "id": "gitlens.historyExplorer", + "name": "GitLens History", + "when": "gitlens:enabled && gitlens:historyExplorer" + }, + { "id": "gitlens.resultsExplorer", "name": "GitLens Results", "when": "gitlens:enabled && gitlens:resultsExplorer" diff --git a/src/configuration.ts b/src/configuration.ts index da1b187..866b812 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -175,12 +175,15 @@ export class Configuration { async updateEffective(section: string, value: any, resource: Uri | null = null) { const inspect = await configuration.inspect(section, resource)!; if (inspect.workspaceFolderValue !== undefined) { + if (inspect.workspaceFolderValue === value) return; await configuration.update(section, value, ConfigurationTarget.WorkspaceFolder, resource); } else if (inspect.workspaceValue !== undefined) { + if (inspect.workspaceValue === value) return; await configuration.update(section, value, ConfigurationTarget.Workspace); } else { + if (inspect.globalValue === value) return; await configuration.update(section, value, ConfigurationTarget.Global); } } diff --git a/src/constants.ts b/src/constants.ts index 271ea9a..5c93864 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -40,6 +40,7 @@ export enum CommandContext { GitExplorerAutoRefresh = 'gitlens:gitExplorer:autoRefresh', GitExplorerView = 'gitlens:gitExplorer:view', HasRemotes = 'gitlens:hasRemotes', + HistoryExplorer = 'gitlens:historyExplorer', Key = 'gitlens:key', KeyMap = 'gitlens:keymap', ResultsExplorer = 'gitlens:resultsExplorer', diff --git a/src/container.ts b/src/container.ts index 535a126..05db281 100644 --- a/src/container.ts +++ b/src/container.ts @@ -12,6 +12,7 @@ import { GitExplorer } from './views/gitExplorer'; import { GitLineTracker } from './trackers/gitLineTracker'; import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider'; import { GitService } from './gitService'; +import { HistoryExplorer } from './views/historyExplorer'; import { Keyboard } from './keyboard'; import { PageProvider } from './pageProvider'; import { ResultsExplorer } from './views/resultsExplorer'; @@ -51,6 +52,19 @@ export class Container { }); } + if (config.historyExplorer.enabled) { + context.subscriptions.push(this._historyExplorer = new HistoryExplorer()); + } + else { + let disposable: Disposable; + disposable = configuration.onDidChange(e => { + if (configuration.changed(e, configuration.name('historyExplorer')('enabled').value)) { + disposable.dispose(); + context.subscriptions.push(this._historyExplorer = new HistoryExplorer()); + } + }); + } + context.subscriptions.push(workspace.registerTextDocumentContentProvider(GitContentProvider.scheme, new GitContentProvider())); context.subscriptions.push(languages.registerCodeLensProvider(GitRevisionCodeLensProvider.selector, new GitRevisionCodeLensProvider())); } @@ -96,6 +110,15 @@ export class Container { return this._gitExplorer!; } + private static _historyExplorer: HistoryExplorer | undefined; + static get historyExplorer() { + if (this._historyExplorer === undefined) { + this._context.subscriptions.push(this._historyExplorer = new HistoryExplorer()); + } + + return this._historyExplorer; + } + private static _keyboard: Keyboard; static get keyboard() { return this._keyboard; diff --git a/src/ui/config.ts b/src/ui/config.ts index 743816e..67e27ce 100644 --- a/src/ui/config.ts +++ b/src/ui/config.ts @@ -222,6 +222,10 @@ export interface IGitExplorerConfig { view: GitExplorerView; } +export interface IHistoryExplorerConfig { + enabled: boolean; +} + export interface IResultsExplorerConfig { files: IExplorersFilesConfig; } @@ -287,6 +291,8 @@ export interface IConfig { toggleMode: AnnotationsToggleMode; }; + historyExplorer: IHistoryExplorerConfig; + hovers: { annotations: { changes: boolean; diff --git a/src/ui/images/settings/gitlens-explorer-history.png b/src/ui/images/settings/gitlens-explorer-history.png index b094bb7..4b42e49 100644 Binary files a/src/ui/images/settings/gitlens-explorer-history.png and b/src/ui/images/settings/gitlens-explorer-history.png differ diff --git a/src/ui/images/settings/gitlens-explorer-repository-history-docked.png b/src/ui/images/settings/gitlens-explorer-repository-history-docked.png new file mode 100644 index 0000000..57efcb3 Binary files /dev/null and b/src/ui/images/settings/gitlens-explorer-repository-history-docked.png differ diff --git a/src/ui/images/settings/gitlens-explorer-repository-history-undocked.png b/src/ui/images/settings/gitlens-explorer-repository-history-undocked.png new file mode 100644 index 0000000..49de22a Binary files /dev/null and b/src/ui/images/settings/gitlens-explorer-repository-history-undocked.png differ diff --git a/src/ui/images/settings/gitlens-explorer-repository-tree-compact.png b/src/ui/images/settings/gitlens-explorer-repository-tree-compact.png index dc9fd6c..4ed6830 100644 Binary files a/src/ui/images/settings/gitlens-explorer-repository-tree-compact.png and b/src/ui/images/settings/gitlens-explorer-repository-tree-compact.png differ diff --git a/src/ui/images/settings/gitlens-explorer-repository-tree.png b/src/ui/images/settings/gitlens-explorer-repository-tree.png index 6dc28c5..14c0c4f 100644 Binary files a/src/ui/images/settings/gitlens-explorer-repository-tree.png and b/src/ui/images/settings/gitlens-explorer-repository-tree.png differ diff --git a/src/ui/images/settings/gitlens-explorer-repository.png b/src/ui/images/settings/gitlens-explorer-repository.png index 02b0673..b85caa7 100644 Binary files a/src/ui/images/settings/gitlens-explorer-repository.png and b/src/ui/images/settings/gitlens-explorer-repository.png differ diff --git a/src/ui/images/settings/gitlens-history-explorer-close.png b/src/ui/images/settings/gitlens-history-explorer-close.png new file mode 100644 index 0000000..cc15427 Binary files /dev/null and b/src/ui/images/settings/gitlens-history-explorer-close.png differ diff --git a/src/ui/images/settings/gitlens-history-explorer.png b/src/ui/images/settings/gitlens-history-explorer.png new file mode 100644 index 0000000..67e3dc8 Binary files /dev/null and b/src/ui/images/settings/gitlens-history-explorer.png differ diff --git a/src/ui/scss/main.scss b/src/ui/scss/main.scss index 744266d..ab20d83 100644 --- a/src/ui/scss/main.scss +++ b/src/ui/scss/main.scss @@ -853,15 +853,7 @@ ul { .setting__hint { color: var(--color--50); font-size: 0.9em; - margin: -1em 0 1em 3em; -} - -.setting__hint--indent-2 { - margin-left: 5em; -} - -.setting__hint--indent-4 { - margin-left: 7em; + margin: -1em 0 1em 1em; } .settings-scope { @@ -908,6 +900,10 @@ ul { margin-left: 2em; } +.ml-3 { + margin-left: 3em; +} + .ml-4 { margin-left: 4em; } diff --git a/src/ui/settings/index.html b/src/ui/settings/index.html index 0c49dd5..1f9c56c 100644 --- a/src/ui/settings/index.html +++ b/src/ui/settings/index.html @@ -128,13 +128,18 @@ -
+
- +
@@ -153,13 +158,13 @@
- +
-

Compacts (flattens) unnecessary nesting when using a tree layouts

+

Compacts (flattens) unnecessary nesting when using a tree layouts

@@ -175,10 +180,18 @@ - - - + + + + + + + + + + +

@@ -187,6 +200,39 @@

+
+
+

GitLens History Explorer + + + +

+

Adds a GitLens History explorer to explore the history of the current file

+
+
+
+
+ + +
+ + +
+ + +
+
+
+ + + + + + +
+
+
+

GitLens Results @@ -211,7 +257,7 @@

-

Compacts (flattens) unnecessary nesting when using a tree layouts

+

Compacts (flattens) unnecessary nesting when using a tree layouts

@@ -223,7 +269,7 @@ - +

@@ -370,7 +416,7 @@ -

When enabled the annotation can be scrolled into view when it is outside the viewport

+

When enabled the annotation can be scrolled into view when it is outside the viewport

@@ -789,7 +835,7 @@
-

Avoids clearing the previous blame information when changing lines to reduce status bar "flashing"

+

Avoids clearing the previous blame information when changing lines to reduce status bar "flashing"

@@ -816,6 +862,7 @@
  • General
  • GitLens Explorer
  • +
  • GitLens History Explorer
  • GitLens Results
  • Code Lens
  • Current Line Blame
  • diff --git a/src/ui/welcome/index.html b/src/ui/welcome/index.html index 1140436..28f1778 100644 --- a/src/ui/welcome/index.html +++ b/src/ui/welcome/index.html @@ -46,6 +46,12 @@
  • NEW + Adds new GitLens History explorer to explore the history of the current file — same as the history view in the GitLens explorer when undocked +
    + GitLens History explorer +
    +
  • +
  • NEW Adds rich tooltip details to the GitLens explorer and GitLens Results view
    diff --git a/src/views/branchFolderNode.ts b/src/views/branchFolderNode.ts index 6195f32..a8538f8 100644 --- a/src/views/branchFolderNode.ts +++ b/src/views/branchFolderNode.ts @@ -1,6 +1,6 @@ 'use strict'; import { Arrays, Objects } from '../system'; -import { TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { BranchNode } from './branchNode'; // import { Container } from '../container'; import { Explorer, ExplorerNode, ResourceType } from './explorerNode'; @@ -37,7 +37,7 @@ export class BranchFolderNode extends ExplorerNode { async getTreeItem(): Promise { const item = new TreeItem(this.label, TreeItemCollapsibleState.Collapsed); item.contextValue = ResourceType.Folder; - item.resourceUri = this.explorer.folderResourceUri; + item.iconPath = ThemeIcon.Folder; item.tooltip = this.label; return item; } diff --git a/src/views/explorerNode.ts b/src/views/explorerNode.ts index 771347c..939e448 100644 --- a/src/views/explorerNode.ts +++ b/src/views/explorerNode.ts @@ -5,6 +5,7 @@ import { Container } from '../container'; import { RefreshNodeCommandArgs } from './explorerCommands'; import { GitUri } from '../gitService'; import { GitExplorer } from './gitExplorer'; +import { HistoryExplorer } from './historyExplorer'; import { ResultsExplorer } from './resultsExplorer'; export interface NamedRef { @@ -61,7 +62,7 @@ export enum ResourceType { Tags = 'gitlens:tags' } -export type Explorer = GitExplorer | ResultsExplorer; +export type Explorer = GitExplorer | HistoryExplorer | ResultsExplorer; // let id = 0; diff --git a/src/views/fileHistoryNode.ts b/src/views/fileHistoryNode.ts index 4e11150..6c1325c 100644 --- a/src/views/fileHistoryNode.ts +++ b/src/views/fileHistoryNode.ts @@ -1,10 +1,9 @@ 'use strict'; import { Iterables } from '../system'; -import { Disposable, TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode'; import { Container } from '../container'; -import { ExplorerNode, MessageNode, ResourceType } from './explorerNode'; -import { GitExplorer } from './gitExplorer'; +import { Explorer, ExplorerNode, MessageNode, ResourceType } from './explorerNode'; import { GitCommitType, GitLogCommit, GitService, GitUri, Repository, RepositoryChange, RepositoryChangeEvent } from '../gitService'; import { Logger } from '../logger'; @@ -13,7 +12,7 @@ export class FileHistoryNode extends ExplorerNode { constructor( uri: GitUri, private readonly repo: Repository, - private readonly explorer: GitExplorer + private readonly explorer: Explorer ) { super(uri); } @@ -85,36 +84,13 @@ export class FileHistoryNode extends ExplorerNode { } private updateSubscription() { - // We only need to subscribe if auto-refresh is enabled, because if it becomes enabled we will be refreshed - if (this.explorer.autoRefresh) { - this.disposable = this.disposable || Disposable.from( - this.explorer.onDidChangeAutoRefresh(this.onAutoRefreshChanged, this), - this.repo.onDidChange(this.onRepoChanged, this) - // Container.gitContextTracker.onDidChangeBlameability(this.onBlameabilityChanged, this) - ); - } - else if (this.disposable !== undefined) { - this.disposable.dispose(); - this.disposable = undefined; - } - } - - private onAutoRefreshChanged() { - this.updateSubscription(); + this.disposable = this.disposable || this.repo.onDidChange(this.onRepoChanged, this); } - // private onBlameabilityChanged(e: BlameabilityChangeEvent) { - // if (!e.blameable || e.reason !== BlameabilityChangeReason.DocumentChanged) return; - - // // Logger.log(`RepositoryNode.onBlameabilityChanged(${e.reason}); triggering node refresh`); - - // this.explorer.refreshNode(this); - // } - private onRepoChanged(e: RepositoryChangeEvent) { if (!e.changed(RepositoryChange.Repository)) return; - Logger.log(`RepositoryNode.onRepoChanged(${e.changes.join()}); triggering node refresh`); + Logger.log(`FileHistoryNode.onRepoChanged(${e.changes.join()}); triggering node refresh`); this.explorer.refreshNode(this); } diff --git a/src/views/folderNode.ts b/src/views/folderNode.ts index 93e5832..bd9d700 100644 --- a/src/views/folderNode.ts +++ b/src/views/folderNode.ts @@ -1,6 +1,6 @@ 'use strict'; import { Arrays, Objects } from '../system'; -import { TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ExplorerFilesLayout, IExplorersFilesConfig } from '../configuration'; import { Explorer, ExplorerNode, ResourceType } from './explorerNode'; import { GitUri } from '../gitService'; @@ -63,7 +63,7 @@ export class FolderNode extends ExplorerNode { // TODO: Change this to expanded once https://github.com/Microsoft/vscode/issues/30918 is fixed const item = new TreeItem(this.label, TreeItemCollapsibleState.Collapsed); item.contextValue = ResourceType.Folder; - item.resourceUri = this.explorer.folderResourceUri; + item.iconPath = ThemeIcon.Folder; item.tooltip = this.label; return item; } diff --git a/src/views/gitExplorer.ts b/src/views/gitExplorer.ts index 0d6864e..46619f7 100644 --- a/src/views/gitExplorer.ts +++ b/src/views/gitExplorer.ts @@ -1,12 +1,12 @@ 'use strict'; import { Functions } from '../system'; -import { commands, ConfigurationChangeEvent, ConfigurationTarget, Disposable, Event, EventEmitter, TextDocumentShowOptions, TextEditor, TreeDataProvider, TreeItem, Uri, window, workspace } from 'vscode'; +import { commands, ConfigurationChangeEvent, ConfigurationTarget, Disposable, Event, EventEmitter, TextDocumentShowOptions, TextEditor, TreeDataProvider, TreeItem, Uri, window } from 'vscode'; import { UriComparer } from '../comparers'; import { configuration, ExplorerFilesLayout, GitExplorerView, IExplorersConfig, IGitExplorerConfig } from '../configuration'; import { CommandContext, GlyphChars, setCommandContext, WorkspaceState } from '../constants'; import { Container } from '../container'; import { RefreshNodeCommandArgs } from './explorerCommands'; -import { ExplorerNode, HistoryNode, MessageNode, RefreshReason, RepositoriesNode, RepositoryNode } from './explorerNodes'; +import { Explorer, ExplorerNode, HistoryNode, MessageNode, RefreshReason, RepositoriesNode, RepositoryNode } from './explorerNodes'; import { GitUri } from '../gitService'; import { Logger } from '../logger'; @@ -21,7 +21,6 @@ export class GitExplorer extends Disposable implements TreeDataProvider(); public get onDidChangeAutoRefresh(): Event { @@ -45,11 +44,13 @@ export class GitExplorer extends Disposable implements TreeDataProvider this.setAutoRefresh(Container.config.gitExplorer.autoRefresh, true), this); commands.registerCommand('gitlens.gitExplorer.setAutoRefreshToOff', () => this.setAutoRefresh(Container.config.gitExplorer.autoRefresh, false), this); - commands.registerCommand('gitlens.gitExplorer.setRenameFollowingOn', () => this.setRenameFollowing(true), this); - commands.registerCommand('gitlens.gitExplorer.setRenameFollowingOff', () => this.setRenameFollowing(false), this); + commands.registerCommand('gitlens.gitExplorer.setRenameFollowingOn', () => GitExplorer.setRenameFollowing(true), this); + commands.registerCommand('gitlens.gitExplorer.setRenameFollowingOff', () => GitExplorer.setRenameFollowing(false), this); commands.registerCommand('gitlens.gitExplorer.switchToHistoryView', () => this.switchTo(GitExplorerView.History), this); commands.registerCommand('gitlens.gitExplorer.switchToRepositoryView', () => this.switchTo(GitExplorerView.Repository), this); + commands.registerCommand('gitlens.gitExplorer.undockHistory', this.undockHistory, this); + Container.context.subscriptions.push( window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveEditorChanged, 500), this), window.onDidChangeVisibleTextEditors(Functions.debounce(this.onVisibleEditorsChanged, 500), this), @@ -62,15 +63,6 @@ export class GitExplorer extends Disposable implements TreeDataProvider e.document && Container.git.isTrackable(e.document.uri))) { @@ -141,11 +151,12 @@ export class GitExplorer extends Disposable implements TreeDataProvider | undefined; @@ -157,7 +168,7 @@ export class GitExplorer extends Disposable implements TreeDataProvider { - switch (this._view) { - case GitExplorerView.History: { - const promise = this.getHistoryNode(editor || window.activeTextEditor); - this._loading = promise.then(_ => Functions.wait(0)); - return promise; - } - default: { - const promise = Container.git.getRepositories(); - this._loading = promise.then(_ => Functions.wait(0)); - - const repositories = [...await promise]; - if (repositories.length === 0) return undefined; // new MessageNode('No repositories found'); - - if (repositories.length === 1) { - const repo = repositories[0]; - return new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this, true); - } - - return new RepositoriesNode(repositories, this); - } - } - } - - private async getHistoryNode(editor: TextEditor | undefined): Promise { - // If we have no active editor, or no visible editors, or no trackable visible editors reset the view - if (editor === undefined || window.visibleTextEditors.length === 0 || !window.visibleTextEditors.some(e => e.document && Container.git.isTrackable(e.document.uri))) return undefined; - // If we do have a visible trackable editor, don't change from the last state (avoids issues when focus switches to the problems/output/debug console panes) - if (editor.document === undefined || !Container.git.isTrackable(editor.document.uri)) return this._root; - - const uri = await GitUri.fromUri(editor.document.uri); - - const repo = await Container.git.getRepository(uri); - if (repo === undefined) return undefined; - - if (UriComparer.equals(uri, this._root && this._root.uri)) return this._root; - - return new HistoryNode(uri, repo, this); - } - getQualifiedCommand(command: string) { return `gitlens.gitExplorer.${command}`; } @@ -218,9 +189,9 @@ export class GitExplorer extends Disposable implements TreeDataProvider(WorkspaceState.GitExplorerAutoRefresh, true); + } + else { + toggled = workspaceEnabled; + await Container.context.workspaceState.update(WorkspaceState.GitExplorerAutoRefresh, workspaceEnabled); - private setRoot(root: ExplorerNode | undefined): boolean { - if (this._root === root) return false; + this._onDidChangeAutoRefresh.fire(); + } - if (this._root !== undefined) { - this._root.dispose(); + if (workspaceEnabled) { + this._autoRefreshDisposable = Container.git.onDidChangeRepositories(this.onRepositoriesChanged, this); + Container.context.subscriptions.push(this._autoRefreshDisposable); + } } - this._root = root; - return true; + setCommandContext(CommandContext.GitExplorerAutoRefresh, enabled && workspaceEnabled); + + if (toggled) { + this.refresh(RefreshReason.AutoRefreshChanged); + } } setView(view: GitExplorerView) { - if (this._view === view) return; + if (this.view === view) return; if (Container.config.gitExplorer.view === GitExplorerView.Auto) { Container.context.workspaceState.update(WorkspaceState.GitExplorerView, view); } - this._view = view; - setCommandContext(CommandContext.GitExplorerView, this._view); + this.view = view; + setCommandContext(CommandContext.GitExplorerView, this.view); if (view !== GitExplorerView.Repository) { Container.git.stopWatchingFileSystem(); @@ -291,45 +273,86 @@ export class GitExplorer extends Disposable implements TreeDataProvider(WorkspaceState.GitExplorerAutoRefresh, true); - } - else { - toggled = workspaceEnabled; - await Container.context.workspaceState.update(WorkspaceState.GitExplorerAutoRefresh, workspaceEnabled); + this._root.dispose(); + this._root = undefined; + } - this._onDidChangeAutoRefresh.fire(); + private async getRootNode(editor?: TextEditor): Promise { + switch (this.view) { + case GitExplorerView.History: { + const promise = this.getHistoryNode(editor || window.activeTextEditor); + this._loading = promise.then(_ => Functions.wait(0)); + return promise; } + default: { + const promise = Container.git.getRepositories(); + this._loading = promise.then(_ => Functions.wait(0)); - if (workspaceEnabled) { - this._autoRefreshDisposable = Container.git.onDidChangeRepositories(this.onRepositoriesChanged, this); - Container.context.subscriptions.push(this._autoRefreshDisposable); + const repositories = [...await promise]; + if (repositories.length === 0) return undefined; // new MessageNode('No repositories found'); + + if (repositories.length === 1) { + const repo = repositories[0]; + return new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this, true); + } + + return new RepositoriesNode(repositories, this); } } + } - setCommandContext(CommandContext.GitExplorerAutoRefresh, enabled && workspaceEnabled); + private async getHistoryNode(editor: TextEditor | undefined): Promise { + return GitExplorer.getHistoryNode(this, editor, this._root); + } - if (toggled) { - this.refresh(RefreshReason.AutoRefreshChanged); + private async setFilesLayout(layout: ExplorerFilesLayout) { + return configuration.update(configuration.name('gitExplorer')('files')('layout').value, layout, ConfigurationTarget.Global); + } + + private setRoot(root: ExplorerNode | undefined): boolean { + if (this._root === root) return false; + + if (this._root !== undefined) { + this._root.dispose(); } + + this._root = root; + return true; + } + + private async undockHistory(switchView: boolean = true) { + Container.historyExplorer.undock(switchView); + } + + static async getHistoryNode(explorer: Explorer, editor: TextEditor | undefined, root: ExplorerNode | undefined): Promise { + // If we have no active editor, or no visible editors, or no trackable visible editors reset the view + if (editor === undefined || window.visibleTextEditors.length === 0 || !window.visibleTextEditors.some(e => e.document && Container.git.isTrackable(e.document.uri))) return undefined; + // If we do have a visible trackable editor, don't change from the last state (avoids issues when focus switches to the problems/output/debug console panes) + if (editor.document === undefined || !Container.git.isTrackable(editor.document.uri)) return root; + + const uri = await GitUri.fromUri(editor.document.uri); + + const repo = await Container.git.getRepository(uri); + if (repo === undefined) return undefined; + + if (UriComparer.equals(uri, root && root.uri)) return root; + + return new HistoryNode(uri, repo, explorer); } - setRenameFollowing(enabled: boolean) { + static setRenameFollowing(enabled: boolean) { configuration.updateEffective(configuration.name('advanced')('fileHistoryFollowsRenames').value, enabled); } } \ No newline at end of file diff --git a/src/views/historyExplorer.ts b/src/views/historyExplorer.ts new file mode 100644 index 0000000..116a522 --- /dev/null +++ b/src/views/historyExplorer.ts @@ -0,0 +1,178 @@ +'use strict'; +import { Functions } from '../system'; +import { commands, ConfigurationChangeEvent, Disposable, Event, EventEmitter, TextEditor, TreeDataProvider, TreeItem, window } from 'vscode'; +import { configuration, GitExplorerView, IExplorersConfig } from '../configuration'; +import { CommandContext, GlyphChars, setCommandContext } from '../constants'; +import { Container } from '../container'; +import { RefreshNodeCommandArgs } from './explorerCommands'; +import { ExplorerNode, MessageNode, RefreshReason } from './explorerNodes'; +import { GitExplorer } from './gitExplorer'; +import { Logger } from '../logger'; + +export * from './explorerNodes'; + +export class HistoryExplorer extends Disposable implements TreeDataProvider { + + private _disposable: Disposable | undefined; + private _root?: ExplorerNode; + + private _onDidChangeTreeData = new EventEmitter(); + public get onDidChangeTreeData(): Event { + return this._onDidChangeTreeData.event; + } + + constructor() { + super(() => this.dispose()); + + Container.explorerCommands; + commands.registerCommand('gitlens.historyExplorer.refresh', this.refresh, this); + commands.registerCommand('gitlens.historyExplorer.refreshNode', this.refreshNode, this); + commands.registerCommand('gitlens.historyExplorer.close', () => this.dock(false), this); + commands.registerCommand('gitlens.historyExplorer.dock', this.dock, this); + + commands.registerCommand('gitlens.historyExplorer.setRenameFollowingOn', () => GitExplorer.setRenameFollowing(true), this); + commands.registerCommand('gitlens.historyExplorer.setRenameFollowingOff', () => GitExplorer.setRenameFollowing(false), this); + + Container.context.subscriptions.push( + window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveEditorChanged, 500), this), + window.onDidChangeVisibleTextEditors(Functions.debounce(this.onVisibleEditorsChanged, 500), this), + configuration.onDidChange(this.onConfigurationChanged, this) + ); + this.onConfigurationChanged(configuration.initializingChangeEvent); + } + + dispose() { + this._disposable && this._disposable.dispose(); + } + + private async onConfigurationChanged(e: ConfigurationChangeEvent) { + const initializing = configuration.initializing(e); + + if (!initializing && + !configuration.changed(e, configuration.name('historyExplorer').value) && + !configuration.changed(e, configuration.name('explorers').value) && + !configuration.changed(e, configuration.name('defaultGravatarsStyle').value) && + !configuration.changed(e, configuration.name('advanced')('fileHistoryFollowsRenames').value)) return; + + if (initializing || configuration.changed(e, configuration.name('historyExplorer')('enabled').value)) { + if (Container.config.historyExplorer.enabled) { + this.undock(!initializing); + } + else { + this.dock(!initializing); + } + } + + if (!initializing && this._root === undefined) { + this.refresh(RefreshReason.ConfigurationChanged); + } + + if (initializing) { + this.setRoot(await this.getRootNode(window.activeTextEditor)); + + this._disposable = window.registerTreeDataProvider('gitlens.historyExplorer', this); + } + } + + private async onActiveEditorChanged(editor: TextEditor | undefined) { + const root = await this.getRootNode(editor); + if (!this.setRoot(root)) return; + + this.refresh(RefreshReason.ActiveEditorChanged, root); + } + + private onVisibleEditorsChanged(editors: TextEditor[]) { + if (this._root === undefined) return; + + // If we have no visible editors, or no trackable visible editors reset the view + if (editors.length === 0 || !editors.some(e => e.document && Container.git.isTrackable(e.document.uri))) { + this.clearRoot(); + + this.refresh(RefreshReason.VisibleEditorsChanged); + } + } + + get config(): IExplorersConfig { + return { ...Container.config.explorers }; + } + + async getChildren(node?: ExplorerNode): Promise { + if (this._root === undefined) return [new MessageNode(`No active file ${GlyphChars.Dash} no history to show`)]; + + if (node === undefined) return this._root.getChildren(); + return node.getChildren(); + } + + async getTreeItem(node: ExplorerNode): Promise { + return node.getTreeItem(); + } + + async dock(switchView: boolean = true) { + if (switchView) { + await Container.gitExplorer.switchTo(GitExplorerView.History); + } + setCommandContext(CommandContext.HistoryExplorer, false); + configuration.updateEffective(configuration.name('historyExplorer')('enabled').value, false); + } + + getQualifiedCommand(command: string) { + return `gitlens.historyExplorer.${command}`; + } + + async refresh(reason?: RefreshReason, root?: ExplorerNode) { + if (reason === undefined) { + reason = RefreshReason.Command; + } + + Logger.log(`HistoryExplorer.refresh`, `reason='${reason}'`); + + if (this._root === undefined || root === undefined) { + this.clearRoot(); + this.setRoot(await this.getRootNode(window.activeTextEditor)); + } + + this._onDidChangeTreeData.fire(); + } + + refreshNode(node: ExplorerNode, args?: RefreshNodeCommandArgs) { + Logger.log(`HistoryExplorer.refreshNode(${(node as any).id})`); + + if (args !== undefined && node.supportsPaging) { + node.maxCount = args.maxCount; + } + node.refresh(); + + // Since a root node won't actually refresh, force everything + this._onDidChangeTreeData.fire(this._root === node ? undefined : node); + } + + async undock(switchView: boolean = true) { + if (switchView) { + await Container.gitExplorer.switchTo(GitExplorerView.Repository); + } + setCommandContext(CommandContext.HistoryExplorer, true); + configuration.updateEffective(configuration.name('historyExplorer')('enabled').value, true); + } + + private clearRoot() { + if (this._root === undefined) return; + + this._root.dispose(); + this._root = undefined; + } + + private async getRootNode(editor: TextEditor | undefined): Promise { + return GitExplorer.getHistoryNode(this, editor, this._root); + } + + private setRoot(root: ExplorerNode | undefined): boolean { + if (this._root === root) return false; + + if (this._root !== undefined) { + this._root.dispose(); + } + + this._root = root; + return true; + } +} \ No newline at end of file diff --git a/src/views/historyNode.ts b/src/views/historyNode.ts index f02394f..b351973 100644 --- a/src/views/historyNode.ts +++ b/src/views/historyNode.ts @@ -1,9 +1,8 @@ 'use strict'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { Container } from '../container'; -import { ExplorerNode, ResourceType } from './explorerNode'; +import { Explorer, ExplorerNode, ResourceType } from './explorerNode'; import { FileHistoryNode } from './fileHistoryNode'; -import { GitExplorer } from './gitExplorer'; import { GitUri, Repository } from '../gitService'; export class HistoryNode extends ExplorerNode { @@ -11,7 +10,7 @@ export class HistoryNode extends ExplorerNode { constructor( uri: GitUri, private readonly repo: Repository, - private readonly explorer: GitExplorer + private readonly explorer: Explorer ) { super(uri); } diff --git a/src/views/resultsExplorer.ts b/src/views/resultsExplorer.ts index d050780..22ef4f7 100644 --- a/src/views/resultsExplorer.ts +++ b/src/views/resultsExplorer.ts @@ -1,6 +1,6 @@ 'use strict'; import { Functions, Strings } from '../system'; -import { commands, ConfigurationChangeEvent, ConfigurationTarget, Disposable, Event, EventEmitter, TreeDataProvider, TreeItem, Uri, window, workspace } from 'vscode'; +import { commands, ConfigurationChangeEvent, ConfigurationTarget, Disposable, Event, EventEmitter, TreeDataProvider, TreeItem, window } from 'vscode'; import { configuration, ExplorerFilesLayout, IExplorersConfig, IResultsExplorerConfig } from '../configuration'; import { CommandContext, GlyphChars, setCommandContext, WorkspaceState } from '../constants'; import { Container } from '../container'; @@ -71,13 +71,6 @@ export class ResultsExplorer extends Disposable implements TreeDataProvider(WorkspaceState.ResultsExplorerKeepResults, false); } @@ -113,7 +106,7 @@ export class ResultsExplorer extends Disposable implements TreeDataProvider