mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 10:12:34 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -5,9 +5,9 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode';
|
||||
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git';
|
||||
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant } from './util';
|
||||
import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType } from 'vscode';
|
||||
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule, DiffOptions } from './git';
|
||||
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util';
|
||||
import { memoize, throttle, debounce } from './decorators';
|
||||
import { toGitUri } from './uri';
|
||||
import { AutoFetcher } from './autofetch';
|
||||
@@ -105,7 +105,7 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
};
|
||||
|
||||
private getIconPath(theme: string): Uri | undefined {
|
||||
private getIconPath(theme: string): Uri {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED: return Resource.Icons[theme].Modified;
|
||||
case Status.MODIFIED: return Resource.Icons[theme].Modified;
|
||||
@@ -123,7 +123,6 @@ export class Resource implements SourceControlResourceState {
|
||||
case Status.DELETED_BY_US: return Resource.Icons[theme].Conflict;
|
||||
case Status.BOTH_ADDED: return Resource.Icons[theme].Conflict;
|
||||
case Status.BOTH_MODIFIED: return Resource.Icons[theme].Conflict;
|
||||
default: return void 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +181,7 @@ export class Resource implements SourceControlResourceState {
|
||||
return { strikeThrough, faded, tooltip, light, dark, letter, color, source: 'git.resource' /*todo@joh*/ };
|
||||
}
|
||||
|
||||
get letter(): string | undefined {
|
||||
get letter(): string {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
@@ -207,12 +206,10 @@ export class Resource implements SourceControlResourceState {
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return 'C';
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get color(): ThemeColor | undefined {
|
||||
get color(): ThemeColor {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
@@ -235,8 +232,6 @@ export class Resource implements SourceControlResourceState {
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return new ThemeColor('gitDecoration.conflictingResourceForeground');
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +256,7 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
}
|
||||
|
||||
get resourceDecoration(): DecorationData | undefined {
|
||||
get resourceDecoration(): DecorationData {
|
||||
const title = this.tooltip;
|
||||
const abbreviation = this.letter;
|
||||
const color = this.color;
|
||||
@@ -280,6 +275,7 @@ export class Resource implements SourceControlResourceState {
|
||||
|
||||
export enum Operation {
|
||||
Status = 'Status',
|
||||
Diff = 'Diff',
|
||||
Add = 'Add',
|
||||
RevertFiles = 'RevertFiles',
|
||||
Commit = 'Commit',
|
||||
@@ -301,7 +297,8 @@ export enum Operation {
|
||||
Tag = 'Tag',
|
||||
Stash = 'Stash',
|
||||
CheckIgnore = 'CheckIgnore',
|
||||
LSTree = 'LSTree'
|
||||
LSTree = 'LSTree',
|
||||
SubmoduleUpdate = 'SubmoduleUpdate'
|
||||
}
|
||||
|
||||
function isReadOnly(operation: Operation): boolean {
|
||||
@@ -330,6 +327,7 @@ function shouldShowProgress(operation: Operation): boolean {
|
||||
|
||||
export interface Operations {
|
||||
isIdle(): boolean;
|
||||
shouldShowProgress(): boolean;
|
||||
isRunning(operation: Operation): boolean;
|
||||
}
|
||||
|
||||
@@ -366,6 +364,18 @@ class OperationsImpl implements Operations {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
shouldShowProgress(): boolean {
|
||||
const operations = this.operations.keys();
|
||||
|
||||
for (const operation of operations) {
|
||||
if (shouldShowProgress(operation)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export interface CommitOptions {
|
||||
@@ -373,7 +383,6 @@ export interface CommitOptions {
|
||||
amend?: boolean;
|
||||
signoff?: boolean;
|
||||
signCommit?: boolean;
|
||||
defaultMsg?: string;
|
||||
}
|
||||
|
||||
export interface GitResourceGroup extends SourceControlResourceGroup {
|
||||
@@ -385,8 +394,33 @@ export interface OperationResult {
|
||||
error: any;
|
||||
}
|
||||
|
||||
class ProgressManager {
|
||||
|
||||
private disposable: IDisposable = EmptyDisposable;
|
||||
|
||||
constructor(repository: Repository) {
|
||||
const start = onceEvent(filterEvent(repository.onDidChangeOperations, () => repository.operations.shouldShowProgress()));
|
||||
const end = onceEvent(filterEvent(debounceEvent(repository.onDidChangeOperations, 300), () => !repository.operations.shouldShowProgress()));
|
||||
|
||||
const setup = () => {
|
||||
this.disposable = start(() => {
|
||||
const promise = eventToPromise(end).then(() => setup());
|
||||
window.withProgress({ location: ProgressLocation.SourceControl }, () => promise);
|
||||
});
|
||||
};
|
||||
|
||||
setup();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class Repository implements Disposable {
|
||||
|
||||
private static readonly InputValidationLength = 72;
|
||||
|
||||
private _onDidChangeRepository = new EventEmitter<Uri>();
|
||||
readonly onDidChangeRepository: Event<Uri> = this._onDidChangeRepository.event;
|
||||
|
||||
@@ -439,6 +473,11 @@ export class Repository implements Disposable {
|
||||
return this._remotes;
|
||||
}
|
||||
|
||||
private _submodules: Submodule[] = [];
|
||||
get submodules(): Submodule[] {
|
||||
return this._submodules;
|
||||
}
|
||||
|
||||
private _operations = new OperationsImpl();
|
||||
get operations(): Operations { return this._operations; }
|
||||
|
||||
@@ -474,7 +513,7 @@ export class Repository implements Disposable {
|
||||
|
||||
const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete);
|
||||
const onRepositoryChange = filterEvent(onWorkspaceChange, uri => isDescendant(repository.root, uri.fsPath));
|
||||
const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git\/index\.lock$/.test(uri.path));
|
||||
const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git(\/index\.lock)?$/.test(uri.path));
|
||||
onRelevantRepositoryChange(this.onFSChange, this, this.disposables);
|
||||
|
||||
const onRelevantGitChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.git\//.test(uri.path));
|
||||
@@ -484,6 +523,7 @@ export class Repository implements Disposable {
|
||||
this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message (press {0} to commit)");
|
||||
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
|
||||
this._sourceControl.quickDiffProvider = this;
|
||||
this._sourceControl.inputBox.validateInput = this.validateInput.bind(this);
|
||||
this.disposables.push(this._sourceControl);
|
||||
|
||||
this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "Merge Changes"));
|
||||
@@ -504,16 +544,56 @@ export class Repository implements Disposable {
|
||||
statusBar.onDidChange(() => this._sourceControl.statusBarCommands = statusBar.commands, null, this.disposables);
|
||||
this._sourceControl.statusBarCommands = statusBar.commands;
|
||||
|
||||
const progressManager = new ProgressManager(this);
|
||||
this.disposables.push(progressManager);
|
||||
|
||||
this.updateCommitTemplate();
|
||||
this.status();
|
||||
}
|
||||
|
||||
validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const setting = config.get<'always' | 'warn' | 'off'>('inputValidation');
|
||||
|
||||
if (setting === 'off') {
|
||||
return;
|
||||
}
|
||||
|
||||
let start = 0, end;
|
||||
let match: RegExpExecArray | null;
|
||||
const regex = /\r?\n/g;
|
||||
|
||||
while ((match = regex.exec(text)) && position > match.index) {
|
||||
start = match.index + match[0].length;
|
||||
}
|
||||
|
||||
end = match ? match.index : text.length;
|
||||
|
||||
const line = text.substring(start, end);
|
||||
|
||||
if (line.length <= Repository.InputValidationLength) {
|
||||
if (setting !== 'always') {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
message: localize('commitMessageCountdown', "{0} characters left in current line", Repository.InputValidationLength - line.length),
|
||||
type: SourceControlInputBoxValidationType.Information
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
message: localize('commitMessageWarning', "{0} characters over {1} in current line", line.length - Repository.InputValidationLength, Repository.InputValidationLength),
|
||||
type: SourceControlInputBoxValidationType.Warning
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
provideOriginalResource(uri: Uri): Uri | undefined {
|
||||
if (uri.scheme !== 'file') {
|
||||
return;
|
||||
}
|
||||
|
||||
return toGitUri(uri, '', true);
|
||||
return toGitUri(uri, '', { replaceFileExtension: true });
|
||||
}
|
||||
|
||||
private async updateCommitTemplate(): Promise<void> {
|
||||
@@ -524,21 +604,15 @@ export class Repository implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
// @throttle
|
||||
// async init(): Promise<void> {
|
||||
// if (this.state !== State.NotAGitRepository) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// await this.git.init(this.workspaceRoot.fsPath);
|
||||
// await this.status();
|
||||
// }
|
||||
|
||||
@throttle
|
||||
async status(): Promise<void> {
|
||||
await this.run(Operation.Status);
|
||||
}
|
||||
|
||||
diff(path: string, options: DiffOptions = {}): Promise<string> {
|
||||
return this.run(Operation.Diff, () => this.repository.diff(path, options));
|
||||
}
|
||||
|
||||
async add(resources: Uri[]): Promise<void> {
|
||||
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath)));
|
||||
}
|
||||
@@ -567,8 +641,18 @@ export class Repository implements Disposable {
|
||||
await this.run(Operation.Clean, async () => {
|
||||
const toClean: string[] = [];
|
||||
const toCheckout: string[] = [];
|
||||
const submodulesToUpdate: string[] = [];
|
||||
|
||||
resources.forEach(r => {
|
||||
const fsPath = r.fsPath;
|
||||
|
||||
for (const submodule of this.submodules) {
|
||||
if (path.join(this.root, submodule.path) === fsPath) {
|
||||
submodulesToUpdate.push(fsPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const raw = r.toString();
|
||||
const scmResource = find(this.workingTreeGroup.resourceStates, sr => sr.resourceUri.toString() === raw);
|
||||
|
||||
@@ -579,11 +663,11 @@ export class Repository implements Disposable {
|
||||
switch (scmResource.type) {
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
toClean.push(r.fsPath);
|
||||
toClean.push(fsPath);
|
||||
break;
|
||||
|
||||
default:
|
||||
toCheckout.push(r.fsPath);
|
||||
toCheckout.push(fsPath);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -598,6 +682,10 @@ export class Repository implements Disposable {
|
||||
promises.push(this.repository.checkout('', toCheckout));
|
||||
}
|
||||
|
||||
if (submodulesToUpdate.length > 0) {
|
||||
promises.push(this.repository.updateSubmodules(submodulesToUpdate));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
});
|
||||
}
|
||||
@@ -702,15 +790,15 @@ export class Repository implements Disposable {
|
||||
async buffer(ref: string, filePath: string): Promise<Buffer> {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
const encoding = configFiles.get<string>('encoding');
|
||||
// const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
// const encoding = configFiles.get<string>('encoding');
|
||||
|
||||
// TODO@joao: REsource config api
|
||||
return await this.repository.buffer(`${ref}:${relativePath}`);
|
||||
});
|
||||
}
|
||||
|
||||
lstree(ref: string, filePath: string): Promise<{ mode: number, object: string, size: number }> {
|
||||
lstree(ref: string, filePath: string): Promise<{ mode: string, object: string, size: number }> {
|
||||
return this.run(Operation.LSTree, () => this.repository.lstree(ref, filePath));
|
||||
}
|
||||
|
||||
@@ -780,7 +868,11 @@ export class Repository implements Disposable {
|
||||
// paths are separated by the null-character
|
||||
resolve(new Set<string>(data.split('\0')));
|
||||
} else {
|
||||
reject(new GitError({ stdout: data, stderr, exitCode }));
|
||||
if (/ is in submodule /.test(stderr)) {
|
||||
reject(new GitError({ stdout: data, stderr, exitCode, gitErrorCode: GitErrorCodes.IsInSubmodule }));
|
||||
} else {
|
||||
reject(new GitError({ stdout: data, stderr, exitCode }));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -807,37 +899,31 @@ export class Repository implements Disposable {
|
||||
throw new Error('Repository not initialized');
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
let error: any = null;
|
||||
let error: any = null;
|
||||
|
||||
this._operations.start(operation);
|
||||
this._onRunOperation.fire(operation);
|
||||
this._operations.start(operation);
|
||||
this._onRunOperation.fire(operation);
|
||||
|
||||
try {
|
||||
const result = await this.retryRun(runOperation);
|
||||
try {
|
||||
const result = await this.retryRun(runOperation);
|
||||
|
||||
if (!isReadOnly(operation)) {
|
||||
await this.updateModelState();
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
error = err;
|
||||
|
||||
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
|
||||
this.state = RepositoryState.Disposed;
|
||||
}
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
this._operations.end(operation);
|
||||
this._onDidRunOperation.fire({ operation, error });
|
||||
if (!isReadOnly(operation)) {
|
||||
await this.updateModelState();
|
||||
}
|
||||
};
|
||||
|
||||
return shouldShowProgress(operation)
|
||||
? window.withProgress({ location: ProgressLocation.SourceControl }, run)
|
||||
: run();
|
||||
return result;
|
||||
} catch (err) {
|
||||
error = err;
|
||||
|
||||
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
|
||||
this.state = RepositoryState.Disposed;
|
||||
}
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
this._operations.end(operation);
|
||||
this._onDidRunOperation.fire({ operation, error });
|
||||
}
|
||||
}
|
||||
|
||||
private async retryRun<T>(runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
|
||||
@@ -868,10 +954,9 @@ export class Repository implements Disposable {
|
||||
this.isRepositoryHuge = didHitLimit;
|
||||
|
||||
if (didHitLimit && !shouldIgnore && !this.didWarnAboutLimit) {
|
||||
const ok = { title: localize('ok', "OK"), isCloseAffordance: true };
|
||||
const neverAgain = { title: localize('neveragain', "Never Show Again") };
|
||||
const neverAgain = { title: localize('neveragain', "Don't Show Again") };
|
||||
|
||||
window.showWarningMessage(localize('huge', "The git repository at '{0}' has too many active changes, only a subset of Git features will be enabled.", this.repository.root), ok, neverAgain).then(result => {
|
||||
window.showWarningMessage(localize('huge', "The git repository at '{0}' has too many active changes, only a subset of Git features will be enabled.", this.repository.root), neverAgain).then(result => {
|
||||
if (result === neverAgain) {
|
||||
config.update('ignoreLimitWarning', true, false);
|
||||
}
|
||||
@@ -896,11 +981,12 @@ export class Repository implements Disposable {
|
||||
// noop
|
||||
}
|
||||
|
||||
const [refs, remotes] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes()]);
|
||||
const [refs, remotes, submodules] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes(), this.repository.getSubmodules()]);
|
||||
|
||||
this._HEAD = HEAD;
|
||||
this._refs = refs;
|
||||
this._remotes = remotes;
|
||||
this._submodules = submodules;
|
||||
|
||||
const index: Resource[] = [];
|
||||
const workingTree: Resource[] = [];
|
||||
@@ -922,10 +1008,8 @@ export class Repository implements Disposable {
|
||||
case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
|
||||
}
|
||||
|
||||
let isModifiedInIndex = false;
|
||||
|
||||
switch (raw.x) {
|
||||
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); isModifiedInIndex = true; break;
|
||||
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
|
||||
case 'A': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
|
||||
case 'D': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
|
||||
case 'R': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
|
||||
@@ -954,13 +1038,9 @@ export class Repository implements Disposable {
|
||||
|
||||
this._sourceControl.count = count;
|
||||
|
||||
// set context key
|
||||
let stateContextKey = '';
|
||||
|
||||
switch (this.state) {
|
||||
case RepositoryState.Idle: stateContextKey = 'idle'; break;
|
||||
case RepositoryState.Disposed: stateContextKey = 'norepo'; break;
|
||||
}
|
||||
// Disable `Discard All Changes` for "fresh" repositories
|
||||
// https://github.com/Microsoft/vscode/issues/43066
|
||||
commands.executeCommand('setContext', 'gitFreshRepository', !this._HEAD || !this._HEAD.commit);
|
||||
|
||||
this._onDidChangeStatus.fire();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user