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

Adds multi-root support

main
Eric Amodio 7 роки тому
джерело
коміт
183c7e79d2
20 змінених файлів з 239 додано та 99 видалено
  1. +1
    -1
      src/commands/closeUnchangedFiles.ts
  2. +1
    -1
      src/commands/diffDirectory.ts
  3. +1
    -1
      src/commands/externalDiff.ts
  4. +1
    -1
      src/commands/openChangedFiles.ts
  5. +1
    -1
      src/commands/showQuickCurrentBranchHistory.ts
  6. +1
    -1
      src/commands/showQuickRepoStatus.ts
  7. +1
    -1
      src/commands/showQuickStashList.ts
  8. +1
    -1
      src/constants.ts
  9. +2
    -5
      src/extension.ts
  10. +36
    -31
      src/git/git.ts
  11. +0
    -2
      src/git/gitContextTracker.ts
  12. +2
    -2
      src/git/gitUri.ts
  13. +91
    -23
      src/gitService.ts
  14. +1
    -1
      src/quickPicks/branchHistory.ts
  15. +1
    -1
      src/quickPicks/commitFileDetails.ts
  16. +1
    -0
      src/views/explorerNode.ts
  17. +1
    -0
      src/views/explorerNodes.ts
  18. +62
    -24
      src/views/gitExplorer.ts
  19. +30
    -0
      src/views/repositoriesNode.ts
  20. +4
    -2
      src/views/repositoryNode.ts

+ 1
- 1
src/commands/closeUnchangedFiles.ts Переглянути файл

@ -25,7 +25,7 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
if (args.uris === undefined) {
args = { ...args };
const repoPath = await this.git.getRepoPathFromUri(uri);
const repoPath = await this.git.getRepoPath(uri);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to close unchanged files`);
const status = await this.git.getStatusForRepo(repoPath);

+ 1
- 1
src/commands/diffDirectory.ts Переглянути файл

@ -41,7 +41,7 @@ export class DiffDirectoryCommand extends ActiveEditorCommand {
uri = getCommandUri(uri, editor);
try {
const repoPath = await this.git.getRepoPathFromUri(uri);
const repoPath = await this.git.getRepoPath(uri);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open directory compare`);
if (!args.shaOrBranch1) {

+ 1
- 1
src/commands/externalDiff.ts Переглянути файл

@ -85,7 +85,7 @@ export class ExternalDiffCommand extends Command {
return commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://git-scm.com/docs/git-config#git-config-difftool'));
}
const repoPath = await this.git.getRepoPathFromUri(undefined);
const repoPath = await this.git.getRepoPath(undefined);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open changed files`);
if (args.files === undefined) {

+ 1
- 1
src/commands/openChangedFiles.ts Переглянути файл

@ -22,7 +22,7 @@ export class OpenChangedFilesCommand extends ActiveEditorCommand {
if (args.uris === undefined) {
args = { ...args };
const repoPath = await this.git.getRepoPathFromUri(uri);
const repoPath = await this.git.getRepoPath(uri);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open changed files`);
const status = await this.git.getStatusForRepo(repoPath);

+ 1
- 1
src/commands/showQuickCurrentBranchHistory.ts Переглянути файл

@ -21,7 +21,7 @@ export class ShowQuickCurrentBranchHistoryCommand extends ActiveEditorCachedComm
uri = getCommandUri(uri, editor);
try {
const repoPath = await this.git.getRepoPathFromUri(uri);
const repoPath = await this.git.getRepoPath(uri);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show branch history`);
const branch = await this.git.getBranch(repoPath);

+ 1
- 1
src/commands/showQuickRepoStatus.ts Переглянути файл

@ -20,7 +20,7 @@ export class ShowQuickRepoStatusCommand extends ActiveEditorCachedCommand {
uri = getCommandUri(uri, editor);
try {
const repoPath = await this.git.getRepoPathFromUri(uri);
const repoPath = await this.git.getRepoPath(uri);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show repository status`);
const status = await this.git.getStatusForRepo(repoPath);

+ 1
- 1
src/commands/showQuickStashList.ts Переглянути файл

@ -23,7 +23,7 @@ export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
uri = getCommandUri(uri, editor);
try {
const repoPath = await this.git.getRepoPathFromUri(uri);
const repoPath = await this.git.getRepoPath(uri);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to show stashed changes`);
const stash = await this.git.getStashList(repoPath);

+ 1
- 1
src/constants.ts Переглянути файл

@ -32,8 +32,8 @@ export enum CommandContext {
GitExplorerFilesLayout = 'gitlens:gitExplorer:files:layout',
GitExplorerView = 'gitlens:gitExplorer:view',
HasRemotes = 'gitlens:hasRemotes',
HasRepository = 'gitlens:hasRepository',
IsBlameable = 'gitlens:isBlameable',
IsRepository = 'gitlens:isRepository',
IsTracked = 'gitlens:isTracked',
Key = 'gitlens:key'
}

+ 2
- 5
src/extension.ts Переглянути файл

@ -26,8 +26,7 @@ export async function activate(context: ExtensionContext) {
const gitlens = extensions.getExtension(QualifiedExtensionId)!;
const gitlensVersion = gitlens.packageJSON.version;
const rootPath = workspace.rootPath && workspace.rootPath.replace(/\\/g, '/');
Logger.log(`GitLens(v${gitlensVersion}) active: ${rootPath}`);
Logger.log(`GitLens(v${gitlensVersion}) active`);
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
const gitPath = cfg.advanced.git;
@ -44,8 +43,6 @@ export async function activate(context: ExtensionContext) {
return;
}
const repoPath = await GitService.getRepoPath(rootPath);
const gitVersion = GitService.getGitVersion();
Logger.log(`Git version: ${gitVersion}`);
@ -60,7 +57,7 @@ export async function activate(context: ExtensionContext) {
await context.globalState.update(GlobalState.GitLensVersion, gitlensVersion);
const git = new GitService(repoPath);
const git = new GitService();
context.subscriptions.push(git);
const gitContextTracker = new GitContextTracker(git);

+ 36
- 31
src/git/git.ts Переглянути файл

@ -45,11 +45,11 @@ interface GitCommandOptions {
cwd: string;
env?: any;
encoding?: string;
overrideErrorHandling?: boolean;
willHandleErrors?: boolean;
}
async function gitCommand(options: GitCommandOptions, ...args: any[]): Promise<string> {
if (options.overrideErrorHandling) return gitCommandCore(options, ...args);
if (options.willHandleErrors) return gitCommandCore(options, ...args);
try {
return await gitCommandCore(options, ...args);
@ -108,15 +108,6 @@ export class Git {
return git;
}
static async getRepoPath(cwd: string | undefined) {
if (cwd === undefined) return '';
const data = await gitCommand({ cwd }, 'rev-parse', '--show-toplevel');
if (!data) return '';
return data.replace(/\r?\n|\r/g, '').replace(/\\/g, '/');
}
static async getVersionedFile(repoPath: string | undefined, fileName: string, branchOrSha: string) {
const data = await Git.show(repoPath, fileName, branchOrSha, 'binary');
if (data === undefined) return undefined;
@ -215,22 +206,6 @@ export class Git {
return gitCommand({ cwd: repoPath }, ...params);
}
static async branch_current(repoPath: string) {
const params = [`rev-parse`, `--abbrev-ref`, `--symbolic-full-name`, `@`, `@{u}`];
const opts = { cwd: repoPath, overrideErrorHandling: true };
try {
return await gitCommand(opts, ...params);
}
catch (ex) {
if (/no upstream configured for branch/.test(ex && ex.toString())) {
return ex.message.split('\n')[0];
}
return gitCommandDefaultErrorHandler(ex, opts, ...params);
}
}
static checkout(repoPath: string, fileName: string, sha: string) {
const [file, root] = Git.splitPath(fileName, repoPath);
@ -239,7 +214,8 @@ export class Git {
static async config_get(key: string, repoPath?: string) {
try {
return await gitCommand({ cwd: repoPath || '', overrideErrorHandling: true }, `config`, `--get`, key);
const data = await gitCommand({ cwd: repoPath || '', willHandleErrors: true }, `config`, `--get`, key);
return data.trim();
}
catch {
return '';
@ -372,7 +348,8 @@ export class Git {
static async ls_files(repoPath: string, fileName: string): Promise<string> {
try {
return await gitCommand({ cwd: repoPath, overrideErrorHandling: true }, 'ls-files', fileName);
const data = await gitCommand({ cwd: repoPath, willHandleErrors: true }, 'ls-files', fileName);
return data.trim();
}
catch {
return '';
@ -387,14 +364,42 @@ export class Git {
return gitCommand({ cwd: repoPath }, 'remote', 'get-url', remote);
}
static async revparse_currentBranch(repoPath: string) {
const params = [`rev-parse`, `--abbrev-ref`, `--symbolic-full-name`, `@`, `@{u}`];
const opts = { cwd: repoPath, willHandleErrors: true } as GitCommandOptions;
try {
const data = await gitCommand(opts, ...params);
return data;
}
catch (ex) {
if (/no upstream configured for branch/.test(ex && ex.toString())) {
return ex.message.split('\n')[0];
}
return gitCommandDefaultErrorHandler(ex, opts, ...params);
}
}
static async revparse_toplevel(cwd: string): Promise<string | undefined> {
try {
const data = await gitCommand({ cwd: cwd, willHandleErrors: true }, 'rev-parse', '--show-toplevel');
return data.trim();
}
catch {
return undefined;
}
}
static async show(repoPath: string | undefined, fileName: string, branchOrSha: string, encoding?: string) {
const [file, root] = Git.splitPath(fileName, repoPath);
if (Git.isUncommitted(branchOrSha)) throw new Error(`sha=${branchOrSha} is uncommitted`);
const opts = { cwd: root, encoding: encoding || defaultEncoding, overrideErrorHandling: true };
const opts = { cwd: root, encoding: encoding || defaultEncoding, willHandleErrors: true } as GitCommandOptions;
const args = `${branchOrSha}:./${file}`;
try {
return await gitCommand(opts, 'show', args);
const data = await gitCommand(opts, 'show', args);
return data;
}
catch (ex) {
const msg = ex && ex.toString();

+ 0
- 2
src/git/gitContextTracker.ts Переглянути файл

@ -35,8 +35,6 @@ export class GitContextTracker extends Disposable {
];
this._disposable = Disposable.from(...subscriptions);
setCommandContext(CommandContext.IsRepository, !!this.git.repoPath);
this._onConfigurationChanged();
}

+ 2
- 2
src/git/gitUri.ts Переглянути файл

@ -97,7 +97,7 @@ export class GitUri extends ((Uri as any) as UriEx) {
static async fromUri(uri: Uri, git: GitService) {
if (uri instanceof GitUri) return uri;
if (!git.isTrackable(uri)) return new GitUri(uri, git.repoPath);
if (!git.isTrackable(uri)) return new GitUri(uri, undefined);
if (uri.scheme === DocumentSchemes.GitLensGit) return new GitUri(uri);
@ -110,7 +110,7 @@ export class GitUri extends ((Uri as any) as UriEx) {
const gitUri = git.getGitUriForFile(uri);
if (gitUri) return gitUri;
return new GitUri(uri, (await git.getRepoPathFromFile(uri.fsPath)) || git.repoPath);
return new GitUri(uri, await git.getRepoPath(uri.fsPath));
}
static fromFileStatus(status: IGitStatusFile, repoPath: string, original?: boolean): GitUri;

+ 91
- 23
src/gitService.ts Переглянути файл

@ -1,8 +1,8 @@
'use strict';
import { Functions, Iterables, Objects } from './system';
import { Disposable, Event, EventEmitter, FileSystemWatcher, Range, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, window, WindowState, workspace } from 'vscode';
import { Disposable, Event, EventEmitter, FileSystemWatcher, Range, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, window, WindowState, workspace, WorkspaceFoldersChangeEvent } from 'vscode';
import { IConfig } from './configuration';
import { DocumentSchemes, ExtensionKey } from './constants';
import { CommandContext, DocumentSchemes, ExtensionKey, setCommandContext } from './constants';
import { RemoteProviderFactory } from './git/remotes/factory';
import { Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitBranchParser, GitCommit, GitCommitType, GitDiff, GitDiffChunkLine, GitDiffParser, GitDiffShortStat, GitLog, GitLogCommit, GitLogParser, GitRemote, GitRemoteParser, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, IGit, setDefaultEncoding } from './git/git';
import { GitUri, IGitCommitInfo, IGitUriData } from './git/gitUri';
@ -51,6 +51,12 @@ interface CachedBlame extends CachedItem { }
interface CachedDiff extends CachedItem<GitDiff> { }
interface CachedLog extends CachedItem<GitLog> { }
export interface Repository {
readonly name: string;
readonly index: number;
readonly path: string;
}
enum RemoveCacheReason {
DocumentClosed,
DocumentSaved
@ -65,6 +71,7 @@ export enum GitRepoSearchBy {
export enum RepoChangedReasons {
Remotes = 'remotes',
Repositories = 'Repositories',
Stash = 'stash',
Unknown = ''
}
@ -102,24 +109,29 @@ export class GitService extends Disposable {
private _focused: boolean = true;
private _gitCache: Map<string, GitCacheEntry>;
private _remotesCache: Map<string, GitRemote[]>;
private _repositories: Map<string, Repository | undefined>;
private _repositoriesPromise: Promise<void> | undefined;
private _repoWatcher: FileSystemWatcher | undefined;
private _trackedCache: Map<string, boolean>;
private _unfocusedChanges: { repo: boolean, fs: boolean } = { repo: false, fs: false };
private _versionedUriCache: Map<string, UriCacheEntry>;
constructor(public repoPath: string) {
constructor() {
super(() => this.dispose());
this._gitCache = new Map();
this._remotesCache = new Map();
this._repositories = new Map();
this._trackedCache = new Map();
this._versionedUriCache = new Map();
this.onConfigurationChanged();
this._repositoriesPromise = this.onWorkspaceFoldersChanged();
const subscriptions: Disposable[] = [
window.onDidChangeWindowState(this.onWindowStateChanged, this),
workspace.onDidChangeConfiguration(this.onConfigurationChanged, this),
workspace.onDidChangeWorkspaceFolders(this.onWorkspaceFoldersChanged, this),
RemoteProviderFactory.onDidChange(this.onRemoteProviderChanged, this)
];
this._disposable = Disposable.from(...subscriptions);
@ -142,6 +154,22 @@ export class GitService extends Disposable {
this._versionedUriCache.clear();
}
public get repoPath(): string | undefined {
if (this._repositories.size !== 1) return undefined;
const repo = Iterables.first(this._repositories.values());
return repo === undefined ? undefined : repo.path;
}
public async getRepositories(): Promise<Repository[]> {
if (this._repositoriesPromise !== undefined) {
await this._repositoriesPromise;
this._repositoriesPromise = undefined;
}
return [...Iterables.filter(this._repositories.values(), r => r !== undefined) as Iterable<Repository>];
}
public get UseCaching() {
return this.config.advanced.caching.enabled;
}
@ -212,6 +240,43 @@ export class GitService extends Disposable {
}
}
private async onWorkspaceFoldersChanged(e?: WorkspaceFoldersChangeEvent) {
let initializing = false;
if (e === undefined) {
if (workspace.workspaceFolders === undefined) return;
initializing = true;
e = {
added: workspace.workspaceFolders,
removed: []
} as WorkspaceFoldersChangeEvent;
}
for (const f of e.added) {
if (f.uri.scheme !== DocumentSchemes.File) continue;
const fsPath = f.uri.fsPath;
const rp = await this.getRepoPathCore(fsPath, true);
if (rp === undefined) {
Logger.log(`onWorkspaceFoldersChanged(${fsPath})`, 'No repository found');
}
this._repositories.set(fsPath, { name: f.name, index: f.index, path: rp } as Repository);
}
for (const f of e.removed) {
if (f.uri.scheme !== DocumentSchemes.File) continue;
this._repositories.delete(f.uri.fsPath);
}
const hasRepository = Iterables.some(this._repositories.values(), rp => rp !== undefined);
await setCommandContext(CommandContext.HasRepository, hasRepository);
if (!initializing) {
this.fireRepoChange(RepoChangedReasons.Repositories);
}
}
private onTextDocumentChanged(e: TextDocumentChangeEvent) {
if (!this.UseCaching) return;
if (e.document.uri.scheme !== DocumentSchemes.File) return;
@ -571,7 +636,7 @@ export class GitService extends Disposable {
Logger.log(`getBranch('${repoPath}')`);
if (repoPath === undefined) return undefined;
const data = await Git.branch_current(repoPath);
const data = await Git.revparse_currentBranch(repoPath);
const branch = data.split('\n');
return new GitBranch(repoPath, branch[0], true, branch[1]);
}
@ -900,24 +965,27 @@ export class GitService extends Disposable {
return remotes;
}
getRepoPath(cwd: string): Promise<string> {
return GitService.getRepoPath(cwd);
}
async getRepoPathFromFile(fileName: string): Promise<string | undefined> {
const log = await this.getLogForFile(undefined, fileName, undefined, { maxCount: 1 });
if (log === undefined) return undefined;
async getRepoPath(filePath: string): Promise<string | undefined>;
async getRepoPath(uri: Uri | undefined): Promise<string | undefined>;
async getRepoPath(filePathOrUri: string | Uri | undefined): Promise<string | undefined> {
if (filePathOrUri === undefined) return this.repoPath;
if (filePathOrUri instanceof GitUri) return filePathOrUri.repoPath;
return log.repoPath;
}
if (typeof filePathOrUri === 'string') return this.getRepoPathCore(filePathOrUri, false);
async getRepoPathFromUri(uri: Uri | undefined): Promise<string | undefined> {
if (!(uri instanceof Uri)) return this.repoPath;
const folder = workspace.getWorkspaceFolder(filePathOrUri);
if (folder !== undefined) {
const rp = this._repositories.get(folder.uri.fsPath);
if (rp !== undefined) return rp.path;
}
const repoPath = (await GitUri.fromUri(uri, this)).repoPath;
if (!repoPath) return this.repoPath;
return this.getRepoPathCore(filePathOrUri.fsPath, false);
}
return repoPath;
private async getRepoPathCore(filePath: string, isDirectory: boolean): Promise<string | undefined> {
const rp = await Git.revparse_toplevel(isDirectory ? filePath : path.dirname(filePath));
console.log(filePath, rp);
return rp;
}
async getStashList(repoPath: string | undefined): Promise<GitStash | undefined> {
@ -1103,12 +1171,12 @@ export class GitService extends Disposable {
return Git.gitInfo().version;
}
static async getRepoPath(cwd: string | undefined): Promise<string> {
const repoPath = await Git.getRepoPath(cwd);
if (!repoPath) return '';
// static async getRepoPath(cwd: string | undefined): Promise<string> {
// const repoPath = await Git.getRepoPath(cwd);
// if (!repoPath) return '';
return repoPath;
}
// return repoPath;
// }
static fromGitContentUri(uri: Uri): IGitUriData {
if (uri.scheme !== DocumentSchemes.GitLensGit) throw new Error(`fromGitUri(uri=${uri}) invalid scheme`);

+ 1
- 1
src/quickPicks/branchHistory.ts Переглянути файл

@ -35,7 +35,7 @@ export class BranchHistoryQuickPick {
} as ShowQuickBranchHistoryCommandArgs
]);
const remotes = (await git.getRemotes((uri && uri.repoPath) || git.repoPath)).filter(r => r.provider !== undefined);
const remotes = (await git.getRemotes((uri && uri.repoPath) || log.repoPath)).filter(r => r.provider !== undefined);
if (remotes.length) {
items.splice(0, 0, new OpenRemotesCommandQuickPickItem(remotes, {
type: 'branch',

+ 1
- 1
src/quickPicks/commitFileDetails.ts Переглянути файл

@ -127,7 +127,7 @@ export class CommitFileDetailsQuickPick {
const remotes = (await git.getRemotes(commit.repoPath)).filter(r => r.provider !== undefined);
if (remotes.length) {
if (commit.workingFileName && commit.status !== 'D') {
const branch = await git.getBranch(commit.repoPath || git.repoPath);
const branch = await git.getBranch(commit.repoPath);
items.push(new OpenRemotesCommandQuickPickItem(remotes, {
type: 'file',
fileName: commit.workingFileName,

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

@ -16,6 +16,7 @@ export declare type ResourceType =
'gitlens:pager' |
'gitlens:remote' |
'gitlens:remotes' |
'gitlens:repositories' |
'gitlens:repository' |
'gitlens:stash' |
'gitlens:stash-file' |

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

@ -9,6 +9,7 @@ export * from './fileHistoryNode';
export * from './historyNode';
export * from './remoteNode';
export * from './remotesNode';
export * from './repositoriesNode';
export * from './repositoryNode';
export * from './stashesNode';
export * from './stashFileNode';

+ 62
- 24
src/views/gitExplorer.ts Переглянути файл

@ -5,7 +5,7 @@ import { Commands, DiffWithCommandArgs, DiffWithCommandArgsRevision, DiffWithPre
import { UriComparer } from '../comparers';
import { ExtensionKey, GitExplorerFilesLayout, IConfig } from '../configuration';
import { CommandContext, GlyphChars, setCommandContext, WorkspaceState } from '../constants';
import { BranchHistoryNode, CommitFileNode, CommitNode, ExplorerNode, HistoryNode, MessageNode, RepositoryNode, StashNode } from './explorerNodes';
import { BranchHistoryNode, CommitFileNode, CommitNode, ExplorerNode, HistoryNode, MessageNode, RepositoriesNode, RepositoryNode, StashNode } from './explorerNodes';
import { GitService, GitUri, RepoChangedReasons } from '../gitService';
export * from './explorerNodes';
@ -72,43 +72,70 @@ export class GitExplorer implements TreeDataProvider {
return node.getTreeItem();
}
private _loading: Promise<void> | undefined;
async getChildren(node?: ExplorerNode): Promise<ExplorerNode[]> {
if (this._loading !== undefined) {
await this._loading;
this._loading = undefined;
}
if (this._root === undefined) {
if (this._view === GitExplorerView.History) return [new MessageNode(`No active file ${GlyphChars.Dash} no history to show`)];
return [];
return [new MessageNode('No repositories found')];
}
if (node === undefined) return this._root.getChildren();
return node.getChildren();
}
private getRootNode(editor?: TextEditor): ExplorerNode | undefined {
private async getRootNode(editor?: TextEditor): Promise<ExplorerNode | undefined> {
switch (this._view) {
case GitExplorerView.History:
return this.getHistoryNode(editor || window.activeTextEditor);
case GitExplorerView.History: {
const promise = this.getHistoryNode(editor || window.activeTextEditor);
this._loading = promise.then(async _ => await Functions.wait(0));
return promise;
}
default: {
const promise = this.git.getRepositories();
this._loading = promise.then(async _ => await Functions.wait(0));
default:
const uri = new GitUri(Uri.file(this.git.repoPath), { repoPath: this.git.repoPath, fileName: this.git.repoPath });
return new RepositoryNode(uri, this.context, this.git);
const repositories = await promise;
if (repositories.length === 0) return undefined; // new MessageNode('No repositories found');
if (repositories.length === 1) {
const repo = repositories[0];
return new RepositoryNode(new GitUri(Uri.file(repo.path), { repoPath: repo.path, fileName: repo.path }), repo, this.context, this.git);
}
return new RepositoriesNode(repositories, this.context, this.git);
}
}
}
private getHistoryNode(editor: TextEditor | undefined): ExplorerNode | undefined {
private async getHistoryNode(editor: TextEditor | undefined): Promise<ExplorerNode | undefined> {
// If we have no active editor, or no visible editors, or no trackable visible editors reset the view
if (editor === undefined || window.visibleTextEditors.length === 0 || !window.visibleTextEditors.some(e => e.document && this.git.isTrackable(e.document.uri))) return undefined;
// If we do have a visible trackable editor, don't change from the last state (avoids issues when focus switches to the problems/output/debug console panes)
if (editor.document === undefined || !this.git.isTrackable(editor.document.uri)) return this._root;
const uri = this.git.getGitUriForFile(editor.document.uri) || new GitUri(editor.document.uri, { repoPath: this.git.repoPath, fileName: editor.document.uri.fsPath });
let uri = this.git.getGitUriForFile(editor.document.uri);
if (uri === undefined) {
const repoPath = await this.git.getRepoPath(editor.document.uri);
if (repoPath === undefined) return undefined;
uri = new GitUri(editor.document.uri, { repoPath: repoPath, fileName: editor.document.uri.fsPath });
}
if (UriComparer.equals(uri, this._root && this._root.uri)) return this._root;
return new HistoryNode(uri, this.context, this.git);
}
private onActiveEditorChanged(editor: TextEditor | undefined) {
private async onActiveEditorChanged(editor: TextEditor | undefined) {
if (this._view !== GitExplorerView.History) return;
const root = this.getRootNode(editor);
const root = await this.getRootNode(editor);
if (root === this._root) return;
this._root = root;
@ -136,15 +163,18 @@ export class GitExplorer implements TreeDataProvider {
view = this.context.workspaceState.get<GitExplorerView>(WorkspaceState.GitExplorerView, GitExplorerView.Repository);
}
this.setView(view);
this._root = this.getRootNode(window.activeTextEditor);
this.refresh();
this.reset(view);
}
}
private onRepoChanged(reasons: RepoChangedReasons[]) {
if (this._view !== GitExplorerView.Repository) return;
// If we are changing the set of repositories then force a root node reset
if (reasons.includes(RepoChangedReasons.Repositories)) {
this._root = undefined;
}
this.refresh();
}
@ -160,9 +190,9 @@ export class GitExplorer implements TreeDataProvider {
}
}
refresh(node?: ExplorerNode, root?: ExplorerNode) {
if (root === undefined && this._view === GitExplorerView.History) {
this._root = this.getRootNode(window.activeTextEditor);
async refresh(node?: ExplorerNode, root?: ExplorerNode) {
if (this._root === undefined || (root === undefined && this._view === GitExplorerView.History)) {
this._root = await this.getRootNode(window.activeTextEditor);
}
this._onDidChangeTreeData.fire(node);
@ -176,6 +206,18 @@ export class GitExplorer implements TreeDataProvider {
this.refresh(node);
}
async reset(view: GitExplorerView, force: boolean = false) {
this.setView(view);
if (force) {
this._root = undefined;
}
this._root = await this.getRootNode(window.activeTextEditor);
if (force) {
this.refresh();
}
}
setView(view: GitExplorerView) {
if (this._view === view) return;
@ -191,14 +233,10 @@ export class GitExplorer implements TreeDataProvider {
}
}
switchTo(view: GitExplorerView) {
async switchTo(view: GitExplorerView) {
if (this._view === view) return;
this.setView(view);
this._root = undefined;
this._root = this.getRootNode(window.activeTextEditor);
this.refresh();
this.reset(view, true);
}
private async applyChanges(node: CommitNode | StashNode) {

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

@ -0,0 +1,30 @@
'use strict';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { ExplorerNode, ResourceType } from './explorerNode';
import { GitService, GitUri, Repository } from '../gitService';
import { RepositoryNode } from './repositoryNode';
export class RepositoriesNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:repositories';
constructor(
private readonly repositories: Repository[],
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(undefined!);
}
async getChildren(): Promise<ExplorerNode[]> {
return this.repositories
.sort((a, b) => a.index - b.index)
.map(repo => new RepositoryNode(new GitUri(Uri.file(repo.path), { repoPath: repo.path, fileName: repo.path }), repo, this.context, this.git));
}
getTreeItem(): TreeItem {
const item = new TreeItem(`Repositories`, TreeItemCollapsibleState.Expanded);
item.contextValue = this.resourceType;
return item;
}
}

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

@ -1,9 +1,10 @@
'use strict';
import { Strings } from '../system';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { BranchesNode } from './branchesNode';
import { GlyphChars } from '../constants';
import { ExplorerNode, ResourceType } from './explorerNode';
import { GitService, GitUri } from '../gitService';
import { GitService, GitUri, Repository } from '../gitService';
import { RemotesNode } from './remotesNode';
import { StatusNode } from './statusNode';
import { StashesNode } from './stashesNode';
@ -14,6 +15,7 @@ export class RepositoryNode extends ExplorerNode {
constructor(
uri: GitUri,
private repo: Repository,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
@ -30,7 +32,7 @@ export class RepositoryNode extends ExplorerNode {
}
getTreeItem(): TreeItem {
const item = new TreeItem(`Repository ${GlyphChars.Dash} ${this.uri.repoPath}`, TreeItemCollapsibleState.Expanded);
const item = new TreeItem(`Repository ${Strings.pad(GlyphChars.Dash, 1, 1)} ${this.repo.name || this.uri.repoPath}`, TreeItemCollapsibleState.Expanded);
item.contextValue = this.resourceType;
return item;
}

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