You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
3.7 KiB

  1. import type { Uri } from 'vscode';
  2. import { isLinux } from '@env/platform';
  3. import { Schemes } from './constants';
  4. import type { Repository } from './git/models/repository';
  5. import { addVslsPrefixIfNeeded, normalizePath } from './system/path';
  6. import { UriTrie } from './system/trie';
  7. // TODO@eamodio don't import from string here since it will break the tests because of ESM dependencies
  8. // import { CharCode } from './string';
  9. const slash = 47; //CharCode.Slash;
  10. export type RepoComparisonKey = string & { __type__: 'RepoComparisonKey' };
  11. export function asRepoComparisonKey(uri: Uri): RepoComparisonKey {
  12. const { path } = normalizeRepoUri(uri);
  13. return path as RepoComparisonKey;
  14. }
  15. export function normalizeRepoUri(uri: Uri): { path: string; ignoreCase: boolean } {
  16. let path;
  17. switch (uri.scheme.toLowerCase()) {
  18. case Schemes.File:
  19. path = normalizePath(uri.fsPath);
  20. return { path: path, ignoreCase: !isLinux };
  21. case Schemes.Git:
  22. case Schemes.GitLens:
  23. path = uri.path;
  24. if (path.charCodeAt(path.length - 1) === slash) {
  25. path = path.slice(1, -1);
  26. } else {
  27. path = path.slice(1);
  28. }
  29. return { path: path, ignoreCase: !isLinux };
  30. case Schemes.Virtual:
  31. case Schemes.GitHub: {
  32. path = uri.path;
  33. if (path.charCodeAt(path.length - 1) === slash) {
  34. path = path.slice(1, -1);
  35. } else {
  36. path = path.slice(1);
  37. }
  38. // TODO@eamodio Revisit this, as we can't strip off the authority details (e.g. metadata) ultimately (since you in theory could have a workspace with more than 1 virtual repo which are the same except for the authority)
  39. const authority = uri.authority?.split('+', 1)[0];
  40. return { path: authority ? `${authority}/${path}` : path, ignoreCase: false };
  41. }
  42. case Schemes.Vsls:
  43. case Schemes.VslsScc:
  44. // Check if this is a root live share folder, if so add the required prefix (required to match repos correctly)
  45. path = addVslsPrefixIfNeeded(uri.path);
  46. if (path.charCodeAt(path.length - 1) === slash) {
  47. path = path.slice(1, -1);
  48. } else {
  49. path = path.slice(1);
  50. }
  51. return { path: path, ignoreCase: false };
  52. case Schemes.PRs: {
  53. path = uri.path;
  54. if (path.charCodeAt(path.length - 1) === slash) {
  55. path = path.slice(1, -1);
  56. } else {
  57. path = path.slice(1);
  58. }
  59. const authority = uri.authority?.split('+', 1)[0];
  60. if (authority === Schemes.GitHub) {
  61. return { path: authority ? `${authority}/${path}` : path, ignoreCase: false };
  62. }
  63. return { path: path, ignoreCase: !isLinux };
  64. }
  65. default:
  66. path = uri.path;
  67. if (path.charCodeAt(path.length - 1) === slash) {
  68. path = path.slice(1, -1);
  69. } else {
  70. path = path.slice(1);
  71. }
  72. return { path: path, ignoreCase: false };
  73. }
  74. }
  75. export class Repositories {
  76. private readonly _trie: UriTrie<Repository>;
  77. private _count: number = 0;
  78. constructor() {
  79. this._trie = new UriTrie<Repository>(normalizeRepoUri);
  80. }
  81. get count(): number {
  82. return this._count;
  83. }
  84. add(repository: Repository): boolean {
  85. const added = this._trie.set(repository.uri, repository);
  86. if (added) {
  87. this._count++;
  88. }
  89. return added;
  90. }
  91. clear(): void {
  92. this._count = 0;
  93. this._trie.clear();
  94. }
  95. forEach(fn: (repository: Repository) => void, thisArg?: unknown): void {
  96. for (const value of this._trie.getDescendants()) {
  97. fn.call(thisArg, value);
  98. }
  99. }
  100. get(uri: Uri): Repository | undefined {
  101. return this._trie.get(uri);
  102. }
  103. getClosest(uri: Uri): Repository | undefined {
  104. return this._trie.getClosest(uri);
  105. }
  106. has(uri: Uri): boolean {
  107. return this._trie.has(uri);
  108. }
  109. remove(uri: Uri, dispose: boolean = true): boolean {
  110. const deleted = this._trie.delete(uri, dispose);
  111. if (deleted) {
  112. this._count--;
  113. }
  114. return deleted;
  115. }
  116. values(): IterableIterator<Repository> {
  117. return this._trie.getDescendants();
  118. }
  119. }