diff --git a/images/dark/icon-clear.svg b/images/dark/icon-clear.svg
new file mode 100644
index 0000000..0317c44
--- /dev/null
+++ b/images/dark/icon-clear.svg
@@ -0,0 +1,4 @@
+
diff --git a/images/light/icon-clear.svg b/images/light/icon-clear.svg
new file mode 100644
index 0000000..21e1875
--- /dev/null
+++ b/images/light/icon-clear.svg
@@ -0,0 +1,4 @@
+
diff --git a/package.json b/package.json
index 279d651..22f46cf 100644
--- a/package.json
+++ b/package.json
@@ -1256,7 +1256,7 @@
"gitlens.views.repositories.includeWorkingTree": {
"type": "boolean",
"default": true,
- "description": "Specifies whether to include working tree files inside the `Repository Status` node of the `Repositories` view",
+ "description": "Specifies whether to include working tree files inside the `Repository` node of the `Repositories` view",
"scope": "window"
},
"gitlens.views.repositories.location": {
@@ -1296,7 +1296,7 @@
"tree"
],
"enumDescriptions": [
- "Automatically switches between displaying files as a `tree` or `list` based on the `#gitlens.views.repositories.files.threshold#` value and the number of files at each nesting level",
+ "Automatically switches between displaying files as a `tree` or `list` based on the `#gitlens.views.results.files.threshold#` value and the number of files at each nesting level",
"Displays files as a list",
"Displays files as a tree"
],
@@ -1325,6 +1325,56 @@
"description": "Specifies where to show the `Results` view",
"scope": "window"
},
+ "gitlens.views.search.enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Specifies whether to show the `Search Commits` view",
+ "scope": "window"
+ },
+ "gitlens.views.search.files.compact": {
+ "type": "boolean",
+ "default": true,
+ "description": "Specifies whether to compact (flatten) unnecessary file nesting in the `Search Commits` view\nOnly applies when `#gitlens.views.search.files.layout#` is set to `tree` or `auto`",
+ "scope": "window"
+ },
+ "gitlens.views.search.files.layout": {
+ "type": "string",
+ "default": "auto",
+ "enum": [
+ "auto",
+ "list",
+ "tree"
+ ],
+ "enumDescriptions": [
+ "Automatically switches between displaying files as a `tree` or `list` based on the `#gitlens.views.search.files.threshold#` value and the number of files at each nesting level",
+ "Displays files as a list",
+ "Displays files as a tree"
+ ],
+ "description": "Specifies how the `Results` view will display files",
+ "scope": "window"
+ },
+ "gitlens.views.search.files.threshold": {
+ "type": "number",
+ "default": 5,
+ "description": "Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the `Search Commits` view\nOnly applies when `#gitlens.views.search.files.layout#` is set to `auto`",
+ "scope": "window"
+ },
+ "gitlens.views.search.location": {
+ "type": "string",
+ "default": "gitlens",
+ "enum": [
+ "gitlens",
+ "explorer",
+ "scm"
+ ],
+ "enumDescriptions": [
+ "Adds to the GitLens view",
+ "Adds to the Explorer view",
+ "Adds to the Source Control view"
+ ],
+ "description": "Specifies where to show the `Search Commits` view",
+ "scope": "window"
+ },
"gitlens.views.stashFileFormat": {
"type": "string",
"default": "${filePath}",
@@ -1548,6 +1598,11 @@
"category": "GitLens"
},
{
+ "command": "gitlens.showSearchView",
+ "title": "Show Search Commits View",
+ "category": "GitLens"
+ },
+ {
"command": "gitlens.diffDirectory",
"title": "Directory Compare Working Tree with...",
"category": "GitLens"
@@ -1703,13 +1758,13 @@
"category": "GitLens"
},
{
- "command": "gitlens.showCommitInResults",
- "title": "Show Commit in Results",
+ "command": "gitlens.showCommitInView",
+ "title": "Show Commit in View",
"category": "GitLens"
},
{
- "command": "gitlens.showFileHistoryInResults",
- "title": "Show File History in Results",
+ "command": "gitlens.showFileHistoryInView",
+ "title": "Show File History in View",
"category": "GitLens"
},
{
@@ -2181,11 +2236,6 @@
}
},
{
- "command": "gitlens.views.repositories.refreshNode",
- "title": "Refresh",
- "category": "GitLens"
- },
- {
"command": "gitlens.views.repositories.setFilesLayoutToAuto",
"title": "Automatic Layout",
"category": "GitLens"
@@ -2220,11 +2270,6 @@
}
},
{
- "command": "gitlens.views.fileHistory.refreshNode",
- "title": "Refresh",
- "category": "GitLens"
- },
- {
"command": "gitlens.views.fileHistory.changeBase",
"title": "Change Base...",
"category": "GitLens",
@@ -2271,11 +2316,6 @@
}
},
{
- "command": "gitlens.views.lineHistory.refreshNode",
- "title": "Refresh",
- "category": "GitLens"
- },
- {
"command": "gitlens.views.lineHistory.changeBase",
"title": "Change Base...",
"category": "GitLens",
@@ -2322,15 +2362,6 @@
}
},
{
- "command": "gitlens.views.results.dismissNode",
- "title": "Dismiss",
- "category": "GitLens",
- "icon": {
- "dark": "images/dark/icon-close-small.svg",
- "light": "images/light/icon-close-small.svg"
- }
- },
- {
"command": "gitlens.views.results.refresh",
"title": "Refresh",
"category": "GitLens",
@@ -2340,11 +2371,6 @@
}
},
{
- "command": "gitlens.views.results.refreshNode",
- "title": "Refresh",
- "category": "GitLens"
- },
- {
"command": "gitlens.views.results.setFilesLayoutToAuto",
"title": "Automatic Layout",
"category": "GitLens"
@@ -2385,6 +2411,71 @@
"dark": "images/dark/icon-swap.svg",
"light": "images/light/icon-swap.svg"
}
+ },
+ {
+ "command": "gitlens.views.search.clear",
+ "title": "Clear Results",
+ "category": "GitLens",
+ "icon": {
+ "dark": "images/dark/icon-clear.svg",
+ "light": "images/light/icon-clear.svg"
+ }
+ },
+ {
+ "command": "gitlens.views.search.refresh",
+ "title": "Refresh",
+ "category": "GitLens",
+ "icon": {
+ "dark": "images/dark/icon-refresh.svg",
+ "light": "images/light/icon-refresh.svg"
+ }
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToAuto",
+ "title": "Automatic Layout",
+ "category": "GitLens"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToList",
+ "title": "List Layout",
+ "category": "GitLens"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToTree",
+ "title": "Tree Layout",
+ "category": "GitLens"
+ },
+ {
+ "command": "gitlens.views.search.setKeepResultsToOn",
+ "title": "Keep Results",
+ "category": "GitLens",
+ "icon": {
+ "dark": "images/dark/icon-lock.svg",
+ "light": "images/light/icon-lock.svg"
+ }
+ },
+ {
+ "command": "gitlens.views.search.setKeepResultsToOff",
+ "title": "Keep Results",
+ "category": "GitLens",
+ "icon": {
+ "dark": "images/dark/icon-locked.svg",
+ "light": "images/light/icon-locked.svg"
+ }
+ },
+ {
+ "command": "gitlens.views.dismissNode",
+ "title": "Dismiss",
+ "category": "GitLens",
+ "icon": {
+ "dark": "images/dark/icon-close-small.svg",
+ "light": "images/light/icon-close-small.svg"
+ }
+ },
+ {
+ "command": "gitlens.views.refreshNode",
+ "title": "Refresh",
+ "category": "GitLens"
}
],
"menus": {
@@ -2506,11 +2597,11 @@
"when": "gitlens:enabled"
},
{
- "command": "gitlens.showCommitInResults",
+ "command": "gitlens.showCommitInView",
"when": "gitlens:activeFileStatus =~ /blameable/"
},
{
- "command": "gitlens.showFileHistoryInResults",
+ "command": "gitlens.showFileHistoryInView",
"when": "gitlens:activeFileStatus =~ /tracked/"
},
{
@@ -2794,10 +2885,6 @@
"when": "false"
},
{
- "command": "gitlens.views.repositories.refreshNode",
- "when": "false"
- },
- {
"command": "gitlens.views.repositories.setFilesLayoutToAuto",
"when": "false"
},
@@ -2822,10 +2909,6 @@
"when": "false"
},
{
- "command": "gitlens.views.fileHistory.refreshNode",
- "when": "false"
- },
- {
"command": "gitlens.views.fileHistory.changeBase",
"when": "false"
},
@@ -2850,10 +2933,6 @@
"when": "false"
},
{
- "command": "gitlens.views.lineHistory.refreshNode",
- "when": "false"
- },
- {
"command": "gitlens.views.lineHistory.changeBase",
"when": "false"
},
@@ -2878,18 +2957,10 @@
"when": "false"
},
{
- "command": "gitlens.views.results.dismissNode",
- "when": "false"
- },
- {
"command": "gitlens.views.results.refresh",
"when": "false"
},
{
- "command": "gitlens.views.results.refreshNode",
- "when": "false"
- },
- {
"command": "gitlens.views.results.setFilesLayoutToAuto",
"when": "false"
},
@@ -2912,6 +2983,42 @@
{
"command": "gitlens.views.results.swapComparision",
"when": "false"
+ },
+ {
+ "command": "gitlens.views.search.clear",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.search.refresh",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToAuto",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToList",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToTree",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.search.setKeepResultsToOn",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.search.setKeepResultsToOff",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.dismissNode",
+ "when": "false"
+ },
+ {
+ "command": "gitlens.views.refreshNode",
+ "when": "false"
}
],
"editor/context": [
@@ -3146,153 +3253,178 @@
],
"view/title": [
{
- "command": "gitlens.showCommitSearch",
- "when": "gitlens:enabled && view =~ /^gitlens.views.repositories:/",
- "group": "navigation@1"
- },
- {
"command": "gitlens.pushRepositories",
- "when": "gitlens:enabled && view =~ /^gitlens.views.repositories:/",
+ "when": "gitlens:enabled && view =~ /^gitlens\\.views\\.repositories:/",
"group": "navigation@6"
},
{
"command": "gitlens.pullRepositories",
- "when": "gitlens:enabled && view =~ /^gitlens.views.repositories:/",
+ "when": "gitlens:enabled && view =~ /^gitlens\\.views\\.repositories:/",
"group": "navigation@7"
},
{
"command": "gitlens.fetchRepositories",
- "when": "gitlens:enabled && view =~ /^gitlens.views.repositories:/",
+ "when": "gitlens:enabled && view =~ /^gitlens\\.views\\.repositories:/",
"group": "navigation@8"
},
{
"command": "gitlens.views.repositories.refresh",
- "when": "view =~ /^gitlens.views.repositories:/",
- "group": "navigation@9"
+ "when": "view =~ /^gitlens\\.views\\.repositories:/",
+ "group": "navigation@98"
},
{
"command": "gitlens.views.repositories.setFilesLayoutToAuto",
- "when": "view =~ /^gitlens.views.repositories:/",
+ "when": "view =~ /^gitlens\\.views\\.repositories:/",
"group": "1_gitlens"
},
{
"command": "gitlens.views.repositories.setFilesLayoutToList",
- "when": "view =~ /^gitlens.views.repositories:/",
+ "when": "view =~ /^gitlens\\.views\\.repositories:/",
"group": "1_gitlens"
},
{
"command": "gitlens.views.repositories.setFilesLayoutToTree",
- "when": "view =~ /^gitlens.views.repositories:/",
+ "when": "view =~ /^gitlens\\.views\\.repositories:/",
"group": "1_gitlens"
},
{
"command": "gitlens.views.repositories.setAutoRefreshToOn",
- "when": "view =~ /^gitlens.views.repositories:/ && config.gitlens.views.repositories.autoRefresh && !gitlens:views:repositories:autoRefresh",
+ "when": "view =~ /^gitlens\\.views\\.repositories:/ && config.gitlens.views.repositories.autoRefresh && !gitlens:views:repositories:autoRefresh",
"group": "2_gitlens"
},
{
"command": "gitlens.views.repositories.setAutoRefreshToOff",
- "when": "view =~ /^gitlens.views.repositories:/ && config.gitlens.views.repositories.autoRefresh && gitlens:views:repositories:autoRefresh",
+ "when": "view =~ /^gitlens\\.views\\.repositories:/ && config.gitlens.views.repositories.autoRefresh && gitlens:views:repositories:autoRefresh",
"group": "2_gitlens"
},
{
"command": "gitlens.views.fileHistory.setEditorFollowingOn",
- "when": "view =~ /^gitlens.views.fileHistory:/ && !gitlens:views:fileHistory:editorFollowing",
+ "when": "view =~ /^gitlens\\.views\\.fileHistory:/ && !gitlens:views:fileHistory:editorFollowing",
"group": "navigation@1"
},
{
"command": "gitlens.views.fileHistory.setEditorFollowingOff",
- "when": "view =~ /^gitlens.views.fileHistory:/ && gitlens:views:fileHistory:editorFollowing",
+ "when": "view =~ /^gitlens\\.views\\.fileHistory:/ && gitlens:views:fileHistory:editorFollowing",
"group": "navigation@1"
},
{
"command": "gitlens.views.fileHistory.changeBase",
- "when": "view =~ /^gitlens.views.fileHistory:/",
+ "when": "view =~ /^gitlens\\.views\\.fileHistory:/",
"group": "navigation@2"
},
{
"command": "gitlens.views.fileHistory.refresh",
- "when": "view =~ /^gitlens.views.fileHistory:/",
+ "when": "view =~ /^gitlens\\.views\\.fileHistory:/",
"group": "navigation@99"
},
{
"command": "gitlens.views.fileHistory.setRenameFollowingOn",
- "when": "view =~ /^gitlens.views.fileHistory:/ && !config.gitlens.advanced.fileHistoryFollowsRenames",
+ "when": "view =~ /^gitlens\\.views\\.fileHistory:/ && !config.gitlens.advanced.fileHistoryFollowsRenames",
"group": "1_gitlens"
},
{
"command": "gitlens.views.fileHistory.setRenameFollowingOff",
- "when": "view =~ /^gitlens.views.fileHistory:/ && config.gitlens.advanced.fileHistoryFollowsRenames",
+ "when": "view =~ /^gitlens\\.views\\.fileHistory:/ && config.gitlens.advanced.fileHistoryFollowsRenames",
"group": "1_gitlens"
},
{
"command": "gitlens.views.lineHistory.setEditorFollowingOn",
- "when": "view =~ /^gitlens.views.lineHistory:/ && !gitlens:views:lineHistory:editorFollowing",
+ "when": "view =~ /^gitlens\\.views\\.lineHistory:/ && !gitlens:views:lineHistory:editorFollowing",
"group": "navigation@1"
},
{
"command": "gitlens.views.lineHistory.setEditorFollowingOff",
- "when": "view =~ /^gitlens.views.lineHistory:/ && gitlens:views:lineHistory:editorFollowing",
+ "when": "view =~ /^gitlens\\.views\\.lineHistory:/ && gitlens:views:lineHistory:editorFollowing",
"group": "navigation@1"
},
{
"command": "gitlens.views.lineHistory.changeBase",
- "when": "view =~ /^gitlens.views.lineHistory:/",
+ "when": "view =~ /^gitlens\\.views\\.lineHistory:/",
"group": "navigation@2"
},
{
"command": "gitlens.views.lineHistory.refresh",
- "when": "view =~ /^gitlens.views.lineHistory:/",
+ "when": "view =~ /^gitlens\\.views\\.lineHistory:/",
"group": "navigation@99"
},
{
"command": "gitlens.views.lineHistory.setRenameFollowingOn",
- "when": "view =~ /^gitlens.views.lineHistory:/ && !config.gitlens.advanced.fileHistoryFollowsRenames",
+ "when": "view =~ /^gitlens\\.views\\.lineHistory:/ && !config.gitlens.advanced.fileHistoryFollowsRenames",
"group": "1_gitlens"
},
{
"command": "gitlens.views.lineHistory.setRenameFollowingOff",
- "when": "view =~ /^gitlens.views.lineHistory:/ && config.gitlens.advanced.fileHistoryFollowsRenames",
+ "when": "view =~ /^gitlens\\.views\\.lineHistory:/ && config.gitlens.advanced.fileHistoryFollowsRenames",
"group": "1_gitlens"
},
{
- "command": "gitlens.showCommitSearch",
- "when": "gitlens:enabled && view =~ /^gitlens.views.results:/",
- "group": "navigation@1"
- },
- {
"command": "gitlens.views.results.setKeepResultsToOn",
- "when": "view =~ /^gitlens.views.results:/ && !gitlens:views:results:keepResults",
+ "when": "view =~ /^gitlens\\.views\\.results:/ && !gitlens:views:results:keepResults",
"group": "navigation@2"
},
{
"command": "gitlens.views.results.setKeepResultsToOff",
- "when": "view =~ /^gitlens.views.results:/ && gitlens:views:results:keepResults",
+ "when": "view =~ /^gitlens\\.views\\.results:/ && gitlens:views:results:keepResults",
"group": "navigation@2"
},
{
"command": "gitlens.views.results.refresh",
- "when": "view =~ /^gitlens.views.results:/",
+ "when": "view =~ /^gitlens\\.views\\.results:/",
"group": "navigation@3"
},
{
"command": "gitlens.views.results.close",
- "when": "view =~ /^gitlens.views.results:/",
+ "when": "view =~ /^gitlens\\.views\\.results:/",
"group": "navigation@9"
},
{
"command": "gitlens.views.results.setFilesLayoutToAuto",
- "when": "view =~ /^gitlens.views.results:/",
+ "when": "view =~ /^gitlens\\.views\\.results:/",
"group": "1_gitlens"
},
{
"command": "gitlens.views.results.setFilesLayoutToList",
- "when": "view =~ /^gitlens.views.results:/",
+ "when": "view =~ /^gitlens\\.views\\.results:/",
"group": "1_gitlens"
},
{
"command": "gitlens.views.results.setFilesLayoutToTree",
- "when": "view =~ /^gitlens.views.results:/",
+ "when": "view =~ /^gitlens\\.views\\.results:/",
+ "group": "1_gitlens"
+ },
+ {
+ "command": "gitlens.views.search.clear",
+ "when": "view =~ /^gitlens\\.views\\.search:/",
+ "group": "navigation@2"
+ },
+ {
+ "command": "gitlens.views.search.setKeepResultsToOn",
+ "when": "view =~ /^gitlens\\.views\\.search:/ && !gitlens:views:search:keepResults",
+ "group": "navigation@3"
+ },
+ {
+ "command": "gitlens.views.search.setKeepResultsToOff",
+ "when": "view =~ /^gitlens\\.views\\.search:/ && gitlens:views:search:keepResults",
+ "group": "navigation@3"
+ },
+ {
+ "command": "gitlens.views.search.refresh",
+ "when": "view =~ /^gitlens\\.views\\.search:/",
+ "group": "navigation@99"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToAuto",
+ "when": "view =~ /^gitlens\\.views\\.search:/",
+ "group": "1_gitlens"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToList",
+ "when": "view =~ /^gitlens\\.views\\.search:/",
+ "group": "1_gitlens"
+ },
+ {
+ "command": "gitlens.views.search.setFilesLayoutToTree",
+ "when": "view =~ /^gitlens\\.views\\.search:/",
"group": "1_gitlens"
}
],
@@ -3460,7 +3592,7 @@
"group": "5_gitlens_1@1"
},
{
- "command": "gitlens.showCommitInResults",
+ "command": "gitlens.showCommitInView",
"when": "viewItem =~ /gitlens:commit\\b/",
"group": "5_gitlens_1@2"
},
@@ -3591,7 +3723,7 @@
"group": "5_gitlens_2@2"
},
{
- "command": "gitlens.showCommitInResults",
+ "command": "gitlens.showCommitInView",
"when": "viewItem =~ /gitlens:file\\b(?!(:stash|:status))/",
"group": "5_gitlens_2@3"
},
@@ -3601,7 +3733,7 @@
"group": "8_gitlens@1"
},
{
- "command": "gitlens.showFileHistoryInResults",
+ "command": "gitlens.showFileHistoryInView",
"when": "viewItem =~ /gitlens:file\\b/",
"group": "8_gitlens@2"
},
@@ -3641,6 +3773,11 @@
"group": "7_gitlens_more@1"
},
{
+ "command": "gitlens.showCommitSearch",
+ "when": "viewItem == gitlens:repository",
+ "group": "inline@1"
+ },
+ {
"command": "gitlens.views.push",
"when": "viewItem == gitlens:repository && gitlens:hasRemotes",
"group": "inline@97",
@@ -3733,13 +3870,13 @@
"group": "inline@1"
},
{
- "command": "gitlens.views.results.dismissNode",
- "when": "viewItem =~ /gitlens:results\\b(?!:(commits|files))/",
+ "command": "gitlens.views.dismissNode",
+ "when": "viewItem =~ /gitlens:(results|search)\\b(?!:(commits|files))/",
"group": "inline@2"
},
{
- "command": "gitlens.views.results.dismissNode",
- "when": "viewItem =~ /gitlens:results\\b(?!:(commits|files))/",
+ "command": "gitlens.views.dismissNode",
+ "when": "viewItem =~ /gitlens:(results|search)\\b(?!:(commits|files))/",
"group": "1_gitlens@1"
},
{
@@ -3793,23 +3930,8 @@
"group": "8_gitlens"
},
{
- "command": "gitlens.views.repositories.refreshNode",
- "when": "view =~ /^gitlens.views.repositories:/ && viewItem =~ /gitlens:(?!file\\b)/",
- "group": "9_gitlens@1"
- },
- {
- "command": "gitlens.views.results.refreshNode",
- "when": "view =~ /^gitlens.views.results:/ && viewItem =~ /gitlens:(?!file\\b)/",
- "group": "9_gitlens@1"
- },
- {
- "command": "gitlens.views.fileHistory.refreshNode",
- "when": "view =~ /^gitlens.views.fileHistory:/ && viewItem =~ /gitlens:(?!file\\b)/",
- "group": "9_gitlens@1"
- },
- {
- "command": "gitlens.views.lineHistory.refreshNode",
- "when": "view =~ /^gitlens.views.lineHistory:/ && viewItem =~ /gitlens:(?!file\\b)/",
+ "command": "gitlens.views.refreshNode",
+ "when": "view =~ /^gitlens\\.views\\./ && viewItem =~ /gitlens:(?!file\\b)/",
"group": "9_gitlens@1"
}
]
@@ -4031,6 +4153,11 @@
"id": "gitlens.views.results:gitlens",
"name": "Results",
"when": "gitlens:enabled && gitlens:views:results && config.gitlens.views.results.location == gitlens"
+ },
+ {
+ "id": "gitlens.views.search:gitlens",
+ "name": "Search Commits",
+ "when": "config.gitlens.views.search.enabled && config.gitlens.views.search.location == gitlens"
}
],
"explorer": [
@@ -4053,6 +4180,11 @@
"id": "gitlens.views.results:explorer",
"name": "GitLens: Results",
"when": "gitlens:enabled && gitlens:views:results && config.gitlens.views.results.location == explorer"
+ },
+ {
+ "id": "gitlens.views.search:explorer",
+ "name": "GitLens: Search Commits",
+ "when": "config.gitlens.views.search.enabled && config.gitlens.views.search.location == explorer"
}
],
"scm": [
@@ -4075,6 +4207,11 @@
"id": "gitlens.views.results:scm",
"name": "GitLens: Results",
"when": "gitlens:enabled && gitlens:views:results && config.gitlens.views.results.location == scm"
+ },
+ {
+ "id": "gitlens.views.search:scm",
+ "name": "GitLens: Search Commits",
+ "when": "config.gitlens.views.search.enabled && config.gitlens.views.search.location == scm"
}
]
}
diff --git a/src/commands/common.ts b/src/commands/common.ts
index cf367e1..d3cea3e 100644
--- a/src/commands/common.ts
+++ b/src/commands/common.ts
@@ -56,10 +56,10 @@ export enum Commands {
PullRepositories = 'gitlens.pullRepositories',
PushRepositories = 'gitlens.pushRepositories',
ResetSuppressedWarnings = 'gitlens.resetSuppressedWarnings',
- ShowCommitInResults = 'gitlens.showCommitInResults',
+ ShowCommitInView = 'gitlens.showCommitInView',
ShowCommitSearch = 'gitlens.showCommitSearch',
ShowFileHistoryView = 'gitlens.showFileHistoryView',
- ShowFileHistoryInResults = 'gitlens.showFileHistoryInResults',
+ ShowFileHistoryInView = 'gitlens.showFileHistoryInView',
ShowLineHistoryView = 'gitlens.showLineHistoryView',
ShowLastQuickPick = 'gitlens.showLastQuickPick',
ShowQuickBranchHistory = 'gitlens.showQuickBranchHistory',
@@ -72,6 +72,7 @@ export enum Commands {
ShowQuickStashList = 'gitlens.showQuickStashList',
ShowRepositoriesView = 'gitlens.showRepositoriesView',
ShowResultsView = 'gitlens.showResultsView',
+ ShowSearchView = 'gitlens.showSearchView',
ShowSettingsPage = 'gitlens.showSettingsPage',
ShowWelcomePage = 'gitlens.showWelcomePage',
StashApply = 'gitlens.stashApply',
@@ -197,9 +198,9 @@ export interface CommandUriContext extends CommandBaseContext {
type: 'uri';
}
-export interface CommandViewContext extends CommandBaseContext {
- type: 'view';
-}
+// export interface CommandViewContext extends CommandBaseContext {
+// type: 'view';
+// }
export interface CommandViewItemContext extends CommandBaseContext {
type: 'viewItem';
@@ -287,7 +288,7 @@ export type CommandContext =
| CommandScmStatesContext
| CommandUnknownContext
| CommandUriContext
- | CommandViewContext
+ // | CommandViewContext
| CommandViewItemContext;
function isScmResourceGroup(group: any): group is SourceControlResourceGroup {
@@ -373,15 +374,11 @@ export abstract class Command implements Disposable {
firstArg = args[0];
}
- let maybeView = false;
if (options.uri && (firstArg == null || firstArg instanceof Uri)) {
const [uri, ...rest] = args as [Uri, any];
if (uri !== undefined) {
return [{ command: command, type: 'uri', editor: editor, uri: uri }, rest];
}
- else {
- maybeView = args.length === 0;
- }
}
if (firstArg instanceof ViewNode) {
@@ -418,10 +415,6 @@ export abstract class Command implements Disposable {
return [{ command: command, type: 'scm-groups', scmResourceGroups: groups }, args.slice(count)];
}
- if (maybeView) {
- return [{ command: command, type: 'view', editor: editor }, args];
- }
-
return [{ command: command, type: 'unknown', editor: editor }, args];
}
}
diff --git a/src/commands/diffBranchWithBranch.ts b/src/commands/diffBranchWithBranch.ts
index 60669bc..9557cad 100644
--- a/src/commands/diffBranchWithBranch.ts
+++ b/src/commands/diffBranchWithBranch.ts
@@ -75,7 +75,7 @@ export class DiffBranchWithBranchCommand extends ActiveEditorCommand {
if (args.ref1 === undefined) return undefined;
}
- await Container.resultsView.addComparison(repoPath, args.ref1, args.ref2);
+ await Container.resultsView.compare(repoPath, args.ref1, args.ref2);
return undefined;
}
diff --git a/src/commands/showCommitSearch.ts b/src/commands/showCommitSearch.ts
index 8537b15..110a07c 100644
--- a/src/commands/showCommitSearch.ts
+++ b/src/commands/showCommitSearch.ts
@@ -5,7 +5,7 @@ import { Container } from '../container';
import { GitRepoSearchBy, GitService, GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { Messages } from '../messages';
-import { CommandQuickPickItem, CommitsQuickPick, ShowCommitsSearchInResultsQuickPickItem } from '../quickpicks';
+import { CommandQuickPickItem, CommitsQuickPick, ShowCommitSearchResultsInViewQuickPickItem } from '../quickpicks';
import { Iterables, Strings } from '../system';
import {
ActiveEditorCachedCommand,
@@ -39,7 +39,7 @@ export interface ShowCommitSearchCommandArgs {
search?: string;
searchBy?: GitRepoSearchBy;
maxCount?: number;
- showInResults?: boolean;
+ showInView?: boolean;
goBackCommand?: CommandQuickPickItem;
}
@@ -51,14 +51,17 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
}
protected async preExecute(context: CommandContext, args: ShowCommitSearchCommandArgs = {}) {
- if (context.type === 'view' || context.type === 'viewItem') {
+ if (context.type === 'viewItem') {
args = { ...args };
- args.showInResults = true;
+ args.showInView = true;
if (isCommandViewContextWithRepo(context)) {
return this.execute(context.editor, context.node.uri, args);
}
}
+ else {
+ // TODO: Add a user setting (default to view?)
+ }
return this.execute(context.editor, context.uri, args);
}
@@ -86,10 +89,14 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
selection = [1, 1];
}
+ if (args.showInView) {
+ await Container.searchView.show();
+ }
+
args.search = await window.showInputBox({
value: args.search,
prompt: `Please enter a search string`,
- placeHolder: `search by message, author (@), files (:), commit id (#), changes (=), changed lines (~)`,
+ placeHolder: `Search commits by message, author (@), files (:), commit id (#), changes (=), changed lines (~)`,
valueSelection: selection
} as InputBoxOptions);
if (args.search === undefined) {
@@ -142,14 +149,11 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
break;
}
- if (args.showInResults) {
- void Container.resultsView.addSearchResults(
- repoPath,
- Container.git.getLogForSearch(repoPath, args.search!, args.searchBy!, {
- maxCount: args.maxCount
- }),
- { label: searchLabel! }
- );
+ if (args.showInView) {
+ void Container.searchView.search(repoPath, args.search, args.searchBy, {
+ maxCount: args.maxCount,
+ label: { label: searchLabel! }
+ });
return;
}
@@ -189,7 +193,9 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
)
: undefined,
showInResultsCommand:
- log !== undefined ? new ShowCommitsSearchInResultsQuickPickItem(log, searchLabel!) : undefined
+ log !== undefined
+ ? new ShowCommitSearchResultsInViewQuickPickItem(log, { label: searchLabel! })
+ : undefined
});
if (pick === undefined) return undefined;
diff --git a/src/commands/showQuickCommitDetails.ts b/src/commands/showQuickCommitDetails.ts
index f686660..58e0a91 100644
--- a/src/commands/showQuickCommitDetails.ts
+++ b/src/commands/showQuickCommitDetails.ts
@@ -3,7 +3,7 @@ import * as paths from 'path';
import { commands, TextEditor, Uri } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
-import { GitCommit, GitLog, GitLogCommit, GitUri } from '../git/gitService';
+import { GitCommit, GitLog, GitLogCommit, GitRepoSearchBy, GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { CommandQuickPickItem, CommitQuickPick, CommitWithFileStatusQuickPickItem } from '../quickpicks';
@@ -22,7 +22,7 @@ export interface ShowQuickCommitDetailsCommandArgs {
sha?: string;
commit?: GitCommit | GitLogCommit;
repoLog?: GitLog;
- showInResults?: boolean;
+ showInView?: boolean;
goBackCommand?: CommandQuickPickItem;
}
@@ -40,13 +40,13 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
}
constructor() {
- super([Commands.ShowCommitInResults, Commands.ShowQuickCommitDetails, Commands.ShowQuickRevisionDetails]);
+ super([Commands.ShowCommitInView, Commands.ShowQuickCommitDetails, Commands.ShowQuickRevisionDetails]);
}
protected async preExecute(context: CommandContext, args: ShowQuickCommitDetailsCommandArgs = {}): Promise {
- if (context.command === Commands.ShowCommitInResults) {
+ if (context.command === Commands.ShowCommitInView) {
args = { ...args };
- args.showInResults = true;
+ args.showInView = true;
}
if (context.command === Commands.ShowQuickRevisionDetails && context.editor !== undefined) {
@@ -135,8 +135,10 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
args.commit.workingFileName = workingFileName;
}
- if (args.showInResults) {
- void (await Container.resultsView.addCommit(args.commit as GitLogCommit));
+ if (args.showInView) {
+ void (await Container.searchView.search(repoPath!, args.commit.sha, GitRepoSearchBy.Sha, {
+ label: { label: `commits with an id matching '${args.commit.shortSha}'` }
+ }));
return undefined;
}
diff --git a/src/commands/showQuickFileHistory.ts b/src/commands/showQuickFileHistory.ts
index 1452e61..0914239 100644
--- a/src/commands/showQuickFileHistory.ts
+++ b/src/commands/showQuickFileHistory.ts
@@ -10,7 +10,7 @@ import {
ChooseFromBranchesAndTagsQuickPickItem,
CommandQuickPickItem,
FileHistoryQuickPick,
- ShowCommitsInResultsQuickPickItem
+ ShowFileHistoryInViewQuickPickItem
} from '../quickpicks';
import { Iterables, Strings } from '../system';
import { ActiveEditorCachedCommand, command, CommandContext, Commands, getCommandUri } from './common';
@@ -21,7 +21,7 @@ export interface ShowQuickFileHistoryCommandArgs {
log?: GitLog;
maxCount?: number;
range?: Range;
- showInResults?: boolean;
+ showInView?: boolean;
goBackCommand?: CommandQuickPickItem;
nextPageCommand?: CommandQuickPickItem;
@@ -30,13 +30,13 @@ export interface ShowQuickFileHistoryCommandArgs {
@command()
export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
constructor() {
- super([Commands.ShowFileHistoryInResults, Commands.ShowQuickFileHistory]);
+ super([Commands.ShowFileHistoryInView, Commands.ShowQuickFileHistory]);
}
protected async preExecute(context: CommandContext, args: ShowQuickFileHistoryCommandArgs = {}): Promise {
- if (context.command === Commands.ShowFileHistoryInResults) {
+ if (context.command === Commands.ShowFileHistoryInView) {
args = { ...args };
- args.showInResults = true;
+ args.showInView = true;
}
return this.execute(context.editor, context.uri, args);
@@ -48,16 +48,19 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
const gitUri = await GitUri.fromUri(uri);
+ if (args.showInView) {
+ await Container.fileHistoryView.showHistoryForUri(gitUri);
+
+ return undefined;
+ }
+
args = { ...args };
const placeHolder = `${gitUri.getFormattedPath({
suffix: args.branchOrTag ? ` (${args.branchOrTag.name})` : undefined
})}${gitUri.sha ? ` ${Strings.pad(GlyphChars.Dot, 1, 1)} ${gitUri.shortSha}` : ''}`;
- let progressCancellation;
- if (!args.showInResults) {
- progressCancellation = FileHistoryQuickPick.showProgress(placeHolder);
- }
+ const progressCancellation = FileHistoryQuickPick.showProgress(placeHolder);
try {
if (args.log === undefined) {
@@ -78,15 +81,6 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
return undefined;
}
- if (args.showInResults) {
- void (await Container.resultsView.addSearchResults(gitUri.repoPath!, args.log, {
- label: placeHolder,
- resultsType: { singular: 'commit', plural: 'commits' }
- }));
-
- return undefined;
- }
-
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
if (args.log.truncated) {
@@ -129,8 +123,8 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
args.branchOrTag instanceof GitTag ? '$(tag)' : '$(git-branch)'
} ${args.branchOrTag.name}`
: gitUri.sha
- ? ` from ${GlyphChars.Space}$(git-commit) ${gitUri.shortSha}`
- : ''
+ ? ` from ${GlyphChars.Space}$(git-commit) ${gitUri.shortSha}`
+ : ''
}`
},
Commands.ShowQuickFileHistory,
@@ -154,12 +148,12 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
[uri, { ...args, log: undefined, maxCount: 0 }]
)
: undefined,
- showInResultsCommand:
+ showInViewCommand:
args.log !== undefined
- ? new ShowCommitsInResultsQuickPickItem(args.log, {
- label: placeHolder,
- resultsType: { singular: 'commit', plural: 'commits' }
- })
+ ? new ShowFileHistoryInViewQuickPickItem(
+ gitUri,
+ (args.branchOrTag && args.branchOrTag.ref) || gitUri.sha
+ )
: undefined
});
if (pick === undefined) return undefined;
diff --git a/src/commands/showView.ts b/src/commands/showView.ts
index 93ced3a..6923f2f 100644
--- a/src/commands/showView.ts
+++ b/src/commands/showView.ts
@@ -9,7 +9,8 @@ export class ShowViewCommand extends Command {
Commands.ShowRepositoriesView,
Commands.ShowFileHistoryView,
Commands.ShowLineHistoryView,
- Commands.ShowResultsView
+ Commands.ShowResultsView,
+ Commands.ShowSearchView
]);
}
@@ -27,6 +28,8 @@ export class ShowViewCommand extends Command {
return Container.lineHistoryView.show();
case Commands.ShowResultsView:
return Container.resultsView.show();
+ case Commands.ShowSearchView:
+ return Container.searchView.show();
}
return undefined;
diff --git a/src/constants.ts b/src/constants.ts
index 040e49e..0cf66d3 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -38,7 +38,8 @@ export enum CommandContext {
ViewsLineHistoryEditorFollowing = 'gitlens:views:lineHistory:editorFollowing',
ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh',
ViewsResults = 'gitlens:views:results',
- ViewsResultsKeepResults = 'gitlens:views:results:keepResults'
+ ViewsResultsKeepResults = 'gitlens:views:results:keepResults',
+ ViewsSearchKeepResults = 'gitlens:views:search:keepResults'
}
export function setCommandContext(key: CommandContext | string, value: any) {
@@ -126,5 +127,6 @@ export const ImageMimetypes: { [key: string]: string } = {
export enum WorkspaceState {
ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh',
- ViewsResultsKeepResults = 'gitlens:views:results:keepResults'
+ ViewsResultsKeepResults = 'gitlens:views:results:keepResults',
+ ViewsSearchKeepResults = 'gitlens:views:search:keepResults'
}
diff --git a/src/container.ts b/src/container.ts
index d34fd95..2c2e0ae 100644
--- a/src/container.ts
+++ b/src/container.ts
@@ -15,6 +15,7 @@ import { FileHistoryView } from './views/fileHistoryView';
import { LineHistoryView } from './views/lineHistoryView';
import { RepositoriesView } from './views/repositoriesView';
import { ResultsView } from './views/resultsView';
+import { SearchView } from './views/searchView';
import { ViewCommands } from './views/viewCommands';
import { SettingsEditor } from './webviews/settingsEditor';
import { WelcomeEditor } from './webviews/welcomeEditor';
@@ -79,6 +80,19 @@ export class Container {
});
}
+ if (config.views.search.enabled) {
+ context.subscriptions.push((this._searchView = new SearchView()));
+ }
+ else {
+ let disposable: Disposable;
+ disposable = configuration.onDidChange(e => {
+ if (configuration.changed(e, configuration.name('views')('search')('enabled').value)) {
+ disposable.dispose();
+ context.subscriptions.push((this._searchView = new SearchView()));
+ }
+ });
+ }
+
context.subscriptions.push(new GitFileSystemProvider());
}
@@ -162,6 +176,15 @@ export class Container {
return this._resultsView;
}
+ private static _searchView: SearchView | undefined;
+ static get searchView() {
+ if (this._searchView === undefined) {
+ this._context.subscriptions.push((this._searchView = new SearchView()));
+ }
+
+ return this._searchView;
+ }
+
private static _settingsEditor: SettingsEditor;
static get settingsEditor() {
return this._settingsEditor;
diff --git a/src/quickpicks/branchHistoryQuickPick.ts b/src/quickpicks/branchHistoryQuickPick.ts
index b826aea..232b9b4 100644
--- a/src/quickpicks/branchHistoryQuickPick.ts
+++ b/src/quickpicks/branchHistoryQuickPick.ts
@@ -1,6 +1,6 @@
'use strict';
import { CancellationTokenSource, QuickPickOptions, window } from 'vscode';
-import { Commands, ShowCommitSearchCommandArgs, ShowQuickBranchHistoryCommandArgs } from '../commands';
+import { Commands, ShowQuickBranchHistoryCommandArgs } from '../commands';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitLog, GitUri, RemoteResource } from '../git/gitService';
@@ -73,28 +73,6 @@ export class BranchHistoryQuickPick {
);
}
- items.splice(
- 0,
- 0,
- new CommandQuickPickItem(
- {
- label: `$(search) Show Commit Search`,
- description: `${Strings.pad(
- GlyphChars.Dash,
- 2,
- 3
- )} search for commits by message, author, files, or commit id`
- },
- Commands.ShowCommitSearch,
- [
- GitUri.fromRepoPath(log.repoPath),
- {
- goBackCommand: currentCommand
- } as ShowCommitSearchCommandArgs
- ]
- )
- );
-
let previousPageCommand: CommandQuickPickItem | undefined = undefined;
if (log.truncated || log.sha) {
diff --git a/src/quickpicks/commitQuickPick.ts b/src/quickpicks/commitQuickPick.ts
index 5a2d738..a2bd6da 100644
--- a/src/quickpicks/commitQuickPick.ts
+++ b/src/quickpicks/commitQuickPick.ts
@@ -31,7 +31,7 @@ import {
OpenFileCommandQuickPickItem,
OpenFilesCommandQuickPickItem,
QuickPickItem,
- ShowCommitInResultsQuickPickItem
+ ShowCommitInViewQuickPickItem
} from './commonQuickPicks';
import { OpenRemotesCommandQuickPickItem } from './remotesQuickPick';
@@ -163,10 +163,10 @@ export class CommitQuickPick {
)
);
- items.splice(index++, 0, new ShowCommitInResultsQuickPickItem(commit));
+ items.splice(index++, 0, new ShowCommitInViewQuickPickItem(commit));
}
else {
- items.splice(index++, 0, new ShowCommitInResultsQuickPickItem(commit));
+ items.splice(index++, 0, new ShowCommitInViewQuickPickItem(commit));
const remotes = await Container.git.getRemotes(commit.repoPath);
if (remotes.length) {
diff --git a/src/quickpicks/commonQuickPicks.ts b/src/quickpicks/commonQuickPicks.ts
index 99293fa..44ecd3b 100644
--- a/src/quickpicks/commonQuickPicks.ts
+++ b/src/quickpicks/commonQuickPicks.ts
@@ -13,9 +13,9 @@ import { Commands, openEditor } from '../commands';
import { configuration } from '../configuration';
import { GlyphChars } from '../constants';
import { Container } from '../container';
-import { GitLog, GitLogCommit, GitStashCommit } from '../git/gitService';
+import { GitLog, GitLogCommit, GitRepoSearchBy, GitStashCommit, GitUri } from '../git/gitService';
import { KeyMapping, Keys } from '../keyboard';
-import { Strings } from '../system';
+import { Functions, Strings } from '../system';
import { BranchesAndTagsQuickPick, BranchQuickPickItem, TagQuickPickItem } from './branchesAndTagsQuickPick';
export function getQuickPickIgnoreFocusOut() {
@@ -214,50 +214,65 @@ export class OpenFilesCommandQuickPickItem extends CommandQuickPickItem {
}
}
-export class ShowCommitInResultsQuickPickItem extends CommandQuickPickItem {
+export class ShowCommitInViewQuickPickItem extends CommandQuickPickItem {
constructor(
public readonly commit: GitLogCommit,
item: QuickPickItem = {
- label: 'Show in Results',
- description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays commit in the GitLens Results view`
+ label: 'Show in View',
+ description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays the commit in the GitLens Search Commits view`
}
) {
super(item, undefined, undefined);
}
async execute(): Promise<{} | undefined> {
- await Container.resultsView.addCommit(this.commit);
+ await Container.searchView.search(this.commit.repoPath, this.commit.sha, GitRepoSearchBy.Sha, {
+ label: { label: `commits with an id matching '${this.commit.shortSha}'` }
+ });
return undefined;
}
}
-export class ShowCommitsInResultsQuickPickItem extends CommandQuickPickItem {
+export class ShowCommitSearchResultsInViewQuickPickItem extends CommandQuickPickItem {
constructor(
public readonly results: GitLog,
public readonly resultsLabel: string | { label: string; resultsType?: { singular: string; plural: string } },
item: QuickPickItem = {
- label: 'Show in Results',
- description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays commits in the GitLens Results view`
+ label: 'Show in View',
+ description: `${Strings.pad(
+ GlyphChars.Dash,
+ 2,
+ 2
+ )} displays the search results in the GitLens Search Commits view`
}
) {
super(item, undefined, undefined);
}
async execute(): Promise<{} | undefined> {
- await Container.resultsView.addSearchResults(this.results.repoPath, this.results, this.resultsLabel);
+ await Container.searchView.showSearchResults(this.results.repoPath, this.results, { label: this.resultsLabel });
return undefined;
}
}
-export class ShowCommitsSearchInResultsQuickPickItem extends ShowCommitsInResultsQuickPickItem {
+export class ShowFileHistoryInViewQuickPickItem extends CommandQuickPickItem {
constructor(
- public readonly results: GitLog,
- public readonly search: string,
+ public readonly uri: GitUri,
+ public readonly baseRef: string | undefined,
item: QuickPickItem = {
- label: 'Show in Results',
- description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays results in the GitLens Results view`
+ label: 'Show in View',
+ description: `${Strings.pad(
+ GlyphChars.Dash,
+ 2,
+ 2
+ )} displays the file history in the GitLens File History view`
}
) {
- super(results, { label: search }, item);
+ super(item, undefined, undefined);
+ }
+
+ async execute(): Promise<{} | undefined> {
+ await Container.fileHistoryView.showHistoryForUri(this.uri, this.baseRef);
+ return undefined;
}
}
diff --git a/src/quickpicks/fileHistoryQuickPick.ts b/src/quickpicks/fileHistoryQuickPick.ts
index 75c503f..3f90fbd 100644
--- a/src/quickpicks/fileHistoryQuickPick.ts
+++ b/src/quickpicks/fileHistoryQuickPick.ts
@@ -37,7 +37,7 @@ export class FileHistoryQuickPick {
pickerOnly?: boolean;
progressCancellation?: CancellationTokenSource;
showAllCommand?: CommandQuickPickItem;
- showInResultsCommand?: CommandQuickPickItem;
+ showInViewCommand?: CommandQuickPickItem;
} = {}
): Promise {
options = { pickerOnly: false, ...options };
@@ -55,9 +55,9 @@ export class FileHistoryQuickPick {
new ChooseFromBranchesAndTagsQuickPickItem(log.repoPath, placeHolder, options.currentCommand)
);
- if (options.showInResultsCommand !== undefined) {
+ if (options.showInViewCommand !== undefined) {
index++;
- items.splice(0, 0, options.showInResultsCommand);
+ items.splice(0, 0, options.showInViewCommand);
}
if (log.truncated || log.sha) {
diff --git a/src/system/function.ts b/src/system/function.ts
index 61eaae8..6f70fc3 100644
--- a/src/system/function.ts
+++ b/src/system/function.ts
@@ -16,6 +16,19 @@ interface IPropOfValue {
}
export namespace Functions {
+ export function cachedOnce(fn: (...args: any[]) => Promise, seed: T): (...args: any[]) => Promise {
+ let cached: T | undefined = seed;
+ return (...args: any[]) => {
+ if (cached !== undefined) {
+ const promise = Promise.resolve(cached);
+ cached = undefined;
+
+ return promise;
+ }
+ return fn(...args);
+ };
+ }
+
export function cancellable(promise: Promise, token: CancellationToken): Promise {
return new Promise((resolve, reject) => {
token.onCancellationRequested(() => resolve(undefined));
@@ -65,7 +78,7 @@ export namespace Functions {
return tracked;
}
- export function isPromise(o: any) {
+ export function isPromise(o: any): o is Promise {
return (typeof o === 'object' || typeof o === 'function') && typeof o.then === 'function';
}
@@ -84,19 +97,6 @@ export namespace Functions {
return propOfCore(o, key);
}
- export function seeded(fn: (...args: any[]) => Promise, seed: T): (...args: any[]) => Promise {
- let cached: T | undefined = seed;
- return (...args: any[]) => {
- if (cached !== undefined) {
- const promise = Promise.resolve(cached);
- cached = undefined;
-
- return promise;
- }
- return fn(...args);
- };
- }
-
export function interval(fn: (...args: any[]) => void, ms: number): Disposable {
let timer: NodeJS.Timer | undefined;
const disposable = {
diff --git a/src/ui/config.ts b/src/ui/config.ts
index 7a426dd..f71d915 100644
--- a/src/ui/config.ts
+++ b/src/ui/config.ts
@@ -156,6 +156,7 @@ export interface ViewsConfig {
lineHistory: LineHistoryViewConfig;
repositories: RepositoriesViewConfig;
results: ResultsViewConfig;
+ search: SearchViewConfig;
stashFileFormat: string;
stashFormat: string;
statusFileFormat: string;
@@ -257,6 +258,12 @@ export interface RemotesUrlsConfig {
fileRange: string;
}
+export interface SearchViewConfig {
+ enabled: boolean;
+ files: ViewsFilesConfig;
+ location: 'explorer' | 'gitlens' | 'scm';
+}
+
export interface Config {
blame: {
avatars: boolean;
diff --git a/src/views/fileHistoryView.ts b/src/views/fileHistoryView.ts
index 10a31f2..9757c50 100644
--- a/src/views/fileHistoryView.ts
+++ b/src/views/fileHistoryView.ts
@@ -3,9 +3,9 @@ import { commands, ConfigurationChangeEvent } from 'vscode';
import { configuration, FileHistoryViewConfig, ViewsConfig } from '../configuration';
import { CommandContext, setCommandContext } from '../constants';
import { Container } from '../container';
-import { FileHistoryTrackerNode, ViewNode } from './nodes';
+import { GitUri } from '../git/gitUri';
+import { FileHistoryTrackerNode } from './nodes';
import { RefreshReason, ViewBase } from './viewBase';
-import { RefreshNodeCommandArgs } from './viewCommands';
export class FileHistoryView extends ViewBase {
constructor() {
@@ -23,11 +23,6 @@ export class FileHistoryView extends ViewBase {
protected registerCommands() {
void Container.viewCommands;
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(), this);
- commands.registerCommand(
- this.getQualifiedCommand('refreshNode'),
- (node: ViewNode, args?: RefreshNodeCommandArgs) => this.refreshNode(node, args),
- this
- );
commands.registerCommand(this.getQualifiedCommand('changeBase'), () => this.changeBase(), this);
commands.registerCommand(
this.getQualifiedCommand('setEditorFollowingOn'),
@@ -78,6 +73,14 @@ export class FileHistoryView extends ViewBase {
return { ...Container.config.views, ...Container.config.views.fileHistory };
}
+ async showHistoryForUri(uri: GitUri, baseRef?: string) {
+ const root = this.ensureRoot();
+
+ this.setEditorFollowing(false);
+ await root.showHistoryForUri(uri, baseRef);
+ return this.show();
+ }
+
private changeBase() {
if (this._root !== undefined) {
void this._root.changeBase();
diff --git a/src/views/lineHistoryView.ts b/src/views/lineHistoryView.ts
index bbf20df..4a66694 100644
--- a/src/views/lineHistoryView.ts
+++ b/src/views/lineHistoryView.ts
@@ -23,11 +23,6 @@ export class LineHistoryView extends ViewBase {
protected registerCommands() {
void Container.viewCommands;
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(), this);
- commands.registerCommand(
- this.getQualifiedCommand('refreshNode'),
- (node: ViewNode, args?: RefreshNodeCommandArgs) => this.refreshNode(node, args),
- this
- );
commands.registerCommand(this.getQualifiedCommand('changeBase'), () => this.changeBase(), this);
commands.registerCommand(
this.getQualifiedCommand('setEditorFollowingOn'),
diff --git a/src/views/nodes.ts b/src/views/nodes.ts
index 4de4d64..facbb7d 100644
--- a/src/views/nodes.ts
+++ b/src/views/nodes.ts
@@ -13,10 +13,10 @@ export * from './nodes/remoteNode';
export * from './nodes/remotesNode';
export * from './nodes/repositoriesNode';
export * from './nodes/repositoryNode';
-export * from './nodes/resultsCommitNode';
export * from './nodes/resultsCommitsNode';
export * from './nodes/resultsComparisonNode';
export * from './nodes/resultsNode';
+export * from './nodes/searchNode';
export * from './nodes/stashesNode';
export * from './nodes/stashFileNode';
export * from './nodes/stashNode';
diff --git a/src/views/nodes/common.ts b/src/views/nodes/common.ts
index 11c4f41..9fde55d 100644
--- a/src/views/nodes/common.ts
+++ b/src/views/nodes/common.ts
@@ -162,7 +162,7 @@ export abstract class PagerNode extends ViewNode {
getCommand(): Command | undefined {
return {
title: 'Refresh',
- command: this.view.getQualifiedCommand('refreshNode'),
+ command: 'gitlens.views.refreshNode',
arguments: [this._parent, this._args]
} as Command;
}
diff --git a/src/views/nodes/fileHistoryTrackerNode.ts b/src/views/nodes/fileHistoryTrackerNode.ts
index 8fc2bd7..8b05f0a 100644
--- a/src/views/nodes/fileHistoryTrackerNode.ts
+++ b/src/views/nodes/fileHistoryTrackerNode.ts
@@ -14,6 +14,7 @@ import { ResourceType, SubscribeableViewNode, unknownGitUri, ViewNode } from './
export class FileHistoryTrackerNode extends SubscribeableViewNode {
private _baseRef: string | undefined;
+ private _fileUri: GitUri | undefined;
private _child: FileHistoryNode | undefined;
constructor(view: FileHistoryView) {
@@ -36,7 +37,7 @@ export class FileHistoryTrackerNode extends SubscribeableViewNode {
if (this._child === undefined) {
- if (this.uri === unknownGitUri) {
+ if (this._fileUri === undefined && this.uri === unknownGitUri) {
return [
new MessageNode(
this.view,
@@ -46,7 +47,7 @@ export class FileHistoryTrackerNode extends SubscribeableViewNode {
private _children: (ViewNode | MessageNode)[] = [];
constructor(view: ResultsView) {
@@ -17,83 +14,85 @@ export class ResultsNode extends ViewNode {
async getChildren(): Promise {
if (this._children.length === 0) {
- const command = {
- title: 'Search Commits',
- command: 'gitlens.showCommitSearch'
- };
-
- return [
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.Message } as ShowCommitSearchCommandArgs]
- },
- `Start a commit search by`,
- 'Click to search'
- ),
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.Message } as ShowCommitSearchCommandArgs]
- },
- `${GlyphChars.Space.repeat(4)} message ${Strings.pad(GlyphChars.Dash, 1, 1)} use `,
- 'Click to search by message'
- ),
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.Author } as ShowCommitSearchCommandArgs]
- },
- `${GlyphChars.Space.repeat(4)} author ${Strings.pad(GlyphChars.Dash, 1, 1)} use @`,
- 'Click to search by author'
- ),
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.Sha } as ShowCommitSearchCommandArgs]
- },
- `${GlyphChars.Space.repeat(4)} commit id ${Strings.pad(GlyphChars.Dash, 1, 1)} use #`,
- 'Click to search by commit id'
- ),
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.Files } as ShowCommitSearchCommandArgs]
- },
- `${GlyphChars.Space.repeat(4)} files ${Strings.pad(GlyphChars.Dash, 1, 1)} use :`,
- 'Click to search by files'
- ),
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.Changes } as ShowCommitSearchCommandArgs]
- },
- `${GlyphChars.Space.repeat(4)} changes ${Strings.pad(GlyphChars.Dash, 1, 1)} use =`,
- 'Click to search by changes'
- ),
- new CommandMessageNode(
- this.view,
- this,
- {
- ...command,
- arguments: [this, { searchBy: GitRepoSearchBy.ChangedLines } as ShowCommitSearchCommandArgs]
- },
- `${GlyphChars.Space.repeat(4)} changed lines ${Strings.pad(GlyphChars.Dash, 1, 1)} use ~`,
- 'Click to search by changed lines'
- )
- ];
+ this._children = [];
+
+ // const command = {
+ // title: 'Search Commits',
+ // command: 'gitlens.showCommitSearch'
+ // };
+
+ // return [
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.Message } as ShowCommitSearchCommandArgs]
+ // },
+ // `Start a commit search by`,
+ // 'Click to search'
+ // ),
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.Message } as ShowCommitSearchCommandArgs]
+ // },
+ // `${GlyphChars.Space.repeat(4)} message ${Strings.pad(GlyphChars.Dash, 1, 1)} use `,
+ // 'Click to search by message'
+ // ),
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.Author } as ShowCommitSearchCommandArgs]
+ // },
+ // `${GlyphChars.Space.repeat(4)} author ${Strings.pad(GlyphChars.Dash, 1, 1)} use @`,
+ // 'Click to search by author'
+ // ),
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.Sha } as ShowCommitSearchCommandArgs]
+ // },
+ // `${GlyphChars.Space.repeat(4)} commit id ${Strings.pad(GlyphChars.Dash, 1, 1)} use #`,
+ // 'Click to search by commit id'
+ // ),
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.Files } as ShowCommitSearchCommandArgs]
+ // },
+ // `${GlyphChars.Space.repeat(4)} files ${Strings.pad(GlyphChars.Dash, 1, 1)} use :`,
+ // 'Click to search by files'
+ // ),
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.Changes } as ShowCommitSearchCommandArgs]
+ // },
+ // `${GlyphChars.Space.repeat(4)} changes ${Strings.pad(GlyphChars.Dash, 1, 1)} use =`,
+ // 'Click to search by changes'
+ // ),
+ // new CommandMessageNode(
+ // this.view,
+ // this,
+ // {
+ // ...command,
+ // arguments: [this, { searchBy: GitRepoSearchBy.ChangedLines } as ShowCommitSearchCommandArgs]
+ // },
+ // `${GlyphChars.Space.repeat(4)} changed lines ${Strings.pad(GlyphChars.Dash, 1, 1)} use ~`,
+ // 'Click to search by changed lines'
+ // )
+ // ];
}
return this._children;
diff --git a/src/views/nodes/searchNode.ts b/src/views/nodes/searchNode.ts
new file mode 100644
index 0000000..3215243
--- /dev/null
+++ b/src/views/nodes/searchNode.ts
@@ -0,0 +1,140 @@
+'use strict';
+import { TreeItem, TreeItemCollapsibleState } from 'vscode';
+import { ShowCommitSearchCommandArgs } from '../../commands';
+import { GlyphChars } from '../../constants';
+import { GitRepoSearchBy } from '../../git/gitService';
+import { debug, Functions, gate, log } from '../../system';
+import { View } from '../viewBase';
+import { CommandMessageNode, MessageNode } from './common';
+import { ResourceType, unknownGitUri, ViewNode } from './viewNode';
+
+export class SearchNode extends ViewNode {
+ private _children: (ViewNode | MessageNode)[] = [];
+
+ constructor(view: View) {
+ super(unknownGitUri, view);
+ }
+
+ async getChildren(): Promise {
+ if (this._children.length === 0) {
+ const command = {
+ title: ' ',
+ command: 'gitlens.showCommitSearch'
+ };
+
+ return [
+ new CommandMessageNode(
+ this.view,
+ this,
+ {
+ ...command,
+ arguments: [this, { searchBy: GitRepoSearchBy.Message } as ShowCommitSearchCommandArgs]
+ },
+ `Search commits by message (use <message-pattern>)`,
+ 'Click to search commits by message'
+ ),
+ new CommandMessageNode(
+ this.view,
+ this,
+ {
+ ...command,
+ arguments: [this, { searchBy: GitRepoSearchBy.Author } as ShowCommitSearchCommandArgs]
+ },
+ `${GlyphChars.Space.repeat(4)} or, by author (use @<author-pattern>)`,
+ 'Click to search commits by author'
+ ),
+ new CommandMessageNode(
+ this.view,
+ this,
+ {
+ ...command,
+ arguments: [this, { searchBy: GitRepoSearchBy.Sha } as ShowCommitSearchCommandArgs]
+ },
+ `${GlyphChars.Space.repeat(4)} or, by commit id (use #<sha>)`,
+ 'Click to search commits by commit id'
+ ),
+ new CommandMessageNode(
+ this.view,
+ this,
+ {
+ ...command,
+ arguments: [this, { searchBy: GitRepoSearchBy.Files } as ShowCommitSearchCommandArgs]
+ },
+ `${GlyphChars.Space.repeat(4)} or, by files (use :<file-pattern>)`,
+ 'Click to search commits by files'
+ ),
+ new CommandMessageNode(
+ this.view,
+ this,
+ {
+ ...command,
+ arguments: [this, { searchBy: GitRepoSearchBy.Changes } as ShowCommitSearchCommandArgs]
+ },
+ `${GlyphChars.Space.repeat(4)} or, by changes (use =<pattern>)`,
+ 'Click to search commits by changes'
+ ),
+ new CommandMessageNode(
+ this.view,
+ this,
+ {
+ ...command,
+ arguments: [this, { searchBy: GitRepoSearchBy.ChangedLines } as ShowCommitSearchCommandArgs]
+ },
+ `${GlyphChars.Space.repeat(4)} or, by changed lines (use ~<pattern>)`,
+ 'Click to search commits by changed lines'
+ )
+ ];
+ }
+
+ return this._children;
+ }
+
+ getTreeItem(): TreeItem {
+ const item = new TreeItem(`Search`, TreeItemCollapsibleState.Expanded);
+ item.contextValue = ResourceType.Results;
+ return item;
+ }
+
+ addOrReplace(results: ViewNode, replace: boolean) {
+ if (this._children.includes(results)) return;
+
+ if (this._children.length !== 0 && replace) {
+ this._children.length = 0;
+ this._children.push(results);
+ }
+ else {
+ this._children.splice(0, 0, results);
+ }
+
+ this.view.triggerNodeChange();
+ }
+
+ @log()
+ clear() {
+ if (this._children.length === 0) return;
+
+ this._children.length = 0;
+ this.view.triggerNodeChange();
+ }
+
+ @log({
+ args: { 0: (n: ViewNode) => n.toString() }
+ })
+ dismiss(node: ViewNode) {
+ if (this._children.length === 0) return;
+
+ const index = this._children.findIndex(n => n === node);
+ if (index === -1) return;
+
+ this._children.splice(index, 1);
+ this.view.triggerNodeChange();
+ }
+
+ @gate()
+ @debug()
+ async refresh() {
+ if (this._children.length === 0) return;
+
+ await Promise.all(this._children.map(c => c.refresh()).filter(Functions.isPromise) as Promise[]);
+ }
+}
diff --git a/src/views/nodes/viewNode.ts b/src/views/nodes/viewNode.ts
index e565ddf..5c05328 100644
--- a/src/views/nodes/viewNode.ts
+++ b/src/views/nodes/viewNode.ts
@@ -36,6 +36,7 @@ export enum ResourceType {
ResultsFile = 'gitlens:file:results',
ResultsFiles = 'gitlens:results:files',
SearchResults = 'gitlens:results:search',
+ Search = 'gitlens:search',
Stash = 'gitlens:stash',
StashFile = 'gitlens:file:stash',
Stashes = 'gitlens:stashes',
@@ -92,6 +93,12 @@ export abstract class ViewNode {
@gate()
@debug()
refresh(reason?: RefreshReason): void | boolean | Promise | Promise {}
+
+ @gate()
+ @debug()
+ triggerChange(): Promise {
+ return this.view.refreshNode(this);
+ }
}
export abstract class ViewRefNode extends ViewNode {
@@ -162,12 +169,6 @@ export abstract class SubscribeableViewNode extends V
}
}
- @gate()
- @debug()
- async triggerChange() {
- return this.view.refreshNode(this);
- }
-
protected abstract async subscribe(): Promise;
@debug()
@@ -227,3 +228,7 @@ export abstract class SubscribeableViewNode extends V
await this._subscription;
}
}
+
+export function canDismissNode(view: View): view is View & { dismissNode(node: ViewNode): void } {
+ return typeof (view as any).dismissNode === 'function';
+}
diff --git a/src/views/repositoriesView.ts b/src/views/repositoriesView.ts
index 74ecc22..e5f96da 100644
--- a/src/views/repositoriesView.ts
+++ b/src/views/repositoriesView.ts
@@ -31,11 +31,6 @@ export class RepositoriesView extends ViewBase {
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(), this);
commands.registerCommand(
- this.getQualifiedCommand('refreshNode'),
- (node: ViewNode, args?: RefreshNodeCommandArgs) => this.refreshNode(node, args),
- this
- );
- commands.registerCommand(
this.getQualifiedCommand('setFilesLayoutToAuto'),
() => this.setFilesLayout(ViewFilesLayout.Auto),
this
diff --git a/src/views/resultsView.ts b/src/views/resultsView.ts
index 381d307..3ec872c 100644
--- a/src/views/resultsView.ts
+++ b/src/views/resultsView.ts
@@ -1,21 +1,10 @@
'use strict';
import { commands, ConfigurationChangeEvent } from 'vscode';
import { configuration, ResultsViewConfig, ViewFilesLayout, ViewsConfig } from '../configuration';
-import { CommandContext, GlyphChars, setCommandContext, WorkspaceState } from '../constants';
+import { CommandContext, setCommandContext, WorkspaceState } from '../constants';
import { Container } from '../container';
-import { GitLog, GitLogCommit } from '../git/gitService';
-import { Functions, Strings } from '../system';
-import {
- NamedRef,
- ResourceType,
- ResultsCommitNode,
- ResultsCommitsNode,
- ResultsComparisonNode,
- ResultsNode,
- ViewNode
-} from './nodes';
+import { NamedRef, ResultsComparisonNode, ResultsNode, ViewNode } from './nodes';
import { RefreshReason, ViewBase } from './viewBase';
-import { RefreshNodeCommandArgs } from './viewCommands';
export class ResultsView extends ViewBase {
constructor() {
@@ -34,13 +23,10 @@ export class ResultsView extends ViewBase {
protected registerCommands() {
void Container.viewCommands;
+ // commands.registerCommand(this.getQualifiedCommand('clear'), () => this.clear(), this);
+ commands.registerCommand(this.getQualifiedCommand('close'), () => this.close(), this);
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(), this);
commands.registerCommand(
- this.getQualifiedCommand('refreshNode'),
- (node: ViewNode, args?: RefreshNodeCommandArgs) => this.refreshNode(node, args),
- this
- );
- commands.registerCommand(
this.getQualifiedCommand('setFilesLayoutToAuto'),
() => this.setFilesLayout(ViewFilesLayout.Auto),
this
@@ -55,13 +41,6 @@ export class ResultsView extends ViewBase {
() => this.setFilesLayout(ViewFilesLayout.Tree),
this
);
-
- commands.registerCommand(
- this.getQualifiedCommand('dismissNode'),
- (node: ViewNode) => this.dismissNode(node),
- this
- );
- commands.registerCommand(this.getQualifiedCommand('close'), () => this.close(), this);
commands.registerCommand(this.getQualifiedCommand('setKeepResultsToOn'), () => this.setKeepResults(true), this);
commands.registerCommand(
this.getQualifiedCommand('setKeepResultsToOff'),
@@ -102,6 +81,12 @@ export class ResultsView extends ViewBase {
return Container.context.workspaceState.get(WorkspaceState.ViewsResultsKeepResults, false);
}
+ clear() {
+ if (this._root === undefined) return;
+
+ this._root.clear();
+ }
+
close() {
if (this._root === undefined) return;
@@ -111,11 +96,13 @@ export class ResultsView extends ViewBase {
setCommandContext(CommandContext.ViewsResults, false);
}
- addCommit(commit: GitLogCommit) {
- return this.addResults(new ResultsCommitNode(this, commit));
+ dismissNode(node: ViewNode) {
+ if (this._root === undefined) return;
+
+ this._root.dismiss(node);
}
- addComparison(repoPath: string, ref1: string | NamedRef, ref2: string | NamedRef) {
+ compare(repoPath: string, ref1: string | NamedRef, ref2: string | NamedRef) {
return this.addResults(
new ResultsComparisonNode(
this,
@@ -126,72 +113,9 @@ export class ResultsView extends ViewBase {
);
}
- addSearchResults(
- repoPath: string,
- resultsOrPromise: GitLog | Promise,
- resultsLabel:
- | string
- | {
- label: string;
- resultsType?: { singular: string; plural: string };
- }
- ) {
- const getCommitsQuery = async (maxCount: number | undefined) => {
- const results = await resultsOrPromise;
-
- let log;
- if (results !== undefined) {
- log = await Functions.seeded(
- results.query === undefined
- ? (maxCount: number | undefined) => Promise.resolve(results)
- : results.query,
- results.maxCount === maxCount ? results : undefined
- )(maxCount);
- }
-
- let label;
- if (typeof resultsLabel === 'string') {
- label = resultsLabel;
- }
- else {
- const count = log !== undefined ? log.count : 0;
- const truncated = log !== undefined ? log.truncated : false;
-
- const resultsType =
- resultsLabel.resultsType === undefined
- ? { singular: 'result', plural: 'results' }
- : resultsLabel.resultsType;
-
- let repository = '';
- if ((await Container.git.getRepositoryCount()) > 1) {
- const repo = await Container.git.getRepository(repoPath);
- repository = ` ${Strings.pad(GlyphChars.Dash, 1, 1)} ${(repo && repo.formattedName) || repoPath}`;
- }
-
- label = `${Strings.pluralize(resultsType.singular, count, {
- number: truncated ? `${count}+` : undefined,
- plural: resultsType.plural,
- zero: 'No'
- })} for ${resultsLabel.label}${repository}`;
- }
-
- return {
- label: label,
- log: log
- };
- };
-
- return this.addResults(
- new ResultsCommitsNode(this, this._root!, repoPath, getCommitsQuery, ResourceType.SearchResults)
- );
- }
-
private async addResults(results: ViewNode) {
- if (this._root === undefined) {
- this._root = this.getRoot();
- }
-
- this._root.addOrReplace(results, !this.keepResults);
+ const root = this.ensureRoot();
+ root.addOrReplace(results, !this.keepResults);
this._enabled = true;
await setCommandContext(CommandContext.ViewsResults, true);
@@ -199,12 +123,6 @@ export class ResultsView extends ViewBase {
setTimeout(() => this._tree!.reveal(results, { select: true }), 250);
}
- private dismissNode(node: ViewNode) {
- if (this._root === undefined) return;
-
- this._root.dismiss(node);
- }
-
private setFilesLayout(layout: ViewFilesLayout) {
return configuration.updateEffective(configuration.name('views')('results')('files')('layout').value, layout);
}
diff --git a/src/views/searchView.ts b/src/views/searchView.ts
new file mode 100644
index 0000000..3072170
--- /dev/null
+++ b/src/views/searchView.ts
@@ -0,0 +1,226 @@
+'use strict';
+import { commands, ConfigurationChangeEvent } from 'vscode';
+import { configuration, SearchViewConfig, ViewFilesLayout, ViewsConfig } from '../configuration';
+import { CommandContext, GlyphChars, setCommandContext, WorkspaceState } from '../constants';
+import { Container } from '../container';
+import { GitLog, GitRepoSearchBy } from '../git/gitService';
+import { Functions, Strings } from '../system';
+import { ResourceType, ResultsCommitsNode, SearchNode, ViewNode } from './nodes';
+import { RefreshReason, ViewBase } from './viewBase';
+
+interface SearchQueryResult {
+ label: string;
+ log: GitLog | undefined;
+}
+
+export class SearchView extends ViewBase {
+ constructor() {
+ super('gitlens.views.search');
+
+ setCommandContext(CommandContext.ViewsSearchKeepResults, this.keepResults);
+ }
+
+ getRoot() {
+ return new SearchNode(this);
+ }
+
+ protected get location(): string {
+ return this.config.location;
+ }
+
+ protected registerCommands() {
+ void Container.viewCommands;
+ commands.registerCommand(this.getQualifiedCommand('clear'), () => this.clear(), this);
+ commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(), this);
+ commands.registerCommand(
+ this.getQualifiedCommand('setFilesLayoutToAuto'),
+ () => this.setFilesLayout(ViewFilesLayout.Auto),
+ this
+ );
+ commands.registerCommand(
+ this.getQualifiedCommand('setFilesLayoutToList'),
+ () => this.setFilesLayout(ViewFilesLayout.List),
+ this
+ );
+ commands.registerCommand(
+ this.getQualifiedCommand('setFilesLayoutToTree'),
+ () => this.setFilesLayout(ViewFilesLayout.Tree),
+ this
+ );
+ commands.registerCommand(this.getQualifiedCommand('setKeepResultsToOn'), () => this.setKeepResults(true), this);
+ commands.registerCommand(
+ this.getQualifiedCommand('setKeepResultsToOff'),
+ () => this.setKeepResults(false),
+ this
+ );
+ }
+
+ protected onConfigurationChanged(e: ConfigurationChangeEvent) {
+ if (
+ !configuration.changed(e, configuration.name('views')('search').value) &&
+ !configuration.changed(e, configuration.name('views').value) &&
+ !configuration.changed(e, configuration.name('defaultGravatarsStyle').value)
+ ) {
+ return;
+ }
+
+ if (configuration.changed(e, configuration.name('views')('search')('location').value)) {
+ this.initialize(this.config.location /*, { showCollapseAll: true } */);
+ }
+
+ if (!configuration.initializing(e) && this._root !== undefined) {
+ void this.refresh(RefreshReason.ConfigurationChanged);
+ }
+ }
+
+ get config(): ViewsConfig & SearchViewConfig {
+ return { ...Container.config.views, ...Container.config.views.search };
+ }
+
+ get keepResults(): boolean {
+ return Container.context.workspaceState.get(WorkspaceState.ViewsSearchKeepResults, false);
+ }
+
+ clear() {
+ if (this._root === undefined) return;
+
+ this._root.clear();
+ }
+
+ dismissNode(node: ViewNode) {
+ if (this._root === undefined) return;
+
+ this._root.dismiss(node);
+ }
+
+ async search(
+ repoPath: string,
+ search: string,
+ searchBy: GitRepoSearchBy,
+ options: {
+ maxCount?: number;
+ label:
+ | string
+ | {
+ label: string;
+ resultsType?: { singular: string; plural: string };
+ };
+ }
+ ) {
+ await this.show();
+
+ const searchQueryFn = this.getSearchQueryFn(
+ repoPath,
+ Container.git.getLogForSearch(repoPath, search, searchBy, {
+ maxCount: options.maxCount
+ }),
+ options
+ );
+
+ return this.addResults(
+ new ResultsCommitsNode(this, this._root!, repoPath, searchQueryFn, ResourceType.SearchResults)
+ );
+ }
+
+ async showSearchResults(
+ repoPath: string,
+ results: GitLog,
+ options: {
+ label:
+ | string
+ | {
+ label: string;
+ resultsType?: { singular: string; plural: string };
+ };
+ }
+ ) {
+ const label = await this.getSearchLabel(repoPath, options.label, results);
+ const searchQueryFn = Functions.cachedOnce(this.getSearchQueryFn(repoPath, results, options), {
+ label: label,
+ log: results
+ });
+
+ return this.addResults(
+ new ResultsCommitsNode(this, this._root!, repoPath, searchQueryFn, ResourceType.SearchResults)
+ );
+ }
+
+ private async addResults(results: ViewNode) {
+ const root = this.ensureRoot();
+ root.addOrReplace(results, !this.keepResults);
+
+ setTimeout(() => this._tree!.reveal(results, { select: true }), 250);
+ }
+
+ private async getSearchLabel(
+ repoPath: string,
+ label:
+ | string
+ | {
+ label: string;
+ resultsType?: { singular: string; plural: string };
+ },
+ log: GitLog | undefined
+ ) {
+ if (typeof label === 'string') return label;
+
+ const count = log !== undefined ? log.count : 0;
+ const truncated = log !== undefined ? log.truncated : false;
+
+ const resultsType =
+ label.resultsType === undefined ? { singular: 'result', plural: 'results' } : label.resultsType;
+
+ let repository = '';
+ if ((await Container.git.getRepositoryCount()) > 1) {
+ const repo = await Container.git.getRepository(repoPath);
+ repository = ` ${Strings.pad(GlyphChars.Dash, 1, 1)} ${(repo && repo.formattedName) || repoPath}`;
+ }
+
+ return `${Strings.pluralize(resultsType.singular, count, {
+ number: truncated ? `${count}+` : undefined,
+ plural: resultsType.plural,
+ zero: 'No'
+ })} for ${label.label}${repository}`;
+ }
+
+ private getSearchQueryFn(
+ repoPath: string,
+ results: Promise | GitLog | undefined,
+ options: {
+ label:
+ | string
+ | {
+ label: string;
+ resultsType?: { singular: string; plural: string };
+ };
+ }
+ ): (maxCount: number | undefined) => Promise {
+ return async (maxCount: number | undefined) => {
+ if (Functions.isPromise(results)) {
+ results = await results;
+ }
+
+ let log;
+ if (results !== undefined) {
+ log = await (results.query === undefined
+ ? (maxCount: number | undefined) => Promise.resolve(results)
+ : results.query)(maxCount);
+ }
+
+ const label = await this.getSearchLabel(repoPath, options.label, log);
+ return {
+ label: label,
+ log: log
+ };
+ };
+ }
+
+ private setFilesLayout(layout: ViewFilesLayout) {
+ return configuration.updateEffective(configuration.name('views')('search')('files')('layout').value, layout);
+ }
+
+ private setKeepResults(enabled: boolean) {
+ Container.context.workspaceState.update(WorkspaceState.ViewsSearchKeepResults, enabled);
+ setCommandContext(CommandContext.ViewsSearchKeepResults, enabled);
+ }
+}
diff --git a/src/views/viewBase.ts b/src/views/viewBase.ts
index d117f47..1342523 100644
--- a/src/views/viewBase.ts
+++ b/src/views/viewBase.ts
@@ -23,6 +23,7 @@ import { ViewNode } from './nodes';
import { isPageable } from './nodes/viewNode';
import { RepositoriesView } from './repositoriesView';
import { ResultsView } from './resultsView';
+import { SearchView } from './searchView';
import { RefreshNodeCommandArgs } from './viewCommands';
export enum RefreshReason {
@@ -30,7 +31,7 @@ export enum RefreshReason {
VisibilityChanged = 'VisibilityChanged'
}
-export type View = RepositoriesView | FileHistoryView | LineHistoryView | ResultsView;
+export type View = RepositoriesView | FileHistoryView | LineHistoryView | ResultsView | SearchView;
export interface TreeViewNodeStateChangeEvent extends TreeViewExpansionEvent {
state: TreeItemCollapsibleState;
diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts
index c03e709..96407ea 100644
--- a/src/views/viewCommands.ts
+++ b/src/views/viewCommands.ts
@@ -19,6 +19,7 @@ import { GitService, GitUri } from '../git/gitService';
import { Arrays } from '../system';
import {
BranchNode,
+ canDismissNode,
CommitFileNode,
CommitNode,
RemoteNode,
@@ -49,6 +50,17 @@ export class ViewCommands implements Disposable {
private _terminalCwd: string | undefined;
constructor() {
+ commands.registerCommand(
+ 'gitlens.views.refreshNode',
+ (node: ViewNode, args?: RefreshNodeCommandArgs) => node.view.refreshNode(node, args),
+ this
+ );
+ commands.registerCommand(
+ 'gitlens.views.dismissNode',
+ (node: ViewNode) => canDismissNode(node.view) && node.view.dismissNode(node),
+ this
+ );
+
commands.registerCommand('gitlens.views.fetch', this.fetch, this);
commands.registerCommand('gitlens.views.pull', this.pull, this);
commands.registerCommand('gitlens.views.push', this.push, this);
@@ -149,19 +161,19 @@ export class ViewCommands implements Disposable {
private compareWithHead(node: ViewNode) {
if (!(node instanceof ViewRefNode)) return;
- return Container.resultsView.addComparison(node.repoPath, node.ref, 'HEAD');
+ return Container.resultsView.compare(node.repoPath, node.ref, 'HEAD');
}
private compareWithRemote(node: BranchNode) {
if (!node.branch.tracking) return;
- return Container.resultsView.addComparison(node.repoPath, node.branch.tracking, node.ref);
+ return Container.resultsView.compare(node.repoPath, node.branch.tracking, node.ref);
}
private compareWithWorking(node: ViewNode) {
if (!(node instanceof ViewRefNode)) return;
- return Container.resultsView.addComparison(node.repoPath, node.ref, '');
+ return Container.resultsView.compare(node.repoPath, node.ref, '');
}
private async compareAncestryWithWorking(node: BranchNode) {
@@ -171,7 +183,7 @@ export class ViewCommands implements Disposable {
const commonAncestor = await Container.git.getMergeBase(node.repoPath, branch.ref, node.ref);
if (commonAncestor === undefined) return;
- return Container.resultsView.addComparison(
+ return Container.resultsView.compare(
node.repoPath,
{ ref: commonAncestor, label: `ancestry with ${node.ref} (${GitService.shortenSha(commonAncestor)})` },
''
@@ -201,7 +213,7 @@ export class ViewCommands implements Disposable {
return;
}
- return Container.resultsView.addComparison(this._selection.repoPath, this._selection.ref, node.ref);
+ return Container.resultsView.compare(this._selection.repoPath, this._selection.ref, node.ref);
}
private _selection: ICompareSelected | undefined;
@@ -310,9 +322,8 @@ export class ViewCommands implements Disposable {
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
) {
const repoPath = node.commit.repoPath;
- const uris = Arrays.filterMap(
- node.commit.files,
- f => (f.status !== 'D' ? GitUri.fromFile(f, repoPath) : undefined)
+ const uris = Arrays.filterMap(node.commit.files, f =>
+ f.status !== 'D' ? GitUri.fromFile(f, repoPath) : undefined
);
for (const uri of uris) {