Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions extensions/git/src/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export class GitCommitInputBoxDiagnosticsManager {

this.migrateInputValidationSettings()
.then(() => {
mapEvent(filterEvent(workspace.onDidChangeTextDocument, e => e.document.uri.scheme === 'vscode-scm'), e => e.document)(this.onDidChangeTextDocument, this, this.disposables);
mapEvent(filterEvent(workspace.onDidChangeTextDocument, e => e.document.uri.scheme === 'vscode-scm' || e.document.languageId === 'git-commit'), e => e.document)(this.onDidChangeTextDocument, this, this.disposables);
filterEvent(workspace.onDidCloseTextDocument, e => e.languageId === 'git-commit')(doc => this.diagnostics.delete(doc.uri), this, this.disposables);
filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.inputValidation') || e.affectsConfiguration('git.inputValidationLength') || e.affectsConfiguration('git.inputValidationSubjectLength'))(this.onDidChangeConfiguration, this, this.disposables);
});
}
Expand Down Expand Up @@ -57,6 +58,11 @@ export class GitCommitInputBoxDiagnosticsManager {
for (const repository of this.model.repositories) {
this.onDidChangeTextDocument(repository.inputBox.document);
}
for (const document of workspace.textDocuments) {
if (document.languageId === 'git-commit') {
this.onDidChangeTextDocument(document);
}
}
}

private onDidChangeTextDocument(document: TextDocument): void {
Expand All @@ -79,10 +85,19 @@ export class GitCommitInputBoxDiagnosticsManager {
const diagnostics: Diagnostic[] = [];
const inputValidationLength = config.get<number>('inputValidationLength', 50);
const inputValidationSubjectLength = config.get<number | undefined>('inputValidationSubjectLength', undefined);
const isCommitEditor = document.languageId === 'git-commit';

let isFirstMessageLine = true;
for (let index = 0; index < document.lineCount; index++) {
const line = document.lineAt(index);
const threshold = index === 0 ? inputValidationSubjectLength ?? inputValidationLength : inputValidationLength;

// Skip git comment/metadata lines in the commit editor
if (isCommitEditor && line.text.startsWith('#')) {
continue;
}

const threshold = isFirstMessageLine ? inputValidationSubjectLength ?? inputValidationLength : inputValidationLength;
isFirstMessageLine = false;

if (line.text.length > threshold) {
const charactersOver = line.text.length - threshold;
Expand Down Expand Up @@ -110,6 +125,7 @@ export class GitCommitInputBoxCodeActionsProvider implements CodeActionProvider

constructor(private readonly diagnosticsManager: GitCommitInputBoxDiagnosticsManager) {
this.disposables.push(languages.registerCodeActionsProvider({ scheme: 'vscode-scm' }, this));
this.disposables.push(languages.registerCodeActionsProvider({ language: 'git-commit' }, this));
}

provideCodeActions(document: TextDocument, range: Range | Selection): CodeAction[] {
Expand Down
14 changes: 8 additions & 6 deletions src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { IExtHostRpcService } from './extHostRpcService.js';
import { IExtHostTerminalService } from './extHostTerminalService.js';
import { Emitter, type Event } from '../../../base/common/event.js';
import { URI } from '../../../base/common/uri.js';
import { AsyncIterableObject, Barrier, type AsyncIterableEmitter } from '../../../base/common/async.js';
import { AsyncIterableProducer, Barrier, DeferredPromise, type AsyncIterableEmitter } from '../../../base/common/async.js';

export interface IExtHostTerminalShellIntegration extends ExtHostTerminalShellIntegrationShape {
readonly _serviceBrand: undefined;
Expand Down Expand Up @@ -400,7 +400,7 @@ class InternalTerminalShellExecution {
private _createDataStream(): AsyncIterable<string> {
if (!this._dataStream) {
if (this._isEnded) {
return AsyncIterableObject.EMPTY;
return AsyncIterableProducer.EMPTY;
}
this._dataStream = new ShellExecutionDataStream();
}
Expand Down Expand Up @@ -432,19 +432,21 @@ class InternalTerminalShellExecution {

class ShellExecutionDataStream extends Disposable {
private _barrier: Barrier | undefined;
private _iterables: AsyncIterableObject<string>[] = [];
private _completionPromises: DeferredPromise<void>[] = [];
private _emitters: AsyncIterableEmitter<string>[] = [];

createIterable(): AsyncIterable<string> {
if (!this._barrier) {
this._barrier = new Barrier();
}
const barrier = this._barrier;
const iterable = new AsyncIterableObject<string>(async emitter => {
const completionPromise = new DeferredPromise<void>();
this._completionPromises.push(completionPromise);
const iterable = new AsyncIterableProducer<string>(async emitter => {
this._emitters.push(emitter);
await barrier.wait();
completionPromise.complete(undefined);
});
this._iterables.push(iterable);
return iterable;
}

Expand All @@ -459,7 +461,7 @@ class ShellExecutionDataStream extends Disposable {
}

async flush(): Promise<void> {
await Promise.all(this._iterables.map(e => e.toPromise()));
await Promise.all(this._completionPromises.map(p => p.p));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ suite('InternalTerminalShellIntegration', () => {
}

async function emitData(data: string): Promise<void> {
// AsyncIterableObjects are initialized in a microtask, this doesn't matter in practice
// AsyncIterableProducers are initialized in a microtask, this doesn't matter in practice
// since the events will always come through in different events.
await new Promise<void>(r => queueMicrotask(r));
si.emitData(data);
Expand Down