Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -13,7 +13,7 @@ import * as path from 'path';
import * as nls from 'vscode-nls';
import * as fs from 'fs';
import { StatusBarCommands } from './statusbar';
import { Branch, Ref, Remote, RefType, GitErrorCodes, Status } from './api/git';
import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change } from './api/git';
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
@@ -94,6 +94,7 @@ export class Resource implements SourceControlResourceState {
case Status.INDEX_COPIED: return Resource.Icons[theme].Copied;
case Status.UNTRACKED: return Resource.Icons[theme].Untracked;
case Status.IGNORED: return Resource.Icons[theme].Ignored;
case Status.INTENT_TO_ADD: return Resource.Icons[theme].Added;
case Status.BOTH_DELETED: return Resource.Icons[theme].Conflict;
case Status.ADDED_BY_US: return Resource.Icons[theme].Conflict;
case Status.DELETED_BY_THEM: return Resource.Icons[theme].Conflict;
@@ -116,6 +117,7 @@ export class Resource implements SourceControlResourceState {
case Status.INDEX_COPIED: return localize('index copied', "Index Copied");
case Status.UNTRACKED: return localize('untracked', "Untracked");
case Status.IGNORED: return localize('ignored', "Ignored");
case Status.INTENT_TO_ADD: return localize('intent to add', "Intent to Add");
case Status.BOTH_DELETED: return localize('both deleted', "Both Deleted");
case Status.ADDED_BY_US: return localize('added by us', "Added By Us");
case Status.DELETED_BY_THEM: return localize('deleted by them', "Deleted By Them");
@@ -166,6 +168,7 @@ export class Resource implements SourceControlResourceState {
case Status.MODIFIED:
return 'M';
case Status.INDEX_ADDED:
case Status.INTENT_TO_ADD:
return 'A';
case Status.INDEX_DELETED:
case Status.DELETED:
@@ -201,6 +204,7 @@ export class Resource implements SourceControlResourceState {
case Status.DELETED:
return new ThemeColor('gitDecoration.deletedResourceForeground');
case Status.INDEX_ADDED:
case Status.INTENT_TO_ADD:
return new ThemeColor('gitDecoration.addedResourceForeground');
case Status.INDEX_RENAMED: // todo@joh - special color?
case Status.UNTRACKED:
@@ -295,7 +299,9 @@ export const enum Operation {
GetObjectDetails = 'GetObjectDetails',
SubmoduleUpdate = 'SubmoduleUpdate',
RebaseContinue = 'RebaseContinue',
Apply = 'Apply'
Apply = 'Apply',
Blame = 'Blame',
Log = 'Log',
}
function isReadOnly(operation: Operation): boolean {
@@ -643,18 +649,43 @@ export class Repository implements Disposable {
};
}
let lineNumber = 0;
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;
lineNumber++;
}
end = match ? match.index : text.length;
const line = text.substring(start, end);
const threshold = Math.max(config.get<number>('inputValidationLength') || 72, 0) || 72;
let threshold = config.get<number>('inputValidationLength', 50);
if (lineNumber === 0) {
const inputValidationSubjectLength = config.get<number | null>('inputValidationSubjectLength', null);
if (inputValidationSubjectLength !== null) {
threshold = inputValidationSubjectLength;
}
}
// const subjectThreshold =
// Math.max(config.get<number>('inputValidationLength') || 50, config.get<number>('subjectValidationLength') || 50, 0) || 50;
if (line.length <= threshold) {
if (setting !== 'always') {
@@ -697,10 +728,18 @@ export class Repository implements Disposable {
return this.run(Operation.Config, () => this.repository.config('local', key));
}
getGlobalConfig(key: string): Promise<string> {
return this.run(Operation.Config, () => this.repository.config('global', key));
}
setConfig(key: string, value: string): Promise<string> {
return this.run(Operation.Config, () => this.repository.config('local', key, value));
}
log(options?: LogOptions): Promise<Commit[]> {
return this.run(Operation.Log, () => this.repository.log(options));
}
@throttle
async status(): Promise<void> {
await this.run(Operation.Status);
@@ -710,19 +749,31 @@ export class Repository implements Disposable {
return this.run(Operation.Diff, () => this.repository.diff(cached));
}
diffWithHEAD(path: string): Promise<string> {
diffWithHEAD(): Promise<Change[]>;
diffWithHEAD(path: string): Promise<string>;
diffWithHEAD(path?: string | undefined): Promise<string | Change[]>;
diffWithHEAD(path?: string | undefined): Promise<string | Change[]> {
return this.run(Operation.Diff, () => this.repository.diffWithHEAD(path));
}
diffWith(ref: string, path: string): Promise<string> {
diffWith(ref: string): Promise<Change[]>;
diffWith(ref: string, path: string): Promise<string>;
diffWith(ref: string, path?: string | undefined): Promise<string | Change[]>;
diffWith(ref: string, path?: string): Promise<string | Change[]> {
return this.run(Operation.Diff, () => this.repository.diffWith(ref, path));
}
diffIndexWithHEAD(path: string): Promise<string> {
diffIndexWithHEAD(): Promise<Change[]>;
diffIndexWithHEAD(path: string): Promise<string>;
diffIndexWithHEAD(path?: string | undefined): Promise<string | Change[]>;
diffIndexWithHEAD(path?: string): Promise<string | Change[]> {
return this.run(Operation.Diff, () => this.repository.diffIndexWithHEAD(path));
}
diffIndexWith(ref: string, path: string): Promise<string> {
diffIndexWith(ref: string): Promise<Change[]>;
diffIndexWith(ref: string, path: string): Promise<string>;
diffIndexWith(ref: string, path?: string | undefined): Promise<string | Change[]>;
diffIndexWith(ref: string, path?: string): Promise<string | Change[]> {
return this.run(Operation.Diff, () => this.repository.diffIndexWith(ref, path));
}
@@ -730,7 +781,10 @@ export class Repository implements Disposable {
return this.run(Operation.Diff, () => this.repository.diffBlobs(object1, object2));
}
diffBetween(ref1: string, ref2: string, path: string): Promise<string> {
diffBetween(ref1: string, ref2: string): Promise<Change[]>;
diffBetween(ref1: string, ref2: string, path: string): Promise<string>;
diffBetween(ref1: string, ref2: string, path?: string | undefined): Promise<string | Change[]>;
diffBetween(ref1: string, ref2: string, path?: string): Promise<string | Change[]> {
return this.run(Operation.Diff, () => this.repository.diffBetween(ref1, ref2, path));
}
@@ -904,8 +958,8 @@ export class Repository implements Disposable {
await this.run(Operation.Fetch, () => this.repository.fetch({ all: true }));
}
async fetch(remote?: string, ref?: string): Promise<void> {
await this.run(Operation.Fetch, () => this.repository.fetch({ remote, ref }));
async fetch(remote?: string, ref?: string, depth?: number): Promise<void> {
await this.run(Operation.Fetch, () => this.repository.fetch({ remote, ref, depth }));
}
@throttle
@@ -918,18 +972,11 @@ export class Repository implements Disposable {
branch = `${head.upstream.name}`;
}
const config = workspace.getConfiguration('git', Uri.file(this.root));
const fetchOnPull = config.get<boolean>('fetchOnPull');
if (fetchOnPull) {
await this.run(Operation.Pull, () => this.repository.pull(true));
} else {
await this.run(Operation.Pull, () => this.repository.pull(true, remote, branch));
}
return this.pullFrom(true, remote, branch);
}
@throttle
async pull(head?: Branch): Promise<void> {
async pull(head?: Branch, unshallow?: boolean): Promise<void> {
let remote: string | undefined;
let branch: string | undefined;
@@ -938,25 +985,22 @@ export class Repository implements Disposable {
branch = `${head.upstream.name}`;
}
const config = workspace.getConfiguration('git', Uri.file(this.root));
const fetchOnPull = config.get<boolean>('fetchOnPull');
if (fetchOnPull) {
await this.run(Operation.Pull, () => this.repository.pull(false));
} else {
await this.run(Operation.Pull, () => this.repository.pull(false, remote, branch));
}
return this.pullFrom(false, remote, branch, unshallow);
}
async pullFrom(rebase?: boolean, remote?: string, branch?: string): Promise<void> {
const config = workspace.getConfiguration('git', Uri.file(this.root));
const fetchOnPull = config.get<boolean>('fetchOnPull');
async pullFrom(rebase?: boolean, remote?: string, branch?: string, unshallow?: boolean): Promise<void> {
await this.run(Operation.Pull, async () => {
await this.maybeAutoStash(async () => {
const config = workspace.getConfiguration('git', Uri.file(this.root));
const fetchOnPull = config.get<boolean>('fetchOnPull');
if (fetchOnPull) {
await this.run(Operation.Pull, () => this.repository.pull(rebase));
} else {
await this.run(Operation.Pull, () => this.repository.pull(rebase, remote, branch));
}
if (fetchOnPull) {
await this.repository.pull(rebase, undefined, undefined, { unshallow });
} else {
await this.repository.pull(rebase, remote, branch, { unshallow });
}
});
});
}
@throttle
@@ -980,6 +1024,10 @@ export class Repository implements Disposable {
await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true, forcePushMode));
}
async blame(path: string): Promise<string> {
return await this.run(Operation.Blame, () => this.repository.blame(path));
}
@throttle
sync(head: Branch): Promise<void> {
return this._sync(head, false);
@@ -1002,26 +1050,28 @@ export class Repository implements Disposable {
}
await this.run(Operation.Sync, async () => {
const config = workspace.getConfiguration('git', Uri.file(this.root));
const fetchOnPull = config.get<boolean>('fetchOnPull');
await this.maybeAutoStash(async () => {
const config = workspace.getConfiguration('git', Uri.file(this.root));
const fetchOnPull = config.get<boolean>('fetchOnPull');
if (fetchOnPull) {
await this.repository.pull(rebase);
} else {
await this.repository.pull(rebase, remoteName, pullBranch);
}
if (fetchOnPull) {
await this.repository.pull(rebase);
} else {
await this.repository.pull(rebase, remoteName, pullBranch);
}
const remote = this.remotes.find(r => r.name === remoteName);
const remote = this.remotes.find(r => r.name === remoteName);
if (remote && remote.isReadOnly) {
return;
}
if (remote && remote.isReadOnly) {
return;
}
const shouldPush = this.HEAD && (typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true);
const shouldPush = this.HEAD && (typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true);
if (shouldPush) {
await this.repository.push(remoteName, pushBranch);
}
if (shouldPush) {
await this.repository.push(remoteName, pushBranch);
}
});
});
}
@@ -1102,7 +1152,8 @@ export class Repository implements Disposable {
const text = lastLine.isEmptyOrWhitespace ? `${textToAppend}\n` : `\n${textToAppend}\n`;
edit.insert(document.uri, lastLine.range.end, text);
workspace.applyEdit(edit);
await workspace.applyEdit(edit);
await document.save();
});
}
@@ -1211,6 +1262,24 @@ export class Repository implements Disposable {
}
}
private static KnownHugeFolderNames = ['node_modules'];
private async findKnownHugeFolderPathsToIgnore(): Promise<string[]> {
const folderPaths: string[] = [];
for (const folderName of Repository.KnownHugeFolderNames) {
const folderPath = path.join(this.repository.root, folderName);
if (await new Promise<boolean>(c => fs.exists(folderPath, c))) {
folderPaths.push(folderPath);
}
}
const ignored = await this.checkIgnore(folderPaths);
return folderPaths.filter(p => !ignored.has(p));
}
@throttle
private async updateModelState(): Promise<void> {
const { status, didHitLimit } = await this.repository.getStatus();
@@ -1221,15 +1290,34 @@ export class Repository implements Disposable {
this.isRepositoryHuge = didHitLimit;
if (didHitLimit && !shouldIgnore && !this.didWarnAboutLimit) {
const knownHugeFolderPaths = await this.findKnownHugeFolderPathsToIgnore();
const gitWarn = localize('huge', "The git repository at '{0}' has too many active changes, only a subset of Git features will be enabled.", this.repository.root);
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), neverAgain).then(result => {
if (knownHugeFolderPaths.length > 0) {
const folderPath = knownHugeFolderPaths[0];
const folderName = path.basename(folderPath);
const addKnown = localize('add known', "Would you like to add '{0}' to .gitignore?", folderName);
const yes = { title: localize('yes', "Yes") };
const result = await window.showWarningMessage(`${gitWarn} ${addKnown}`, yes, neverAgain);
if (result === neverAgain) {
config.update('ignoreLimitWarning', true, false);
this.didWarnAboutLimit = true;
} else if (result === yes) {
this.ignore([Uri.file(folderPath)]);
}
} else {
const result = await window.showWarningMessage(gitWarn, neverAgain);
if (result === neverAgain) {
config.update('ignoreLimitWarning', true, false);
}
});
this.didWarnAboutLimit = true;
this.didWarnAboutLimit = true;
}
}
let HEAD: Branch | undefined;
@@ -1287,6 +1375,7 @@ export class Repository implements Disposable {
switch (raw.y) {
case 'M': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
case 'D': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
case 'A': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break;
}
return undefined;
});
@@ -1339,6 +1428,22 @@ export class Repository implements Disposable {
}
}
private async maybeAutoStash<T>(runOperation: () => Promise<T>): Promise<T> {
const config = workspace.getConfiguration('git', Uri.file(this.root));
const shouldAutoStash = config.get<boolean>('autoStash')
&& this.workingTreeGroup.resourceStates.some(r => r.type !== Status.UNTRACKED && r.type !== Status.IGNORED);
if (!shouldAutoStash) {
return await runOperation();
}
await this.repository.createStash(undefined, true);
const result = await runOperation();
await this.repository.popStash();
return result;
}
private onFSChange(_uri: Uri): void {
const config = workspace.getConfiguration('git');
const autorefresh = config.get<boolean>('autorefresh');