Browse Source

Combines search & compare views

main
Eric Amodio 4 years ago
parent
commit
32183eca73
42 changed files with 1381 additions and 1842 deletions
  1. +0
    -4
      images/dark/icon-pin-small-selected.svg
  2. +0
    -3
      images/dark/icon-pin-small.svg
  3. +0
    -3
      images/dark/icon-pin.svg
  4. +0
    -3
      images/dark/icon-unpin.svg
  5. +0
    -4
      images/light/icon-pin-small-selected.svg
  6. +0
    -3
      images/light/icon-pin-small.svg
  7. +0
    -3
      images/light/icon-pin.svg
  8. +0
    -3
      images/light/icon-unpin.svg
  9. +165
    -375
      package.json
  10. +3
    -5
      src/commands/common.ts
  11. +1
    -1
      src/commands/diffBranchWith.ts
  12. +21
    -8
      src/commands/git/search.ts
  13. +1
    -1
      src/commands/quickCommand.buttons.ts
  14. +8
    -8
      src/commands/quickCommand.steps.ts
  15. +2
    -2
      src/commands/searchCommits.ts
  16. +3
    -6
      src/commands/showView.ts
  17. +3
    -14
      src/config.ts
  18. +28
    -8
      src/constants.ts
  19. +7
    -18
      src/container.ts
  20. +2
    -2
      src/quickpicks/commitQuickPickItems.ts
  21. +1
    -1
      src/quickpicks/quickPicksItems.ts
  22. +0
    -184
      src/views/compareView.ts
  23. +1
    -3
      src/views/nodes.ts
  24. +20
    -18
      src/views/nodes/compareBranchNode.ts
  25. +0
    -231
      src/views/nodes/compareNode.ts
  26. +20
    -8
      src/views/nodes/comparePickerNode.ts
  27. +58
    -72
      src/views/nodes/compareResultsNode.ts
  28. +3
    -4
      src/views/nodes/pullRequestNode.ts
  29. +50
    -44
      src/views/nodes/resultsCommitsNode.ts
  30. +0
    -147
      src/views/nodes/searchNode.ts
  31. +0
    -64
      src/views/nodes/searchResultsCommitsNode.ts
  32. +297
    -0
      src/views/nodes/searchResultsNode.ts
  33. +1
    -5
      src/views/nodes/viewNode.ts
  34. +502
    -0
      src/views/searchAndCompareView.ts
  35. +0
    -279
      src/views/searchView.ts
  36. +5
    -10
      src/views/viewBase.ts
  37. +6
    -6
      src/views/viewCommands.ts
  38. +0
    -135
      src/webviews/apps/settings/partials/views.search.html
  39. +50
    -22
      src/webviews/apps/settings/partials/views.searchAndCompare.html
  40. +4
    -15
      src/webviews/apps/settings/settings.html
  41. +1
    -2
      src/webviews/settingsWebview.ts

+ 0
- 4
images/dark/icon-pin-small-selected.svg View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#fff" fill-opacity=".1" stroke="#C5C5C5" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/>
<path fill="#C5C5C5" fill-rule="evenodd" d="M5.47 1.518c-.2.029-.323.283-.252.516.025.082.037.097.248.307l.434.33.402.229s.343.092.234.309c-.022.048-.702 3.532-.702 3.532l-.055.229c-.03.158-.335.453-.335.453l-1.387 1.39s-.349.36-.527.553c-.067.136-.014.356.081.45.125.125-.037.116 1.99.116 2.078 0 1.865.24 1.865.24s.161 4.102.234 4.328c.073.226.525.222.6 0 .065-.222.236-4.328.236-4.328s-.211-.234 1.863-.24c2.03.002 1.862.013 1.996-.117.089-.097.141-.33.075-.455l-.521-.546s-.937-.929-1.4-1.391c-.289-.29-.296-.283-.329-.455a2.352 2.352 0 0 0-.056-.227S9.5 3.324 9.463 3.208c-.1-.216.234-.308.234-.308l.402-.226s.133-.023.434-.333c.212-.212.23-.242.253-.307.07-.235.06-.485-.258-.519-.08-.011-1.3-.116-2.521-.115-1.229.001-2.46.108-2.536.118zM8.347 2.56l.937 4.636s.047.25.111.397c.181.416.725.796.725.796s.669.57.502.625c-.156.068-5.08.067-5.241 0-.167-.057.502-.625.502-.625s.54-.38.724-.796c.066-.147.115-.397.115-.397l.934-4.637s.208-.102.35-.1c.139 0 .341.101.341.101z" clip-rule="evenodd"/>
</svg>

+ 0
- 3
images/dark/icon-pin-small.svg View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#C5C5C5" fill-rule="evenodd" d="M5.47 1.518c-.2.029-.323.283-.252.516.025.082.037.097.248.307l.434.33.402.229s.343.092.234.309c-.022.048-.702 3.532-.702 3.532l-.055.229c-.03.158-.335.453-.335.453l-1.387 1.39s-.349.36-.527.553c-.067.136-.014.356.081.45.125.125-.037.116 1.99.116 2.078 0 1.865.24 1.865.24s.161 4.102.234 4.328c.073.226.525.222.6 0 .065-.222.236-4.328.236-4.328s-.211-.234 1.863-.24c2.03.002 1.862.013 1.996-.117.089-.097.141-.33.075-.455l-.521-.546s-.937-.929-1.4-1.391c-.289-.29-.296-.283-.329-.455a2.352 2.352 0 0 0-.056-.227S9.5 3.324 9.463 3.208c-.1-.216.234-.308.234-.308l.402-.226s.133-.023.434-.333c.212-.212.23-.242.253-.307.07-.235.06-.485-.258-.519-.08-.011-1.3-.116-2.521-.115-1.229.001-2.46.108-2.536.118zM8.347 2.56l.937 4.636s.047.25.111.397c.181.416.725.796.725.796s.669.57.502.625c-.156.068-5.08.067-5.241 0-.167-.057.502-.625.502-.625s.54-.38.724-.796c.066-.147.115-.397.115-.397l.934-4.637s.208-.102.35-.1c.139 0 .341.101.341.101z" clip-rule="evenodd"/>
</svg>

+ 0
- 3
images/dark/icon-pin.svg View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#C5C5C5" fill-rule="evenodd" d="M4.95.143c-.241.034-.39.341-.305.622.03.098.045.116.299.37l.524.397.484.277s.414.11.283.372c-.027.058-.847 4.26-.847 4.26l-.066.275c-.037.19-.404.547-.404.547L3.246 8.94s-.421.433-.636.666c-.081.164-.017.43.098.542.15.151-.045.14 2.399.14 2.506 0 2.25.29 2.25.29s.194 4.946.281 5.22c.088.272.633.267.724 0 .078-.269.285-5.22.285-5.22s-.255-.282 2.245-.29c2.448.003 2.246.017 2.408-.141.107-.117.17-.397.09-.548-.212-.22-.628-.66-.628-.66s-1.13-1.119-1.687-1.676c-.35-.35-.359-.341-.398-.548a2.82 2.82 0 0 0-.067-.274s-.803-4.12-.847-4.26c-.121-.261.282-.372.282-.372l.485-.273s.16-.027.524-.401c.255-.256.277-.292.304-.37.086-.284.072-.585-.31-.626A35.293 35.293 0 0 0 8.006 0a36.01 36.01 0 0 0-3.058.143zm3.468 1.256l1.13 5.59s.057.301.134.48c.219.501.874.959.874.959s.807.686.606.753c-.189.082-6.126.081-6.32 0-.202-.068.605-.753.605-.753s.652-.46.874-.96c.078-.177.138-.479.138-.479l1.126-5.591s.25-.123.422-.121c.167 0 .411.122.411.122z" clip-rule="evenodd"/>
</svg>

+ 0
- 3
images/dark/icon-unpin.svg View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#C5C5C5" fill-rule="evenodd" d="M10.579 1.28c-.195-.145-.517-.034-.655.226-.049.09-.05.114-.05.472l.09.652.146.538s.215.372-.064.463c-.06.022-3.61 2.413-3.61 2.413l-.242.148c-.16.11-.672.102-.672.102l-2.368.003s-.604.008-.92.02c-.174.06-.316.294-.315.454 0 .213-.13.067 1.597 1.795 1.773 1.772 1.386 1.796 1.386 1.796s-3.36 3.635-3.491 3.89c-.131.255.258.637.512.511.244-.134 3.891-3.488 3.891-3.488s.02-.38 1.794 1.382c1.728 1.733 1.576 1.6 1.801 1.602.159-.006.402-.16.453-.322.005-.307.02-.911.02-.911s-.006-1.59-.006-2.379c0-.494-.013-.495.106-.668.042-.062.112-.175.146-.242 0 0 2.346-3.481 2.414-3.612.099-.27.462-.063.462-.063l.536.15s.133.095.654.087c.362 0 .402-.01.477-.046.261-.14.465-.363.223-.663a35.31 35.31 0 0 0-2.052-2.248 36.038 36.038 0 0 0-2.263-2.061zm1.565 3.342L8.99 9.374s-.173.253-.244.434c-.2.51-.06 1.296-.06 1.296s.084 1.056-.105.96c-.192-.074-4.39-4.273-4.47-4.468-.093-.191.962-.105.962-.105s.785.137 1.296-.06c.181-.07.436-.242.436-.242l4.75-3.157s.264.09.384.213c.118.119.205.377.205.377z" clip-rule="evenodd"/>
</svg>

+ 0
- 4
images/light/icon-pin-small-selected.svg View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#000" fill-opacity=".1" stroke="#424242" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/>
<path fill="#424242" fill-rule="evenodd" d="M5.47 1.518c-.2.029-.323.283-.252.516.025.082.037.097.248.307l.434.33.402.229s.343.092.234.309c-.022.048-.702 3.532-.702 3.532l-.055.229c-.03.158-.335.453-.335.453l-1.387 1.39s-.349.36-.527.553c-.067.136-.014.356.081.45.125.125-.037.116 1.99.116 2.078 0 1.865.24 1.865.24s.161 4.102.234 4.328c.073.226.525.222.6 0 .065-.222.236-4.328.236-4.328s-.211-.234 1.863-.24c2.03.002 1.862.013 1.996-.117.089-.097.141-.33.075-.455l-.521-.546s-.937-.929-1.4-1.391c-.289-.29-.296-.283-.329-.455a2.352 2.352 0 0 0-.056-.227S9.5 3.324 9.463 3.208c-.1-.216.234-.308.234-.308l.402-.226s.133-.023.434-.333c.212-.212.23-.242.253-.307.07-.235.06-.485-.258-.519-.08-.011-1.3-.116-2.521-.115-1.229.001-2.46.108-2.536.118zM8.347 2.56l.937 4.636s.047.25.111.397c.181.416.725.796.725.796s.669.57.502.625c-.156.068-5.08.067-5.241 0-.167-.057.502-.625.502-.625s.54-.38.724-.796c.066-.147.115-.397.115-.397l.934-4.637s.208-.102.35-.1c.139 0 .341.101.341.101z" clip-rule="evenodd"/>
</svg>

+ 0
- 3
images/light/icon-pin-small.svg View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#424242" fill-rule="evenodd" d="M5.47 1.518c-.2.029-.323.283-.252.516.025.082.037.097.248.307l.434.33.402.229s.343.092.234.309c-.022.048-.702 3.532-.702 3.532l-.055.229c-.03.158-.335.453-.335.453l-1.387 1.39s-.349.36-.527.553c-.067.136-.014.356.081.45.125.125-.037.116 1.99.116 2.078 0 1.865.24 1.865.24s.161 4.102.234 4.328c.073.226.525.222.6 0 .065-.222.236-4.328.236-4.328s-.211-.234 1.863-.24c2.03.002 1.862.013 1.996-.117.089-.097.141-.33.075-.455l-.521-.546s-.937-.929-1.4-1.391c-.289-.29-.296-.283-.329-.455a2.352 2.352 0 0 0-.056-.227S9.5 3.324 9.463 3.208c-.1-.216.234-.308.234-.308l.402-.226s.133-.023.434-.333c.212-.212.23-.242.253-.307.07-.235.06-.485-.258-.519-.08-.011-1.3-.116-2.521-.115-1.229.001-2.46.108-2.536.118zM8.347 2.56l.937 4.636s.047.25.111.397c.181.416.725.796.725.796s.669.57.502.625c-.156.068-5.08.067-5.241 0-.167-.057.502-.625.502-.625s.54-.38.724-.796c.066-.147.115-.397.115-.397l.934-4.637s.208-.102.35-.1c.139 0 .341.101.341.101z" clip-rule="evenodd"/>
</svg>

+ 0
- 3
images/light/icon-pin.svg View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#424242" fill-rule="evenodd" d="M4.95.143c-.241.034-.39.341-.305.622.03.098.045.116.299.37l.524.397.484.277s.414.11.283.372c-.027.058-.847 4.26-.847 4.26l-.066.275c-.037.19-.404.547-.404.547L3.246 8.94s-.421.433-.636.666c-.081.164-.017.43.098.542.15.151-.045.14 2.399.14 2.506 0 2.25.29 2.25.29s.194 4.946.281 5.22c.088.272.633.267.724 0 .078-.269.285-5.22.285-5.22s-.255-.282 2.245-.29c2.448.003 2.246.017 2.408-.141.107-.117.17-.397.09-.548-.212-.22-.628-.66-.628-.66s-1.13-1.119-1.687-1.676c-.35-.35-.359-.341-.398-.548a2.82 2.82 0 0 0-.067-.274s-.803-4.12-.847-4.26c-.121-.261.282-.372.282-.372l.485-.273s.16-.027.524-.401c.255-.256.277-.292.304-.37.086-.284.072-.585-.31-.626A35.293 35.293 0 0 0 8.006 0a36.01 36.01 0 0 0-3.058.143zm3.468 1.256l1.13 5.59s.057.301.134.48c.219.501.874.959.874.959s.807.686.606.753c-.189.082-6.126.081-6.32 0-.202-.068.605-.753.605-.753s.652-.46.874-.96c.078-.177.138-.479.138-.479l1.126-5.591s.25-.123.422-.121c.167 0 .411.122.411.122z" clip-rule="evenodd"/>
</svg>

+ 0
- 3
images/light/icon-unpin.svg View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#424242" fill-rule="evenodd" d="M10.579 1.28c-.195-.145-.517-.034-.655.226-.049.09-.05.114-.05.472l.09.652.146.538s.215.372-.064.463c-.06.022-3.61 2.413-3.61 2.413l-.242.148c-.16.11-.672.102-.672.102l-2.368.003s-.604.008-.92.02c-.174.06-.316.294-.315.454 0 .213-.13.067 1.597 1.795 1.773 1.772 1.386 1.796 1.386 1.796s-3.36 3.635-3.491 3.89c-.131.255.258.637.512.511.244-.134 3.891-3.488 3.891-3.488s.02-.38 1.794 1.382c1.728 1.733 1.576 1.6 1.801 1.602.159-.006.402-.16.453-.322.005-.307.02-.911.02-.911s-.006-1.59-.006-2.379c0-.494-.013-.495.106-.668.042-.062.112-.175.146-.242 0 0 2.346-3.481 2.414-3.612.099-.27.462-.063.462-.063l.536.15s.133.095.654.087c.362 0 .402-.01.477-.046.261-.14.465-.363.223-.663a35.31 35.31 0 0 0-2.052-2.248 36.038 36.038 0 0 0-2.263-2.061zm1.565 3.342L8.99 9.374s-.173.253-.244.434c-.2.51-.06 1.296-.06 1.296s.084 1.056-.105.96c-.192-.074-4.39-4.273-4.47-4.468-.093-.191.962-.105.962-.105s.785.137 1.296-.06c.181-.07.436-.242.436-.242l4.75-3.157s.264.09.384.213c.118.119.205.377.205.377z" clip-rule="evenodd"/>
</svg>

+ 165
- 375
package.json View File

@ -595,10 +595,6 @@
"scope": "window" "scope": "window"
}, },
"gitlens.gitCommands.search.showResultsInView": { "gitlens.gitCommands.search.showResultsInView": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to show the commit search results in the _Search Commits_ view or directly within the quick pick menu",
"scope": "window",
"deprecationMessage": "Depreciated: This setting has been renamed to gitlens.gitCommands.search.showResultsInSideBar", "deprecationMessage": "Depreciated: This setting has been renamed to gitlens.gitCommands.search.showResultsInSideBar",
"markdownDeprecationMessage": "Depreciated: This setting has been renamed to `#gitlens.gitCommands.search.showResultsInSideBar#`" "markdownDeprecationMessage": "Depreciated: This setting has been renamed to `#gitlens.gitCommands.search.showResultsInSideBar#`"
}, },
@ -1696,52 +1692,6 @@
"markdownDescription": "Specifies whether to show a comparison of the current branch or the working tree with a user-selected reference (branch, tag. etc) in the _Commits_ view", "markdownDescription": "Specifies whether to show a comparison of the current branch or the working tree with a user-selected reference (branch, tag. etc) in the _Commits_ view",
"scope": "window" "scope": "window"
}, },
"gitlens.views.compare.avatars": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to show avatar images instead of commit (or status) icons in the _Compare Commits_ view",
"scope": "window"
},
"gitlens.views.compare.files.compact": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to compact (flatten) unnecessary file nesting in the _Compare Commits_ view. Only applies when `#gitlens.views.compare.files.layout#` is set to `tree` or `auto`",
"scope": "window"
},
"gitlens.views.compare.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.compare.files.threshold#` value and the number of files at each nesting level",
"Displays files as a list",
"Displays files as a tree"
],
"markdownDescription": "Specifies how the _Compare Commits_ view will display files",
"scope": "window"
},
"gitlens.views.compare.files.threshold": {
"type": "number",
"default": 5,
"markdownDescription": "Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the _Compare Commits_ view. Only applies when `#gitlens.views.compare.files.layout#` is set to `auto`",
"scope": "window"
},
"gitlens.views.compare.pullRequests.enabled": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to query for pull requests associated with branches and commits in the _Compare Commits_ view. Requires a connection to a supported remote service (e.g. GitHub)",
"scope": "window"
},
"gitlens.views.compare.pullRequests.showForCommits": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to show pull requests (if any) associated with commits in the _Compare Commits_ view. Requires a connection to a supported remote service (e.g. GitHub)",
"scope": "window"
},
"gitlens.views.contributors.avatars": { "gitlens.views.contributors.avatars": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
@ -2003,19 +1953,19 @@
"markdownDescription": "Specifies whether to show a comparison of the current branch or the working tree with a user-selected reference (branch, tag. etc) in the _Repositories_ view", "markdownDescription": "Specifies whether to show a comparison of the current branch or the working tree with a user-selected reference (branch, tag. etc) in the _Repositories_ view",
"scope": "window" "scope": "window"
}, },
"gitlens.views.search.avatars": {
"gitlens.views.searchAndCompare.avatars": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"markdownDescription": "Specifies whether to show avatar images instead of commit (or status) icons in the _Search Commits_ view",
"markdownDescription": "Specifies whether to show avatar images instead of commit (or status) icons in the _Search & Compare_ view",
"scope": "window" "scope": "window"
}, },
"gitlens.views.search.files.compact": {
"gitlens.views.searchAndCompare.files.compact": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"markdownDescription": "Specifies whether to compact (flatten) unnecessary file nesting in the _Search Commits_ view. Only applies when `#gitlens.views.search.files.layout#` is set to `tree` or `auto`",
"markdownDescription": "Specifies whether to compact (flatten) unnecessary file nesting in the _Search & Compare_ view. Only applies when `#gitlens.views.searchAndCompare.files.layout#` is set to `tree` or `auto`",
"scope": "window" "scope": "window"
}, },
"gitlens.views.search.files.layout": {
"gitlens.views.searchAndCompare.files.layout": {
"type": "string", "type": "string",
"default": "auto", "default": "auto",
"enum": [ "enum": [
@ -2024,29 +1974,29 @@
"tree" "tree"
], ],
"enumDescriptions": [ "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",
"Automatically switches between displaying files as a `tree` or `list` based on the `#gitlens.views.searchAndCompare.files.threshold#` value and the number of files at each nesting level",
"Displays files as a list", "Displays files as a list",
"Displays files as a tree" "Displays files as a tree"
], ],
"markdownDescription": "Specifies how the _Search Commits_ view will display files",
"markdownDescription": "Specifies how the _Search & Compare_ view will display files",
"scope": "window" "scope": "window"
}, },
"gitlens.views.search.files.threshold": {
"gitlens.views.searchAndCompare.files.threshold": {
"type": "number", "type": "number",
"default": 5, "default": 5,
"markdownDescription": "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. Only applies when `#gitlens.views.search.files.layout#` is set to `auto`",
"markdownDescription": "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 & Compare_ view. Only applies when `#gitlens.views.searchAndCompare.files.layout#` is set to `auto`",
"scope": "window" "scope": "window"
}, },
"gitlens.views.search.pullRequests.enabled": {
"gitlens.views.searchAndCompare.pullRequests.enabled": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"markdownDescription": "Specifies whether to query for pull requests associated with commits in the _Search Commits_ view. Requires a connection to a supported remote service (e.g. GitHub)",
"markdownDescription": "Specifies whether to query for pull requests associated with commits in the _Search & Compare_ view. Requires a connection to a supported remote service (e.g. GitHub)",
"scope": "window" "scope": "window"
}, },
"gitlens.views.search.pullRequests.showForCommits": {
"gitlens.views.searchAndCompare.pullRequests.showForCommits": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"markdownDescription": "Specifies whether to show pull requests (if any) associated with commits in the _Search Commits_ view. Requires a connection to a supported remote service (e.g. GitHub)",
"markdownDescription": "Specifies whether to show pull requests (if any) associated with commits in the _Search & Compare_ view. Requires a connection to a supported remote service (e.g. GitHub)",
"scope": "window" "scope": "window"
}, },
"gitlens.views.showRelativeDateMarkers": { "gitlens.views.showRelativeDateMarkers": {
@ -2464,12 +2414,6 @@
"icon": "$(gear)" "icon": "$(gear)"
}, },
{ {
"command": "gitlens.showSettingsPage#compare-view",
"title": "Open Settings",
"category": "GitLens",
"icon": "$(gear)"
},
{
"command": "gitlens.showSettingsPage#contributors-view", "command": "gitlens.showSettingsPage#contributors-view",
"title": "Open Settings", "title": "Open Settings",
"category": "GitLens", "category": "GitLens",
@ -2500,7 +2444,7 @@
"icon": "$(gear)" "icon": "$(gear)"
}, },
{ {
"command": "gitlens.showSettingsPage#search-commits-view",
"command": "gitlens.showSettingsPage#search-compare-view",
"title": "Open Settings", "title": "Open Settings",
"category": "GitLens", "category": "GitLens",
"icon": "$(gear)" "icon": "$(gear)"
@ -2523,11 +2467,6 @@
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.showCompareView",
"title": "Show Compare View",
"category": "GitLens"
},
{
"command": "gitlens.showFileHistoryView", "command": "gitlens.showFileHistoryView",
"title": "Show File History View", "title": "Show File History View",
"category": "GitLens" "category": "GitLens"
@ -2543,8 +2482,8 @@
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.showSearchView",
"title": "Show Search Commits View",
"command": "gitlens.showSearchAndCompareView",
"title": "Show Search And Compare Commits View",
"category": "GitLens" "category": "GitLens"
}, },
{ {
@ -3767,96 +3706,6 @@
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.views.compare.clear",
"title": "Clear Results",
"category": "GitLens",
"icon": "$(clear-all)"
},
{
"command": "gitlens.views.compare.copy",
"title": "Copy",
"category": "GitLens"
},
{
"command": "gitlens.views.compare.pinComparison",
"title": "Pin Comparison",
"category": "GitLens",
"icon": {
"dark": "images/dark/icon-pin.svg",
"light": "images/light/icon-pin.svg"
}
},
{
"command": "gitlens.views.compare.unpinComparison",
"title": "Unpin Comparison",
"category": "GitLens",
"icon": "$(pin)"
},
{
"command": "gitlens.views.compare.refresh",
"title": "Refresh",
"category": "GitLens",
"icon": "$(refresh)"
},
{
"command": "gitlens.views.compare.selectForCompare",
"title": "Compare References...",
"category": "GitLens",
"icon": "$(compare-changes)"
},
{
"command": "gitlens.views.compare.setFilesLayoutToAuto",
"title": "Automatic Layout",
"category": "GitLens",
"icon": "$(list-tree)"
},
{
"command": "gitlens.views.compare.setFilesLayoutToList",
"title": "List Layout",
"category": "GitLens",
"icon": {
"dark": "images/dark/icon-view-auto.svg",
"light": "images/light/icon-view-auto.svg"
}
},
{
"command": "gitlens.views.compare.setFilesLayoutToTree",
"title": "Tree Layout",
"category": "GitLens",
"icon": "$(list-flat)"
},
{
"command": "gitlens.views.compare.setKeepResultsToOn",
"title": "Keep Results",
"category": "GitLens",
"icon": "$(unlock)"
},
{
"command": "gitlens.views.compare.setKeepResultsToOff",
"title": "Keep Results",
"category": "GitLens",
"icon": "$(lock)"
},
{
"command": "gitlens.views.compare.setShowAvatarsOn",
"title": "Show Avatars",
"category": "GitLens"
},
{
"command": "gitlens.views.compare.setShowAvatarsOff",
"title": "Hide Avatars",
"category": "GitLens"
},
{
"command": "gitlens.views.compare.swapComparison",
"title": "Swap Comparison",
"category": "GitLens",
"icon": {
"dark": "images/dark/icon-swap.svg",
"light": "images/light/icon-swap.svg"
}
},
{
"command": "gitlens.views.contributors.copy", "command": "gitlens.views.contributors.copy",
"title": "Copy", "title": "Copy",
"category": "GitLens" "category": "GitLens"
@ -4129,36 +3978,60 @@
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.views.search.clear",
"command": "gitlens.views.searchAndCompare.clear",
"title": "Clear Results", "title": "Clear Results",
"category": "GitLens", "category": "GitLens",
"icon": "$(clear-all)" "icon": "$(clear-all)"
}, },
{ {
"command": "gitlens.views.search.copy",
"command": "gitlens.views.searchAndCompare.copy",
"title": "Copy", "title": "Copy",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.views.search.refresh",
"command": "gitlens.views.searchAndCompare.pin",
"title": "Pin",
"category": "GitLens",
"icon": "$(pin)"
},
{
"command": "gitlens.views.searchAndCompare.unpin",
"title": "Unpin",
"category": "GitLens",
"icon": "$(pinned)"
},
{
"command": "gitlens.views.searchAndCompare.refresh",
"title": "Refresh", "title": "Refresh",
"category": "GitLens", "category": "GitLens",
"icon": "$(refresh)" "icon": "$(refresh)"
}, },
{ {
"command": "gitlens.views.search.searchCommits",
"command": "gitlens.views.searchAndCompare.searchCommits",
"title": "Search Commits", "title": "Search Commits",
"category": "GitLens", "category": "GitLens",
"icon": "$(search)" "icon": "$(search)"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToAuto",
"command": "gitlens.views.searchAndCompare.edit",
"title": "Edit",
"category": "GitLens",
"icon": "$(edit)"
},
{
"command": "gitlens.views.searchAndCompare.selectForCompare",
"title": "Compare References...",
"category": "GitLens",
"icon": "$(compare-changes)"
},
{
"command": "gitlens.views.searchAndCompare.setFilesLayoutToAuto",
"title": "Automatic Layout", "title": "Automatic Layout",
"category": "GitLens", "category": "GitLens",
"icon": "$(list-tree)" "icon": "$(list-tree)"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToList",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToList",
"title": "List Layout", "title": "List Layout",
"category": "GitLens", "category": "GitLens",
"icon": { "icon": {
@ -4167,34 +4040,43 @@
} }
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToTree",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToTree",
"title": "Tree Layout", "title": "Tree Layout",
"category": "GitLens", "category": "GitLens",
"icon": "$(list-flat)" "icon": "$(list-flat)"
}, },
{ {
"command": "gitlens.views.search.setKeepResultsToOn",
"command": "gitlens.views.searchAndCompare.setKeepResultsToOn",
"title": "Keep Results", "title": "Keep Results",
"category": "GitLens", "category": "GitLens",
"icon": "$(unlock)" "icon": "$(unlock)"
}, },
{ {
"command": "gitlens.views.search.setKeepResultsToOff",
"command": "gitlens.views.searchAndCompare.setKeepResultsToOff",
"title": "Keep Results", "title": "Keep Results",
"category": "GitLens", "category": "GitLens",
"icon": "$(lock)" "icon": "$(lock)"
}, },
{ {
"command": "gitlens.views.search.setShowAvatarsOn",
"command": "gitlens.views.searchAndCompare.setShowAvatarsOn",
"title": "Show Avatars", "title": "Show Avatars",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.views.search.setShowAvatarsOff",
"command": "gitlens.views.searchAndCompare.setShowAvatarsOff",
"title": "Hide Avatars", "title": "Hide Avatars",
"category": "GitLens" "category": "GitLens"
}, },
{ {
"command": "gitlens.views.searchAndCompare.swapComparison",
"title": "Swap Comparison",
"category": "GitLens",
"icon": {
"dark": "images/dark/icon-swap.svg",
"light": "images/light/icon-swap.svg"
}
},
{
"command": "gitlens.views.stashes.copy", "command": "gitlens.views.stashes.copy",
"title": "Copy", "title": "Copy",
"category": "GitLens" "category": "GitLens"
@ -4292,10 +4174,6 @@
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.showSettingsPage#compare-view",
"when": "false"
},
{
"command": "gitlens.showSettingsPage#contributors-view", "command": "gitlens.showSettingsPage#contributors-view",
"when": "false" "when": "false"
}, },
@ -4316,7 +4194,7 @@
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.showSettingsPage#search-commits-view",
"command": "gitlens.showSettingsPage#search-compare-view",
"when": "false" "when": "false"
}, },
{ {
@ -4328,10 +4206,6 @@
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.showCompareView",
"when": "gitlens:enabled"
},
{
"command": "gitlens.showFileHistoryView", "command": "gitlens.showFileHistoryView",
"when": "gitlens:enabled" "when": "gitlens:enabled"
}, },
@ -4344,7 +4218,7 @@
"when": "gitlens:enabled" "when": "gitlens:enabled"
}, },
{ {
"command": "gitlens.showSearchView",
"command": "gitlens.showSearchAndCompareView",
"when": "gitlens:enabled" "when": "gitlens:enabled"
}, },
{ {
@ -5084,62 +4958,6 @@
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.compare.clear",
"when": "false"
},
{
"command": "gitlens.views.compare.copy",
"when": "false"
},
{
"command": "gitlens.views.compare.pinComparison",
"when": "false"
},
{
"command": "gitlens.views.compare.unpinComparison",
"when": "false"
},
{
"command": "gitlens.views.compare.refresh",
"when": "false"
},
{
"command": "gitlens.views.compare.selectForCompare",
"when": "gitlens:enabled && config.gitlens.views.compare.enabled"
},
{
"command": "gitlens.views.compare.setFilesLayoutToAuto",
"when": "false"
},
{
"command": "gitlens.views.compare.setFilesLayoutToList",
"when": "false"
},
{
"command": "gitlens.views.compare.setFilesLayoutToTree",
"when": "false"
},
{
"command": "gitlens.views.compare.setKeepResultsToOn",
"when": "false"
},
{
"command": "gitlens.views.compare.setKeepResultsToOff",
"when": "false"
},
{
"command": "gitlens.views.compare.setShowAvatarsOn",
"when": "false"
},
{
"command": "gitlens.views.compare.setShowAvatarsOff",
"when": "false"
},
{
"command": "gitlens.views.compare.swapComparison",
"when": "false"
},
{
"command": "gitlens.views.contributors.copy", "command": "gitlens.views.contributors.copy",
"when": "false" "when": "false"
}, },
@ -5328,47 +5146,67 @@
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.clear",
"command": "gitlens.views.searchAndCompare.clear",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.copy",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.pin",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.unpin",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.copy",
"command": "gitlens.views.searchAndCompare.refresh",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.refresh",
"command": "gitlens.views.searchAndCompare.searchCommits",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.searchCommits",
"command": "gitlens.views.searchAndCompare.edit",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToAuto",
"command": "gitlens.views.searchAndCompare.selectForCompare",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToList",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToAuto",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToTree",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToList",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setKeepResultsToOn",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToTree",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setKeepResultsToOff",
"command": "gitlens.views.searchAndCompare.setKeepResultsToOn",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setShowAvatarsOn",
"command": "gitlens.views.searchAndCompare.setKeepResultsToOff",
"when": "false" "when": "false"
}, },
{ {
"command": "gitlens.views.search.setShowAvatarsOff",
"command": "gitlens.views.searchAndCompare.setShowAvatarsOn",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.setShowAvatarsOff",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.swapComparison",
"when": "false" "when": "false"
}, },
{ {
@ -5964,56 +5802,6 @@
"group": "1_gitlens@1" "group": "1_gitlens@1"
}, },
{ {
"command": "gitlens.views.compare.selectForCompare",
"when": "view =~ /^gitlens\\.views\\.compare/",
"group": "navigation@10"
},
{
"command": "gitlens.views.compare.setKeepResultsToOn",
"when": "view =~ /^gitlens\\.views\\.compare/ && !gitlens:views:compare:keepResults",
"group": "navigation@11"
},
{
"command": "gitlens.views.compare.setKeepResultsToOff",
"when": "view =~ /^gitlens\\.views\\.compare/ && gitlens:views:compare:keepResults",
"group": "navigation@11"
},
{
"command": "gitlens.views.compare.setFilesLayoutToList",
"when": "view =~ /^gitlens\\.views\\.compare/ && config.gitlens.views.compare.files.layout == auto",
"group": "navigation@50"
},
{
"command": "gitlens.views.compare.setFilesLayoutToTree",
"when": "view =~ /^gitlens\\.views\\.compare/ && config.gitlens.views.compare.files.layout == list",
"group": "navigation@50"
},
{
"command": "gitlens.views.compare.setFilesLayoutToAuto",
"when": "view =~ /^gitlens\\.views\\.compare/ && config.gitlens.views.compare.files.layout == tree",
"group": "navigation@50"
},
{
"command": "gitlens.views.compare.clear",
"when": "view =~ /^gitlens\\.views\\.compare/",
"group": "navigation@98"
},
{
"command": "gitlens.views.compare.refresh",
"when": "view =~ /^gitlens\\.views\\.compare/",
"group": "navigation@99"
},
{
"command": "gitlens.views.compare.setShowAvatarsOn",
"when": "view =~ /^gitlens\\.views\\.compare/ && !config.gitlens.views.compare.avatars",
"group": "1_gitlens@0"
},
{
"command": "gitlens.views.compare.setShowAvatarsOff",
"when": "view =~ /^gitlens\\.views\\.compare/ && config.gitlens.views.compare.avatars",
"group": "1_gitlens@0"
},
{
"command": "gitlens.views.addAuthors", "command": "gitlens.views.addAuthors",
"when": "view =~ /^gitlens\\.views\\.contributors/", "when": "view =~ /^gitlens\\.views\\.contributors/",
"group": "navigation@10" "group": "navigation@10"
@ -6224,56 +6012,77 @@
"group": "2_gitlens@0" "group": "2_gitlens@0"
}, },
{ {
"command": "gitlens.views.search.searchCommits",
"when": "view =~ /^gitlens\\.views\\.search/",
"command": "gitlens.views.searchAndCompare.searchCommits",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/",
"group": "navigation@10" "group": "navigation@10"
}, },
{ {
"command": "gitlens.views.search.setKeepResultsToOn",
"when": "view =~ /^gitlens\\.views\\.search/ && !gitlens:views:search:keepResults",
"command": "gitlens.views.searchAndCompare.selectForCompare",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/",
"group": "navigation@11" "group": "navigation@11"
}, },
{ {
"command": "gitlens.views.search.setKeepResultsToOff",
"when": "view =~ /^gitlens\\.views\\.search/ && gitlens:views:search:keepResults",
"group": "navigation@11"
"command": "gitlens.views.searchAndCompare.setKeepResultsToOn",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && !gitlens:views:searchAndCompare:keepResults",
"group": "navigation@12"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToList",
"when": "view =~ /^gitlens\\.views\\.search/ && config.gitlens.views.search.files.layout == auto",
"command": "gitlens.views.searchAndCompare.setKeepResultsToOff",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && gitlens:views:searchAndCompare:keepResults",
"group": "navigation@13"
},
{
"command": "gitlens.views.searchAndCompare.setFilesLayoutToAuto",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && config.gitlens.views.searchAndCompare.files.layout == tree",
"group": "navigation@50" "group": "navigation@50"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToTree",
"when": "view =~ /^gitlens\\.views\\.search/ && config.gitlens.views.search.files.layout == list",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToList",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && config.gitlens.views.searchAndCompare.files.layout == auto",
"group": "navigation@50" "group": "navigation@50"
}, },
{ {
"command": "gitlens.views.search.setFilesLayoutToAuto",
"when": "view =~ /^gitlens\\.views\\.search/ && config.gitlens.views.search.files.layout == tree",
"command": "gitlens.views.searchAndCompare.setFilesLayoutToTree",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && config.gitlens.views.searchAndCompare.files.layout == list",
"group": "navigation@50" "group": "navigation@50"
}, },
{ {
"command": "gitlens.views.search.clear",
"when": "view =~ /^gitlens\\.views\\.search/",
"command": "gitlens.views.searchAndCompare.clear",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/",
"group": "navigation@98" "group": "navigation@98"
}, },
{ {
"command": "gitlens.views.search.refresh",
"when": "view =~ /^gitlens\\.views\\.search/",
"command": "gitlens.views.searchAndCompare.refresh",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/",
"group": "navigation@99" "group": "navigation@99"
}, },
{ {
"command": "gitlens.views.search.setShowAvatarsOn",
"when": "view =~ /^gitlens\\.views\\.search/ && !config.gitlens.views.search.avatars",
"command": "gitlens.views.searchAndCompare.setShowAvatarsOn",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && !config.gitlens.views.searchAndCompare.avatars",
"group": "1_gitlens@0" "group": "1_gitlens@0"
}, },
{ {
"command": "gitlens.views.search.setShowAvatarsOff",
"when": "view =~ /^gitlens\\.views\\.search/ && config.gitlens.views.search.avatars",
"command": "gitlens.views.searchAndCompare.setShowAvatarsOff",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/ && config.gitlens.views.searchAndCompare.avatars",
"group": "1_gitlens@0" "group": "1_gitlens@0"
}, },
{ {
"command": "gitlens.views.searchAndCompare.copy",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.pin",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.unpin",
"when": "false"
},
{
"command": "gitlens.views.searchAndCompare.swapComparison",
"when": "false"
},
{
"command": "gitlens.stashSave", "command": "gitlens.stashSave",
"when": "!gitlens:readonly && view =~ /^gitlens\\.views\\.stashes/", "when": "!gitlens:readonly && view =~ /^gitlens\\.views\\.stashes/",
"group": "navigation@10" "group": "navigation@10"
@ -6369,11 +6178,6 @@
"group": "9_gitlens@1" "group": "9_gitlens@1"
}, },
{ {
"command": "gitlens.showSettingsPage#compare-view",
"when": "view =~ /^gitlens\\.views\\.compare/",
"group": "9_gitlens@1"
},
{
"command": "gitlens.showSettingsPage#contributors-view", "command": "gitlens.showSettingsPage#contributors-view",
"when": "view =~ /^gitlens\\.views\\.contributors/", "when": "view =~ /^gitlens\\.views\\.contributors/",
"group": "9_gitlens@1" "group": "9_gitlens@1"
@ -6399,8 +6203,8 @@
"group": "9_gitlens@1" "group": "9_gitlens@1"
}, },
{ {
"command": "gitlens.showSettingsPage#search-commits-view",
"when": "view =~ /^gitlens\\.views\\.search/",
"command": "gitlens.showSettingsPage#search-compare-view",
"when": "view =~ /^gitlens\\.views\\.searchAndCompare\\b/",
"group": "9_gitlens@1" "group": "9_gitlens@1"
}, },
{ {
@ -7149,7 +6953,7 @@
}, },
{ {
"command": "gitlens.views.dismissNode", "command": "gitlens.views.dismissNode",
"when": "viewItem =~ /gitlens:(compare:picker:ref|compare:results\\b(?!.*?\\b\\+pinned\\b)|search)\\b(?!:(commits|files))/",
"when": "viewItem =~ /gitlens:(compare:picker|(compare|search):results\\b(?!.*?\\b\\+pinned\\b))\\b(?!:(commits|files))/",
"group": "inline@99" "group": "inline@99"
}, },
{ {
@ -7193,57 +6997,57 @@
"group": "9_gitlens@1" "group": "9_gitlens@1"
}, },
{ {
"command": "gitlens.views.compare.swapComparison",
"command": "gitlens.views.searchAndCompare.swapComparison",
"when": "viewItem =~ /gitlens:compare:results\\b/", "when": "viewItem =~ /gitlens:compare:results\\b/",
"group": "inline@3"
"group": "inline@1"
}, },
{ {
"command": "gitlens.views.refreshNode", "command": "gitlens.views.refreshNode",
"when": "viewItem =~ /gitlens:compare:(branch(?=.*?\\b\\+comparing\\b)|results)\\b/", "when": "viewItem =~ /gitlens:compare:(branch(?=.*?\\b\\+comparing\\b)|results)\\b/",
"group": "inline@4"
"group": "inline@97"
},
{
"command": "gitlens.views.refreshNode",
"when": "viewItem =~ /gitlens:search:results\\b/",
"group": "inline@97"
}, },
{ {
"command": "gitlens.views.compare.pinComparison",
"when": "viewItem =~ /gitlens:compare:results\\b(?!.*?\\b\\+pinned\\b)/",
"command": "gitlens.views.searchAndCompare.pin",
"when": "viewItem =~ /gitlens:(compare|search):results\\b(?!.*?\\b\\+pinned\\b)/",
"group": "inline@98" "group": "inline@98"
}, },
{ {
"command": "gitlens.views.compare.unpinComparison",
"when": "viewItem =~ /gitlens:compare:results\\b(?=.*?\\b\\+pinned\\b)/",
"command": "gitlens.views.searchAndCompare.unpin",
"when": "viewItem =~ /gitlens:(compare|search):results\\b(?=.*?\\b\\+pinned\\b)/",
"group": "inline@98" "group": "inline@98"
}, },
{ {
"command": "gitlens.views.openDirectoryDiff",
"command": "gitlens.views.searchAndCompare.swapComparison",
"when": "viewItem =~ /gitlens:compare:results\\b/", "when": "viewItem =~ /gitlens:compare:results\\b/",
"group": "2_gitlens_quickopen@1"
"group": "1_gitlens_actions@2"
}, },
{ {
"command": "gitlens.views.compare.swapComparison",
"command": "gitlens.views.openDirectoryDiff",
"when": "viewItem =~ /gitlens:compare:results\\b/", "when": "viewItem =~ /gitlens:compare:results\\b/",
"group": "1_gitlens_actions@2"
"group": "2_gitlens_quickopen@1"
}, },
{ {
"command": "gitlens.views.compare.pinComparison",
"when": "viewItem =~ /gitlens:compare:results\\b(?!.*?\\b\\+pinned\\b)/",
"command": "gitlens.views.searchAndCompare.pin",
"when": "viewItem =~ /gitlens:(compare|search):results\\b(?!.*?\\b\\+pinned\\b)/",
"group": "8_gitlens_actions@1" "group": "8_gitlens_actions@1"
}, },
{ {
"command": "gitlens.views.compare.unpinComparison",
"when": "viewItem =~ /gitlens:compare:results\\b(?=.*?\\b\\+pinned\\b)/",
"command": "gitlens.views.searchAndCompare.unpin",
"when": "viewItem =~ /gitlens:(compare|search):results\\b(?=.*?\\b\\+pinned\\b)/",
"group": "8_gitlens_actions@1" "group": "8_gitlens_actions@1"
}, },
{ {
"command": "gitlens.views.search.searchCommits",
"command": "gitlens.views.searchAndCompare.edit",
"when": "viewItem == gitlens:search:results", "when": "viewItem == gitlens:search:results",
"group": "inline@1" "group": "inline@1"
}, },
{ {
"command": "gitlens.views.refreshNode",
"when": "viewItem == gitlens:search:results",
"group": "inline@2"
},
{
"command": "gitlens.views.search.searchCommits",
"command": "gitlens.views.searchAndCompare.edit",
"when": "viewItem == gitlens:search:results", "when": "viewItem == gitlens:search:results",
"group": "1_gitlens_actions@1" "group": "1_gitlens_actions@1"
}, },
@ -7339,7 +7143,7 @@
}, },
{ {
"command": "gitlens.views.dismissNode", "command": "gitlens.views.dismissNode",
"when": "viewItem =~ /gitlens:(compare:picker:ref|compare:results\\b(?!.*?\\b\\+pinned\\b)|search)\\b(?!:(commits|files))/",
"when": "viewItem =~ /gitlens:(compare:picker:ref|(compare|search):results\\b(?!.*?\\b\\+pinned\\b))\\b(?!:(commits|files))/",
"group": "8_gitlens_actions@98" "group": "8_gitlens_actions@98"
}, },
{ {
@ -7623,12 +7427,6 @@
"when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.commits/" "when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.commits/"
}, },
{ {
"command": "gitlens.views.compare.copy",
"key": "ctrl+c",
"mac": "cmd+c",
"when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.compare/"
},
{
"command": "gitlens.views.contributors.copy", "command": "gitlens.views.contributors.copy",
"key": "ctrl+c", "key": "ctrl+c",
"mac": "cmd+c", "mac": "cmd+c",
@ -7665,10 +7463,10 @@
"when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.stashes/" "when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.stashes/"
}, },
{ {
"command": "gitlens.views.search.copy",
"command": "gitlens.views.searchAndCompare.copy",
"key": "ctrl+c", "key": "ctrl+c",
"mac": "cmd+c", "mac": "cmd+c",
"when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.search/"
"when": "gitlens:enabled && focusedView =~ /^gitlens\\.views\\.searchAndCompare\\b/"
}, },
{ {
"command": "gitlens.views.tags.copy", "command": "gitlens.views.tags.copy",
@ -7805,20 +7603,12 @@
"visibility": "collapsed" "visibility": "collapsed"
}, },
{ {
"id": "gitlens.views.search",
"name": "Search Commits",
"id": "gitlens.views.searchAndCompare",
"name": "Search & Compare",
"when": "!gitlens:disabled", "when": "!gitlens:disabled",
"contextualTitle": "GitLens", "contextualTitle": "GitLens",
"icon": "images/views/search.svg", "icon": "images/views/search.svg",
"visibility": "collapsed" "visibility": "collapsed"
},
{
"id": "gitlens.views.compare",
"name": "Compare Commits",
"when": "!gitlens:disabled",
"contextualTitle": "GitLens",
"icon": "images/views/compare.svg",
"visibility": "collapsed"
} }
] ]
} }

+ 3
- 5
src/commands/common.ts View File

@ -87,11 +87,10 @@ export enum Commands {
ResetSuppressedWarnings = 'gitlens.resetSuppressedWarnings', ResetSuppressedWarnings = 'gitlens.resetSuppressedWarnings',
RevealCommitInView = 'gitlens.revealCommitInView', RevealCommitInView = 'gitlens.revealCommitInView',
SearchCommits = 'gitlens.showCommitSearch', SearchCommits = 'gitlens.showCommitSearch',
SearchCommitsInView = 'gitlens.views.search.searchCommits',
SearchCommitsInView = 'gitlens.views.searchAndCompare.searchCommits',
SetViewsLayout = 'gitlens.setViewsLayout', SetViewsLayout = 'gitlens.setViewsLayout',
ShowCommitInView = 'gitlens.showCommitInView', ShowCommitInView = 'gitlens.showCommitInView',
ShowCommitsInView = 'gitlens.showCommitsInView', ShowCommitsInView = 'gitlens.showCommitsInView',
ShowCompareView = 'gitlens.showCompareView',
ShowFileHistoryView = 'gitlens.showFileHistoryView', ShowFileHistoryView = 'gitlens.showFileHistoryView',
ShowFileHistoryInView = 'gitlens.showFileHistoryInView', ShowFileHistoryInView = 'gitlens.showFileHistoryInView',
ShowLineHistoryView = 'gitlens.showLineHistoryView', ShowLineHistoryView = 'gitlens.showLineHistoryView',
@ -107,18 +106,17 @@ export enum Commands {
ShowQuickCommitRevisionInDiffRight = 'gitlens.showQuickRevisionDetailsInDiffRight', ShowQuickCommitRevisionInDiffRight = 'gitlens.showQuickRevisionDetailsInDiffRight',
ShowQuickStashList = 'gitlens.showQuickStashList', ShowQuickStashList = 'gitlens.showQuickStashList',
ShowRepositoriesView = 'gitlens.showRepositoriesView', ShowRepositoriesView = 'gitlens.showRepositoriesView',
ShowSearchView = 'gitlens.showSearchView',
ShowSearchAndCompareView = 'gitlens.showSearchAndCompareView',
ShowHistoryPage = 'gitlens.showHistoryPage', ShowHistoryPage = 'gitlens.showHistoryPage',
ShowSettingsPage = 'gitlens.showSettingsPage', ShowSettingsPage = 'gitlens.showSettingsPage',
ShowSettingsPageAndJumpToBranchesView = 'gitlens.showSettingsPage#branches-view', ShowSettingsPageAndJumpToBranchesView = 'gitlens.showSettingsPage#branches-view',
ShowSettingsPageAndJumpToCommitsView = 'gitlens.showSettingsPage#commits-view', ShowSettingsPageAndJumpToCommitsView = 'gitlens.showSettingsPage#commits-view',
ShowSettingsPageAndJumpToCompareView = 'gitlens.showSettingsPage#compare-view',
ShowSettingsPageAndJumpToContributorsView = 'gitlens.showSettingsPage#contributors-view', ShowSettingsPageAndJumpToContributorsView = 'gitlens.showSettingsPage#contributors-view',
ShowSettingsPageAndJumpToFileHistoryView = 'gitlens.showSettingsPage#file-history-view', ShowSettingsPageAndJumpToFileHistoryView = 'gitlens.showSettingsPage#file-history-view',
ShowSettingsPageAndJumpToLineHistoryView = 'gitlens.showSettingsPage#line-history-view', ShowSettingsPageAndJumpToLineHistoryView = 'gitlens.showSettingsPage#line-history-view',
ShowSettingsPageAndJumpToRemotesView = 'gitlens.showSettingsPage#remotes-view', ShowSettingsPageAndJumpToRemotesView = 'gitlens.showSettingsPage#remotes-view',
ShowSettingsPageAndJumpToRepositoriesView = 'gitlens.showSettingsPage#repositories-view', ShowSettingsPageAndJumpToRepositoriesView = 'gitlens.showSettingsPage#repositories-view',
ShowSettingsPageAndJumpToSearchCommitsView = 'gitlens.showSettingsPage#search-commits-view',
ShowSettingsPageAndJumpToSearchAndCompareView = 'gitlens.showSettingsPage#search-compare-view',
ShowSettingsPageAndJumpToStashesView = 'gitlens.showSettingsPage#stashes-view', ShowSettingsPageAndJumpToStashesView = 'gitlens.showSettingsPage#stashes-view',
ShowSettingsPageAndJumpToTagsView = 'gitlens.showSettingsPage#tags-view', ShowSettingsPageAndJumpToTagsView = 'gitlens.showSettingsPage#tags-view',
ShowWelcomePage = 'gitlens.showWelcomePage', ShowWelcomePage = 'gitlens.showWelcomePage',

+ 1
- 1
src/commands/diffBranchWith.ts View File

@ -83,7 +83,7 @@ export class DiffBranchWithCommand extends ActiveEditorCommand {
if (args.ref2 == null) return; if (args.ref2 == null) return;
} }
void (await Container.compareView.compare(repoPath, args.ref1, args.ref2));
void (await Container.searchAndCompareView.compare(repoPath, args.ref1, args.ref2));
} catch (ex) { } catch (ex) {
Logger.error(ex, 'DiffBranchWithCommand'); Logger.error(ex, 'DiffBranchWithCommand');
void Messages.showGenericErrorMessage('Unable to open branch compare'); void Messages.showGenericErrorMessage('Unable to open branch compare');

+ 21
- 8
src/commands/git/search.ts View File

@ -3,6 +3,7 @@ import { GlyphChars } from '../../constants';
import { Container } from '../../container'; import { Container } from '../../container';
import { GitLog, GitLogCommit, Repository, SearchOperators, searchOperators, SearchPattern } from '../../git/git'; import { GitLog, GitLogCommit, Repository, SearchOperators, searchOperators, SearchPattern } from '../../git/git';
import { GitCommandsCommand } from '../gitCommands'; import { GitCommandsCommand } from '../gitCommands';
import { SearchResultsNode } from '../../views/nodes';
import { import {
appendReposToTitle, appendReposToTitle,
PartialStepState, PartialStepState,
@ -29,7 +30,7 @@ interface Context {
interface State extends Required<SearchPattern> { interface State extends Required<SearchPattern> {
repo: string | Repository; repo: string | Repository;
showResultsInSideBar: boolean;
showResultsInSideBar: boolean | SearchResultsNode;
} }
export interface SearchGitCommandArgs { export interface SearchGitCommandArgs {
@ -159,14 +160,16 @@ export class SearchGitCommand extends QuickCommand {
context.resultsKey = searchKey; context.resultsKey = searchKey;
} }
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (state.showResultsInSideBar) { if (state.showResultsInSideBar) {
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
search, search,
{ {
label: { label: `for ${state.pattern}` }, label: { label: `for ${state.pattern}` },
}, },
context.resultsPromise, context.resultsPromise,
state.showResultsInSideBar instanceof SearchResultsNode ? state.showResultsInSideBar : undefined,
); );
break; break;
@ -188,7 +191,7 @@ export class SearchGitCommand extends QuickCommand {
showInSideBarButton: { showInSideBarButton: {
button: QuickCommandButtons.ShowResultsInSideBar, button: QuickCommandButtons.ShowResultsInSideBar,
onDidClick: () => onDidClick: () =>
void Container.searchView.search(
void Container.searchAndCompareView.search(
repoPath, repoPath,
search, search,
{ {
@ -262,17 +265,27 @@ export class SearchGitCommand extends QuickCommand {
const matchCaseButton = new QuickCommandButtons.MatchCaseToggle(state.matchCase); const matchCaseButton = new QuickCommandButtons.MatchCaseToggle(state.matchCase);
const matchAllButton = new QuickCommandButtons.MatchAllToggle(state.matchAll); const matchAllButton = new QuickCommandButtons.MatchAllToggle(state.matchAll);
const matchRegexButton = new QuickCommandButtons.MatchRegexToggle(state.matchRegex); const matchRegexButton = new QuickCommandButtons.MatchRegexToggle(state.matchRegex);
const showResultsToggleButton = new QuickCommandButtons.ShowResultsToggle(state.showResultsInSideBar, () => {
state.showResultsInSideBar = !state.showResultsInSideBar;
showResultsToggleButton.on = state.showResultsInSideBar;
});
const additionalButtons = [matchCaseButton, matchAllButton, matchRegexButton];
if (!SearchResultsNode.is(state.showResultsInSideBar)) {
const showResultsToggleButton = new QuickCommandButtons.ShowResultsToggle(
state.showResultsInSideBar,
() => {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
state.showResultsInSideBar = !state.showResultsInSideBar;
showResultsToggleButton.on = state.showResultsInSideBar;
},
);
additionalButtons.push(showResultsToggleButton);
}
const step = QuickCommand.createPickStep<QuickPickItemOfT<SearchOperators>>({ const step = QuickCommand.createPickStep<QuickPickItemOfT<SearchOperators>>({
title: appendReposToTitle(context.title, state, context), title: appendReposToTitle(context.title, state, context),
placeholder: 'e.g. "Updates dependencies" author:eamodio', placeholder: 'e.g. "Updates dependencies" author:eamodio',
matchOnDescription: true, matchOnDescription: true,
matchOnDetail: true, matchOnDetail: true,
additionalButtons: [matchCaseButton, matchAllButton, matchRegexButton, showResultsToggleButton],
additionalButtons: additionalButtons,
items: items, items: items,
value: state.pattern, value: state.pattern,
onDidAccept: (quickpick): boolean => { onDidAccept: (quickpick): boolean => {

+ 1
- 1
src/commands/quickCommand.buttons.ts View File

@ -108,7 +108,7 @@ export namespace QuickCommandButtons {
}; };
export const ShowResultsInSideBar: QuickInputButton = { export const ShowResultsInSideBar: QuickInputButton = {
iconPath: new ThemeIcon('search'),
iconPath: new ThemeIcon('link-external'),
tooltip: 'Show Results in Side Bar', tooltip: 'Show Results in Side Bar',
}; };

+ 8
- 8
src/commands/quickCommand.steps.ts View File

@ -814,7 +814,7 @@ export function* pickCommitStep<
} }
if (button === QuickCommandButtons.SearchInSideBar) { if (button === QuickCommandButtons.SearchInSideBar) {
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
{ pattern: SearchPattern.fromCommit(quickpick.activeItems[0].item.ref) }, { pattern: SearchPattern.fromCommit(quickpick.activeItems[0].item.ref) },
{ {
@ -842,7 +842,7 @@ export function* pickCommitStep<
}); });
} else { } else {
const commit = quickpick.activeItems[0].item; const commit = quickpick.activeItems[0].item;
await Container.searchView.search(
await Container.searchAndCompareView.search(
commit.repoPath, commit.repoPath,
{ pattern: SearchPattern.fromCommit(commit) }, { pattern: SearchPattern.fromCommit(commit) },
{ {
@ -933,7 +933,7 @@ export function* pickCommitsStep<
} }
if (button === QuickCommandButtons.SearchInSideBar) { if (button === QuickCommandButtons.SearchInSideBar) {
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
{ pattern: SearchPattern.fromCommit(quickpick.activeItems[0].item.ref) }, { pattern: SearchPattern.fromCommit(quickpick.activeItems[0].item.ref) },
{ {
@ -961,7 +961,7 @@ export function* pickCommitsStep<
}); });
} else { } else {
const commit = quickpick.activeItems[0].item; const commit = quickpick.activeItems[0].item;
await Container.searchView.search(
await Container.searchAndCompareView.search(
commit.repoPath, commit.repoPath,
{ pattern: SearchPattern.fromCommit(commit) }, { pattern: SearchPattern.fromCommit(commit) },
{ {
@ -1183,7 +1183,7 @@ export function* pickStashStep<
if (button === QuickCommandButtons.SearchInSideBar) { if (button === QuickCommandButtons.SearchInSideBar) {
if (quickpick.activeItems.length === 0) return; if (quickpick.activeItems.length === 0) return;
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
{ pattern: SearchPattern.fromCommit(quickpick.activeItems[0].item.stashName) }, { pattern: SearchPattern.fromCommit(quickpick.activeItems[0].item.stashName) },
{ {
@ -1305,7 +1305,7 @@ export async function* showCommitOrStashStep<
: [QuickCommandButtons.RevealInSideBar, QuickCommandButtons.SearchInSideBar], : [QuickCommandButtons.RevealInSideBar, QuickCommandButtons.SearchInSideBar],
onDidClickButton: (quickpick, button) => { onDidClickButton: (quickpick, button) => {
if (button === QuickCommandButtons.SearchInSideBar) { if (button === QuickCommandButtons.SearchInSideBar) {
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
{ pattern: SearchPattern.fromCommit(state.reference.ref) }, { pattern: SearchPattern.fromCommit(state.reference.ref) },
{ {
@ -1559,7 +1559,7 @@ export function* showCommitOrStashFilesStep<
additionalButtons: [QuickCommandButtons.RevealInSideBar, QuickCommandButtons.SearchInSideBar], additionalButtons: [QuickCommandButtons.RevealInSideBar, QuickCommandButtons.SearchInSideBar],
onDidClickButton: (quickpick, button) => { onDidClickButton: (quickpick, button) => {
if (button === QuickCommandButtons.SearchInSideBar) { if (button === QuickCommandButtons.SearchInSideBar) {
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
{ pattern: SearchPattern.fromCommit(state.reference.ref) }, { pattern: SearchPattern.fromCommit(state.reference.ref) },
{ {
@ -1631,7 +1631,7 @@ export async function* showCommitOrStashFileStep<
additionalButtons: [QuickCommandButtons.RevealInSideBar, QuickCommandButtons.SearchInSideBar], additionalButtons: [QuickCommandButtons.RevealInSideBar, QuickCommandButtons.SearchInSideBar],
onDidClickButton: (quickpick, button) => { onDidClickButton: (quickpick, button) => {
if (button === QuickCommandButtons.SearchInSideBar) { if (button === QuickCommandButtons.SearchInSideBar) {
void Container.searchView.search(
void Container.searchAndCompareView.search(
state.repo.path, state.repo.path,
{ pattern: SearchPattern.fromCommit(state.reference.ref) }, { pattern: SearchPattern.fromCommit(state.reference.ref) },
{ {

+ 2
- 2
src/commands/searchCommits.ts View File

@ -2,7 +2,7 @@
import { executeGitCommand } from '../commands'; import { executeGitCommand } from '../commands';
import { Command, command, CommandContext, Commands, isCommandViewContextWithRepo } from './common'; import { Command, command, CommandContext, Commands, isCommandViewContextWithRepo } from './common';
import { SearchPattern } from '../git/git'; import { SearchPattern } from '../git/git';
import { SearchResultsCommitsNode } from '../views/nodes';
import { SearchResultsNode } from '../views/nodes';
export interface SearchCommitsCommandArgs { export interface SearchCommitsCommandArgs {
search?: Partial<SearchPattern>; search?: Partial<SearchPattern>;
@ -24,7 +24,7 @@ export class SearchCommitsCommand extends Command {
args = { ...args }; args = { ...args };
args.showResultsInSideBar = true; args.showResultsInSideBar = true;
if (context.node instanceof SearchResultsCommitsNode) {
if (context.node instanceof SearchResultsNode) {
args.repoPath = context.node.repoPath; args.repoPath = context.node.repoPath;
args.search = context.node.search; args.search = context.node.search;
args.prefillOnly = true; args.prefillOnly = true;

+ 3
- 6
src/commands/showView.ts View File

@ -6,11 +6,10 @@ import { command, Command, CommandContext, Commands } from './common';
export class ShowViewCommand extends Command { export class ShowViewCommand extends Command {
constructor() { constructor() {
super([ super([
Commands.ShowCompareView,
Commands.ShowFileHistoryView, Commands.ShowFileHistoryView,
Commands.ShowLineHistoryView, Commands.ShowLineHistoryView,
Commands.ShowRepositoriesView, Commands.ShowRepositoriesView,
Commands.ShowSearchView,
Commands.ShowSearchAndCompareView,
]); ]);
} }
@ -20,16 +19,14 @@ export class ShowViewCommand extends Command {
execute(command: Commands) { execute(command: Commands) {
switch (command) { switch (command) {
case Commands.ShowCompareView:
return Container.compareView.show();
case Commands.ShowFileHistoryView: case Commands.ShowFileHistoryView:
return Container.fileHistoryView.show(); return Container.fileHistoryView.show();
case Commands.ShowLineHistoryView: case Commands.ShowLineHistoryView:
return Container.lineHistoryView.show(); return Container.lineHistoryView.show();
case Commands.ShowRepositoriesView: case Commands.ShowRepositoriesView:
return Container.repositoriesView.show(); return Container.repositoriesView.show();
case Commands.ShowSearchView:
return Container.searchView.show();
case Commands.ShowSearchAndCompareView:
return Container.searchAndCompareView.show();
} }
return Promise.resolve(undefined); return Promise.resolve(undefined);

+ 3
- 14
src/config.ts View File

@ -431,13 +431,12 @@ export const viewsCommonConfigKeys: (keyof ViewsCommonConfig)[] = [
interface ViewsConfigs { interface ViewsConfigs {
branches: BranchesViewConfig; branches: BranchesViewConfig;
commits: CommitsViewConfig; commits: CommitsViewConfig;
compare: CompareViewConfig;
contributors: ContributorsViewConfig; contributors: ContributorsViewConfig;
fileHistory: FileHistoryViewConfig; fileHistory: FileHistoryViewConfig;
lineHistory: LineHistoryViewConfig; lineHistory: LineHistoryViewConfig;
remotes: RemotesViewConfig; remotes: RemotesViewConfig;
repositories: RepositoriesViewConfig; repositories: RepositoriesViewConfig;
search: SearchViewConfig;
searchAndCompare: SearchAndCompareViewConfig;
stashes: StashesViewConfig; stashes: StashesViewConfig;
tags: TagsViewConfig; tags: TagsViewConfig;
welcome: WelcomeViewConfig; welcome: WelcomeViewConfig;
@ -454,8 +453,7 @@ export const viewsConfigKeys: ViewsConfigKeys[] = [
'stashes', 'stashes',
'tags', 'tags',
'contributors', 'contributors',
'search',
'compare',
'searchAndCompare',
]; ];
export type ViewsConfig = ViewsCommonConfig & ViewsConfigs; export type ViewsConfig = ViewsCommonConfig & ViewsConfigs;
@ -486,15 +484,6 @@ export interface CommitsViewConfig {
showBranchComparison: false | ViewShowBranchComparison; showBranchComparison: false | ViewShowBranchComparison;
} }
export interface CompareViewConfig {
avatars: boolean;
files: ViewsFilesConfig;
pullRequests: {
enabled: boolean;
showForCommits: boolean;
};
}
export interface ContributorsViewConfig { export interface ContributorsViewConfig {
avatars: boolean; avatars: boolean;
files: ViewsFilesConfig; files: ViewsFilesConfig;
@ -545,7 +534,7 @@ export interface RepositoriesViewConfig {
showBranchComparison: false | ViewShowBranchComparison; showBranchComparison: false | ViewShowBranchComparison;
} }
export interface SearchViewConfig {
export interface SearchAndCompareViewConfig {
avatars: boolean; avatars: boolean;
files: ViewsFilesConfig; files: ViewsFilesConfig;
pullRequests: { pullRequests: {

+ 28
- 8
src/constants.ts View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
import { commands, TextDocument, TextEditor, window } from 'vscode'; import { commands, TextDocument, TextEditor, window } from 'vscode';
import { ViewShowBranchComparison } from './config'; import { ViewShowBranchComparison } from './config';
import { SearchPattern } from './git/git';
export const applicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679'; export const applicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
export const extensionId = 'gitlens'; export const extensionId = 'gitlens';
@ -43,12 +44,11 @@ export enum CommandContext {
ViewsCanCompare = 'gitlens:views:canCompare', ViewsCanCompare = 'gitlens:views:canCompare',
ViewsCanCompareFile = 'gitlens:views:canCompare:file', ViewsCanCompareFile = 'gitlens:views:canCompare:file',
ViewsCommitsMyCommitsOnly = 'gitlens:views:commits:myCommitsOnly', ViewsCommitsMyCommitsOnly = 'gitlens:views:commits:myCommitsOnly',
ViewsCompareKeepResults = 'gitlens:views:compare:keepResults',
ViewsFileHistoryCursorFollowing = 'gitlens:views:fileHistory:cursorFollowing', ViewsFileHistoryCursorFollowing = 'gitlens:views:fileHistory:cursorFollowing',
ViewsFileHistoryEditorFollowing = 'gitlens:views:fileHistory:editorFollowing', ViewsFileHistoryEditorFollowing = 'gitlens:views:fileHistory:editorFollowing',
ViewsLineHistoryEditorFollowing = 'gitlens:views:lineHistory:editorFollowing', ViewsLineHistoryEditorFollowing = 'gitlens:views:lineHistory:editorFollowing',
ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh', ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh',
ViewsSearchKeepResults = 'gitlens:views:search:keepResults',
ViewsSearchAndCompareKeepResults = 'gitlens:views:searchAndCompare:keepResults',
Vsls = 'gitlens:vsls', Vsls = 'gitlens:vsls',
} }
@ -165,14 +165,34 @@ export interface NamedRef {
} }
export interface PinnedComparison { export interface PinnedComparison {
type: 'comparison';
timestamp: number;
path: string; path: string;
ref1: NamedRef; ref1: NamedRef;
ref2: NamedRef; ref2: NamedRef;
notation: '..' | '...' | undefined;
notation?: '..' | '...';
} }
export interface PinnedComparisons {
[id: string]: PinnedComparison;
export interface PinnedSearch {
type: 'search';
timestamp: number;
path: string;
labels: {
label: string;
queryLabel:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
};
search: SearchPattern;
}
export type PinnedItem = PinnedComparison | PinnedSearch;
export interface PinnedItems {
[id: string]: PinnedItem;
} }
export interface StarredBranches { export interface StarredBranches {
@ -186,10 +206,10 @@ export interface StarredRepositories {
export enum WorkspaceState { export enum WorkspaceState {
BranchComparisons = 'gitlens:branch:comparisons', BranchComparisons = 'gitlens:branch:comparisons',
DefaultRemote = 'gitlens:remote:default', DefaultRemote = 'gitlens:remote:default',
PinnedComparisons = 'gitlens:pinned:comparisons',
DeprecatedPinnedComparisons = 'gitlens:pinned:comparisons',
StarredBranches = 'gitlens:starred:branches', StarredBranches = 'gitlens:starred:branches',
StarredRepositories = 'gitlens:starred:repositories', StarredRepositories = 'gitlens:starred:repositories',
ViewsCompareKeepResults = 'gitlens:views:compare:keepResults',
ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh', ViewsRepositoriesAutoRefresh = 'gitlens:views:repositories:autoRefresh',
ViewsSearchKeepResults = 'gitlens:views:search:keepResults',
ViewsSearchAndCompareKeepResults = 'gitlens:views:searchAndCompare:keepResults',
ViewsSearchAndComparePinnedItems = 'gitlens:views:searchAndCompare:pinned',
} }

+ 7
- 18
src/container.ts View File

@ -18,13 +18,12 @@ import { GitDocumentTracker } from './trackers/gitDocumentTracker';
import { GitLineTracker } from './trackers/gitLineTracker'; import { GitLineTracker } from './trackers/gitLineTracker';
import { BranchesView } from './views/branchesView'; import { BranchesView } from './views/branchesView';
import { CommitsView } from './views/commitsView'; import { CommitsView } from './views/commitsView';
import { CompareView } from './views/compareView';
import { ContributorsView } from './views/contributorsView'; import { ContributorsView } from './views/contributorsView';
import { FileHistoryView } from './views/fileHistoryView'; import { FileHistoryView } from './views/fileHistoryView';
import { LineHistoryView } from './views/lineHistoryView'; import { LineHistoryView } from './views/lineHistoryView';
import { RemotesView } from './views/remotesView'; import { RemotesView } from './views/remotesView';
import { RepositoriesView } from './views/repositoriesView'; import { RepositoriesView } from './views/repositoriesView';
import { SearchView } from './views/searchView';
import { SearchAndCompareView } from './views/searchAndCompareView';
import { StashesView } from './views/stashesView'; import { StashesView } from './views/stashesView';
import { TagsView } from './views/tagsView'; import { TagsView } from './views/tagsView';
import { ViewCommands } from './views/viewCommands'; import { ViewCommands } from './views/viewCommands';
@ -68,8 +67,7 @@ export class Container {
context.subscriptions.push((this._stashesView = new StashesView())); context.subscriptions.push((this._stashesView = new StashesView()));
context.subscriptions.push((this._tagsView = new TagsView())); context.subscriptions.push((this._tagsView = new TagsView()));
context.subscriptions.push((this._contributorsView = new ContributorsView())); context.subscriptions.push((this._contributorsView = new ContributorsView()));
context.subscriptions.push((this._searchView = new SearchView()));
context.subscriptions.push((this._compareView = new CompareView()));
context.subscriptions.push((this._searchAndCompareView = new SearchAndCompareView()));
if (config.views.lineHistory.enabled) { if (config.views.lineHistory.enabled) {
context.subscriptions.push((this._lineHistoryView = new LineHistoryView())); context.subscriptions.push((this._lineHistoryView = new LineHistoryView()));
@ -151,15 +149,6 @@ export class Container {
return this._commitsView; return this._commitsView;
} }
private static _compareView: CompareView | undefined;
static get compareView() {
if (this._compareView === undefined) {
this._context.subscriptions.push((this._compareView = new CompareView()));
}
return this._compareView;
}
private static _config: Config | undefined; private static _config: Config | undefined;
static get config() { static get config() {
if (this._config === undefined) { if (this._config === undefined) {
@ -266,13 +255,13 @@ export class Container {
return this._repositoriesView; return this._repositoriesView;
} }
private static _searchView: SearchView | undefined;
static get searchView() {
if (this._searchView === undefined) {
this._context.subscriptions.push((this._searchView = new SearchView()));
private static _searchAndCompareView: SearchAndCompareView | undefined;
static get searchAndCompareView() {
if (this._searchAndCompareView === undefined) {
this._context.subscriptions.push((this._searchAndCompareView = new SearchAndCompareView()));
} }
return this._searchView;
return this._searchAndCompareView;
} }
private static _settingsWebview: SettingsWebview; private static _settingsWebview: SettingsWebview;

+ 2
- 2
src/quickpicks/commitQuickPickItems.ts View File

@ -86,7 +86,7 @@ export class CommitCompareWithHEADCommandQuickPickItem extends CommandQuickPickI
} }
execute(_options: { preserveFocus?: boolean; preview?: boolean }): Promise<void> { execute(_options: { preserveFocus?: boolean; preview?: boolean }): Promise<void> {
return Container.compareView.compare(this.commit.repoPath, this.commit.ref, 'HEAD');
return Container.searchAndCompareView.compare(this.commit.repoPath, this.commit.ref, 'HEAD');
} }
} }
@ -96,7 +96,7 @@ export class CommitCompareWithWorkingCommandQuickPickItem extends CommandQuickPi
} }
execute(_options: { preserveFocus?: boolean; preview?: boolean }): Promise<void> { execute(_options: { preserveFocus?: boolean; preview?: boolean }): Promise<void> {
return Container.compareView.compare(this.commit.repoPath, this.commit.ref, '');
return Container.searchAndCompareView.compare(this.commit.repoPath, this.commit.ref, '');
} }
} }

+ 1
- 1
src/quickpicks/quickPicksItems.ts View File

@ -213,7 +213,7 @@ export class SearchForCommitQuickPickItem extends CommandQuickPickItem {
} }
async execute(options?: { preserveFocus?: boolean; preview?: boolean }): Promise<void> { async execute(options?: { preserveFocus?: boolean; preview?: boolean }): Promise<void> {
void (await Container.searchView.search(
void (await Container.searchAndCompareView.search(
this.reference.repoPath, this.reference.repoPath,
{ {
pattern: SearchPattern.fromCommit(this.reference), pattern: SearchPattern.fromCommit(this.reference),

+ 0
- 184
src/views/compareView.ts View File

@ -1,184 +0,0 @@
'use strict';
import { commands, ConfigurationChangeEvent } from 'vscode';
import { CompareViewConfig, configuration, ViewFilesLayout } from '../configuration';
import {
CommandContext,
NamedRef,
PinnedComparison,
PinnedComparisons,
setCommandContext,
WorkspaceState,
} from '../constants';
import { Container } from '../container';
import { CompareNode, CompareResultsNode, nodeSupportsConditionalDismissal, ViewNode } from './nodes';
import { ViewBase } from './viewBase';
export class CompareView extends ViewBase<CompareNode, CompareViewConfig> {
protected readonly configKey = 'compare';
constructor() {
super('gitlens.views.compare', 'Compare');
void setCommandContext(CommandContext.ViewsCompareKeepResults, this.keepResults);
}
getRoot() {
return new CompareNode(this);
}
protected registerCommands() {
void Container.viewCommands;
commands.registerCommand(this.getQualifiedCommand('clear'), () => this.clear(), this);
commands.registerCommand(
this.getQualifiedCommand('copy'),
() => commands.executeCommand('gitlens.views.copy', this.selection),
this,
);
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(true), 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,
);
commands.registerCommand(this.getQualifiedCommand('setShowAvatarsOn'), () => this.setShowAvatars(true), this);
commands.registerCommand(this.getQualifiedCommand('setShowAvatarsOff'), () => this.setShowAvatars(false), this);
commands.registerCommand(this.getQualifiedCommand('pinComparison'), this.pinComparison, this);
commands.registerCommand(this.getQualifiedCommand('unpinComparison'), this.unpinComparison, this);
commands.registerCommand(this.getQualifiedCommand('swapComparison'), this.swapComparison, this);
commands.registerCommand(this.getQualifiedCommand('selectForCompare'), this.selectForCompare, this);
commands.registerCommand(this.getQualifiedCommand('compareWithSelected'), this.compareWithSelected, this);
}
protected filterConfigurationChanged(e: ConfigurationChangeEvent) {
const changed = super.filterConfigurationChanged(e);
if (
!changed &&
!configuration.changed(e, 'defaultDateFormat') &&
!configuration.changed(e, 'defaultDateSource') &&
!configuration.changed(e, 'defaultDateStyle') &&
!configuration.changed(e, 'defaultGravatarsStyle')
) {
return false;
}
return true;
}
get keepResults(): boolean {
return Container.context.workspaceState.get<boolean>(WorkspaceState.ViewsCompareKeepResults, false);
}
clear() {
this.root?.clear();
}
dismissNode(node: ViewNode) {
if (this.root == null) return;
if (nodeSupportsConditionalDismissal(node) && node.canDismiss() === false) return;
this.root.dismiss(node);
}
compare(repoPath: string, ref1: string | NamedRef, ref2: string | NamedRef) {
return this.addResults(
new CompareResultsNode(
this,
repoPath,
typeof ref1 === 'string' ? { ref: ref1 } : ref1,
typeof ref2 === 'string' ? { ref: ref2 } : ref2,
),
);
}
compareWithSelected(repoPath?: string, ref?: string | NamedRef) {
const root = this.ensureRoot();
void root.compareWithSelected(repoPath, ref);
}
selectForCompare(repoPath?: string, ref?: string | NamedRef) {
const root = this.ensureRoot();
void root.selectForCompare(repoPath, ref);
}
getPinnedComparisons() {
const pinned = Container.context.workspaceState.get<PinnedComparisons>(WorkspaceState.PinnedComparisons);
if (pinned == null) return [];
return Object.values(pinned).map(p => new CompareResultsNode(this, p.path, p.ref1, p.ref2, true));
}
async updatePinnedComparison(id: string, pin?: PinnedComparison) {
let pinned = Container.context.workspaceState.get<PinnedComparisons>(WorkspaceState.PinnedComparisons);
if (pinned == null) {
pinned = Object.create(null) as PinnedComparisons;
}
if (pin !== undefined) {
pinned[id] = { ...pin };
} else {
const { [id]: _, ...rest } = pinned;
pinned = rest;
}
await Container.context.workspaceState.update(WorkspaceState.PinnedComparisons, pinned);
}
private async addResults(results: ViewNode) {
if (!this.visible) {
await this.show();
}
const root = this.ensureRoot();
root.addOrReplace(results, !this.keepResults);
setImmediate(() => this.reveal(results, { expand: true, focus: true, select: true }));
}
private setFilesLayout(layout: ViewFilesLayout) {
return configuration.updateEffective('views', this.configKey, 'files', 'layout', layout);
}
private setKeepResults(enabled: boolean) {
void Container.context.workspaceState.update(WorkspaceState.ViewsCompareKeepResults, enabled);
void setCommandContext(CommandContext.ViewsCompareKeepResults, enabled);
}
private setShowAvatars(enabled: boolean) {
return configuration.updateEffective('views', this.configKey, 'avatars', enabled);
}
private pinComparison(node: ViewNode) {
if (!(node instanceof CompareResultsNode)) return undefined;
return node.pin();
}
private swapComparison(node: ViewNode) {
if (!(node instanceof CompareResultsNode)) return undefined;
return node.swap();
}
private unpinComparison(node: ViewNode) {
if (!(node instanceof CompareResultsNode)) return undefined;
return node.unpin();
}
}

+ 1
- 3
src/views/nodes.ts View File

@ -10,7 +10,6 @@ export * from './nodes/branchTrackingStatusNode';
export * from './nodes/commitFileNode'; export * from './nodes/commitFileNode';
export * from './nodes/commitNode'; export * from './nodes/commitNode';
export * from './nodes/compareBranchNode'; export * from './nodes/compareBranchNode';
export * from './nodes/compareNode';
export * from './nodes/compareResultsNode'; export * from './nodes/compareResultsNode';
export * from './nodes/contributorNode'; export * from './nodes/contributorNode';
export * from './nodes/contributorsNode'; export * from './nodes/contributorsNode';
@ -28,8 +27,7 @@ export * from './nodes/repositoryNode';
export * from './nodes/resultsCommitsNode'; export * from './nodes/resultsCommitsNode';
export * from './nodes/resultsFileNode'; export * from './nodes/resultsFileNode';
export * from './nodes/resultsFilesNode'; export * from './nodes/resultsFilesNode';
export * from './nodes/searchNode';
export * from './nodes/searchResultsCommitsNode';
export * from './nodes/searchResultsNode';
export * from './nodes/stashesNode'; export * from './nodes/stashesNode';
export * from './nodes/stashFileNode'; export * from './nodes/stashFileNode';
export * from './nodes/stashNode'; export * from './nodes/stashNode';

+ 20
- 18
src/views/nodes/compareBranchNode.ts View File

@ -64,44 +64,46 @@ export class CompareBranchNode extends ViewNode
this, this,
this.uri.repoPath!, this.uri.repoPath!,
'Behind', 'Behind',
this.getCommitsQuery(
GitRevision.createRange(this.branch.ref, this._compareWith.ref || 'HEAD', '..'),
),
{ {
id: 'behind',
description: Strings.pluralize('commit', aheadBehind?.behind ?? 0),
expand: false,
includeRepoName: true,
query: this.getCommitsQuery(
GitRevision.createRange(this.branch.ref, this._compareWith.ref || 'HEAD', '..'),
),
files: { files: {
ref1: this.compareWithWorkingTree ? '' : this.branch.ref, ref1: this.compareWithWorkingTree ? '' : this.branch.ref,
ref2: this._compareWith.ref || 'HEAD', ref2: this._compareWith.ref || 'HEAD',
query: this.getBehindFilesQuery.bind(this), query: this.getBehindFilesQuery.bind(this),
}, },
}, },
{
id: 'behind',
description: Strings.pluralize('commit', aheadBehind?.behind ?? 0),
expand: false,
},
), ),
new ResultsCommitsNode( new ResultsCommitsNode(
this.view, this.view,
this, this,
this.uri.repoPath!, this.uri.repoPath!,
'Ahead', 'Ahead',
this.getCommitsQuery(
GitRevision.createRange(
this._compareWith.ref || 'HEAD',
this.compareWithWorkingTree ? '' : this.branch.ref,
'..',
),
),
{ {
id: 'ahead',
description: Strings.pluralize('commit', aheadBehind?.ahead ?? 0),
expand: false,
includeRepoName: true,
query: this.getCommitsQuery(
GitRevision.createRange(
this._compareWith.ref || 'HEAD',
this.compareWithWorkingTree ? '' : this.branch.ref,
'..',
),
),
files: { files: {
ref1: this._compareWith.ref || 'HEAD', ref1: this._compareWith.ref || 'HEAD',
ref2: this.compareWithWorkingTree ? '' : this.branch.ref, ref2: this.compareWithWorkingTree ? '' : this.branch.ref,
query: this.getAheadFilesQuery.bind(this), query: this.getAheadFilesQuery.bind(this),
}, },
}, },
{
id: 'ahead',
description: Strings.pluralize('commit', aheadBehind?.ahead ?? 0),
expand: false,
},
), ),
]; ];
} }

+ 0
- 231
src/views/nodes/compareNode.ts View File

@ -1,231 +0,0 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { getRepoPathOrPrompt } from '../../commands';
import { BranchSorting, TagSorting } from '../../configuration';
import { CommandContext, NamedRef, setCommandContext } from '../../constants';
import { GitRevision } from '../../git/git';
import { ReferencePicker, ReferencesQuickPickIncludes } from '../../quickpicks';
import { debug, gate, Iterables, log, Promises } from '../../system';
import { CompareView } from '../compareView';
import { MessageNode } from './common';
import { ComparePickerNode } from './comparePickerNode';
import { ContextValues, unknownGitUri, ViewNode } from './viewNode';
interface RepoRef {
label: string;
repoPath: string;
ref: string | NamedRef;
}
export class CompareNode extends ViewNode<CompareView> {
private _children: (ViewNode | MessageNode)[] = [];
private _comparePickerNode: ComparePickerNode | undefined;
constructor(view: CompareView) {
super(unknownGitUri, view);
}
private _selectedRef: RepoRef | undefined;
get selectedRef(): RepoRef | undefined {
return this._selectedRef;
}
getChildren(): ViewNode[] {
if (this._children.length === 0) {
// Not really sure why I can't reuse this node -- but if I do the Tree errors out with an id already exists error
this._comparePickerNode = new ComparePickerNode(this.view, this);
this._children = [this._comparePickerNode];
const pinned = this.view.getPinnedComparisons();
if (pinned.length !== 0) {
this._children.push(...pinned);
}
} else if (this._comparePickerNode === undefined || !this._children.includes(this._comparePickerNode)) {
// Not really sure why I can't reuse this node -- but if I do the Tree errors out with an id already exists error
this._comparePickerNode = new ComparePickerNode(this.view, this);
this._children.splice(0, 0, this._comparePickerNode);
if (this._selectedRef !== undefined) {
const node = this._comparePickerNode;
setImmediate(() => this.view.reveal(node, { focus: false, select: true }));
}
}
return this._children;
}
getTreeItem(): TreeItem {
const item = new TreeItem('Compare', TreeItemCollapsibleState.Expanded);
item.contextValue = ContextValues.Compare;
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);
// Re-add the pinned comparisons
const pinned = this.view.getPinnedComparisons();
if (pinned.length !== 0) {
this._children.push(...pinned);
}
} else {
if (this._comparePickerNode !== undefined) {
const index = this._children.indexOf(this._comparePickerNode);
if (index !== -1) {
this._children.splice(index, 1);
}
}
this._children.splice(0, 0, results);
}
this.view.triggerNodeChange();
}
@log()
clear() {
this._selectedRef = undefined;
void setCommandContext(CommandContext.ViewsCanCompare, false);
this._children.length = 0;
this.view.triggerNodeChange();
}
@log({
args: { 0: (n: ViewNode) => n.toString() },
})
dismiss(node: ViewNode) {
this._selectedRef = undefined;
void setCommandContext(CommandContext.ViewsCanCompare, false);
if (this._children.length !== 0) {
const index = this._children.indexOf(node);
if (index === -1) return;
this._children.splice(index, 1);
}
this.view.triggerNodeChange();
}
@gate()
@debug()
async refresh() {
if (this._children.length === 0) return;
const promises: Promise<any>[] = [
...Iterables.filterMap(this._children, c => {
const result = c.refresh === undefined ? false : c.refresh();
return Promises.is<boolean | void>(result) ? result : undefined;
}),
];
await Promise.all(promises);
}
async compareWithSelected(repoPath?: string, ref?: string | NamedRef) {
if (this._selectedRef === undefined) return;
if (repoPath === undefined) {
repoPath = this._selectedRef.repoPath;
} else if (repoPath !== this._selectedRef.repoPath) {
// If we don't have a matching repoPath, then start over
void this.selectForCompare(repoPath, ref);
return;
}
if (ref === undefined) {
const pick = await ReferencePicker.show(
repoPath,
`Compare ${this.getRefName(this._selectedRef.ref)} with`,
'Choose a reference to compare with',
{
allowEnteringRefs: true,
picked:
typeof this._selectedRef.ref === 'string' ? this._selectedRef.ref : this._selectedRef.ref.ref,
// checkmarks: true,
include:
ReferencesQuickPickIncludes.BranchesAndTags |
ReferencesQuickPickIncludes.HEAD |
ReferencesQuickPickIncludes.WorkingTree,
sort: {
branches: { current: true, orderBy: BranchSorting.DateDesc },
tags: { orderBy: TagSorting.DateDesc },
},
},
);
if (pick === undefined) {
await this.view.show();
await this.view.reveal(this._comparePickerNode!, { focus: true, select: true });
return;
}
ref = pick.ref;
}
const ref1 = this._selectedRef;
this._selectedRef = undefined;
void setCommandContext(CommandContext.ViewsCanCompare, false);
void (await this.view.compare(repoPath, ref1.ref, ref));
}
async selectForCompare(repoPath?: string, ref?: string | NamedRef) {
if (repoPath === undefined) {
repoPath = await getRepoPathOrPrompt('Compare');
}
if (repoPath === undefined) {
await this.view.show();
await this.view.reveal(this._comparePickerNode!, { focus: true, select: true });
return;
}
let autoCompare = false;
if (ref === undefined) {
const pick = await ReferencePicker.show(repoPath, 'Compare', 'Choose a reference to compare', {
allowEnteringRefs: true,
// checkmarks: false,
include:
ReferencesQuickPickIncludes.BranchesAndTags |
ReferencesQuickPickIncludes.HEAD |
ReferencesQuickPickIncludes.WorkingTree,
sort: {
branches: { current: true, orderBy: BranchSorting.DateDesc },
tags: { orderBy: TagSorting.DateDesc },
},
});
if (pick == null) {
await this.view.show();
await this.view.reveal(this._comparePickerNode!, { focus: true, select: true });
return;
}
ref = pick.ref;
autoCompare = true;
}
this._selectedRef = { label: this.getRefName(ref), repoPath: repoPath, ref: ref };
void setCommandContext(CommandContext.ViewsCanCompare, true);
void (await this.triggerChange());
await this.view.reveal(this._comparePickerNode!, { focus: true, select: true });
if (autoCompare) {
void (await this.compareWithSelected());
}
}
private getRefName(ref: string | NamedRef) {
return typeof ref === 'string'
? GitRevision.shorten(ref, { strings: { working: 'Working Tree' } })!
: ref.label ?? GitRevision.shorten(ref.ref)!;
}
}

+ 20
- 8
src/views/nodes/comparePickerNode.ts View File

@ -1,23 +1,35 @@
'use strict'; 'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GlyphChars } from '../../constants';
import { GlyphChars, NamedRef } from '../../constants';
import { Container } from '../../container'; import { Container } from '../../container';
import { CompareView } from '../compareView';
import { CompareNode } from './compareNode';
import { SearchAndCompareView, SearchAndCompareViewNode } from '../searchAndCompareView';
import { ContextValues, unknownGitUri, ViewNode } from './viewNode'; import { ContextValues, unknownGitUri, ViewNode } from './viewNode';
export class ComparePickerNode extends ViewNode<CompareView> {
constructor(view: CompareView, protected readonly parent: CompareNode) {
interface RepoRef {
label: string;
repoPath: string;
ref: string | NamedRef;
}
export class ComparePickerNode extends ViewNode<SearchAndCompareView> {
readonly order: number = Date.now();
readonly pinned: boolean = false;
constructor(view: SearchAndCompareView, parent: SearchAndCompareViewNode, public readonly selectedRef: RepoRef) {
super(unknownGitUri, view, parent); super(unknownGitUri, view, parent);
} }
get canDismiss(): boolean {
return true;
}
getChildren(): ViewNode[] { getChildren(): ViewNode[] {
return []; return [];
} }
async getTreeItem(): Promise<TreeItem> { async getTreeItem(): Promise<TreeItem> {
const selectedRef = this.parent.selectedRef;
const repoPath = selectedRef !== undefined ? selectedRef.repoPath : undefined;
const selectedRef = this.selectedRef;
const repoPath = selectedRef?.repoPath;
let description; let description;
if (repoPath !== undefined) { if (repoPath !== undefined) {
@ -28,7 +40,7 @@ export class ComparePickerNode extends ViewNode {
} }
let item; let item;
if (selectedRef === undefined) {
if (selectedRef == null) {
item = new TreeItem( item = new TreeItem(
'Compare <branch, tag, or ref> with <branch, tag, or ref>', 'Compare <branch, tag, or ref> with <branch, tag, or ref>',
TreeItemCollapsibleState.None, TreeItemCollapsibleState.None,

+ 58
- 72
src/views/nodes/compareResultsNode.ts View File

@ -1,59 +1,58 @@
'use strict'; 'use strict';
import { Disposable, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { NamedRef } from '../../constants'; import { NamedRef } from '../../constants';
import { Container } from '../../container'; import { Container } from '../../container';
import { GitRevision } from '../../git/git'; import { GitRevision } from '../../git/git';
import { GitUri } from '../../git/gitUri'; import { GitUri } from '../../git/gitUri';
import { debug, gate, log, Strings } from '../../system'; import { debug, gate, log, Strings } from '../../system';
import { CompareView } from '../compareView';
import { CommitsQueryResults, ResultsCommitsNode } from './resultsCommitsNode'; import { CommitsQueryResults, ResultsCommitsNode } from './resultsCommitsNode';
import { FilesQueryResults } from './resultsFilesNode'; import { FilesQueryResults } from './resultsFilesNode';
import { ContextValues, ViewNode } from './viewNode'; import { ContextValues, ViewNode } from './viewNode';
import { RepositoryNode } from './repositoryNode'; import { RepositoryNode } from './repositoryNode';
import { TreeViewNodeCollapsibleStateChangeEvent } from '../viewBase';
import { SearchAndCompareView } from '../searchAndCompareView';
let instanceId = 0; let instanceId = 0;
export class CompareResultsNode extends ViewNode<CompareView> implements Disposable {
export class CompareResultsNode extends ViewNode<SearchAndCompareView> {
static key = ':compare-results'; static key = ':compare-results';
static getId(repoPath: string, ref1: string, ref2: string, instanceId: number): string { static getId(repoPath: string, ref1: string, ref2: string, instanceId: number): string {
return `${RepositoryNode.getId(repoPath)}${this.key}(${ref1}|${ref2}):${instanceId}`; return `${RepositoryNode.getId(repoPath)}${this.key}(${ref1}|${ref2}):${instanceId}`;
} }
static getPinnableId(repoPath: string, ref1: string, ref2: string) {
return Strings.sha1(`${repoPath}|${ref1}|${ref2}`);
}
private _children: ViewNode[] | undefined; private _children: ViewNode[] | undefined;
private _disposable: Disposable;
private _instanceId: number; private _instanceId: number;
constructor( constructor(
view: CompareView,
view: SearchAndCompareView,
parent: ViewNode,
public readonly repoPath: string, public readonly repoPath: string,
private _ref: NamedRef, private _ref: NamedRef,
private _compareWith: NamedRef, private _compareWith: NamedRef,
private _pinned: boolean = false,
private _pinned: number = 0,
) { ) {
super(GitUri.fromRepoPath(repoPath), view);
super(GitUri.fromRepoPath(repoPath), view, parent);
this._instanceId = instanceId++; this._instanceId = instanceId++;
this._disposable = this.view.onDidChangeNodeCollapsibleState(this.onCollapsibleStateChanged, this);
} }
dispose() {
this._disposable.dispose();
get id(): string {
return CompareResultsNode.getId(this.repoPath, this._ref.ref, this._compareWith.ref, this._instanceId);
} }
private _collapsibleState: TreeItemCollapsibleState | undefined;
private onCollapsibleStateChanged(e: TreeViewNodeCollapsibleStateChangeEvent<ViewNode>) {
if (e.element !== this) return;
this._collapsibleState = e.state;
get canDismiss(): boolean {
return !this.pinned;
} }
get id(): string {
return CompareResultsNode.getId(this.repoPath, this._ref.ref, this._compareWith.ref, this._instanceId);
private readonly _order: number = Date.now();
get order(): number {
return this._pinned || this._order;
} }
get pinned(): boolean { get pinned(): boolean {
return this._pinned;
return this._pinned !== 0;
} }
async getChildren(): Promise<ViewNode[]> { async getChildren(): Promise<ViewNode[]> {
@ -68,40 +67,42 @@ export class CompareResultsNode extends ViewNode implements Disposa
this, this,
this.uri.repoPath!, this.uri.repoPath!,
'Behind', 'Behind',
this.getCommitsQuery(
GitRevision.createRange(this._ref.ref, this._compareWith?.ref ?? 'HEAD', '..'),
),
{ {
id: 'behind',
description: Strings.pluralize('commit', aheadBehind?.behind ?? 0),
expand: false,
includeRepoName: true,
query: this.getCommitsQuery(
GitRevision.createRange(this._ref.ref, this._compareWith?.ref ?? 'HEAD', '..'),
),
files: { files: {
ref1: this._ref.ref, ref1: this._ref.ref,
ref2: this._compareWith.ref || 'HEAD', ref2: this._compareWith.ref || 'HEAD',
query: this.getBehindFilesQuery.bind(this), query: this.getBehindFilesQuery.bind(this),
}, },
}, },
{
id: 'behind',
description: Strings.pluralize('commit', aheadBehind?.behind ?? 0),
expand: false,
},
), ),
new ResultsCommitsNode( new ResultsCommitsNode(
this.view, this.view,
this, this,
this.uri.repoPath!, this.uri.repoPath!,
'Ahead', 'Ahead',
this.getCommitsQuery(
GitRevision.createRange(this._compareWith?.ref ?? 'HEAD', this._ref.ref, '..'),
),
{ {
id: 'ahead',
description: Strings.pluralize('commit', aheadBehind?.ahead ?? 0),
expand: false,
includeRepoName: true,
query: this.getCommitsQuery(
GitRevision.createRange(this._compareWith?.ref ?? 'HEAD', this._ref.ref, '..'),
),
files: { files: {
ref1: this._compareWith.ref || 'HEAD', ref1: this._compareWith.ref || 'HEAD',
ref2: this._ref.ref, ref2: this._ref.ref,
query: this.getAheadFilesQuery.bind(this), query: this.getAheadFilesQuery.bind(this),
}, },
}, },
{
id: 'ahead',
description: Strings.pluralize('commit', aheadBehind?.ahead ?? 0),
expand: false,
},
), ),
]; ];
} }
@ -122,52 +123,36 @@ export class CompareResultsNode extends ViewNode implements Disposa
this._compareWith.label ?? this._compareWith.label ??
GitRevision.shorten(this._compareWith.ref, { strings: { working: 'Working Tree' } }) GitRevision.shorten(this._compareWith.ref, { strings: { working: 'Working Tree' } })
}`, }`,
this._collapsibleState ?? TreeItemCollapsibleState.Collapsed,
TreeItemCollapsibleState.Collapsed,
); );
item.contextValue = `${ContextValues.CompareResults}${this._pinned ? '+pinned' : ''}`; item.contextValue = `${ContextValues.CompareResults}${this._pinned ? '+pinned' : ''}`;
item.description = description; item.description = description;
if (this._pinned) { if (this._pinned) {
item.iconPath = {
dark: Container.context.asAbsolutePath('images/dark/icon-pin-small.svg'),
light: Container.context.asAbsolutePath('images/light/icon-pin-small.svg'),
};
item.iconPath = new ThemeIcon('pinned');
} }
return item; return item;
} }
canDismiss(): boolean {
return !this._pinned;
}
// eslint-disable-next-line @typescript-eslint/require-await
@gate() @gate()
@debug() @debug()
async getDiffRefs(): Promise<[string, string]> { async getDiffRefs(): Promise<[string, string]> {
// if (this.comparisonNotation === '..') {
// return [
// (await Container.git.getMergeBase(this.repoPath, this._compareWith.ref, this._ref.ref)) ??
// this._compareWith.ref,
// this._ref.ref,
// ];
// }
return [this._compareWith.ref, this._ref.ref];
return Promise.resolve([this._compareWith.ref, this._ref.ref]);
} }
@log() @log()
async pin() { async pin() {
if (this._pinned) return;
if (this.pinned) return;
await this.view.updatePinnedComparison(this.getPinnableId(), {
this._pinned = Date.now();
await this.view.updatePinned(this.getPinnableId(), {
type: 'comparison',
timestamp: this._pinned,
path: this.repoPath, path: this.repoPath,
ref1: this._ref, ref1: this._ref,
ref2: this._compareWith, ref2: this._compareWith,
notation: undefined,
}); });
this._pinned = true;
void this.triggerChange();
setImmediate(() => this.view.reveal(this, { focus: true, select: true }));
} }
@gate() @gate()
@ -188,28 +173,33 @@ export class CompareResultsNode extends ViewNode implements Disposa
this._compareWith = ref1; this._compareWith = ref1;
// If we were pinned, remove the existing pin and save a new one // If we were pinned, remove the existing pin and save a new one
if (this._pinned) {
await this.view.updatePinnedComparison(currentId);
await this.view.updatePinnedComparison(this.getPinnableId(), {
if (this.pinned) {
await this.view.updatePinned(currentId);
await this.view.updatePinned(this.getPinnableId(), {
type: 'comparison',
timestamp: this._pinned,
path: this.repoPath, path: this.repoPath,
ref1: this._ref, ref1: this._ref,
ref2: this._compareWith, ref2: this._compareWith,
notation: undefined,
}); });
} }
this._children = undefined; this._children = undefined;
this.view.triggerNodeChange(this);
this.view.triggerNodeChange(this.parent);
setImmediate(() => this.view.reveal(this, { expand: true, focus: true, select: true }));
} }
@log() @log()
async unpin() { async unpin() {
if (!this._pinned) return;
if (!this.pinned) return;
await this.view.updatePinnedComparison(this.getPinnableId());
this._pinned = 0;
await this.view.updatePinned(this.getPinnableId());
setImmediate(() => this.view.reveal(this, { focus: true, select: true }));
}
this._pinned = false;
void this.triggerChange();
private getPinnableId() {
return CompareResultsNode.getPinnableId(this.repoPath, this._ref.ref, this._compareWith.ref);
} }
private async getAheadFilesQuery(): Promise<FilesQueryResults> { private async getAheadFilesQuery(): Promise<FilesQueryResults> {
@ -294,8 +284,4 @@ export class CompareResultsNode extends ViewNode implements Disposa
return results as CommitsQueryResults; return results as CommitsQueryResults;
}; };
} }
private getPinnableId() {
return Strings.sha1(`${this.repoPath}|${this._ref.ref}|${this._compareWith.ref}`);
}
} }

+ 3
- 4
src/views/nodes/pullRequestNode.ts View File

@ -2,18 +2,17 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { BranchesView } from '../branchesView'; import { BranchesView } from '../branchesView';
import { CommitsView } from '../commitsView'; import { CommitsView } from '../commitsView';
import { CompareView } from '../compareView';
import { ContributorsView } from '../contributorsView'; import { ContributorsView } from '../contributorsView';
import { GitBranch, GitCommit, PullRequest, PullRequestState } from '../../git/git'; import { GitBranch, GitCommit, PullRequest, PullRequestState } from '../../git/git';
import { GitUri } from '../../git/gitUri'; import { GitUri } from '../../git/gitUri';
import { RemotesView } from '../remotesView'; import { RemotesView } from '../remotesView';
import { RepositoriesView } from '../repositoriesView'; import { RepositoriesView } from '../repositoriesView';
import { RepositoryNode } from './repositoryNode'; import { RepositoryNode } from './repositoryNode';
import { SearchView } from '../searchView';
import { SearchAndCompareView } from '../searchAndCompareView';
import { ContextValues, ViewNode } from './viewNode'; import { ContextValues, ViewNode } from './viewNode';
export class PullRequestNode extends ViewNode< export class PullRequestNode extends ViewNode<
BranchesView | CommitsView | CompareView | ContributorsView | RemotesView | RepositoriesView | SearchView
BranchesView | CommitsView | ContributorsView | RemotesView | RepositoriesView | SearchAndCompareView
> { > {
static key = ':pullrequest'; static key = ':pullrequest';
static getId(repoPath: string, number: number, ref: string): string { static getId(repoPath: string, number: number, ref: string): string {
@ -21,7 +20,7 @@ export class PullRequestNode extends ViewNode<
} }
constructor( constructor(
view: BranchesView | CommitsView | CompareView | ContributorsView | RemotesView | RepositoriesView | SearchView,
view: BranchesView | CommitsView | ContributorsView | RemotesView | RepositoriesView | SearchAndCompareView,
parent: ViewNode, parent: ViewNode,
public readonly pullRequest: PullRequest, public readonly pullRequest: PullRequest,
public readonly branchOrCommit: GitBranch | GitCommit, public readonly branchOrCommit: GitBranch | GitCommit,

+ 50
- 44
src/views/nodes/resultsCommitsNode.ts View File

@ -2,7 +2,6 @@
import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { CommitNode } from './commitNode'; import { CommitNode } from './commitNode';
import { LoadMoreNode } from './common'; import { LoadMoreNode } from './common';
import { GlyphChars } from '../../constants';
import { Container } from '../../container'; import { Container } from '../../container';
import { GitLog } from '../../git/git'; import { GitLog } from '../../git/git';
import { GitUri } from '../../git/gitUri'; import { GitUri } from '../../git/gitUri';
@ -19,48 +18,50 @@ export interface CommitsQueryResults {
more?(limit: number | undefined): Promise<void>; more?(limit: number | undefined): Promise<void>;
} }
export class ResultsCommitsNode extends ViewNode<ViewsWithFiles> implements PageableViewNode {
export class ResultsCommitsNode<View extends ViewsWithFiles = ViewsWithFiles>
extends ViewNode<View>
implements PageableViewNode {
constructor( constructor(
view: ViewsWithFiles,
view: View,
parent: ViewNode, parent: ViewNode,
public readonly repoPath: string, public readonly repoPath: string,
private _label: string, private _label: string,
private readonly _commitsQuery: (limit: number | undefined) => Promise<CommitsQueryResults>,
private readonly _options: {
id?: string;
description?: string;
expand?: boolean;
includeRepoName?: boolean;
private readonly _results: {
query: (limit: number | undefined) => Promise<CommitsQueryResults>;
deferred?: boolean;
files?: { files?: {
ref1: string; ref1: string;
ref2: string; ref2: string;
query: () => Promise<FilesQueryResults>; query: () => Promise<FilesQueryResults>;
}; };
},
private readonly _options: {
id?: string;
description?: string;
expand?: boolean;
} = {}, } = {},
splatted?: boolean,
) { ) {
super(GitUri.fromRepoPath(repoPath), view, parent); super(GitUri.fromRepoPath(repoPath), view, parent);
this._options = { expand: true, includeRepoName: true, ..._options };
if (splatted != null) {
this.splatted = splatted;
}
this._options = { expand: true, ..._options };
} }
get id(): string { get id(): string {
return `${this.parent!.id}:results:commits${this._options.id ? `:${this._options.id}` : ''}`; return `${this.parent!.id}:results:commits${this._options.id ? `:${this._options.id}` : ''}`;
} }
get type(): ContextValues {
return ContextValues.ResultsCommits;
}
async getChildren(): Promise<ViewNode[]> { async getChildren(): Promise<ViewNode[]> {
const { log } = await this.getCommitsQueryResults(); const { log } = await this.getCommitsQueryResults();
if (log == null) return []; if (log == null) return [];
const options = { expand: this._options.expand && log.count === 1 };
const getBranchAndTagTips = await Container.git.getBranchesAndTagsTipsFn(this.uri.repoPath); const getBranchAndTagTips = await Container.git.getBranchesAndTagsTipsFn(this.uri.repoPath);
const children = []; const children = [];
const { files } = this._options;
const { files } = this._results;
if (files != null) { if (files != null) {
children.push( children.push(
new ResultsFilesNode(this.view, this, this.uri.repoPath!, files.ref1, files.ref2, files.query, { new ResultsFilesNode(this.view, this, this.uri.repoPath!, files.ref1, files.ref2, files.query, {
@ -69,6 +70,8 @@ export class ResultsCommitsNode extends ViewNode implements Page
); );
} }
const options = { expand: this._options.expand && log.count === 1 };
children.push( children.push(
...insertDateMarkers( ...insertDateMarkers(
Iterables.map( Iterables.map(
@ -90,38 +93,35 @@ export class ResultsCommitsNode extends ViewNode implements Page
async getTreeItem(): Promise<TreeItem> { async getTreeItem(): Promise<TreeItem> {
let label; let label;
let log;
let state; let state;
try {
({ label, log } = await Promises.cancellable(this.getCommitsQueryResults(), 100));
state =
log == null || log.count === 0
? TreeItemCollapsibleState.None
: this._options.expand || log.count === 1
? TreeItemCollapsibleState.Expanded
: TreeItemCollapsibleState.Collapsed;
} catch (ex) {
if (ex instanceof Promises.CancellationError) {
ex.promise.then(() => this.triggerChange(false));
}
// Need to use Collapsed before we have results or the item won't show up in the view until the children are awaited
// https://github.com/microsoft/vscode/issues/54806 & https://github.com/microsoft/vscode/issues/62214
if (this._results.deferred) {
label = this._label;
state = TreeItemCollapsibleState.Collapsed; state = TreeItemCollapsibleState.Collapsed;
}
let description = this._options.description;
if (this._options.includeRepoName && (await Container.git.getRepositoryCount()) > 1) {
const repo = await Container.git.getRepository(this.repoPath);
description = `${description ? `${description} ${GlyphChars.Dot} ` : ''}${
repo?.formattedName ?? this.repoPath
}`;
} else {
try {
let log;
({ label, log } = await Promises.cancellable(this.getCommitsQueryResults(), 100));
state =
log == null || log.count === 0
? TreeItemCollapsibleState.None
: this._options.expand || log.count === 1
? TreeItemCollapsibleState.Expanded
: TreeItemCollapsibleState.Collapsed;
} catch (ex) {
if (ex instanceof Promises.CancellationError) {
ex.promise.then(() => this.triggerChange(false));
}
// Need to use Collapsed before we have results or the item won't show up in the view until the children are awaited
// https://github.com/microsoft/vscode/issues/54806 & https://github.com/microsoft/vscode/issues/62214
state = TreeItemCollapsibleState.Collapsed;
}
} }
const item = new TreeItem(label ?? this._label, state); const item = new TreeItem(label ?? this._label, state);
item.contextValue = this.type;
item.description = description;
item.contextValue = ContextValues.ResultsCommits;
item.description = this._options.description;
item.id = this.id; item.id = this.id;
return item; return item;
@ -139,9 +139,15 @@ export class ResultsCommitsNode extends ViewNode implements Page
private _commitsQueryResults: Promise<CommitsQueryResults> | undefined; private _commitsQueryResults: Promise<CommitsQueryResults> | undefined;
private async getCommitsQueryResults() { private async getCommitsQueryResults() {
if (this._commitsQueryResults == null) { if (this._commitsQueryResults == null) {
this._commitsQueryResults = this._commitsQuery(this.limit ?? Container.config.advanced.maxSearchItems);
this._commitsQueryResults = this._results.query(this.limit ?? Container.config.advanced.maxSearchItems);
const results = await this._commitsQueryResults; const results = await this._commitsQueryResults;
this._hasMore = results.hasMore; this._hasMore = results.hasMore;
if (this._results.deferred) {
this._results.deferred = false;
void this.triggerChange(false);
}
} }
return this._commitsQueryResults; return this._commitsQueryResults;

+ 0
- 147
src/views/nodes/searchNode.ts View File

@ -1,147 +0,0 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { SearchCommitsCommandArgs } from '../../commands';
import { GlyphChars } from '../../constants';
import { debug, gate, Iterables, log, Promises } from '../../system';
import { View } from '../viewBase';
import { CommandMessageNode, MessageNode } from './common';
import { ContextValues, unknownGitUri, ViewNode } from './viewNode';
import { SearchOperators } from '../../git/git';
export class SearchNode extends ViewNode {
private _children: (ViewNode | MessageNode)[] = [];
constructor(view: View) {
super(unknownGitUri, view);
}
getChildren(): ViewNode[] {
if (this._children.length === 0) {
const command = {
title: ' ',
command: 'gitlens.showCommitSearch',
};
const getCommandArgs = (search: SearchOperators): SearchCommitsCommandArgs => {
return {
search: { pattern: search },
prefillOnly: true,
};
};
return [
new CommandMessageNode(
this.view,
this,
{
...command,
arguments: [this, getCommandArgs('message:')],
},
'Search by Message',
`pattern or message: pattern or =: pattern ${GlyphChars.Dash} use quotes to search for phrases`,
`Click to search for commits with matching messages ${GlyphChars.Dash} use quotes to search for phrases`,
),
new CommandMessageNode(
this.view,
this,
{
...command,
arguments: [this, getCommandArgs('author:')],
},
`${GlyphChars.Space.repeat(4)} or, Author`,
'author: pattern or @: pattern',
'Click to search for commits with matching authors',
),
new CommandMessageNode(
this.view,
this,
{
...command,
arguments: [this, getCommandArgs('commit:')],
},
`${GlyphChars.Space.repeat(4)} or, Commit ID`,
'commit: sha or #: sha',
'Click to search for commits with matching commit ids',
),
new CommandMessageNode(
this.view,
this,
{
...command,
arguments: [this, getCommandArgs('file:')],
},
`${GlyphChars.Space.repeat(4)} or, Files`,
'file: glob or ?: glob',
'Click to search for commits with matching files',
),
new CommandMessageNode(
this.view,
this,
{
...command,
arguments: [this, getCommandArgs('change:')],
},
`${GlyphChars.Space.repeat(4)} or, Changes`,
'change: pattern or ~: pattern',
'Click to search for commits with matching changes',
),
];
}
return this._children;
}
getTreeItem(): TreeItem {
const item = new TreeItem('Search', TreeItemCollapsibleState.Expanded);
item.contextValue = ContextValues.Search;
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;
const promises: Promise<any>[] = [
...Iterables.filterMap(this._children, c => {
const result = c.refresh === undefined ? false : c.refresh();
return Promises.is<boolean | void>(result) ? result : undefined;
}),
];
await Promise.all(promises);
}
}

+ 0
- 64
src/views/nodes/searchResultsCommitsNode.ts View File

@ -1,64 +0,0 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Commands, SearchCommitsCommandArgs } from '../../commands';
import { ViewsWithFiles } from '../viewBase';
import { CommitsQueryResults, ResultsCommitsNode } from './resultsCommitsNode';
import { ContextValues, ViewNode } from './viewNode';
import { RepositoryNode } from './repositoryNode';
import { SearchPattern } from '../../git/git';
let instanceId = 0;
export class SearchResultsCommitsNode extends ResultsCommitsNode {
static key = ':search-results';
static getId(repoPath: string, search: SearchPattern | undefined, instanceId: number): string {
return `${RepositoryNode.getId(repoPath)}${this.key}(${
search === undefined ? '?' : SearchPattern.toKey(search)
}):${instanceId}`;
}
private _instanceId: number;
constructor(
view: ViewsWithFiles,
parent: ViewNode,
repoPath: string,
public readonly search: SearchPattern,
label: string,
commitsQuery: (limit: number | undefined) => Promise<CommitsQueryResults>,
) {
super(view, parent, repoPath, label, commitsQuery, {
expand: true,
includeRepoName: true,
});
this._instanceId = instanceId++;
}
get id(): string {
return SearchResultsCommitsNode.getId(this.repoPath, this.search, this._instanceId);
}
get type(): ContextValues {
return ContextValues.SearchResults;
}
async getTreeItem(): Promise<TreeItem> {
const item = await super.getTreeItem();
if (item.collapsibleState === TreeItemCollapsibleState.None) {
const args: SearchCommitsCommandArgs = {
search: this.search,
prefillOnly: true,
showResultsInSideBar: true,
};
item.command = {
title: 'Search Commits',
command: Commands.SearchCommitsInView,
arguments: [args],
};
}
return item;
}
}

+ 297
- 0
src/views/nodes/searchResultsNode.ts View File

@ -0,0 +1,297 @@
'use strict';
import { ThemeIcon, TreeItem } from 'vscode';
import { executeGitCommand } from '../../commands';
import { Container } from '../../container';
import { GitLog, SearchPattern } from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { RepositoryNode } from './repositoryNode';
import { CommitsQueryResults, ResultsCommitsNode } from './resultsCommitsNode';
import { SearchAndCompareView } from '../searchAndCompareView';
import { debug, gate, log, Strings } from '../../system';
import { ContextValues, PageableViewNode, ViewNode } from './viewNode';
let instanceId = 0;
interface SearchQueryResults {
readonly label: string;
readonly log: GitLog | undefined;
readonly hasMore: boolean;
more?(limit: number | undefined): Promise<void>;
}
export class SearchResultsNode extends ViewNode<SearchAndCompareView> implements PageableViewNode {
static key = ':search-results';
static getId(repoPath: string, search: SearchPattern | undefined, instanceId: number): string {
return `${RepositoryNode.getId(repoPath)}${this.key}(${
search == null ? '?' : SearchPattern.toKey(search)
}):${instanceId}`;
}
static getPinnableId(repoPath: string, search: SearchPattern) {
return Strings.sha1(`${repoPath}|${SearchPattern.toKey(search)}`);
}
static is(node: any): node is SearchResultsNode {
return node instanceof SearchResultsNode;
}
private _instanceId: number;
constructor(
view: SearchAndCompareView,
parent: ViewNode,
public readonly repoPath: string,
search: SearchPattern,
private _labels: {
label: string;
queryLabel:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
resultsType?: { singular: string; plural: string };
},
private _searchQueryOrLog?:
| ((limit: number | undefined) => Promise<CommitsQueryResults>)
| Promise<GitLog | undefined>
| GitLog
| undefined,
private _pinned: number = 0,
) {
super(GitUri.fromRepoPath(repoPath), view, parent);
this._search = search;
this._instanceId = instanceId++;
this._order = Date.now();
}
get id(): string {
return SearchResultsNode.getId(this.repoPath, this.search, this._instanceId);
}
get canDismiss(): boolean {
return !this.pinned;
}
private readonly _order: number = Date.now();
get order(): number {
return this._pinned || this._order;
}
get pinned(): boolean {
return this._pinned !== 0;
}
private _search: SearchPattern;
get search(): SearchPattern {
return this._search;
}
private _resultsNode: ResultsCommitsNode | undefined;
private ensureResults() {
if (this._resultsNode == null) {
let deferred;
if (this._searchQueryOrLog == null) {
deferred = true;
this._searchQueryOrLog = this.getSearchQuery({
label: this._labels.queryLabel,
});
} else if (typeof this._searchQueryOrLog !== 'function') {
this._searchQueryOrLog = this.getSearchQuery(
{
label: this._labels.queryLabel,
},
this._searchQueryOrLog,
);
}
this._resultsNode = new ResultsCommitsNode(
this.view,
this,
this.repoPath,
this._labels.label,
{
query: this._searchQueryOrLog,
deferred: deferred,
},
{
expand: !this.pinned,
},
true,
);
}
return this._resultsNode;
}
async getChildren(): Promise<ViewNode[]> {
return this.ensureResults().getChildren();
}
async getTreeItem(): Promise<TreeItem> {
const item = await this.ensureResults().getTreeItem();
item.contextValue = `${ContextValues.SearchResults}${this._pinned ? '+pinned' : ''}`;
if ((await Container.git.getRepositoryCount()) > 1) {
const repo = await Container.git.getRepository(this.repoPath);
item.description = repo?.formattedName ?? this.repoPath;
}
if (this._pinned) {
item.iconPath = new ThemeIcon('pinned');
}
// if (item.collapsibleState === TreeItemCollapsibleState.None) {
// const args: SearchCommitsCommandArgs = {
// search: this.search,
// prefillOnly: true,
// showResultsInSideBar: true,
// };
// item.command = {
// title: 'Search Commits',
// command: Commands.SearchCommitsInView,
// arguments: [args],
// };
// }
return item;
}
get hasMore() {
return this.ensureResults().hasMore;
}
async loadMore(limit?: number) {
return this.ensureResults().loadMore(limit);
}
async edit(search?: {
pattern: SearchPattern;
labels: {
label: string;
queryLabel:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
resultsType?: { singular: string; plural: string };
};
log: Promise<GitLog | undefined> | GitLog | undefined;
}) {
if (search == null) {
void (await executeGitCommand({
command: 'search',
prefillOnly: true,
state: {
repo: this.repoPath,
...this.search,
showResultsInSideBar: this,
},
}));
return;
}
this._search = search.pattern;
this._labels = search.labels;
this._searchQueryOrLog = search.log;
this._resultsNode = undefined;
void this.triggerChange(false);
}
@gate()
@debug()
refresh(reset: boolean = false) {
this._resultsNode?.refresh(reset);
}
@log()
async pin() {
if (this.pinned) return;
this._pinned = Date.now();
await this.view.updatePinned(this.getPinnableId(), {
type: 'search',
timestamp: this._pinned,
path: this.repoPath,
labels: this._labels,
search: this.search,
});
setImmediate(() => this.view.reveal(this, { focus: true, select: true }));
}
@log()
async unpin() {
if (!this.pinned) return;
this._pinned = 0;
await this.view.updatePinned(this.getPinnableId());
setImmediate(() => this.view.reveal(this, { focus: true, select: true }));
}
private getPinnableId() {
return SearchResultsNode.getPinnableId(this.repoPath, this.search);
}
private getSearchLabel(
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
},
log: GitLog | undefined,
): string {
if (typeof label === 'string') return label;
const count = log?.count ?? 0;
const resultsType =
label.resultsType === undefined ? { singular: 'result', plural: 'results' } : label.resultsType;
return `${Strings.pluralize(resultsType.singular, count, {
number: log?.hasMore ?? false ? `${count}+` : undefined,
plural: resultsType.plural,
zero: 'No',
})} ${label.label}`;
}
private getSearchQuery(
options: {
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
},
log?: Promise<GitLog | undefined> | GitLog,
): (limit: number | undefined) => Promise<SearchQueryResults> {
let useCacheOnce = true;
return async (limit: number | undefined) => {
log = await (log ?? Container.git.getLogForSearch(this.repoPath, this.search));
if (!useCacheOnce && log != null && log.query != null) {
log = await log.query(limit);
}
useCacheOnce = false;
const results: Mutable<SearchQueryResults> = {
label: this.getSearchLabel(options.label, log),
log: log,
hasMore: log?.hasMore ?? false,
};
if (results.hasMore) {
results.more = async (limit: number | undefined) => {
results.log = (await results.log?.more?.(limit)) ?? results.log;
results.label = this.getSearchLabel(options.label, results.log);
results.hasMore = results.log?.hasMore ?? true;
};
}
return results;
};
}
}

+ 1
- 5
src/views/nodes/viewNode.ts View File

@ -41,7 +41,7 @@ export enum ContextValues {
ResultsCommits = 'gitlens:results:commits', ResultsCommits = 'gitlens:results:commits',
ResultsFile = 'gitlens:file:results', ResultsFile = 'gitlens:file:results',
ResultsFiles = 'gitlens:results:files', ResultsFiles = 'gitlens:results:files',
Search = 'gitlens:search',
SearchAndCompare = 'gitlens:searchAndCompare',
SearchResults = 'gitlens:search:results', SearchResults = 'gitlens:search:results',
Stash = 'gitlens:stash', Stash = 'gitlens:stash',
StashFile = 'gitlens:file:stash', StashFile = 'gitlens:file:stash',
@ -142,10 +142,6 @@ export function nodeSupportsClearing(node: ViewNode): node is ViewNode & { clear
return typeof (node as ViewNode & { clear(): void | Promise<void> }).clear === 'function'; return typeof (node as ViewNode & { clear(): void | Promise<void> }).clear === 'function';
} }
export function nodeSupportsConditionalDismissal(node: ViewNode): node is ViewNode & { canDismiss(): boolean } {
return typeof (node as ViewNode & { canDismiss(): boolean }).canDismiss === 'function';
}
export interface PageableViewNode { export interface PageableViewNode {
readonly id: string; readonly id: string;
limit?: number; limit?: number;

+ 502
- 0
src/views/searchAndCompareView.ts View File

@ -0,0 +1,502 @@
'use strict';
import { commands, ConfigurationChangeEvent, TreeItem, TreeItemCollapsibleState } from 'vscode';
import {
BranchSorting,
configuration,
SearchAndCompareViewConfig,
TagSorting,
ViewFilesLayout,
} from '../configuration';
import { CommandContext, NamedRef, PinnedItem, PinnedItems, setCommandContext, WorkspaceState } from '../constants';
import { Container } from '../container';
import { GitLog, GitRevision, SearchPattern } from '../git/git';
import { CompareResultsNode, ContextValues, SearchResultsNode, unknownGitUri, ViewNode } from './nodes';
import { debug, gate, Iterables, log, Promises } from '../system';
import { ViewBase } from './viewBase';
import { ComparePickerNode } from './nodes/comparePickerNode';
import { ReferencePicker, ReferencesQuickPickIncludes } from '../quickpicks';
import { getRepoPathOrPrompt } from '../commands';
interface DeprecatedPinnedComparison {
path: string;
ref1: NamedRef;
ref2: NamedRef;
notation?: '..' | '...';
}
interface DeprecatedPinnedComparisons {
[id: string]: DeprecatedPinnedComparison;
}
export class SearchAndCompareViewNode extends ViewNode<SearchAndCompareView> {
protected splatted = true;
private comparePicker: ComparePickerNode | undefined;
constructor(view: SearchAndCompareView) {
super(unknownGitUri, view);
}
private _children: (ComparePickerNode | CompareResultsNode | SearchResultsNode)[] | undefined;
private get children(): (ComparePickerNode | CompareResultsNode | SearchResultsNode)[] {
if (this._children == null) {
this._children = [];
// Get pinned searches & comparisons
const pinned = this.view.getPinned();
if (pinned.length !== 0) {
this._children.push(...pinned);
}
}
return this._children;
}
getChildren(): ViewNode[] {
return this.children.sort((a, b) => (a.pinned ? -1 : 1) - (b.pinned ? -1 : 1) || b.order - a.order);
}
getTreeItem(): TreeItem {
this.splatted = false;
const item = new TreeItem('SearchAndCompare', TreeItemCollapsibleState.Expanded);
item.contextValue = ContextValues.SearchAndCompare;
return item;
}
addOrReplace(results: CompareResultsNode | SearchResultsNode, replace: boolean) {
if (this.children.includes(results)) return;
if (replace) {
this.clear();
}
this.children.push(results);
this.view.triggerNodeChange();
}
@log()
clear(silent: boolean = false) {
if (this.children.length === 0) return;
this.removeComparePicker(true);
const index = this._children!.findIndex(c => !c.pinned);
if (index !== -1) {
this._children!.splice(index, this._children!.length);
}
if (!silent) {
this.view.triggerNodeChange();
}
}
@log({
args: { 0: (n: ViewNode) => n.toString() },
})
dismiss(node: ComparePickerNode | CompareResultsNode | SearchResultsNode) {
if (node === this.comparePicker) {
this.removeComparePicker();
return;
}
if (this.children.length === 0) return;
const index = this.children.indexOf(node);
if (index === -1) return;
this.children.splice(index, 1);
this.view.triggerNodeChange();
}
@gate()
@debug()
async refresh() {
if (this.children.length === 0) return;
const promises: Promise<any>[] = [
...Iterables.filterMap(this.children, c => {
const result = c.refresh === undefined ? false : c.refresh();
return Promises.is<boolean | void>(result) ? result : undefined;
}),
];
await Promise.all(promises);
}
async compareWithSelected(repoPath?: string, ref?: string | NamedRef) {
const selectedRef = this.comparePicker?.selectedRef;
if (selectedRef == null) return;
if (repoPath == null) {
repoPath = selectedRef.repoPath;
} else if (repoPath !== selectedRef.repoPath) {
// If we don't have a matching repoPath, then start over
void this.selectForCompare(repoPath, ref);
return;
}
if (ref == null) {
const pick = await ReferencePicker.show(
repoPath,
`Compare ${this.getRefName(selectedRef.ref)} with`,
'Choose a reference to compare with',
{
allowEnteringRefs: true,
picked: typeof selectedRef.ref === 'string' ? selectedRef.ref : selectedRef.ref.ref,
// checkmarks: true,
include:
ReferencesQuickPickIncludes.BranchesAndTags |
ReferencesQuickPickIncludes.HEAD |
ReferencesQuickPickIncludes.WorkingTree,
sort: {
branches: { current: true, orderBy: BranchSorting.DateDesc },
tags: { orderBy: TagSorting.DateDesc },
},
},
);
if (pick == null) {
if (this.comparePicker != null) {
await this.view.show();
await this.view.reveal(this.comparePicker, { focus: true, select: true });
}
return;
}
ref = pick.ref;
}
this.removeComparePicker();
void (await this.view.compare(repoPath, selectedRef.ref, ref));
}
async selectForCompare(repoPath?: string, ref?: string | NamedRef) {
if (repoPath == null) {
repoPath = await getRepoPathOrPrompt('Compare');
}
if (repoPath == null) return;
this.removeComparePicker(true);
let autoCompare = false;
if (ref == null) {
const pick = await ReferencePicker.show(repoPath, 'Compare', 'Choose a reference to compare', {
allowEnteringRefs: true,
// checkmarks: false,
include:
ReferencesQuickPickIncludes.BranchesAndTags |
ReferencesQuickPickIncludes.HEAD |
ReferencesQuickPickIncludes.WorkingTree,
sort: {
branches: { current: true, orderBy: BranchSorting.DateDesc },
tags: { orderBy: TagSorting.DateDesc },
},
});
if (pick == null) {
await this.triggerChange();
return;
}
ref = pick.ref;
autoCompare = true;
}
this.comparePicker = new ComparePickerNode(this.view, this, {
label: this.getRefName(ref),
repoPath: repoPath,
ref: ref,
});
this.children.splice(0, 0, this.comparePicker);
void setCommandContext(CommandContext.ViewsCanCompare, true);
await this.triggerChange();
await this.view.reveal(this.comparePicker, { focus: false, select: true });
if (autoCompare) {
await this.compareWithSelected();
}
}
private getRefName(ref: string | NamedRef) {
return typeof ref === 'string'
? GitRevision.shorten(ref, { strings: { working: 'Working Tree' } })!
: ref.label ?? GitRevision.shorten(ref.ref)!;
}
private removeComparePicker(silent: boolean = false) {
void setCommandContext(CommandContext.ViewsCanCompare, false);
if (this.comparePicker != null) {
const index = this.children.indexOf(this.comparePicker);
if (index !== -1) {
this.children.splice(index, 1);
if (!silent) {
void this.triggerChange();
}
}
this.comparePicker = undefined;
}
}
}
export class SearchAndCompareView extends ViewBase<SearchAndCompareViewNode, SearchAndCompareViewConfig> {
protected readonly configKey = 'searchAndCompare';
constructor() {
super('gitlens.views.searchAndCompare', 'Search & Compare');
void setCommandContext(CommandContext.ViewsSearchAndCompareKeepResults, this.keepResults);
}
getRoot() {
return new SearchAndCompareViewNode(this);
}
protected registerCommands() {
void Container.viewCommands;
commands.registerCommand(this.getQualifiedCommand('clear'), () => this.clear(), this);
commands.registerCommand(
this.getQualifiedCommand('copy'),
() => commands.executeCommand('gitlens.views.copy', this.selection),
this,
);
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(true), 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,
);
commands.registerCommand(this.getQualifiedCommand('setShowAvatarsOn'), () => this.setShowAvatars(true), this);
commands.registerCommand(this.getQualifiedCommand('setShowAvatarsOff'), () => this.setShowAvatars(false), this);
commands.registerCommand(this.getQualifiedCommand('pin'), this.pin, this);
commands.registerCommand(this.getQualifiedCommand('unpin'), this.unpin, this);
commands.registerCommand(this.getQualifiedCommand('edit'), this.edit, this);
commands.registerCommand(this.getQualifiedCommand('swapComparison'), this.swapComparison, this);
commands.registerCommand(this.getQualifiedCommand('selectForCompare'), this.selectForCompare, this);
commands.registerCommand(this.getQualifiedCommand('compareWithSelected'), this.compareWithSelected, this);
}
protected filterConfigurationChanged(e: ConfigurationChangeEvent) {
const changed = super.filterConfigurationChanged(e);
if (
!changed &&
!configuration.changed(e, 'defaultDateFormat') &&
!configuration.changed(e, 'defaultDateSource') &&
!configuration.changed(e, 'defaultDateStyle') &&
!configuration.changed(e, 'defaultGravatarsStyle')
) {
return false;
}
return true;
}
get keepResults(): boolean {
return Container.context.workspaceState.get<boolean>(WorkspaceState.ViewsSearchAndCompareKeepResults, true);
}
clear() {
this.root?.clear();
}
dismissNode(node: ViewNode) {
if (
this.root == null ||
(!(node instanceof ComparePickerNode) &&
!(node instanceof CompareResultsNode) &&
!(node instanceof SearchResultsNode)) ||
!node.canDismiss
) {
return;
}
this.root.dismiss(node);
}
compare(repoPath: string, ref1: string | NamedRef, ref2: string | NamedRef) {
return this.addResults(
new CompareResultsNode(
this,
this.ensureRoot(),
repoPath,
typeof ref1 === 'string' ? { ref: ref1 } : ref1,
typeof ref2 === 'string' ? { ref: ref2 } : ref2,
),
);
}
compareWithSelected(repoPath?: string, ref?: string | NamedRef) {
void this.ensureRoot().compareWithSelected(repoPath, ref);
}
selectForCompare(repoPath?: string, ref?: string | NamedRef) {
void this.ensureRoot().selectForCompare(repoPath, ref);
}
async search(
repoPath: string,
search: SearchPattern,
{
label,
reveal,
}: {
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
reveal?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
};
},
results?: Promise<GitLog | undefined> | GitLog,
updateNode?: SearchResultsNode,
) {
if (!this.visible) {
await this.show();
}
const labels = { label: `Results ${typeof label === 'string' ? label : label.label}`, queryLabel: label };
if (updateNode != null) {
await updateNode.edit({ pattern: search, labels: labels, log: results });
return;
}
await this.addResults(new SearchResultsNode(this, this.root!, repoPath, search, labels, results), reveal);
}
getPinned() {
let savedPins = Container.context.workspaceState.get<PinnedItems>(
WorkspaceState.ViewsSearchAndComparePinnedItems,
);
if (savedPins == null) {
// Migrate any deprecated pinned items
const deprecatedPins = Container.context.workspaceState.get<DeprecatedPinnedComparisons>(
WorkspaceState.DeprecatedPinnedComparisons,
);
if (deprecatedPins == null) return [];
savedPins = Object.create(null) as PinnedItems;
for (const p of Object.values(deprecatedPins)) {
savedPins[CompareResultsNode.getPinnableId(p.path, p.ref1.ref, p.ref2.ref)] = {
type: 'comparison',
timestamp: Date.now(),
path: p.path,
ref1: p.ref1,
ref2: p.ref2,
};
}
void Container.context.workspaceState.update(WorkspaceState.ViewsSearchAndComparePinnedItems, savedPins);
void Container.context.workspaceState.update(WorkspaceState.DeprecatedPinnedComparisons, undefined);
}
const root = this.ensureRoot();
return Object.values(savedPins)
.sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0))
.map(p =>
p.type === 'comparison'
? new CompareResultsNode(this, root, p.path, p.ref1, p.ref2, p.timestamp)
: new SearchResultsNode(this, root, p.path, p.search, p.labels, undefined, p.timestamp),
);
}
async updatePinned(id: string, pin?: PinnedItem) {
let pinned = Container.context.workspaceState.get<PinnedItems>(WorkspaceState.ViewsSearchAndComparePinnedItems);
if (pinned == null) {
pinned = Object.create(null) as PinnedItems;
}
if (pin != null) {
pinned[id] = { ...pin };
} else {
const { [id]: _, ...rest } = pinned;
pinned = rest;
}
await Container.context.workspaceState.update(WorkspaceState.ViewsSearchAndComparePinnedItems, pinned);
this.triggerNodeChange(this.ensureRoot());
}
private async addResults(
results: CompareResultsNode | SearchResultsNode,
options: {
expand?: boolean | number;
focus?: boolean;
select?: boolean;
} = { expand: true, focus: true, select: true },
) {
if (!this.visible) {
await this.show();
}
const root = this.ensureRoot();
root.addOrReplace(results, !this.keepResults);
setImmediate(() => this.reveal(results, options));
}
private edit(node: SearchResultsNode) {
if (!(node instanceof SearchResultsNode)) return undefined;
return node.edit();
}
private setFilesLayout(layout: ViewFilesLayout) {
return configuration.updateEffective('views', this.configKey, 'files', 'layout', layout);
}
private setKeepResults(enabled: boolean) {
void Container.context.workspaceState.update(WorkspaceState.ViewsSearchAndCompareKeepResults, enabled);
void setCommandContext(CommandContext.ViewsSearchAndCompareKeepResults, enabled);
}
private setShowAvatars(enabled: boolean) {
return configuration.updateEffective('views', this.configKey, 'avatars', enabled);
}
private pin(node: CompareResultsNode | SearchResultsNode) {
if (!(node instanceof CompareResultsNode) && !(node instanceof SearchResultsNode)) return undefined;
return node.pin();
}
private swapComparison(node: CompareResultsNode) {
if (!(node instanceof CompareResultsNode)) return undefined;
return node.swap();
}
private unpin(node: CompareResultsNode | SearchResultsNode) {
if (!(node instanceof CompareResultsNode) && !(node instanceof SearchResultsNode)) return undefined;
return node.unpin();
}
}

+ 0
- 279
src/views/searchView.ts View File

@ -1,279 +0,0 @@
'use strict';
import { commands, ConfigurationChangeEvent } from 'vscode';
import { configuration, SearchViewConfig, ViewFilesLayout } from '../configuration';
import { CommandContext, setCommandContext, WorkspaceState } from '../constants';
import { Container } from '../container';
import { GitLog, SearchPattern } from '../git/git';
import { Functions, Strings } from '../system';
import { nodeSupportsConditionalDismissal, SearchNode, SearchResultsCommitsNode, ViewNode } from './nodes';
import { ViewBase } from './viewBase';
interface SearchQueryResults {
readonly label: string;
readonly log: GitLog | undefined;
readonly hasMore: boolean;
more?(limit: number | undefined): Promise<void>;
}
export class SearchView extends ViewBase<SearchNode, SearchViewConfig> {
protected readonly configKey = 'search';
constructor() {
super('gitlens.views.search', 'Search Commits');
void setCommandContext(CommandContext.ViewsSearchKeepResults, this.keepResults);
}
getRoot() {
return new SearchNode(this);
}
protected registerCommands() {
void Container.viewCommands;
commands.registerCommand(this.getQualifiedCommand('clear'), () => this.clear(), this);
commands.registerCommand(
this.getQualifiedCommand('copy'),
() => commands.executeCommand('gitlens.views.copy', this.selection),
this,
);
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(true), 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,
);
commands.registerCommand(this.getQualifiedCommand('setShowAvatarsOn'), () => this.setShowAvatars(true), this);
commands.registerCommand(this.getQualifiedCommand('setShowAvatarsOff'), () => this.setShowAvatars(false), this);
}
protected filterConfigurationChanged(e: ConfigurationChangeEvent) {
const changed = super.filterConfigurationChanged(e);
if (
!changed &&
!configuration.changed(e, 'defaultDateFormat') &&
!configuration.changed(e, 'defaultDateSource') &&
!configuration.changed(e, 'defaultDateStyle') &&
!configuration.changed(e, 'defaultGravatarsStyle')
) {
return false;
}
return true;
}
get keepResults(): boolean {
return Container.context.workspaceState.get<boolean>(WorkspaceState.ViewsSearchKeepResults, false);
}
clear() {
this.root?.clear();
}
dismissNode(node: ViewNode) {
if (this.root == null) return;
if (nodeSupportsConditionalDismissal(node) && node.canDismiss() === false) return;
this.root.dismiss(node);
}
async search(
repoPath: string,
search: SearchPattern,
{
label,
reveal,
...options
}: {
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
limit?: number;
reveal?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
};
},
results?: Promise<GitLog | undefined> | GitLog,
) {
if (!this.visible) {
await this.show();
}
const searchQueryFn = this.getSearchQueryFn(
results ?? Container.git.getLogForSearch(repoPath, search, options),
{ label: label },
);
return this.addResults(
new SearchResultsCommitsNode(
this,
this.root!,
repoPath,
search,
`Results ${typeof label === 'string' ? label : label.label}`,
searchQueryFn,
),
reveal,
);
}
showSearchResults(
repoPath: string,
search: SearchPattern,
log: GitLog,
{
label,
reveal,
...options
}: {
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
limit?: number;
reveal?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
};
},
) {
const labelString = this.getSearchLabel(label, log);
const results: Mutable<Partial<SearchQueryResults>> = {
label: labelString,
log: log,
hasMore: log.hasMore,
};
if (results.hasMore) {
results.more = async (limit: number | undefined) => {
results.log = (await results.log?.more?.(limit)) ?? results.log;
results.label = this.getSearchLabel(label, results.log);
results.hasMore = results.log?.hasMore ?? true;
};
}
const searchQueryFn = Functions.cachedOnce(
this.getSearchQueryFn(log, { label: label, ...options }),
results as SearchQueryResults,
);
return this.addResults(
new SearchResultsCommitsNode(this, this.root!, repoPath, search, labelString, searchQueryFn),
reveal,
);
}
private addResults(
results: ViewNode,
options: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
} = { select: true, expand: true },
) {
const root = this.ensureRoot();
root.addOrReplace(results, !this.keepResults);
setImmediate(() => void this.reveal(results, options));
}
private getSearchLabel(
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
},
log: GitLog | undefined,
) {
if (typeof label === 'string') return label;
const count = log?.count ?? 0;
const resultsType =
label.resultsType === undefined ? { singular: 'result', plural: 'results' } : label.resultsType;
return `${Strings.pluralize(resultsType.singular, count, {
number: log?.hasMore ?? false ? `${count}+` : undefined,
plural: resultsType.plural,
zero: 'No',
})} ${label.label}`;
}
private getSearchQueryFn(
logOrPromise: Promise<GitLog | undefined> | GitLog | undefined,
options: {
label:
| string
| {
label: string;
resultsType?: { singular: string; plural: string };
};
},
): (limit: number | undefined) => Promise<SearchQueryResults> {
let useCacheOnce = true;
return async (limit: number | undefined) => {
let log = await logOrPromise;
if (!useCacheOnce && log !== undefined && log.query !== undefined) {
log = await log.query(limit);
}
useCacheOnce = false;
const results: Mutable<Partial<SearchQueryResults>> = {
label: this.getSearchLabel(options.label, log),
log: log,
hasMore: log?.hasMore,
};
if (results.hasMore) {
results.more = async (limit: number | undefined) => {
results.log = (await results.log?.more?.(limit)) ?? results.log;
results.label = this.getSearchLabel(options.label, results.log);
results.hasMore = results.log?.hasMore ?? true;
};
}
return results as SearchQueryResults;
};
}
private setFilesLayout(layout: ViewFilesLayout) {
return configuration.updateEffective('views', this.configKey, 'files', 'layout', layout);
}
private setKeepResults(enabled: boolean) {
void Container.context.workspaceState.update(WorkspaceState.ViewsSearchKeepResults, enabled);
void setCommandContext(CommandContext.ViewsSearchKeepResults, enabled);
}
private setShowAvatars(enabled: boolean) {
return configuration.updateEffective('views', this.configKey, 'avatars', enabled);
}
}

+ 5
- 10
src/views/viewBase.ts View File

@ -18,18 +18,16 @@ import {
} from 'vscode'; } from 'vscode';
import { BranchesView } from './branchesView'; import { BranchesView } from './branchesView';
import { CommitsView } from './commitsView'; import { CommitsView } from './commitsView';
import { CompareView } from './compareView';
import { import {
BranchesViewConfig, BranchesViewConfig,
CommitsViewConfig, CommitsViewConfig,
CompareViewConfig,
configuration, configuration,
ContributorsViewConfig, ContributorsViewConfig,
FileHistoryViewConfig, FileHistoryViewConfig,
LineHistoryViewConfig, LineHistoryViewConfig,
RemotesViewConfig, RemotesViewConfig,
RepositoriesViewConfig, RepositoriesViewConfig,
SearchViewConfig,
SearchAndCompareViewConfig,
StashesViewConfig, StashesViewConfig,
TagsViewConfig, TagsViewConfig,
ViewsCommonConfig, ViewsCommonConfig,
@ -45,31 +43,29 @@ import { Logger } from '../logger';
import { PageableViewNode, ViewNode } from './nodes'; import { PageableViewNode, ViewNode } from './nodes';
import { RemotesView } from './remotesView'; import { RemotesView } from './remotesView';
import { RepositoriesView } from './repositoriesView'; import { RepositoriesView } from './repositoriesView';
import { SearchView } from './searchView';
import { SearchAndCompareView } from './searchAndCompareView';
import { StashesView } from './stashesView'; import { StashesView } from './stashesView';
import { debug, Functions, log, Promises, Strings } from '../system'; import { debug, Functions, log, Promises, Strings } from '../system';
import { TagsView } from './tagsView'; import { TagsView } from './tagsView';
export type View = export type View =
| BranchesView | BranchesView
| CompareView
| ContributorsView | ContributorsView
| FileHistoryView | FileHistoryView
| CommitsView | CommitsView
| LineHistoryView | LineHistoryView
| RemotesView | RemotesView
| RepositoriesView | RepositoriesView
| SearchView
| SearchAndCompareView
| StashesView | StashesView
| TagsView; | TagsView;
export type ViewsWithFiles = export type ViewsWithFiles =
| BranchesView | BranchesView
| CompareView
| ContributorsView | ContributorsView
| CommitsView | CommitsView
| RemotesView | RemotesView
| RepositoriesView | RepositoriesView
| SearchView
| SearchAndCompareView
| StashesView | StashesView
| TagsView; | TagsView;
@ -81,14 +77,13 @@ export abstract class ViewBase<
RootNode extends ViewNode<View>, RootNode extends ViewNode<View>,
ViewConfig extends ViewConfig extends
| BranchesViewConfig | BranchesViewConfig
| CompareViewConfig
| ContributorsViewConfig | ContributorsViewConfig
| FileHistoryViewConfig | FileHistoryViewConfig
| CommitsViewConfig | CommitsViewConfig
| LineHistoryViewConfig | LineHistoryViewConfig
| RemotesViewConfig | RemotesViewConfig
| RepositoriesViewConfig | RepositoriesViewConfig
| SearchViewConfig
| SearchAndCompareViewConfig
| StashesViewConfig | StashesViewConfig
| TagsViewConfig | TagsViewConfig
> implements TreeDataProvider<ViewNode>, Disposable { > implements TreeDataProvider<ViewNode>, Disposable {

+ 6
- 6
src/views/viewCommands.ts View File

@ -570,7 +570,7 @@ export class ViewCommands {
private compareWithHead(node: ViewRefNode) { private compareWithHead(node: ViewRefNode) {
if (!(node instanceof ViewRefNode)) return Promise.resolve(); if (!(node instanceof ViewRefNode)) return Promise.resolve();
return Container.compareView.compare(node.repoPath, node.ref, 'HEAD');
return Container.searchAndCompareView.compare(node.repoPath, node.ref, 'HEAD');
} }
@debug() @debug()
@ -578,14 +578,14 @@ export class ViewCommands {
if (!(node instanceof BranchNode)) return Promise.resolve(); if (!(node instanceof BranchNode)) return Promise.resolve();
if (!node.branch.tracking) return Promise.resolve(); if (!node.branch.tracking) return Promise.resolve();
return Container.compareView.compare(node.repoPath, node.branch.tracking, node.ref);
return Container.searchAndCompareView.compare(node.repoPath, node.branch.tracking, node.ref);
} }
@debug() @debug()
private compareWithWorking(node: ViewRefNode) { private compareWithWorking(node: ViewRefNode) {
if (!(node instanceof ViewRefNode)) return Promise.resolve(); if (!(node instanceof ViewRefNode)) return Promise.resolve();
return Container.compareView.compare(node.repoPath, node.ref, '');
return Container.searchAndCompareView.compare(node.repoPath, node.ref, '');
} }
@debug() @debug()
@ -598,7 +598,7 @@ export class ViewCommands {
const commonAncestor = await Container.git.getMergeBase(node.repoPath, branch.ref, node.ref.ref); const commonAncestor = await Container.git.getMergeBase(node.repoPath, branch.ref, node.ref.ref);
if (commonAncestor == null) return undefined; if (commonAncestor == null) return undefined;
return Container.compareView.compare(
return Container.searchAndCompareView.compare(
node.repoPath, node.repoPath,
{ ref: commonAncestor, label: `ancestry with ${node.ref.ref} (${GitRevision.shorten(commonAncestor)})` }, { ref: commonAncestor, label: `ancestry with ${node.ref.ref} (${GitRevision.shorten(commonAncestor)})` },
'', '',
@ -609,14 +609,14 @@ export class ViewCommands {
private compareWithSelected(node: ViewRefNode) { private compareWithSelected(node: ViewRefNode) {
if (!(node instanceof ViewRefNode)) return; if (!(node instanceof ViewRefNode)) return;
Container.compareView.compareWithSelected(node.repoPath, node.ref);
Container.searchAndCompareView.compareWithSelected(node.repoPath, node.ref);
} }
@debug() @debug()
private selectForCompare(node: ViewRefNode) { private selectForCompare(node: ViewRefNode) {
if (!(node instanceof ViewRefNode)) return; if (!(node instanceof ViewRefNode)) return;
Container.compareView.selectForCompare(node.repoPath, node.ref);
Container.searchAndCompareView.selectForCompare(node.repoPath, node.ref);
} }
@debug() @debug()

+ 0
- 135
src/webviews/apps/settings/partials/views.search.html View File

@ -1,135 +0,0 @@
<section id="search-commits-view" class="section--settings section--collapsible">
<div class="section__header">
<h2>
Search Commits view
<a
class="link__learn-more"
title="Learn more"
href="https://github.com/eamodio/vscode-gitlens/tree/master/#search-commits-view-"
>
<i class="icon icon__info"></i>
</a>
</h2>
<p class="section__header-hint">
Adds a Search Commits view to search and explore commit histories by message, author, files, id, etc
</p>
</div>
<div class="section__collapsible">
<div class="section__group">
<div class="section__content">
<div class="settings settings--fixed ml-1">
<div class="section__group">
<div class="section__content">
<div class="settings settings--fixed">
<div class="setting">
<div class="setting__input">
<input
id="views.search.pullRequests.enabled"
name="views.search.pullRequests.enabled"
type="checkbox"
data-setting
/>
<label for="views.search.pullRequests.enabled"
>Show associated Pull Requests</label
>
</div>
<p class="setting__hint">
Requires a connection to a supported remote service (e.g. GitHub)
</p>
</div>
<div class="settings settings--fixed ml-2">
<div class="setting" data-enablement="views.search.pullRequests.enabled">
<div class="setting__input">
<input
id="views.search.pullRequests.showForCommits"
name="views.search.pullRequests.showForCommits"
type="checkbox"
data-setting
disabled
/>
<label for="views.search.pullRequests.showForCommits"
>Show the PR that introduced each commit</label
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="setting">
<div class="setting__input">
<label for="views.search.files.layout">Layout files</label>
<div class="select-container">
<select id="views.search.files.layout" name="views.search.files.layout" data-setting>
<option value="auto">automatically</option>
<option value="list">as a list</option>
<option value="tree">as a tree</option>
</select>
</div>
</div>
</div>
<div class="setting">
<div class="setting__input">
<input
id="views.search.files.compact"
name="views.search.files.compact"
type="checkbox"
data-setting
/>
<label for="views.search.files.compact">Use compact file layout</label>
</div>
<p class="setting__hint">Compacts (flattens) unnecessary nesting when using a tree layouts</p>
</div>
<div class="setting">
<div class="setting__input">
<input id="views.search.avatars" name="views.search.avatars" type="checkbox" data-setting />
<label for="views.search.avatars">Use author avatars</label>
</div>
</div>
</div>
</div>
<div class="section__preview">
<img
class="image__preview hidden"
src="#{root}/images/settings/view-search.png"
data-visibility="views.search.files.layout !tree"
/>
<img
class="image__preview hidden"
src="#{root}/images/settings/view-search-tree-compact.png"
data-visibility="views.search.files.layout =tree &amp; views.search.files.compact"
/>
<img
class="image__preview hidden"
src="#{root}/images/settings/view-search-tree.png"
data-visibility="views.search.files.layout =tree &amp; views.search.files.compact =false"
/>
<img
class="image__preview--overlay hidden"
src="#{root}/images/settings/view-search-avatars.png"
data-visibility="views.search.avatars"
/>
</div>
</div>
<div class="section__group">
<p class="section__hint">
<i class="icon icon__info"></i> For more options, open
<a
class="command"
title="Open Settings"
href="command:workbench.action.openSettings?%22gitlens.views.search%22"
>Settings</a
>
and search for <b><i>gitlens.views.search</i></b> or <b><i>gitlens.views</i></b>
</p>
</div>
</div>
</section>

src/webviews/apps/settings/partials/views.compare.html → src/webviews/apps/settings/partials/views.searchAndCompare.html View File

@ -1,18 +1,19 @@
<section id="compare-view" class="section--settings section--collapsible">
<section id="search-compare-view" class="section--settings section--collapsible">
<div class="section__header"> <div class="section__header">
<h2> <h2>
Compare view
Search &amp; Compare view
<a <a
class="link__learn-more" class="link__learn-more"
title="Learn more" title="Learn more"
href="https://github.com/eamodio/vscode-gitlens/tree/master/#compare-view-"
href="https://github.com/eamodio/vscode-gitlens/tree/master/#search-commits-view-"
> >
<i class="icon icon__info"></i> <i class="icon icon__info"></i>
</a> </a>
</h2> </h2>
<p class="section__header-hint"> <p class="section__header-hint">
Adds a Compare view to visualize comparisons between branches, tags, commits, and more
Adds a Search &amp; Compare view to search and explore commit histories by message, author, files, id, etc,
or visualize comparisons between branches, tags, commits, and more
</p> </p>
</div> </div>
@ -26,12 +27,12 @@
<div class="setting"> <div class="setting">
<div class="setting__input"> <div class="setting__input">
<input <input
id="views.compare.pullRequests.enabled"
name="views.compare.pullRequests.enabled"
id="views.searchAndCompare.pullRequests.enabled"
name="views.searchAndCompare.pullRequests.enabled"
type="checkbox" type="checkbox"
data-setting data-setting
/> />
<label for="views.compare.pullRequests.enabled"
<label for="views.searchAndCompare.pullRequests.enabled"
>Show associated Pull Requests</label >Show associated Pull Requests</label
> >
</div> </div>
@ -41,16 +42,16 @@
</div> </div>
<div class="settings settings--fixed ml-2"> <div class="settings settings--fixed ml-2">
<div class="setting" data-enablement="views.compare.pullRequests.enabled">
<div class="setting" data-enablement="views.searchAndCompare.pullRequests.enabled">
<div class="setting__input"> <div class="setting__input">
<input <input
id="views.compare.pullRequests.showForCommits"
name="views.compare.pullRequests.showForCommits"
id="views.searchAndCompare.pullRequests.showForCommits"
name="views.searchAndCompare.pullRequests.showForCommits"
type="checkbox" type="checkbox"
data-setting data-setting
disabled disabled
/> />
<label for="views.compare.pullRequests.showForCommits"
<label for="views.searchAndCompare.pullRequests.showForCommits"
>Show the PR that introduced each commit</label >Show the PR that introduced each commit</label
> >
</div> </div>
@ -62,9 +63,13 @@
<div class="setting"> <div class="setting">
<div class="setting__input"> <div class="setting__input">
<label for="views.compare.files.layout">Layout files</label>
<label for="views.searchAndCompare.files.layout">Layout files</label>
<div class="select-container"> <div class="select-container">
<select id="views.compare.files.layout" name="views.compare.files.layout" data-setting>
<select
id="views.searchAndCompare.files.layout"
name="views.searchAndCompare.files.layout"
data-setting
>
<option value="auto">automatically</option> <option value="auto">automatically</option>
<option value="list">as a list</option> <option value="list">as a list</option>
<option value="tree">as a tree</option> <option value="tree">as a tree</option>
@ -76,12 +81,12 @@
<div class="setting"> <div class="setting">
<div class="setting__input"> <div class="setting__input">
<input <input
id="views.compare.files.compact"
name="views.compare.files.compact"
id="views.searchAndCompare.files.compact"
name="views.searchAndCompare.files.compact"
type="checkbox" type="checkbox"
data-setting data-setting
/> />
<label for="views.compare.files.compact">Use compact file layout</label>
<label for="views.searchAndCompare.files.compact">Use compact file layout</label>
</div> </div>
<p class="setting__hint">Compacts (flattens) unnecessary nesting when using a tree layouts</p> <p class="setting__hint">Compacts (flattens) unnecessary nesting when using a tree layouts</p>
</div> </div>
@ -89,12 +94,12 @@
<div class="setting"> <div class="setting">
<div class="setting__input"> <div class="setting__input">
<input <input
id="views.compare.avatars"
name="views.compare.avatars"
id="views.searchAndCompare.avatars"
name="views.searchAndCompare.avatars"
type="checkbox" type="checkbox"
data-setting data-setting
/> />
<label for="views.compare.avatars">Use author avatars</label>
<label for="views.searchAndCompare.avatars">Use author avatars</label>
</div> </div>
</div> </div>
</div> </div>
@ -103,6 +108,29 @@
<div class="section__preview"> <div class="section__preview">
<img <img
class="image__preview hidden" class="image__preview hidden"
src="#{root}/images/settings/view-search.png"
data-visibility="views.searchAndCompare.files.layout !tree"
/>
<img
class="image__preview hidden"
src="#{root}/images/settings/view-search-tree-compact.png"
data-visibility="views.searchAndCompare.files.layout =tree &amp; views.searchAndCompare.files.compact"
/>
<img
class="image__preview hidden"
src="#{root}/images/settings/view-search-tree.png"
data-visibility="views.searchAndCompare.files.layout =tree &amp; views.searchAndCompare.files.compact =false"
/>
<img
class="image__preview--overlay hidden"
src="#{root}/images/settings/view-search-avatars.png"
data-visibility="views.searchAndCompare.avatars"
/>
</div>
<!-- <div class="section__preview">
<img
class="image__preview hidden"
src="#{root}/images/settings/view-compare.png" src="#{root}/images/settings/view-compare.png"
data-visibility="views.compare.files.layout !tree" data-visibility="views.compare.files.layout !tree"
/> />
@ -121,7 +149,7 @@
src="#{root}/images/settings/view-compare-avatars.png" src="#{root}/images/settings/view-compare-avatars.png"
data-visibility="views.compare.avatars" data-visibility="views.compare.avatars"
/> />
</div>
</div> -->
</div> </div>
<div class="section__group"> <div class="section__group">
@ -130,10 +158,10 @@
<a <a
class="command" class="command"
title="Open Settings" title="Open Settings"
href="command:workbench.action.openSettings?%22gitlens.views.compare%22"
href="command:workbench.action.openSettings?%22gitlens.views.searchAndCompare%22"
>Settings</a >Settings</a
> >
and search for <b><i>gitlens.views.compare</i></b> or <b><i>gitlens.views</i></b>
and search for <b><i>gitlens.views.searchAndCompare</i></b> or <b><i>gitlens.views</i></b>
</p> </p>
</div> </div>
</div> </div>

+ 4
- 15
src/webviews/apps/settings/settings.html View File

@ -207,9 +207,7 @@
<!-- prettier-ignore --> <!-- prettier-ignore -->
<%= require('html-loader!./partials/views.contributors.html') %> <%= require('html-loader!./partials/views.contributors.html') %>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<%= require('html-loader!./partials/views.search.html') %>
<!-- prettier-ignore -->
<%= require('html-loader!./partials/views.compare.html') %>
<%= require('html-loader!./partials/views.searchAndCompare.html') %>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<%= require('html-loader!./partials/blame.html') %> <%= require('html-loader!./partials/blame.html') %>
<!-- prettier-ignore --> <!-- prettier-ignore -->
@ -369,18 +367,9 @@
<a <a
class="sidebar__jump-link" class="sidebar__jump-link"
data-action="jump" data-action="jump"
href="#search-commits-view"
title="Jump to Search Commits view settings"
>Search Commits view</a
>
</li>
<li>
<a
class="sidebar__jump-link"
data-action="jump"
href="#compare-view"
title="Jump to Compare view settings"
>Compare view</a
href="#search-compare-view"
title="Jump to Search &amp; Compare view settings"
>Search &amp; Compare view</a
> >
</li> </li>

+ 1
- 2
src/webviews/settingsWebview.ts View File

@ -24,13 +24,12 @@ export class SettingsWebview extends WebviewBase {
...[ ...[
Commands.ShowSettingsPageAndJumpToBranchesView, Commands.ShowSettingsPageAndJumpToBranchesView,
Commands.ShowSettingsPageAndJumpToCommitsView, Commands.ShowSettingsPageAndJumpToCommitsView,
Commands.ShowSettingsPageAndJumpToCompareView,
Commands.ShowSettingsPageAndJumpToContributorsView, Commands.ShowSettingsPageAndJumpToContributorsView,
Commands.ShowSettingsPageAndJumpToFileHistoryView, Commands.ShowSettingsPageAndJumpToFileHistoryView,
Commands.ShowSettingsPageAndJumpToLineHistoryView, Commands.ShowSettingsPageAndJumpToLineHistoryView,
Commands.ShowSettingsPageAndJumpToRemotesView, Commands.ShowSettingsPageAndJumpToRemotesView,
Commands.ShowSettingsPageAndJumpToRepositoriesView, Commands.ShowSettingsPageAndJumpToRepositoriesView,
Commands.ShowSettingsPageAndJumpToSearchCommitsView,
Commands.ShowSettingsPageAndJumpToSearchAndCompareView,
Commands.ShowSettingsPageAndJumpToStashesView, Commands.ShowSettingsPageAndJumpToStashesView,
Commands.ShowSettingsPageAndJumpToTagsView, Commands.ShowSettingsPageAndJumpToTagsView,
].map(c => { ].map(c => {

Loading…
Cancel
Save