This commit is contained in:
Ladislau Szomoru 2022-02-04 21:04:40 +01:00
parent 99f3c2c7e7
commit cf040aa0db
No known key found for this signature in database
GPG key ID: 2B88287CB9DB080B
3 changed files with 121 additions and 39 deletions

View file

@ -0,0 +1,113 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace } from 'vscode';
import * as nls from 'vscode-nls';
import { Repository, Operation } from './repository';
import { dispose } from './util';
import { Branch } from './api/git';
const localize = nls.loadMessageBundle();
interface ActionButtonState {
readonly HEAD: Branch | undefined;
readonly isSyncRunning: boolean;
readonly repositoryHasNoChanges: boolean;
}
export class ActionButtonCommand {
private _onDidChange = new EventEmitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
private _state: ActionButtonState;
private get state() { return this._state; }
private set state(state: ActionButtonState) {
if (JSON.stringify(this._state) !== JSON.stringify(state)) {
this._state = state;
this._onDidChange.fire();
}
}
private disposables: Disposable[] = [];
constructor(readonly repository: Repository) {
this._state = { HEAD: undefined, isSyncRunning: false, repositoryHasNoChanges: false };
repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables);
repository.onDidChangeOperations(this.onDidChangeOperations, this, this.disposables);
}
get button(): SourceControlActionButton | undefined {
if (!this.state.HEAD || !this.state.HEAD.name || !this.state.HEAD.commit) { return undefined; }
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
const showActionButton = config.get<string>('showUnpublishedCommitsButton', 'whenEmpty');
const postCommitCommand = config.get<string>('postCommitCommand');
const noPostCommitCommand = postCommitCommand !== 'sync' && postCommitCommand !== 'push';
let actionButton: SourceControlActionButton | undefined;
if (showActionButton === 'always' || (showActionButton === 'whenEmpty' && this.state.repositoryHasNoChanges && noPostCommitCommand)) {
if (this.state.HEAD.upstream) {
if (this.state.HEAD.ahead) {
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
const rebaseWhenSync = config.get<string>('rebaseWhenSync');
const ahead = `${this.state.HEAD.ahead}$(arrow-up)`;
const behind = this.state.HEAD.behind ? `${this.state.HEAD.behind}$(arrow-down) ` : '';
const icon = this.state.isSyncRunning ? '$(sync~spin)' : '$(sync)';
actionButton = {
command: {
command: this.state.isSyncRunning ? '' : rebaseWhenSync ? 'git.syncRebase' : 'git.sync',
title: localize('scm button sync title', "{0} {1}{2}", icon, behind, ahead),
tooltip: this.state.isSyncRunning ?
localize('syncing changes', "Synchronizing Changes...")
: this.repository.syncTooltip,
arguments: [this.repository.sourceControl],
},
description: localize('scm button sync description', "{0} Sync Changes {1}{2}", icon, behind, ahead)
};
}
} else {
actionButton = {
command: {
command: this.state.isSyncRunning ? '' : 'git.publish',
title: localize('scm button publish title', "$(cloud-upload) Publish Branch"),
tooltip: this.state.isSyncRunning ?
localize('scm button publish branch running', "Publishing Branch...") :
localize('scm button publish branch', "Publish Branch"),
arguments: [this.repository.sourceControl],
}
};
}
}
return actionButton;
}
private onDidChangeOperations(): void {
const isSyncRunning = this.repository.operations.isRunning(Operation.Sync) ||
this.repository.operations.isRunning(Operation.Push) ||
this.repository.operations.isRunning(Operation.Pull);
this.state = { ...this.state, isSyncRunning };
}
private onDidRunGitStatus(): void {
this.state = {
...this.state,
HEAD: this.repository.HEAD,
repositoryHasNoChanges:
this.repository.indexGroup.resourceStates.length === 0 &&
this.repository.mergeGroup.resourceStates.length === 0 &&
this.repository.untrackedGroup.resourceStates.length === 0 &&
this.repository.workingTreeGroup.resourceStates.length === 0
};
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}

View file

@ -5,7 +5,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration, commands, SourceControlActionButton } from 'vscode';
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration, commands } from 'vscode';
import TelemetryReporter from '@vscode/extension-telemetry';
import * as nls from 'vscode-nls';
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions, BranchQuery, FetchOptions } from './api/git';
@ -20,6 +20,7 @@ import { Log, LogLevel } from './log';
import { IPushErrorHandlerRegistry } from './pushError';
import { ApiRepository } from './api/api1';
import { IRemoteSourcePublisherRegistry } from './remotePublisher';
import { ActionButtonCommand } from './actionButton';
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
@ -966,6 +967,11 @@ export class Repository implements Disposable {
statusBar.onDidChange(() => this._sourceControl.statusBarCommands = statusBar.commands, null, this.disposables);
this._sourceControl.statusBarCommands = statusBar.commands;
const actionButton = new ActionButtonCommand(this);
this.disposables.push(actionButton);
actionButton.onDidChange(() => this._sourceControl.actionButton = actionButton.button);
this._sourceControl.actionButton = actionButton.button;
const progressManager = new ProgressManager(this);
this.disposables.push(progressManager);
@ -1935,43 +1941,6 @@ export class Repository implements Disposable {
return undefined;
});
let actionButton: SourceControlActionButton | undefined;
if (HEAD !== undefined) {
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
const showActionButton = config.get<string>('showUnpublishedCommitsButton', 'whenEmpty');
const postCommitCommand = config.get<string>('postCommitCommand');
if (showActionButton === 'always' || (showActionButton === 'whenEmpty' && workingTree.length === 0 && index.length === 0 && untracked.length === 0 && merge.length === 0 && postCommitCommand !== 'sync' && postCommitCommand !== 'push')) {
if (HEAD.name && HEAD.commit) {
if (HEAD.upstream) {
if (HEAD.ahead) {
const rebaseWhenSync = config.get<string>('rebaseWhenSync');
actionButton = {
command: {
command: rebaseWhenSync ? 'git.syncRebase' : 'git.sync',
title: localize('scm button sync title', "$(sync) {0}{1}", HEAD.behind ? `${HEAD.behind}$(arrow-down) ` : '', `${HEAD.ahead}$(arrow-up)`),
tooltip: this.syncTooltip,
arguments: [this._sourceControl],
},
description: localize('scm button sync description', "$(sync) Sync Changes {0}{1}", HEAD.behind ? `${HEAD.behind}$(arrow-down) ` : '', `${HEAD.ahead}$(arrow-up)`)
};
}
} else {
actionButton = {
command: {
command: 'git.publish',
title: localize('scm button publish title', "$(cloud-upload) Publish Branch"),
tooltip: localize('scm button publish tooltip', "Publish Branch"),
arguments: [this._sourceControl],
}
};
}
}
}
}
this._sourceControl.actionButton = actionButton;
// set resource groups
this.mergeGroup.resourceStates = merge;
this.indexGroup.resourceStates = index;

View file

@ -2503,7 +2503,7 @@ export class SCMActionButton implements IDisposable {
if (button.description) {
// ButtonWithDescription
this.button = new ButtonWithDescription(this.container, { supportIcons: true });
this.button = new ButtonWithDescription(this.container, { supportIcons: true, title: button.command.tooltip });
(this.button as ButtonWithDescription).description = button.description;
} else {
// Button