Merge commit 'refs/pull/80083/head' of github.com:microsoft/vscode into pr/80083

This commit is contained in:
Joao Moreno
2019-10-25 12:15:59 +02:00
4 changed files with 208 additions and 34 deletions
+70
View File
@@ -1054,6 +1054,61 @@
"command": "git.revealInExplorer",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "2_view"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "navigation"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == untracked",
"group": "navigation"
},
{
"command": "git.openHEADFile",
"when": "scmProvider == git && scmResourceGroup == untracked",
"group": "navigation"
},
{
"command": "git.openFile",
"when": "scmProvider == git && scmResourceGroup == untracked",
"group": "navigation"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == untracked",
"group": "1_modification"
},
{
"command": "git.clean",
"when": "scmProvider == git && scmResourceGroup == untracked && !gitFreshRepository",
"group": "1_modification"
},
{
"command": "git.clean",
"when": "scmProvider == git && scmResourceGroup == untracked && !gitFreshRepository",
"group": "inline"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == untracked",
"group": "inline"
},
{
"command": "git.openFile2",
"when": "scmProvider == git && scmResourceGroup == untracked && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",
"group": "inline0"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == untracked && config.git.showInlineOpenFileAction && !config.git.openDiffOnClick",
"group": "inline0"
},
{
"command": "git.ignore",
"when": "scmProvider == git && scmResourceGroup == untracked",
"group": "1_modification@3"
}
],
"editor/title": [
@@ -1457,6 +1512,21 @@
],
"default": "committerdate",
"description": "%config.branchSortOrder%"
},
"git.handleUntracked": {
"type": "string",
"enum": [
"withchanges",
"separate",
"hide"
],
"enumDescriptions": [
"%config.handleUntracked.withchanges%",
"%config.handleUntracked.separate%",
"%config.handleUntracked.hide%"
],
"default": "withchanges",
"description": "%config.handleUntracked%"
}
}
},
+6 -2
View File
@@ -1,6 +1,6 @@
{
"displayName": "Git",
"description": "Git SCM Integration",
"displayName": "Hide Untracked Files (Git)",
"description": "Copy of the built-in Git extension which hides untracked files",
"command.clone": "Clone",
"command.init": "Initialize Repository",
"command.openRepository": "Open Repository",
@@ -131,6 +131,10 @@
"config.openDiffOnClick": "Controls whether the diff editor should be opened when clicking a change. Otherwise the regular editor will be opened.",
"config.supportCancellation": "Controls whether a notification comes up when running the Sync action, which allows the user to cancel the operation.",
"config.branchSortOrder": "Controls the sort order for branches.",
"config.handleUntracked": "Controls how untracked files are presented in the activity bar.",
"config.handleUntracked.withchanges": "Show with other unstaged changes, commit under \"Commit All\"",
"config.handleUntracked.separate": "Separate in list and badge counter, don't commit under \"Commit All\"",
"config.handleUntracked.hide": "Exclude from list and badge counter, don't commit under \"Commit All\"",
"colors.added": "Color for added resources.",
"colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.",
+58 -14
View File
@@ -3,19 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor, MessageOptions, WorkspaceFolder } from 'vscode';
import { Git, CommitOptions, Stash, ForcePushMode } from './git';
import { Repository, Resource, ResourceGroupType } from './repository';
import { Model } from './model';
import { toGitUri, fromGitUri } from './uri';
import { grep, isDescendant, pathEquals } from './util';
import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange, getModifiedRange } from './staging';
import * as path from 'path';
import { lstat, Stats } from 'fs';
import * as os from 'os';
import * as path from 'path';
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder } from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry';
import * as nls from 'vscode-nls';
import { Ref, RefType, Branch, GitErrorCodes, Status } from './api/git';
import { Branch, GitErrorCodes, Ref, RefType, Status } from './api/git';
import { CommitOptions, ForcePushMode, Git, Stash } from './git';
import { Model } from './model';
import { Repository, Resource, ResourceGroupType } from './repository';
import { applyLineChanges, getModifiedRange, intersectDiffWithRange, invertLineChange, toLineRanges } from './staging';
import { fromGitUri, toGitUri } from './uri';
import { grep, isDescendant, pathEquals } from './util';
const localize = nls.loadMessageBundle();
@@ -872,7 +872,8 @@ export class CommandCenter {
}
const workingTree = selection.filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree);
const scmResources = [...workingTree, ...resolved, ...unresolved];
const untracked = selection.filter(s => s.resourceGroupType === ResourceGroupType.Untracked);
const scmResources = [...workingTree, ...untracked, ...resolved, ...unresolved];
this.outputChannel.appendLine(`git.stage.scmResources ${scmResources.length}`);
if (!scmResources.length) {
@@ -913,7 +914,49 @@ export class CommandCenter {
}
}
await repository.add([]);
const handleUntracked =
workspace
.getConfiguration('git', Uri.file(repository.root))
.get<'withchanges' | 'separate' | 'hide'>('handleUntracked') ||
'withchanges';
let includeUntracked;
switch (handleUntracked) {
case 'withchanges':
includeUntracked = true;
break;
case 'separate':
if (repository.untrackedGroup.resourceStates.length > 0) {
const message = localize(
'also add untracked files',
'Would you like to also add and stage untracked files?'
);
const yes = localize('yes', "Yes");
const no = localize('no', 'No');
const pick = await window.showInformationMessage(
message,
{ modal: true },
yes,
no
);
if (pick === yes) {
includeUntracked = true;
} else if (pick === no) {
includeUntracked = false;
} else {
return;
}
} else {
// Doesn't matter
includeUntracked = false;
}
break;
case 'hide':
includeUntracked = false;
break;
}
await repository.add([], includeUntracked ? undefined : { update: true });
}
private async _stageDeletionConflict(repository: Repository, uri: Uri): Promise<void> {
@@ -1137,8 +1180,8 @@ export class CommandCenter {
resourceStates = [resource];
}
const scmResources = resourceStates
.filter(s => s instanceof Resource && s.resourceGroupType === ResourceGroupType.WorkingTree) as Resource[];
const scmResources = resourceStates.filter(s => s instanceof Resource
&& (s.resourceGroupType === ResourceGroupType.WorkingTree || s.resourceGroupType === ResourceGroupType.Untracked)) as Resource[];
if (!scmResources.length) {
return;
@@ -2159,7 +2202,8 @@ export class CommandCenter {
}
private async _stash(repository: Repository, includeUntracked = false): Promise<void> {
const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0;
const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0
&& (!includeUntracked || repository.untrackedGroup.resourceStates.length === 0);
const noStagedChanges = repository.indexGroup.resourceStates.length === 0;
if (noUnstagedChanges && noStagedChanges) {
+74 -18
View File
@@ -3,17 +3,17 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, Decoration, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode';
import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, combinedDisposable } from './util';
import { memoize, throttle, debounce } from './decorators';
import { toGitUri } from './uri';
import { AutoFetcher } from './autofetch';
import * as path from 'path';
import * as nls from 'vscode-nls';
import * as fs from 'fs';
import * as path from 'path';
import { CancellationToken, Command, Disposable, env, Event, EventEmitter, LogLevel, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, Decoration } from 'vscode';
import * as nls from 'vscode-nls';
import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status } from './api/git';
import { AutoFetcher } from './autofetch';
import { debounce, memoize, throttle } from './decorators';
import { Commit, CommitOptions, ForcePushMode, GitError, Repository as BaseRepository, Stash, Submodule } from './git';
import { StatusBarCommands } from './statusbar';
import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change } from './api/git';
import { toGitUri } from './uri';
import { anyEvent, combinedDisposable, debounceEvent, dispose, EmptyDisposable, eventToPromise, filterEvent, find, IDisposable, isDescendant, onceEvent } from './util';
import { IFileWatcher, watch } from './watch';
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
@@ -33,7 +33,8 @@ export const enum RepositoryState {
export const enum ResourceGroupType {
Merge,
Index,
WorkingTree
WorkingTree,
Untracked
}
export class Resource implements SourceControlResourceState {
@@ -570,6 +571,9 @@ export class Repository implements Disposable {
private _workingTreeGroup: SourceControlResourceGroup;
get workingTreeGroup(): GitResourceGroup { return this._workingTreeGroup as GitResourceGroup; }
private _untrackedGroup: SourceControlResourceGroup;
get untrackedGroup(): GitResourceGroup { return this._untrackedGroup as GitResourceGroup; }
private _HEAD: Branch | undefined;
get HEAD(): Branch | undefined {
return this._HEAD;
@@ -642,6 +646,7 @@ export class Repository implements Disposable {
this.mergeGroup.resourceStates = [];
this.indexGroup.resourceStates = [];
this.workingTreeGroup.resourceStates = [];
this.untrackedGroup.resourceStates = [];
this._sourceControl.count = 0;
}
@@ -709,6 +714,7 @@ export class Repository implements Disposable {
this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "MERGE CHANGES"));
this._indexGroup = this._sourceControl.createResourceGroup('index', localize('staged changes', "STAGED CHANGES"));
this._workingTreeGroup = this._sourceControl.createResourceGroup('workingTree', localize('changes', "CHANGES"));
this._untrackedGroup = this._sourceControl.createResourceGroup('untracked', localize('untracked changes', 'UNTRACKED'));
const updateIndexGroupVisibility = () => {
const config = workspace.getConfiguration('git', root);
@@ -722,11 +728,16 @@ export class Repository implements Disposable {
const onConfigListenerForBranchSortOrder = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.branchSortOrder', root));
onConfigListenerForBranchSortOrder(this.updateModelState, this, this.disposables);
const onConfigListenerForUntracked = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.handleUntracked', root));
onConfigListenerForUntracked(this.updateModelState, this, this.disposables);
this.mergeGroup.hideWhenEmpty = true;
this.untrackedGroup.hideWhenEmpty = true;
this.disposables.push(this.mergeGroup);
this.disposables.push(this.indexGroup);
this.disposables.push(this.workingTreeGroup);
this.disposables.push(this.untrackedGroup);
this.disposables.push(new AutoFetcher(this, globalState));
@@ -912,8 +923,8 @@ export class Repository implements Disposable {
return this.run(Operation.HashObject, () => this.repository.hashObject(data));
}
async add(resources: Uri[]): Promise<void> {
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath)));
async add(resources: Uri[], opts?: { update?: boolean }): Promise<void> {
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath), opts));
}
async rm(resources: Uri[]): Promise<void> {
@@ -1496,16 +1507,44 @@ export class Repository implements Disposable {
this._submodules = submodules!;
this.rebaseCommit = rebaseCommit;
const handleUntracked =
config.get<'withchanges' | 'separate' | 'hide'>('handleUntracked') ||
'withchanges';
const index: Resource[] = [];
const workingTree: Resource[] = [];
const merge: Resource[] = [];
const untracked: Resource[] = [];
status.forEach(raw => {
const uri = Uri.file(path.join(this.repository.root, raw.path));
const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined;
const renameUri = raw.rename
? Uri.file(path.join(this.repository.root, raw.rename))
: undefined;
switch (raw.x + raw.y) {
case '??': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
case '??':
switch (handleUntracked) {
case 'withchanges':
return workingTree.push(
new Resource(
ResourceGroupType.WorkingTree,
uri,
Status.UNTRACKED,
useIcons
)
);
case 'separate':
return untracked.push(
new Resource(
ResourceGroupType.Untracked,
uri,
Status.UNTRACKED,
useIcons
)
);
case 'hide':
return undefined;
}
case '!!': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
case 'DD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons));
case 'AU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons));
@@ -1536,6 +1575,7 @@ export class Repository implements Disposable {
this.mergeGroup.resourceStates = merge;
this.indexGroup.resourceStates = index;
this.workingTreeGroup.resourceStates = workingTree;
this.untrackedGroup.resourceStates = untracked;
// set count badge
this.setCountBadge();
@@ -1546,12 +1586,28 @@ export class Repository implements Disposable {
}
private setCountBadge(): void {
const countBadge = workspace.getConfiguration('git').get<string>('countBadge');
let count = this.mergeGroup.resourceStates.length + this.indexGroup.resourceStates.length + this.workingTreeGroup.resourceStates.length;
const config = workspace.getConfiguration('git');
const countBadge = config.get<string>('countBadge');
const handleUntracked =
config.get<'withchanges' | 'separate' | 'hide'>('handleUntracked') ||
'withchanges';
let count =
this.mergeGroup.resourceStates.length +
this.indexGroup.resourceStates.length +
this.workingTreeGroup.resourceStates.length;
switch (countBadge) {
case 'off': count = 0; break;
case 'tracked': count = count - this.workingTreeGroup.resourceStates.filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED).length; break;
case 'tracked':
if (handleUntracked === 'withchanges') {
count -= this.workingTreeGroup.resourceStates.filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED).length;
}
break;
case 'all':
if (handleUntracked === 'separate') {
count += this.untrackedGroup.resourceStates.length;
}
break;
}
this._sourceControl.count = count;
@@ -1653,7 +1709,7 @@ export class Repository implements Disposable {
const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8);
return head
+ (this.workingTreeGroup.resourceStates.length > 0 ? '*' : '')
+ (this.workingTreeGroup.resourceStates.length + this.untrackedGroup.resourceStates.length > 0 ? '*' : '')
+ (this.indexGroup.resourceStates.length > 0 ? '+' : '')
+ (this.mergeGroup.resourceStates.length > 0 ? '!' : '');
}