Skip to content

Commit 72a0322

Browse files
committed
Merge branch 'scm-commit-box'
2 parents e164925 + e70f9ee commit 72a0322

19 files changed

Lines changed: 374 additions & 116 deletions

File tree

extensions/git/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@
9494
"dark": "resources/icons/dark/clean.svg"
9595
}
9696
},
97+
{
98+
"command": "git.commit",
99+
"title": "%command.commit%",
100+
"category": "Git"
101+
},
97102
{
98103
"command": "git.commitStaged",
99104
"title": "%command.commitStaged%",
@@ -165,6 +170,14 @@
165170
"category": "Git"
166171
}
167172
],
173+
"keybindings": [
174+
{
175+
"command": "git.commitWithInput",
176+
"key": "ctrl+enter",
177+
"mac": "cmd+enter",
178+
"when": "inSCMInput"
179+
}
180+
],
168181
"menus": {
169182
"scm/title": [
170183
{

extensions/git/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"command.unstageAll": "Unstage All",
99
"command.clean": "Clean",
1010
"command.cleanAll": "Clean All",
11+
"command.commit": "Commit",
1112
"command.commitStaged": "Commit Staged",
1213
"command.commitStagedSigned": "Commit Staged (Signed Off)",
1314
"command.commitAll": "Commit All",

extensions/git/src/commands.ts

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import { Uri, commands, scm, Disposable, SCMResourceGroup, SCMResource, window, workspace, QuickPickItem, OutputChannel } from 'vscode';
99
import { IRef, RefType } from './git';
1010
import { Model, Resource, Status } from './model';
11+
import { CommitController } from './commit';
1112
import * as path from 'path';
1213
import * as nls from 'vscode-nls';
1314

@@ -125,7 +126,11 @@ export class CommandCenter {
125126

126127
private disposables: Disposable[];
127128

128-
constructor(private model: Model, private outputChannel: OutputChannel) {
129+
constructor(
130+
private model: Model,
131+
private commitController: CommitController,
132+
private outputChannel: OutputChannel
133+
) {
129134
this.disposables = CommandCenter.Commands
130135
.map(({ commandId, method }) => commands.registerCommand(commandId, method, this));
131136
}
@@ -286,7 +291,7 @@ export class CommandCenter {
286291
return;
287292
}
288293

289-
return await this.model.clean(resource);
294+
await this.model.clean(resource);
290295
}
291296

292297
@CommandCenter.Command('git.cleanAll')
@@ -301,13 +306,45 @@ export class CommandCenter {
301306
return;
302307
}
303308

304-
return await this.model.clean(...this.model.workingTreeGroup.resources);
309+
await this.model.clean(...this.model.workingTreeGroup.resources);
305310
}
306311

307-
@CommandCenter.CatchErrors
308-
async commit(message: string): Promise<void> {
312+
private async _commit(fn: () => Promise<string>): Promise<boolean> {
313+
if (this.model.indexGroup.resources.length === 0 && this.model.workingTreeGroup.resources.length === 0) {
314+
window.showInformationMessage(localize('no changes', "There are no changes to commit."));
315+
return false;
316+
}
317+
318+
const message = await fn();
319+
320+
if (!message) {
321+
// TODO@joao: show modal dialog to confirm empty message commit
322+
return false;
323+
}
324+
309325
const all = this.model.indexGroup.resources.length === 0;
310-
return this.model.commit(message, { all });
326+
await this.model.commit(message, { all });
327+
328+
return true;
329+
}
330+
331+
@CommandCenter.Command('git.commit')
332+
@CommandCenter.CatchErrors
333+
async commit(): Promise<void> {
334+
await this._commit(async () => await window.showInputBox({
335+
placeHolder: localize('commit message', "Commit message"),
336+
prompt: localize('provide commit message', "Please provide a commit message")
337+
}));
338+
}
339+
340+
@CommandCenter.Command('git.commitWithInput')
341+
@CommandCenter.CatchErrors
342+
async commitWithInput(): Promise<void> {
343+
const didCommit = await this._commit(async () => this.commitController.message);
344+
345+
if (didCommit) {
346+
this.commitController.message = '';
347+
}
311348
}
312349

313350
@CommandCenter.Command('git.commitStaged')

extensions/git/src/commit.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import { workspace, window, languages, Disposable, Uri, TextDocumentChangeEvent, HoverProvider, Hover, TextEditor, Position, TextDocument, Range, TextEditorDecorationType, WorkspaceEdit } from 'vscode';
9+
import { Model } from './model';
10+
import { filterEvent } from './util';
11+
import * as nls from 'vscode-nls';
12+
13+
const localize = nls.loadMessageBundle();
14+
const scmInputUri = Uri.parse('scm:input');
15+
16+
function isSCMInput(uri: Uri) {
17+
return uri.toString() === scmInputUri.toString();
18+
}
19+
20+
interface Diagnostic {
21+
range: Range;
22+
message: string;
23+
}
24+
25+
// TODO@Joao: hover dissapears if editor is scrolled
26+
export class CommitController implements HoverProvider {
27+
28+
private visibleTextEditorsDisposable: Disposable;
29+
private editor: TextEditor;
30+
private diagnostics: Diagnostic[] = [];
31+
private decorationType: TextEditorDecorationType;
32+
private disposables: Disposable[] = [];
33+
34+
get message(): string | undefined {
35+
if (!this.editor) {
36+
return;
37+
}
38+
39+
return this.editor.document.getText();
40+
}
41+
42+
set message(message: string | undefined) {
43+
if (!this.editor || message === undefined) {
44+
return;
45+
}
46+
47+
const document = this.editor.document;
48+
const start = document.lineAt(0).range.start;
49+
const end = document.lineAt(document.lineCount - 1).range.end;
50+
const range = new Range(start, end);
51+
const edit = new WorkspaceEdit();
52+
edit.replace(scmInputUri, range, message);
53+
workspace.applyEdit(edit);
54+
}
55+
56+
constructor(private model: Model) {
57+
this.visibleTextEditorsDisposable = window.onDidChangeVisibleTextEditors(this.onVisibleTextEditors, this);
58+
this.onVisibleTextEditors(window.visibleTextEditors);
59+
60+
this.decorationType = window.createTextEditorDecorationType({
61+
isWholeLine: true,
62+
color: 'rgb(228, 157, 43)',
63+
dark: {
64+
color: 'rgb(220, 211, 71)'
65+
}
66+
});
67+
}
68+
69+
private onVisibleTextEditors(editors: TextEditor[]): void {
70+
const [editor] = editors.filter(e => isSCMInput(e.document.uri));
71+
72+
if (!editor) {
73+
return;
74+
}
75+
76+
this.visibleTextEditorsDisposable.dispose();
77+
this.editor = editor;
78+
79+
const onDidChange = filterEvent(workspace.onDidChangeTextDocument, e => e.document && isSCMInput(e.document.uri));
80+
onDidChange(this.onSCMInputChange, this, this.disposables);
81+
82+
languages.registerHoverProvider({ scheme: 'scm' }, this);
83+
}
84+
85+
private onSCMInputChange(e: TextDocumentChangeEvent): void {
86+
this.diagnostics = [];
87+
88+
const range = e.document.lineAt(0).range;
89+
const length = range.end.character - range.start.character;
90+
91+
if (length > 80) {
92+
const message = localize('too long', "You should keep the first line under 50 characters.\n\nYou can use more lines for extra information.");
93+
this.diagnostics.push({ range, message });
94+
}
95+
96+
this.editor.setDecorations(this.decorationType, this.diagnostics.map(d => d.range));
97+
}
98+
99+
provideHover(document: TextDocument, position: Position): Hover | undefined {
100+
const [decoration] = this.diagnostics.filter(d => d.range.contains(position));
101+
102+
if (!decoration) {
103+
return;
104+
}
105+
106+
return new Hover(decoration.message, decoration.range);
107+
}
108+
109+
dispose(): void {
110+
this.disposables.forEach(d => d.dispose());
111+
}
112+
}

extensions/git/src/main.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { filterEvent, anyEvent } from './util';
1515
import { GitContentProvider } from './contentProvider';
1616
import { AutoFetcher } from './autofetch';
1717
import { MergeDecorator } from './merge';
18+
import { CommitController } from './commit';
1819
import * as nls from 'vscode-nls';
1920

2021
const localize = nls.config()();
@@ -41,7 +42,8 @@ async function init(disposables: Disposable[]): Promise<void> {
4142
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
4243
git.onOutput(str => outputChannel.append(str), null, disposables);
4344

44-
const commandCenter = new CommandCenter(model, outputChannel);
45+
const commitHandler = new CommitController(model);
46+
const commandCenter = new CommandCenter(model, commitHandler, outputChannel);
4547
const provider = new GitSCMProvider(model, commandCenter);
4648
const contentProvider = new GitContentProvider(git, rootPath, onGitChange);
4749
const checkoutStatusBar = new CheckoutStatusBar(model);
@@ -50,6 +52,7 @@ async function init(disposables: Disposable[]): Promise<void> {
5052
const mergeDecorator = new MergeDecorator(model);
5153

5254
disposables.push(
55+
commitHandler,
5356
commandCenter,
5457
provider,
5558
contentProvider,

extensions/git/src/scmProvider.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ export class GitSCMProvider implements SCMProvider {
2121
scm.registerSCMProvider('git', this);
2222
}
2323

24-
commit(message: string): Thenable<void> {
25-
return this.commandCenter.commit(message);
26-
}
27-
2824
open(resource: Resource): ProviderResult<void> {
2925
return this.commandCenter.open(resource);
3026
}

src/vs/editor/contrib/hover/browser/hover.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
2424
import EditorContextKeys = editorCommon.EditorContextKeys;
2525

2626
@editorContribution
27-
class ModesHoverController implements editorCommon.IEditorContribution {
27+
export class ModesHoverController implements editorCommon.IEditorContribution {
2828

2929
private static ID = 'editor.contrib.hover';
3030

src/vs/workbench/electron-browser/workbench.main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ import 'vs/workbench/parts/search/browser/search.contribution';
4343
import 'vs/workbench/parts/search/browser/searchViewlet'; // can be packaged separately
4444
import 'vs/workbench/parts/search/browser/openAnythingHandler'; // can be packaged separately
4545

46-
import 'vs/workbench/parts/scm/browser/scm.contribution';
47-
import 'vs/workbench/parts/scm/browser/scmViewlet'; // can be packaged separately
46+
import 'vs/workbench/parts/scm/electron-browser/scm.contribution';
47+
import 'vs/workbench/parts/scm/electron-browser/scmViewlet'; // can be packaged separately
4848

4949
import 'vs/workbench/parts/git/electron-browser/git.contribution';
5050
import 'vs/workbench/parts/git/browser/gitQuickOpen';

src/vs/workbench/parts/scm/browser/dirtydiffDecorator.ts renamed to src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts

File renamed without changes.

src/vs/workbench/parts/scm/browser/media/check-inverse.svg renamed to src/vs/workbench/parts/scm/electron-browser/media/check-inverse.svg

File renamed without changes.

0 commit comments

Comments
 (0)