Переглянути джерело

Adds Search Commits view

Renames showCommitInResults to showCommitInView
Renames showFileHistoryInResults to showFileHistoryInView
main
Eric Amodio 6 роки тому
джерело
коміт
3f3b8d28d6
31 змінених файлів з 941 додано та 489 видалено
  1. +4
    -0
      images/dark/icon-clear.svg
  2. +4
    -0
      images/light/icon-clear.svg
  3. +257
    -120
      package.json
  4. +7
    -14
      src/commands/common.ts
  5. +1
    -1
      src/commands/diffBranchWithBranch.ts
  6. +20
    -14
      src/commands/showCommitSearch.ts
  7. +9
    -7
      src/commands/showQuickCommitDetails.ts
  8. +19
    -25
      src/commands/showQuickFileHistory.ts
  9. +4
    -1
      src/commands/showView.ts
  10. +4
    -2
      src/constants.ts
  11. +23
    -0
      src/container.ts
  12. +1
    -23
      src/quickpicks/branchHistoryQuickPick.ts
  13. +3
    -3
      src/quickpicks/commitQuickPick.ts
  14. +31
    -16
      src/quickpicks/commonQuickPicks.ts
  15. +3
    -3
      src/quickpicks/fileHistoryQuickPick.ts
  16. +14
    -14
      src/system/function.ts
  17. +7
    -0
      src/ui/config.ts
  18. +10
    -7
      src/views/fileHistoryView.ts
  19. +0
    -5
      src/views/lineHistoryView.ts
  20. +1
    -1
      src/views/nodes.ts
  21. +1
    -1
      src/views/nodes/common.ts
  22. +21
    -2
      src/views/nodes/fileHistoryTrackerNode.ts
  23. +0
    -28
      src/views/nodes/resultsCommitNode.ts
  24. +82
    -83
      src/views/nodes/resultsNode.ts
  25. +140
    -0
      src/views/nodes/searchNode.ts
  26. +11
    -6
      src/views/nodes/viewNode.ts
  27. +0
    -5
      src/views/repositoriesView.ts
  28. +17
    -99
      src/views/resultsView.ts
  29. +226
    -0
      src/views/searchView.ts
  30. +2
    -1
      src/views/viewBase.ts
  31. +19
    -8
      src/views/viewCommands.ts

+ 4
- 0
images/dark/icon-clear.svg Переглянути файл

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 22">
<path fill="#C5C5C5" d="M7.065 16H15v2H2.056v-2h5.009zm3.661-12H7.385L8.44 5.061 7.505 6H15V4h-4.274zm-7.489 8H2.056v2H15v-2H3.237zm4.208-4l.995 1-.995 1H15V8H7.445z"/>
<path fill="#f48771" d="M5.072 7.03L7.032 9l-1.054 1.061-1.96-1.97-1.961 1.97L1 9l1.96-1.97L1 5.061 2.056 4l1.96 1.97L5.977 4l1.057 1.061L5.072 7.03z"/>
</svg>

+ 4
- 0
images/light/icon-clear.svg Переглянути файл

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 22">
<path fill="#424242" d="M7.065 16H15v2H2.056v-2h5.009zm3.661-12H7.385L8.44 5.061 7.505 6H15V4h-4.274zm-7.489 8H2.056v2H15v-2H3.237zm4.208-4l.995 1-.995 1H15V8H7.445z"/>
<path fill="#A1260D" d="M5.072 7.03L7.032 9l-1.054 1.061-1.96-1.97-1.961 1.97L1 9l1.96-1.97L1 5.061 2.056 4l1.96 1.97L5.977 4l1.057 1.061L5.072 7.03z"/>
</svg>

+ 257
- 120
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"
}
]
}

+ 7
- 14
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];
}
}

+ 1
- 1
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;
}

+ 20
- 14
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 (@<pattern>), files (:<pattern>), commit id (#<sha>), changes (=<pattern>), changed lines (~<pattern>)`,
placeHolder: `Search commits by message, author (@<pattern>), files (:<pattern>), commit id (#<sha>), changes (=<pattern>), changed lines (~<pattern>)`,
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;

+ 9
- 7
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<any> {
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;
}

+ 19
- 25
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<any> {
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;

+ 4
- 1
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;

+ 4
- 2
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'
}

+ 23
- 0
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;

+ 1
- 23
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) {

+ 3
- 3
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) {

+ 31
- 16
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;
}
}

+ 3
- 3
src/quickpicks/fileHistoryQuickPick.ts Переглянути файл

@ -37,7 +37,7 @@ export class FileHistoryQuickPick {
pickerOnly?: boolean;
progressCancellation?: CancellationTokenSource;
showAllCommand?: CommandQuickPickItem;
showInResultsCommand?: CommandQuickPickItem;
showInViewCommand?: CommandQuickPickItem;
} = {}
): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
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) {

+ 14
- 14
src/system/function.ts Переглянути файл

@ -16,6 +16,19 @@ interface IPropOfValue {
}
export namespace Functions {
export function cachedOnce<T>(fn: (...args: any[]) => Promise<T>, seed: T): (...args: any[]) => Promise<T> {
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<T>(promise: Promise<T>, token: CancellationToken): Promise<T | undefined> {
return new Promise<T | undefined>((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<any> {
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<T>(fn: (...args: any[]) => Promise<T>, seed: T): (...args: any[]) => Promise<T> {
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 = {

+ 7
- 0
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;

+ 10
- 7
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<FileHistoryTrackerNode> {
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();

+ 0
- 5
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'),

+ 1
- 1
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';

+ 1
- 1
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;
}

+ 21
- 2
src/views/nodes/fileHistoryTrackerNode.ts Переглянути файл

@ -14,6 +14,7 @@ import { ResourceType, SubscribeableViewNode, unknownGitUri, ViewNode } from './
export class FileHistoryTrackerNode extends SubscribeableViewNode<FileHistoryView> {
private _baseRef: string | undefined;
private _fileUri: GitUri | undefined;
private _child: FileHistoryNode | undefined;
constructor(view: FileHistoryView) {
@ -36,7 +37,7 @@ export class FileHistoryTrackerNode extends SubscribeableViewNode
async getChildren(): Promise<ViewNode[]> {
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
];
}
const uri = this.uri;
const uri = this._fileUri || this.uri;
const fileUri = new GitUri(uri, { ...uri, sha: this._baseRef || uri.sha } as GitCommitish);
this._child = new FileHistoryNode(fileUri, this.view, this);
}
@ -136,9 +137,27 @@ export class FileHistoryTrackerNode extends SubscribeableViewNode
@log()
setEditorFollowing(enabled: boolean) {
if (enabled && this._fileUri !== undefined) {
this._fileUri = undefined;
this._baseRef = undefined;
this._uri = unknownGitUri;
// Don't need to call triggerChange here, since canSubscribe will do it
}
this.canSubscribe = enabled;
}
@gate()
@log()
async showHistoryForUri(uri: GitUri, baseRef?: string) {
this._fileUri = uri;
this._baseRef = baseRef;
this._uri = unknownGitUri;
await this.triggerChange();
}
@debug()
protected async subscribe() {
return Disposable.from(

+ 0
- 28
src/views/nodes/resultsCommitNode.ts Переглянути файл

@ -1,28 +0,0 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GitLogCommit } from '../../git/gitService';
import { ResultsView } from '../resultsView';
import { CommitNode } from './commitNode';
import { ResourceType, ViewNode } from './viewNode';
export class ResultsCommitNode extends ViewNode {
constructor(
view: ResultsView,
public readonly commit: GitLogCommit
) {
super(commit.toGitUri(), view);
}
getChildren(): ViewNode[] {
return [new CommitNode(this.view, this, this.commit)];
}
getTreeItem(): TreeItem {
const item = new TreeItem(
`1 result for commits with an id matching '${this.commit.shortSha}'`,
TreeItemCollapsibleState.Expanded
);
item.contextValue = ResourceType.Results;
return item;
}
}

+ 82
- 83
src/views/nodes/resultsNode.ts Переглянути файл

@ -1,14 +1,11 @@
'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, Strings } from '../../system';
import { debug, Functions, gate, log } from '../../system';
import { ResultsView } from '../resultsView';
import { CommandMessageNode, MessageNode } from './common';
import { MessageNode } from './common';
import { ResourceType, unknownGitUri, ViewNode } from './viewNode';
export class ResultsNode extends ViewNode {
export class ResultsNode extends ViewNode<ResultsView> {
private _children: (ViewNode | MessageNode)[] = [];
constructor(view: ResultsView) {
@ -17,83 +14,85 @@ export class ResultsNode extends ViewNode {
async getChildren(): Promise<ViewNode[]> {
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 <message-pattern>`,
'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 @<author-pattern>`,
'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 #<sha>`,
'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 :<file-pattern>`,
'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 =<pattern>`,
'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 ~<pattern>`,
'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 <message-pattern>`,
// '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 @<author-pattern>`,
// '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 #<sha>`,
// '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 :<file-pattern>`,
// '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 =<pattern>`,
// '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 ~<pattern>`,
// 'Click to search by changed lines'
// )
// ];
}
return this._children;

+ 140
- 0
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<ViewNode[]> {
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 &lt;message-pattern&gt;)`,
'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 @&lt;author-pattern&gt;)`,
'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 #&lt;sha&gt;)`,
'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 :&lt;file-pattern&gt;)`,
'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 =&lt;pattern&gt;)`,
'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 ~&lt;pattern&gt;)`,
'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<any>[]);
}
}

+ 11
- 6
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<void> | Promise<boolean> {}
@gate()
@debug()
triggerChange(): Promise<void> {
return this.view.refreshNode(this);
}
}
export abstract class ViewRefNode<TView extends View = View> extends ViewNode<TView> {
@ -162,12 +169,6 @@ export abstract class SubscribeableViewNode extends V
}
}
@gate()
@debug()
async triggerChange() {
return this.view.refreshNode(this);
}
protected abstract async subscribe(): Promise<Disposable | undefined>;
@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';
}

+ 0
- 5
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

+ 17
- 99
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<ResultsNode> {
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<boolean>(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<GitLog | undefined>,
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);
}

+ 226
- 0
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<SearchNode> {
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<boolean>(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> | GitLog | undefined,
options: {
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
}
): (maxCount: number | undefined) => Promise<SearchQueryResult> {
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);
}
}

+ 2
- 1
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<T> extends TreeViewExpansionEvent<T> {
state: TreeItemCollapsibleState;

+ 19
- 8
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) {

Завантаження…
Відмінити
Зберегти