mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Merge branch 'main' into aiday/indentationOnInitOnly
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-markdown-languageservice\n\n// current milestone name\n$milestone=milestone:\"June 2023\""
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release\n\n// current milestone name\n$milestone=milestone:\"June 2023\""
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
|
||||
@@ -165,7 +165,7 @@ function nodejs(platform, arch) {
|
||||
if (platform === 'win32') {
|
||||
if (product.nodejsRepository) {
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejsRepository}...`);
|
||||
return assetFromGithub(product.nodejsRepository, nodeVersion, name => name === `win-${arch}-node.exe`)
|
||||
return assetFromGithub(product.nodejsRepository, nodeVersion, name => name === `win-${arch}-node-patched.exe`)
|
||||
.pipe(rename('node.exe'));
|
||||
}
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from https://nodejs.org`);
|
||||
|
||||
@@ -76,7 +76,7 @@ function darwinBundleDocumentTypes(types, icon) {
|
||||
});
|
||||
}
|
||||
exports.config = {
|
||||
version: product.electronRepository ? '22.5.5' : util.getElectronVersion(),
|
||||
version: product.electronRepository ? '22.5.7' : util.getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2023 Microsoft. All rights reserved',
|
||||
@@ -193,7 +193,7 @@ function getElectron(arch) {
|
||||
};
|
||||
}
|
||||
async function main(arch = process.arch) {
|
||||
const version = product.electronRepository ? '22.5.5' : util.getElectronVersion();
|
||||
const version = product.electronRepository ? '22.5.7' : util.getElectronVersion();
|
||||
const electronPath = path.join(root, '.build', 'electron');
|
||||
const versionFile = path.join(electronPath, 'version');
|
||||
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`;
|
||||
|
||||
@@ -91,7 +91,7 @@ function darwinBundleDocumentTypes(types: { [name: string]: string | string[] },
|
||||
}
|
||||
|
||||
export const config = {
|
||||
version: product.electronRepository ? '22.5.5' : util.getElectronVersion(),
|
||||
version: product.electronRepository ? '22.5.7' : util.getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2023 Microsoft. All rights reserved',
|
||||
@@ -212,7 +212,7 @@ function getElectron(arch: string): () => NodeJS.ReadWriteStream {
|
||||
}
|
||||
|
||||
async function main(arch = process.arch): Promise<void> {
|
||||
const version = product.electronRepository ? '22.5.5' : util.getElectronVersion();
|
||||
const version = product.electronRepository ? '22.5.7' : util.getElectronVersion();
|
||||
const electronPath = path.join(root, '.build', 'electron');
|
||||
const versionFile = path.join(electronPath, 'version');
|
||||
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`;
|
||||
|
||||
@@ -140,7 +140,7 @@ export async function getPackageManager(extensionContext: ExtensionContext, fold
|
||||
window.showInformationMessage(multiplePMWarning, learnMore, neverShowAgain).then(result => {
|
||||
switch (result) {
|
||||
case neverShowAgain: extensionContext.globalState.update(neverShowWarning, true); break;
|
||||
case learnMore: env.openExternal(Uri.parse('https://nodejs.dev/learn/the-package-lock-json-file'));
|
||||
case learnMore: env.openExternal(Uri.parse('https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -152,7 +152,8 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
|
||||
const length = this.length + diff;
|
||||
|
||||
if (this.sortedIndexes.length > 0 && sortedIndexes.length === 0 && length > 0) {
|
||||
sortedIndexes.push(Math.min(firstSortedIndex ?? length - 1, length - 1));
|
||||
const first = this.sortedIndexes.find(index => index >= start) ?? length - 1;
|
||||
sortedIndexes.push(Math.min(first, length - 1));
|
||||
}
|
||||
|
||||
this.renderer.splice(start, deleteCount, elements.length);
|
||||
|
||||
@@ -382,7 +382,7 @@ class CodeMain {
|
||||
|
||||
// Print --status usage info
|
||||
if (environmentMainService.args.status) {
|
||||
logService.warn(localize('statusWarning', "Warning: The --status argument can only be used if {0} is already running. Please run it again after {0} has started.", productService.nameShort));
|
||||
console.log(localize('statusWarning', "Warning: The --status argument can only be used if {0} is already running. Please run it again after {0} has started.", productService.nameShort));
|
||||
|
||||
throw new ExpectedError('Terminating...');
|
||||
}
|
||||
|
||||
@@ -1157,6 +1157,8 @@ export interface IDiffEditor extends editorCommon.IEditor {
|
||||
*/
|
||||
getModel(): editorCommon.IDiffEditorModel | null;
|
||||
|
||||
createViewModel(model: editorCommon.IDiffEditorModel): editorCommon.IDiffEditorViewModel;
|
||||
|
||||
/**
|
||||
* Sets the current model attached to this editor.
|
||||
* If the previous model was created by the editor via the value key in the options
|
||||
@@ -1165,7 +1167,7 @@ export interface IDiffEditor extends editorCommon.IEditor {
|
||||
* will not be destroyed.
|
||||
* It is safe to call setModel(null) to simply detach the current model from the editor.
|
||||
*/
|
||||
setModel(model: editorCommon.IDiffEditorModel | null): void;
|
||||
setModel(model: editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null): void;
|
||||
|
||||
/**
|
||||
* Get the `original` editor.
|
||||
|
||||
@@ -488,7 +488,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
return this._modelData.model;
|
||||
}
|
||||
|
||||
public setModel(_model: ITextModel | editorCommon.IDiffEditorModel | null = null): void {
|
||||
public setModel(_model: ITextModel | editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null = null): void {
|
||||
const model = <ITextModel | null>_model;
|
||||
if (this._modelData === null && model === null) {
|
||||
// Current model is the new model
|
||||
|
||||
@@ -829,7 +829,20 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
};
|
||||
}
|
||||
|
||||
public setModel(model: editorCommon.IDiffEditorModel | null): void {
|
||||
public createViewModel(model: editorCommon.IDiffEditorModel): editorCommon.IDiffEditorViewModel {
|
||||
return {
|
||||
model,
|
||||
async waitForDiff() {
|
||||
// noop
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public setModel(model: editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null): void {
|
||||
if (model && 'model' in model) {
|
||||
model = model.model;
|
||||
}
|
||||
|
||||
// Guard us against partial null model
|
||||
if (model && (!model.original || !model.modified)) {
|
||||
throw new Error(!model.original ? 'DiffEditorWidget.setModel: Original model is null' : 'DiffEditorWidget.setModel: Modified model is null');
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IDimension } from 'vs/editor/common/core/dimension';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditor, IEditorAction, IEditorDecorationsCollection, IEditorModel, IEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IDiffEditorViewModel, IEditor, IEditorAction, IEditorDecorationsCollection, IEditorModel, IEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationsChangeAccessor, IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
|
||||
export abstract class DelegatingEditor extends Disposable implements IEditor {
|
||||
@@ -34,7 +34,7 @@ export abstract class DelegatingEditor extends Disposable implements IEditor {
|
||||
abstract saveViewState(): IEditorViewState | null;
|
||||
abstract restoreViewState(state: IEditorViewState | null): void;
|
||||
abstract getModel(): IEditorModel | null;
|
||||
abstract setModel(model: IEditorModel | null): void;
|
||||
abstract setModel(model: IEditorModel | null | IDiffEditorViewModel): void;
|
||||
|
||||
// #region editorBrowser.IDiffEditor: Delegating to modified Editor
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';
|
||||
import { findLast } from 'vs/base/common/arrays';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IObservable, ISettableObservable, autorun, derived, keepAlive, observableValue, waitForState } from 'vs/base/common/observable';
|
||||
import { disposableObservableValue } from 'vs/base/common/observableImpl/base';
|
||||
import { IObservable, ISettableObservable, autorun, derived, keepAlive, observableValue } from 'vs/base/common/observable';
|
||||
import { disposableObservableValue, transaction } from 'vs/base/common/observableImpl/base';
|
||||
import { derivedWithStore } from 'vs/base/common/observableImpl/derived';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
@@ -32,7 +32,7 @@ import { IDimension } from 'vs/editor/common/core/dimension';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
|
||||
import { EditorType, IContentSizeChangedEvent, IDiffEditorModel, IDiffEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { EditorType, IContentSizeChangedEvent, IDiffEditorModel, IDiffEditorViewModel, IDiffEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -306,7 +306,6 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
if (!m) { return; }
|
||||
|
||||
const movedText = m.diff.get()!.movedTexts.find(m => m.lineRangeMapping.originalRange.contains(e.position.lineNumber));
|
||||
|
||||
m.syncedMovedTexts.set(movedText, undefined);
|
||||
}));
|
||||
return editor;
|
||||
@@ -322,7 +321,6 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
if (!m) { return; }
|
||||
|
||||
const movedText = m.diff.get()!.movedTexts.find(m => m.lineRangeMapping.modifiedRange.contains(e.position.lineNumber));
|
||||
|
||||
m.syncedMovedTexts.set(movedText, undefined);
|
||||
}));
|
||||
// Revert change when an arrow is clicked.
|
||||
@@ -484,22 +482,27 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
}
|
||||
}
|
||||
|
||||
override getModel(): IDiffEditorModel | null { return this._model.get(); }
|
||||
|
||||
override setModel(model: IDiffEditorModel | null): void {
|
||||
this._originalEditor.setModel(model ? model.original : null);
|
||||
this._modifiedEditor.setModel(model ? model.modified : null);
|
||||
|
||||
this._model.set(model, undefined);
|
||||
|
||||
this._diffModel.set(model ? new DiffModel(
|
||||
public createViewModel(model: IDiffEditorModel): IDiffEditorViewModel {
|
||||
return new DiffModel(
|
||||
model,
|
||||
this._options.map(o => o.ignoreTrimWhitespace),
|
||||
this._options.map(o => o.maxComputationTime),
|
||||
this._options.map(o => o.experimental.collapseUnchangedRegions!),
|
||||
this._options.map(o => o.experimental.showMoves! && o.renderSideBySide),
|
||||
this._instantiationService.createInstance(WorkerBasedDocumentDiffProvider, this._options.get())
|
||||
) : undefined, undefined);
|
||||
);
|
||||
}
|
||||
|
||||
override getModel(): IDiffEditorModel | null { return this._model.get(); }
|
||||
|
||||
override setModel(model: IDiffEditorModel | null | IDiffEditorViewModel): void {
|
||||
const vm = model ? ('model' in model) ? model : this.createViewModel(model) : undefined;
|
||||
this._originalEditor.setModel(vm ? vm.model.original : null);
|
||||
this._modifiedEditor.setModel(vm ? vm.model.modified : null);
|
||||
transaction(tx => {
|
||||
this._model.set(vm?.model ?? null, tx);
|
||||
this._diffModel.set(vm as (DiffModel | undefined), tx);
|
||||
});
|
||||
}
|
||||
|
||||
override updateOptions(_newOptions: IDiffEditorOptions): void {
|
||||
@@ -641,7 +644,7 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
return;
|
||||
}
|
||||
// wait for the diff computation to finish
|
||||
waitForState(diffModel.isDiffUpToDate, s => s).then(() => {
|
||||
this.waitForDiff().then(() => {
|
||||
const diffs = diffModel.diff.get()?.mappings;
|
||||
if (!diffs || diffs.length === 0) {
|
||||
return;
|
||||
@@ -649,6 +652,15 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
this._goTo(diffs[0]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public async waitForDiff(): Promise<void> {
|
||||
const diffModel = this._diffModel.get();
|
||||
if (!diffModel) {
|
||||
return;
|
||||
}
|
||||
await diffModel.waitForDiff();
|
||||
}
|
||||
}
|
||||
|
||||
function validateDiffEditorOptions(options: Readonly<IDiffEditorOptions>, defaults: ValidDiffEditorBaseOptions): ValidDiffEditorBaseOptions {
|
||||
|
||||
@@ -5,27 +5,32 @@
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IObservable, IReader, ITransaction, derived, observableSignal, observableSignalFromEvent, observableValue, transaction } from 'vs/base/common/observable';
|
||||
import { IObservable, IReader, ITransaction, derived, observableSignal, observableSignalFromEvent, observableValue, transaction, waitForState } from 'vs/base/common/observable';
|
||||
import { autorunWithStore2 } from 'vs/base/common/observableImpl/autorun';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IDocumentDiff, IDocumentDiffProvider } from 'vs/editor/common/diff/documentDiffProvider';
|
||||
import { LineRangeMapping, MovedText, RangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { LineRangeMapping, MovedText, RangeMapping, SimpleLineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { lineRangeMappingFromRangeMappings } from 'vs/editor/common/diff/standardLinesDiffComputer';
|
||||
import { IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||
import { IDiffEditorModel, IDiffEditorViewModel } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { TextEditInfo } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper';
|
||||
import { combineTextEditInfos } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/combineTextEditInfos';
|
||||
import { lengthAdd, lengthDiffNonNegative, lengthOfRange, lengthToPosition, lengthZero, positionToLength } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';
|
||||
import { lengthAdd, lengthDiffNonNegative, lengthGetLineCount, lengthOfRange, lengthToPosition, lengthZero, positionToLength } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';
|
||||
|
||||
export class DiffModel extends Disposable {
|
||||
export class DiffModel extends Disposable implements IDiffEditorViewModel {
|
||||
private readonly _isDiffUpToDate = observableValue<boolean>('isDiffUpToDate', false);
|
||||
public readonly isDiffUpToDate: IObservable<boolean> = this._isDiffUpToDate;
|
||||
|
||||
private _lastDiff: IDocumentDiff | undefined;
|
||||
private readonly _diff = observableValue<DiffState | undefined>('diff', undefined);
|
||||
public readonly diff: IObservable<DiffState | undefined> = this._diff;
|
||||
|
||||
private readonly _unchangedRegions = observableValue<{ regions: UnchangedRegion[]; originalDecorationIds: string[]; modifiedDecorationIds: string[] }>('unchangedRegion', { regions: [], originalDecorationIds: [], modifiedDecorationIds: [] });
|
||||
private readonly _unchangedRegions = observableValue<{ regions: UnchangedRegion[]; originalDecorationIds: string[]; modifiedDecorationIds: string[] }>(
|
||||
'unchangedRegion',
|
||||
{ regions: [], originalDecorationIds: [], modifiedDecorationIds: [] }
|
||||
);
|
||||
public readonly unchangedRegions: IObservable<UnchangedRegion[]> = derived('unchangedRegions', r =>
|
||||
this._hideUnchangedRegions.read(r) ? this._unchangedRegions.read(r).regions : []
|
||||
);
|
||||
@@ -50,11 +55,14 @@ export class DiffModel extends Disposable {
|
||||
if (!diff) {
|
||||
return;
|
||||
}
|
||||
/*const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._diff.set(
|
||||
applyModifiedEdits(diff, textEdits, model.original, model.modified),
|
||||
undefined
|
||||
);*/
|
||||
if (!this._showMoves.get()) {
|
||||
const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._lastDiff = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified);
|
||||
this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined);
|
||||
const currentSyncedMovedText = this.syncedMovedTexts.get();
|
||||
this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, undefined);
|
||||
}
|
||||
|
||||
debouncer.schedule();
|
||||
}));
|
||||
this._register(model.original.onDidChangeContent((e) => {
|
||||
@@ -62,11 +70,13 @@ export class DiffModel extends Disposable {
|
||||
if (!diff) {
|
||||
return;
|
||||
}
|
||||
/*const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._diff.set(
|
||||
applyOriginalEdits(diff, textEdits, model.original, model.modified),
|
||||
undefined
|
||||
);*/
|
||||
if (!this._showMoves.get()) {
|
||||
const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._lastDiff = applyOriginalEdits(this._lastDiff!, textEdits, model.original, model.modified);
|
||||
this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined);
|
||||
const currentSyncedMovedText = this.syncedMovedTexts.get();
|
||||
this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, undefined);
|
||||
}
|
||||
debouncer.schedule();
|
||||
}));
|
||||
|
||||
@@ -137,8 +147,11 @@ export class DiffModel extends Disposable {
|
||||
);
|
||||
|
||||
transaction(tx => {
|
||||
this._lastDiff = result;
|
||||
this._diff.set(DiffState.fromDiffResult(result), tx);
|
||||
this._isDiffUpToDate.set(true, tx);
|
||||
const currentSyncedMovedText = this.syncedMovedTexts.get();
|
||||
this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, tx);
|
||||
|
||||
this._unchangedRegions.set(
|
||||
{
|
||||
@@ -152,7 +165,7 @@ export class DiffModel extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
public revealModifiedLine(lineNumber: number, tx: ITransaction): void {
|
||||
public ensureModifiedLineIsVisible(lineNumber: number, tx: ITransaction): void {
|
||||
const unchangedRegions = this._unchangedRegions.get().regions;
|
||||
for (const r of unchangedRegions) {
|
||||
if (r.getHiddenModifiedRange(undefined).contains(lineNumber)) {
|
||||
@@ -162,7 +175,7 @@ export class DiffModel extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public revealOriginalLine(lineNumber: number, tx: ITransaction): void {
|
||||
public ensureOriginalLineIsVisible(lineNumber: number, tx: ITransaction): void {
|
||||
const unchangedRegions = this._unchangedRegions.get().regions;
|
||||
for (const r of unchangedRegions) {
|
||||
if (r.getHiddenOriginalRange(undefined).contains(lineNumber)) {
|
||||
@@ -171,6 +184,10 @@ export class DiffModel extends Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async waitForDiff(): Promise<void> {
|
||||
await waitForState(this.isDiffUpToDate, s => s);
|
||||
}
|
||||
}
|
||||
|
||||
export class DiffState {
|
||||
@@ -315,38 +332,17 @@ function applyOriginalEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], orig
|
||||
return diff;
|
||||
}
|
||||
|
||||
const diffTextEdits = diff.changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(
|
||||
positionToLength(c.modifiedRange.getStartPosition()),
|
||||
positionToLength(c.modifiedRange.getEndPosition()),
|
||||
lengthOfRange(c.originalRange).toLength(),
|
||||
)));
|
||||
|
||||
const combined = combineTextEditInfos(diffTextEdits, textEdits);
|
||||
|
||||
let lastModifiedEndOffset = lengthZero;
|
||||
let lastOriginalEndOffset = lengthZero;
|
||||
const rangeMappings = combined.map(c => {
|
||||
const originalStartOffset = lengthAdd(lastOriginalEndOffset, lengthDiffNonNegative(lastModifiedEndOffset, c.startOffset));
|
||||
lastModifiedEndOffset = c.endOffset;
|
||||
lastOriginalEndOffset = lengthAdd(originalStartOffset, c.newLength);
|
||||
|
||||
return new RangeMapping(
|
||||
Range.fromPositions(lengthToPosition(originalStartOffset), lengthToPosition(lastOriginalEndOffset)),
|
||||
Range.fromPositions(lengthToPosition(c.startOffset), lengthToPosition(c.endOffset)),
|
||||
);
|
||||
});
|
||||
|
||||
const changes = lineRangeMappingFromRangeMappings(
|
||||
rangeMappings,
|
||||
originalTextModel.getLinesContent(),
|
||||
modifiedTextModel.getLinesContent(),
|
||||
);
|
||||
const diff2 = flip(diff);
|
||||
const diff3 = applyModifiedEdits(diff2, textEdits, modifiedTextModel, originalTextModel);
|
||||
return flip(diff3);
|
||||
}
|
||||
|
||||
function flip(diff: IDocumentDiff): IDocumentDiff {
|
||||
return {
|
||||
identical: false,
|
||||
quitEarly: false,
|
||||
changes,
|
||||
moves: [],
|
||||
changes: diff.changes.map(c => c.flip()),
|
||||
moves: diff.moves.map(m => m.flip()),
|
||||
identical: diff.identical,
|
||||
quitEarly: diff.quitEarly,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -355,7 +351,63 @@ function applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], orig
|
||||
return diff;
|
||||
}
|
||||
|
||||
const diffTextEdits = diff.changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(
|
||||
const changes = applyModifiedEditsToLineRangeMappings(diff.changes, textEdits, originalTextModel, modifiedTextModel);
|
||||
|
||||
const moves = diff.moves.map(m => {
|
||||
const newModifiedRange = applyEditToLineRange(m.lineRangeMapping.modifiedRange, textEdits);
|
||||
return newModifiedRange ? new MovedText(
|
||||
new SimpleLineRangeMapping(m.lineRangeMapping.originalRange, newModifiedRange),
|
||||
applyModifiedEditsToLineRangeMappings(m.changes, textEdits, originalTextModel, modifiedTextModel),
|
||||
) : undefined;
|
||||
}).filter(isDefined);
|
||||
|
||||
return {
|
||||
identical: false,
|
||||
quitEarly: false,
|
||||
changes,
|
||||
moves,
|
||||
};
|
||||
}
|
||||
|
||||
function applyEditToLineRange(range: LineRange, textEdits: TextEditInfo[]): LineRange | undefined {
|
||||
let rangeStartLineNumber = range.startLineNumber;
|
||||
let rangeEndLineNumberEx = range.endLineNumberExclusive;
|
||||
|
||||
for (let i = textEdits.length - 1; i >= 0; i--) {
|
||||
const textEdit = textEdits[i];
|
||||
const textEditStartLineNumber = lengthGetLineCount(textEdit.startOffset) + 1;
|
||||
const textEditEndLineNumber = lengthGetLineCount(textEdit.endOffset) + 1;
|
||||
const newLengthLineCount = lengthGetLineCount(textEdit.newLength);
|
||||
const delta = newLengthLineCount - (textEditEndLineNumber - textEditStartLineNumber);
|
||||
|
||||
if (textEditEndLineNumber < rangeStartLineNumber) {
|
||||
// the text edit is before us
|
||||
rangeStartLineNumber += delta;
|
||||
rangeEndLineNumberEx += delta;
|
||||
} else if (textEditStartLineNumber > rangeEndLineNumberEx) {
|
||||
// the text edit is after us
|
||||
// NOOP
|
||||
} else if (textEditStartLineNumber < rangeStartLineNumber && rangeEndLineNumberEx < textEditEndLineNumber) {
|
||||
// the range is fully contained in the text edit
|
||||
return undefined;
|
||||
} else if (textEditStartLineNumber < rangeStartLineNumber && textEditEndLineNumber <= rangeEndLineNumberEx) {
|
||||
// the text edit ends inside our range
|
||||
rangeStartLineNumber = textEditEndLineNumber + 1;
|
||||
rangeStartLineNumber += delta;
|
||||
rangeEndLineNumberEx += delta;
|
||||
} else if (rangeStartLineNumber <= textEditStartLineNumber && textEditEndLineNumber < rangeStartLineNumber) {
|
||||
// the text edit starts inside our range
|
||||
rangeEndLineNumberEx = textEditStartLineNumber;
|
||||
} else {
|
||||
rangeEndLineNumberEx += delta;
|
||||
}
|
||||
}
|
||||
|
||||
return new LineRange(rangeStartLineNumber, rangeEndLineNumberEx);
|
||||
}
|
||||
|
||||
function applyModifiedEditsToLineRangeMappings(changes: readonly LineRangeMapping[], textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): LineRangeMapping[] {
|
||||
const diffTextEdits = changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(
|
||||
positionToLength(c.originalRange.getStartPosition()),
|
||||
positionToLength(c.originalRange.getEndPosition()),
|
||||
lengthOfRange(c.modifiedRange).toLength(),
|
||||
@@ -376,16 +428,10 @@ function applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], orig
|
||||
);
|
||||
});
|
||||
|
||||
const changes = lineRangeMappingFromRangeMappings(
|
||||
const newChanges = lineRangeMappingFromRangeMappings(
|
||||
rangeMappings,
|
||||
originalTextModel.getLinesContent(),
|
||||
modifiedTextModel.getLinesContent(),
|
||||
);
|
||||
|
||||
return {
|
||||
identical: false,
|
||||
quitEarly: false,
|
||||
changes,
|
||||
moves: [],
|
||||
};
|
||||
return newChanges;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,9 @@ export class MovedBlocksLinesPart extends Disposable {
|
||||
const originalScrollTop = observableFromEvent(this._originalEditor.onDidScrollChange, () => this._originalEditor.getScrollTop());
|
||||
const modifiedScrollTop = observableFromEvent(this._modifiedEditor.onDidScrollChange, () => this._modifiedEditor.getScrollTop());
|
||||
|
||||
|
||||
this._register(autorun('update', (reader) => {
|
||||
element.replaceChildren();
|
||||
|
||||
const info = this._originalEditorLayoutInfo.read(reader);
|
||||
const info2 = this._modifiedEditorLayoutInfo.read(reader);
|
||||
if (!info || !info2) {
|
||||
@@ -56,8 +57,6 @@ export class MovedBlocksLinesPart extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
element.replaceChildren();
|
||||
|
||||
let idx = 0;
|
||||
for (const m of moves) {
|
||||
function computeLineStart(range: LineRange, editor: ICodeEditor) {
|
||||
|
||||
@@ -28,8 +28,8 @@ export class UnchangedRangesFeature extends Disposable {
|
||||
const m = this._diffModel.get();
|
||||
transaction(tx => {
|
||||
for (const s of this._originalEditor.getSelections() || []) {
|
||||
m?.revealOriginalLine(s.getStartPosition().lineNumber, tx);
|
||||
m?.revealOriginalLine(s.getEndPosition().lineNumber, tx);
|
||||
m?.ensureOriginalLineIsVisible(s.getStartPosition().lineNumber, tx);
|
||||
m?.ensureOriginalLineIsVisible(s.getEndPosition().lineNumber, tx);
|
||||
}
|
||||
});
|
||||
}));
|
||||
@@ -38,8 +38,8 @@ export class UnchangedRangesFeature extends Disposable {
|
||||
const m = this._diffModel.get();
|
||||
transaction(tx => {
|
||||
for (const s of this._modifiedEditor.getSelections() || []) {
|
||||
m?.revealModifiedLine(s.getStartPosition().lineNumber, tx);
|
||||
m?.revealModifiedLine(s.getEndPosition().lineNumber, tx);
|
||||
m?.ensureModifiedLineIsVisible(s.getStartPosition().lineNumber, tx);
|
||||
m?.ensureModifiedLineIsVisible(s.getEndPosition().lineNumber, tx);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -20,6 +20,8 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
private diffAlgorithm: DiffAlgorithmName | IDocumentDiffProvider = 'advanced';
|
||||
private diffAlgorithmOnDidChangeSubscription: IDisposable | undefined = undefined;
|
||||
|
||||
private static readonly diffCache = new Map<string, { result: IDocumentDiff; context: string }>();
|
||||
|
||||
constructor(
|
||||
options: IWorkerBasedDocumentDiffProviderOptions,
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
|
||||
@@ -58,6 +60,13 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
};
|
||||
}
|
||||
|
||||
const uriKey = JSON.stringify([original.uri.toString(), modified.uri.toString()]);
|
||||
const context = JSON.stringify([original.id, modified.id, original.getAlternativeVersionId(), modified.getAlternativeVersionId(), JSON.stringify(options)]);
|
||||
const c = WorkerBasedDocumentDiffProvider.diffCache.get(uriKey);
|
||||
if (c && c.context === context) {
|
||||
return c.result;
|
||||
}
|
||||
|
||||
const sw = StopWatch.create(true);
|
||||
const result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options, this.diffAlgorithm);
|
||||
const timeMs = sw.elapsed();
|
||||
@@ -81,6 +90,12 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
throw new Error('no diff result available');
|
||||
}
|
||||
|
||||
// max 10 items in cache
|
||||
if (WorkerBasedDocumentDiffProvider.diffCache.size > 10) {
|
||||
WorkerBasedDocumentDiffProvider.diffCache.delete(WorkerBasedDocumentDiffProvider.diffCache.keys().next().value);
|
||||
}
|
||||
|
||||
WorkerBasedDocumentDiffProvider.diffCache.set(uriKey, { result, context });
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,10 @@ export class LineRangeMapping {
|
||||
public get changedLineCount() {
|
||||
return Math.max(this.originalRange.length, this.modifiedRange.length);
|
||||
}
|
||||
|
||||
public flip(): LineRangeMapping {
|
||||
return new LineRangeMapping(this.modifiedRange, this.originalRange, this.innerChanges?.map(c => c.flip()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +134,10 @@ export class RangeMapping {
|
||||
public toString(): string {
|
||||
return `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`;
|
||||
}
|
||||
|
||||
public flip(): RangeMapping {
|
||||
return new RangeMapping(this.modifiedRange, this.originalRange);
|
||||
}
|
||||
}
|
||||
|
||||
export class SimpleLineRangeMapping {
|
||||
@@ -142,6 +150,10 @@ export class SimpleLineRangeMapping {
|
||||
public toString(): string {
|
||||
return `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`;
|
||||
}
|
||||
|
||||
public flip(): SimpleLineRangeMapping {
|
||||
return new SimpleLineRangeMapping(this.modifiedRange, this.originalRange);
|
||||
}
|
||||
}
|
||||
|
||||
export class MovedText {
|
||||
@@ -161,4 +173,8 @@ export class MovedText {
|
||||
this.lineRangeMapping = lineRangeMapping;
|
||||
this.changes = changes;
|
||||
}
|
||||
|
||||
public flip(): MovedText {
|
||||
return new MovedText(this.lineRangeMapping.flip(), this.changes.map(c => c.flip()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,12 @@ export interface IDiffEditorModel {
|
||||
modified: ITextModel;
|
||||
}
|
||||
|
||||
export interface IDiffEditorViewModel {
|
||||
readonly model: IDiffEditorModel;
|
||||
|
||||
waitForDiff(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event describing that an editor has had its model reset (i.e. `editor.setModel()`).
|
||||
*/
|
||||
@@ -153,7 +159,7 @@ export interface IEditorAction {
|
||||
run(args?: unknown): Promise<void>;
|
||||
}
|
||||
|
||||
export type IEditorModel = ITextModel | IDiffEditorModel;
|
||||
export type IEditorModel = ITextModel | IDiffEditorModel | IDiffEditorViewModel;
|
||||
|
||||
/**
|
||||
* A (serializable) state of the cursors.
|
||||
|
||||
Vendored
+12
-2
@@ -2501,6 +2501,7 @@ declare namespace monaco.editor {
|
||||
constructor(originalRange: LineRange, modifiedRange: LineRange, innerChanges: RangeMapping[] | undefined);
|
||||
toString(): string;
|
||||
get changedLineCount(): any;
|
||||
flip(): LineRangeMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2517,6 +2518,7 @@ declare namespace monaco.editor {
|
||||
readonly modifiedRange: Range;
|
||||
constructor(originalRange: Range, modifiedRange: Range);
|
||||
toString(): string;
|
||||
flip(): RangeMapping;
|
||||
}
|
||||
|
||||
export class MovedText {
|
||||
@@ -2528,6 +2530,7 @@ declare namespace monaco.editor {
|
||||
*/
|
||||
readonly changes: readonly LineRangeMapping[];
|
||||
constructor(lineRangeMapping: SimpleLineRangeMapping, changes: readonly LineRangeMapping[]);
|
||||
flip(): MovedText;
|
||||
}
|
||||
|
||||
export class SimpleLineRangeMapping {
|
||||
@@ -2535,6 +2538,7 @@ declare namespace monaco.editor {
|
||||
readonly modifiedRange: LineRange;
|
||||
constructor(originalRange: LineRange, modifiedRange: LineRange);
|
||||
toString(): string;
|
||||
flip(): SimpleLineRangeMapping;
|
||||
}
|
||||
export interface IDimension {
|
||||
width: number;
|
||||
@@ -2619,6 +2623,11 @@ declare namespace monaco.editor {
|
||||
modified: ITextModel;
|
||||
}
|
||||
|
||||
export interface IDiffEditorViewModel {
|
||||
readonly model: IDiffEditorModel;
|
||||
waitForDiff(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event describing that an editor has had its model reset (i.e. `editor.setModel()`).
|
||||
*/
|
||||
@@ -2653,7 +2662,7 @@ declare namespace monaco.editor {
|
||||
run(args?: unknown): Promise<void>;
|
||||
}
|
||||
|
||||
export type IEditorModel = ITextModel | IDiffEditorModel;
|
||||
export type IEditorModel = ITextModel | IDiffEditorModel | IDiffEditorViewModel;
|
||||
|
||||
/**
|
||||
* A (serializable) state of the cursors.
|
||||
@@ -6022,6 +6031,7 @@ declare namespace monaco.editor {
|
||||
* Type the getModel() of IEditor.
|
||||
*/
|
||||
getModel(): IDiffEditorModel | null;
|
||||
createViewModel(model: IDiffEditorModel): IDiffEditorViewModel;
|
||||
/**
|
||||
* Sets the current model attached to this editor.
|
||||
* If the previous model was created by the editor via the value key in the options
|
||||
@@ -6030,7 +6040,7 @@ declare namespace monaco.editor {
|
||||
* will not be destroyed.
|
||||
* It is safe to call setModel(null) to simply detach the current model from the editor.
|
||||
*/
|
||||
setModel(model: IDiffEditorModel | null): void;
|
||||
setModel(model: IDiffEditorModel | IDiffEditorViewModel | null): void;
|
||||
/**
|
||||
* Get the `original` editor.
|
||||
*/
|
||||
|
||||
@@ -145,7 +145,7 @@ export async function main(desc: ProductDescription, args: string[]): Promise<vo
|
||||
// Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path zsh)"`
|
||||
case 'zsh': file = 'shellIntegration-rc.zsh'; break;
|
||||
// Usage: `string match -q "$TERM_PROGRAM" "vscode"; and . (code --locate-shell-integration-path fish)`
|
||||
case 'fish': file = 'shellIntegration.fish'; break;
|
||||
case 'fish': file = 'fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish'; break;
|
||||
default: throw new Error('Error using --locate-shell-integration-path: Invalid shell type');
|
||||
}
|
||||
console.log(resolve(__dirname, '../..', 'workbench', 'contrib', 'terminal', 'browser', 'media', file));
|
||||
|
||||
@@ -816,15 +816,12 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
}
|
||||
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: ExtHostTerminalIdentifier): number | null {
|
||||
let index: number | null = null;
|
||||
array.some((item, i) => {
|
||||
const thisId = item._id;
|
||||
if (thisId === id) {
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
const index = array.findIndex(item => {
|
||||
return item._id === id;
|
||||
});
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
||||
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
|
||||
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IRelativePatternDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { CellEditType, ICellPartialMetadataEdit, IDocumentMetadataEdit, isTextStreamMime } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellEditType, ICellMetadataEdit, IDocumentMetadataEdit, isTextStreamMime } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
@@ -775,7 +775,7 @@ export interface IFileSnippetTextEdit {
|
||||
export interface IFileCellEdit {
|
||||
readonly _type: FileEditType.Cell;
|
||||
readonly uri: URI;
|
||||
readonly edit?: ICellPartialMetadataEdit | IDocumentMetadataEdit;
|
||||
readonly edit?: ICellMetadataEdit | IDocumentMetadataEdit;
|
||||
readonly notebookMetadata?: Record<string, any>;
|
||||
readonly metadata?: vscode.WorkspaceEditEntryMetadata;
|
||||
}
|
||||
@@ -832,7 +832,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
}
|
||||
|
||||
private replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: Record<string, any>, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.PartialMetadata, index, metadata: cellMetadata } });
|
||||
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Metadata, index, metadata: cellMetadata } });
|
||||
}
|
||||
|
||||
// --- text
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
import { isObject, assertIsDefined, withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { isObject, assertIsDefined, withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { AbstractTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
@@ -133,7 +133,10 @@ export class TextDiffEditor extends AbstractTextEditor<IDiffEditorViewState> imp
|
||||
// Set Editor Model
|
||||
const control = assertIsDefined(this.diffEditorControl);
|
||||
const resolvedDiffEditorModel = resolvedModel as TextDiffEditorModel;
|
||||
control.setModel(withUndefinedAsNull(resolvedDiffEditorModel.textDiffEditorModel));
|
||||
|
||||
const vm = resolvedDiffEditorModel.textDiffEditorModel ? control.createViewModel(resolvedDiffEditorModel.textDiffEditorModel) : null;
|
||||
await vm?.waitForDiff();
|
||||
control.setModel(vm);
|
||||
|
||||
// Restore view state (unless provided by options)
|
||||
let hasPreviousViewState = false;
|
||||
|
||||
@@ -87,9 +87,9 @@
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.monaco-workbench .notifications-list-container .monaco-list:focus-within .notification-list-item .notification-list-item-toolbar-container,
|
||||
.monaco-workbench .notifications-list-container .notification-list-item:hover .notification-list-item-toolbar-container,
|
||||
.monaco-workbench .notifications-list-container .monaco-list-row.focused .notification-list-item .notification-list-item-toolbar-container,
|
||||
.monaco-workbench .notifications-list-container .notification-list-item.expanded .notification-list-item-toolbar-container {
|
||||
.monaco-workbench .notifications-list-container .monaco-list-row.focused .notification-list-item .notification-list-item-toolbar-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,22 +13,26 @@ import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
|
||||
|
||||
|
||||
const inputBox = localize('chat.requestHistory', 'In the input box, use up and down arrows to navigate your request history. Edit input and use enter or the submit button to run a new request.');
|
||||
|
||||
export function getAccessibilityHelpText(accessor: ServicesAccessor, type: 'chat' | 'inline'): string {
|
||||
const keybindingService = accessor.get(IKeybindingService);
|
||||
const content = [];
|
||||
if (type === 'chat') {
|
||||
content.push(localize('chat.overview', 'Chat responses will be announced as they come in. A response will indicate the number of code blocks, if any, and then the rest of the response.'));
|
||||
content.push(localize('chat.requestHistory', 'In the input box, use up and down arrows to navigate your request history. Edit input and use enter to run a new request.'));
|
||||
content.push(descriptionForCommand('chat.action.focus', localize('workbench.action.chat.focus', 'The Focus Chat command ({0}) focuses the chat request/response list, which can be navigated with UpArrow/DownArrow.',), localize('workbench.action.chat.focusNoKb', 'The Focus Chat List command focuses the chat request/response list, which can be navigated with UpArrow/DownArrow and is currently not triggerable by a keybinding.'), keybindingService));
|
||||
content.push(localize('chat.overview', 'The chat view is comprised of an input box and a request/response list. The input box is used to make requests and the list is used to display responses.'));
|
||||
content.push(inputBox);
|
||||
content.push(localize('chat.announcement', 'Chat responses will be announced as they come in. A response will indicate the number of code blocks, if any, and then the rest of the response.'));
|
||||
content.push(descriptionForCommand('chat.action.focus', localize('workbench.action.chat.focus', 'The Focus Chat command ({0}) focuses the chat request/response list, which can be navigated with up and down arrows.',), localize('workbench.action.chat.focusNoKb', 'The Focus Chat List command focuses the chat request/response list, which can be navigated with UpArrow/DownArrow and is currently not triggerable by a keybinding.'), keybindingService));
|
||||
content.push(descriptionForCommand('workbench.action.chat.focusInput', localize('workbench.action.chat.focusInput', 'The Focus Chat Input command ({0}) focuses the input box for chat requests.'), localize('workbench.action.interactiveSession.focusInputNoKb', 'Focus Chat Input command focuses the input box for chat requests and is currently not triggerable by a keybinding.'), keybindingService));
|
||||
content.push(descriptionForCommand('workbench.action.chat.nextCodeBlock', localize('workbench.action.chat.nextCodeBlock', 'The Chat: Next Code Block command ({0}) focuses the next code block within a response.'), localize('workbench.action.chat.nextCodeBlockNoKb', 'The Chat: Next Code Block command focuses the next code block within a response and is currently not triggerable by a keybinding.'), keybindingService));
|
||||
content.push(descriptionForCommand('workbench.action.chat.clear', localize('workbench.action.chat.clear', 'The Chat Clear command ({0}) clears the request/response list.'), localize('workbench.action.chat.clearNoKb', 'The Chat Clear command clears the request/response list and is currently not triggerable by a keybinding.'), keybindingService));
|
||||
} else {
|
||||
const startChatKeybinding = keybindingService.lookupKeybinding('inlineChat.start')?.getAriaLabel();
|
||||
content.push(localize('inlineChat.overview', "Inline chat occurs within a code editor and takes into account current selection. It is useful for refactoring, fixing, and more. Keep in mind that Copilot generated code may be incorrect."));
|
||||
content.push(localize('inlineChat.access', "It can be activated via the Fix and Explain with Copilot context menu actions or directly using the command: Inline Chat: Start Code Chat ({0}).", startChatKeybinding));
|
||||
content.push(localize('chat.requestHistoryInline', 'In the input box, use up and down arrows to navigate your request history. Edit input and use enter or the make request button to run a new request.'));
|
||||
content.push(localize('inlineChat.contextActions', "Explain and Fix with Copilot actions run a request prefixed with /fix or /explain. These prefixes can be used directly in the input box to apply those specific actions."));
|
||||
content.push(localize('inlineChat.overview', "Inline chat occurs within a code editor and takes into account the current selection. It is useful for refactoring, fixing, and more. Keep in mind that AI generated code may be incorrect."));
|
||||
content.push(localize('inlineChat.access', "It can be activated via quick fix actions or directly using the command: Inline Chat: Start Code Chat ({0}).", startChatKeybinding));
|
||||
content.push(inputBox);
|
||||
content.push(localize('inlineChat.contextActions', "Context menu actions may run a request prefixed with /fix or /explain. These prefixes can be used directly in the input box to apply those specific actions."));
|
||||
content.push(localize('inlineChat.fix', "When a request is prefixed with /fix, a response will indicate the problem with the current code. A diff editor will be rendered and can be reached by tabbing."));
|
||||
const diffReviewKeybinding = keybindingService.lookupKeybinding('editor.action.diffReview.next')?.getAriaLabel();
|
||||
content.push(diffReviewKeybinding ? localize('inlineChat.diff', "Once in the diff editor, enter review mode with ({0}). Use up and down arrows to navigate lines with the proposed changes.", diffReviewKeybinding) : localize('inlineChat.diffNoKb', "Tab again to enter the Diff editor with the changes and enter review mode with the Go to Next Difference Command. Use Up/DownArrow to navigate lines with the proposed changes."));
|
||||
|
||||
@@ -82,8 +82,8 @@
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.interactive-item-container .header .monaco-toolbar .checked .action-label,
|
||||
.interactive-item-container .header .monaco-toolbar .checked .action-label:hover {
|
||||
.interactive-item-container .header .monaco-toolbar .checked.action-label,
|
||||
.interactive-item-container .header .monaco-toolbar .checked.action-label:hover {
|
||||
color: var(--vscode-inputOption-activeForeground) !important;
|
||||
border-color: var(--vscode-inputOption-activeBorder);
|
||||
background-color: var(--vscode-inputOption-activeBackground);
|
||||
|
||||
@@ -707,14 +707,15 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
|
||||
|
||||
hasEdits = true;
|
||||
|
||||
const contents = encodeBase64((await this.fileService.readFile(uri)).value);
|
||||
editSessionSize += contents.length;
|
||||
if (editSessionSize > this.editSessionsStorageService.SIZE_LIMIT) {
|
||||
this.notificationService.error(localize('payload too large', 'Your working changes exceed the size limit and cannot be stored.'));
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (await this.fileService.exists(uri)) {
|
||||
const contents = encodeBase64((await this.fileService.readFile(uri)).value);
|
||||
editSessionSize += contents.length;
|
||||
if (editSessionSize > this.editSessionsStorageService.SIZE_LIMIT) {
|
||||
this.notificationService.error(localize('payload too large', 'Your working changes exceed the size limit and cannot be stored.'));
|
||||
return undefined;
|
||||
}
|
||||
|
||||
workingChanges.push({ type: ChangeType.Addition, fileType: FileType.File, contents: contents, relativeFilePath: relativeFilePath });
|
||||
} else {
|
||||
// Assume it's a deletion
|
||||
|
||||
@@ -33,7 +33,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
|
||||
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
public readonly SIZE_LIMIT = 1024 * 1024 * 2; // 2 MB
|
||||
public readonly SIZE_LIMIT = Math.floor(1024 * 1024 * 1.9); // 2 MB
|
||||
|
||||
private serverConfiguration = this.productService['editSessions.store'];
|
||||
private machineClient: IUserDataSyncMachinesService | undefined;
|
||||
|
||||
@@ -26,6 +26,7 @@ registerAction2(InlineChatActions.StartSessionAction);
|
||||
registerAction2(InlineChatActions.UnstashSessionAction);
|
||||
registerAction2(InlineChatActions.MakeRequestAction);
|
||||
registerAction2(InlineChatActions.StopRequestAction);
|
||||
registerAction2(InlineChatActions.ReRunRequestAction);
|
||||
registerAction2(InlineChatActions.DiscardAction);
|
||||
registerAction2(InlineChatActions.DiscardToClipboardAction);
|
||||
registerAction2(InlineChatActions.DiscardUndoToNewFileAction);
|
||||
|
||||
@@ -159,6 +159,28 @@ export class MakeRequestAction extends AbstractInlineChatAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class ReRunRequestAction extends AbstractInlineChatAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'inlineChat.regenerate',
|
||||
title: localize('rerun', 'Regenerate Response'),
|
||||
icon: Codicon.refresh,
|
||||
precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_EMPTY.negate(), CTX_INLINE_CHAT_LAST_RESPONSE_TYPE),
|
||||
menu: {
|
||||
id: MENU_INLINE_CHAT_WIDGET_STATUS,
|
||||
group: '0_main',
|
||||
order: 1,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
override runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController): void {
|
||||
ctrl.regenerate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class StopRequestAction extends AbstractInlineChatAction {
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EditResponse, EmptyResponse, ErrorResponse, ExpansionState, IInlineChatSessionService, MarkdownResponse, Session, SessionExchange } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession';
|
||||
import { EditResponse, EmptyResponse, ErrorResponse, ExpansionState, IInlineChatSessionService, MarkdownResponse, Session, SessionExchange, SessionPrompt } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession';
|
||||
import { EditModeStrategy, LivePreviewStrategy, LiveStrategy, PreviewStrategy } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies';
|
||||
import { InlineChatZoneWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget';
|
||||
import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_LAST_FEEDBACK, IInlineChatRequest, IInlineChatResponse, INLINE_CHAT_ID, EditMode, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, InlineChatResponseType, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
@@ -58,7 +58,8 @@ const enum Message {
|
||||
PAUSE_SESSION = 1 << 2,
|
||||
CANCEL_REQUEST = 1 << 3,
|
||||
CANCEL_INPUT = 1 << 4,
|
||||
ACCEPT_INPUT = 1 << 5
|
||||
ACCEPT_INPUT = 1 << 5,
|
||||
RERUN_INPUT = 1 << 6,
|
||||
}
|
||||
|
||||
export interface InlineChatRunOptions {
|
||||
@@ -196,14 +197,15 @@ export class InlineChatController implements IEditorContribution {
|
||||
private _showWidget(initialRender: boolean = false) {
|
||||
assertType(this._activeSession);
|
||||
assertType(this._strategy);
|
||||
assertType(this._editor.hasModel());
|
||||
|
||||
let widgetPosition: Position | null;
|
||||
let widgetPosition: Position | undefined;
|
||||
if (initialRender) {
|
||||
widgetPosition = this._editor.getPosition();
|
||||
} else {
|
||||
widgetPosition = this._strategy.getWidgetPosition();
|
||||
widgetPosition = this._strategy.getWidgetPosition() ?? this._zone.value.position ?? this._activeSession.wholeRange.value.getEndPosition();
|
||||
}
|
||||
const position = ((widgetPosition ?? this._zone.value.position) ?? this._activeSession.wholeRange.value.getEndPosition());
|
||||
const position = (widgetPosition);
|
||||
this._zone.value.show(position);
|
||||
if (initialRender) {
|
||||
this._zone.value.setMargins(position);
|
||||
@@ -284,7 +286,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
|
||||
this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []);
|
||||
this._zone.value.widget.placeholder = this._getPlaceholderText();
|
||||
this._zone.value.widget.value = this._activeSession.lastInput ?? '';
|
||||
this._zone.value.widget.value = this._activeSession.lastInput?.value ?? '';
|
||||
this._zone.value.widget.updateInfo(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect"));
|
||||
this._zone.value.widget.preferredExpansionState = this._activeSession.lastExpansionState;
|
||||
this._showWidget(true);
|
||||
@@ -374,6 +376,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
|
||||
private async [State.WAIT_FOR_INPUT](options: InlineChatRunOptions | undefined): Promise<State.ACCEPT | State.CANCEL | State.PAUSE | State.WAIT_FOR_INPUT | State.MAKE_REQUEST> {
|
||||
assertType(this._activeSession);
|
||||
assertType(this._strategy);
|
||||
|
||||
this._zone.value.widget.placeholder = this._getPlaceholderText();
|
||||
|
||||
@@ -413,6 +416,15 @@ export class InlineChatController implements IEditorContribution {
|
||||
return State.PAUSE;
|
||||
}
|
||||
|
||||
if (message & Message.RERUN_INPUT && this._activeSession.lastExchange) {
|
||||
const { lastExchange } = this._activeSession;
|
||||
this._activeSession.addInput(lastExchange.prompt.retry());
|
||||
if (lastExchange.response instanceof EditResponse) {
|
||||
await this._strategy.undoChanges(lastExchange.response);
|
||||
}
|
||||
return State.MAKE_REQUEST;
|
||||
}
|
||||
|
||||
if (!this._zone.value.widget.value) {
|
||||
return State.WAIT_FOR_INPUT;
|
||||
}
|
||||
@@ -436,7 +448,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
return State.WAIT_FOR_INPUT;
|
||||
}
|
||||
|
||||
this._activeSession.addInput(input);
|
||||
this._activeSession.addInput(new SessionPrompt(input));
|
||||
return State.MAKE_REQUEST;
|
||||
}
|
||||
|
||||
@@ -460,10 +472,10 @@ export class InlineChatController implements IEditorContribution {
|
||||
|
||||
const sw = StopWatch.create();
|
||||
const request: IInlineChatRequest = {
|
||||
prompt: this._activeSession.lastInput,
|
||||
prompt: this._activeSession.lastInput.value,
|
||||
attempt: this._activeSession.lastInput.attempt,
|
||||
selection: this._editor.getSelection(),
|
||||
wholeRange: this._activeSession.wholeRange.value,
|
||||
attempt: 0,
|
||||
};
|
||||
const task = this._activeSession.provider.provideResponse(this._activeSession.session, request, requestCts.token);
|
||||
this._log('request started', this._activeSession.provider.debugName, this._activeSession.session, request);
|
||||
@@ -479,7 +491,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
if (reply?.type === 'message') {
|
||||
response = new MarkdownResponse(this._activeSession.textModelN.uri, reply);
|
||||
} else if (reply) {
|
||||
response = new EditResponse(this._activeSession.textModelN.uri, reply);
|
||||
response = new EditResponse(this._activeSession.textModelN.uri, this._activeSession.textModelN.getAlternativeVersionId(), reply);
|
||||
} else {
|
||||
response = new EmptyResponse();
|
||||
}
|
||||
@@ -499,7 +511,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
msgListener.dispose();
|
||||
typeListener.dispose();
|
||||
|
||||
this._activeSession.addExchange(new SessionExchange(request.prompt, response));
|
||||
this._activeSession.addExchange(new SessionExchange(this._activeSession.lastInput, response));
|
||||
|
||||
if (message & Message.CANCEL_SESSION) {
|
||||
return State.CANCEL;
|
||||
@@ -663,6 +675,10 @@ export class InlineChatController implements IEditorContribution {
|
||||
this._messages.fire(Message.ACCEPT_INPUT);
|
||||
}
|
||||
|
||||
regenerate(): void {
|
||||
this._messages.fire(Message.RERUN_INPUT);
|
||||
}
|
||||
|
||||
cancelCurrentRequest(): void {
|
||||
this._messages.fire(Message.CANCEL_INPUT | Message.CANCEL_REQUEST);
|
||||
}
|
||||
@@ -700,7 +716,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
|
||||
viewInChat() {
|
||||
if (this._activeSession?.lastExchange?.response instanceof MarkdownResponse) {
|
||||
this._instaService.invokeFunction(showMessageResponse, this._activeSession.lastExchange.prompt, this._activeSession.lastExchange.response.raw.message.value);
|
||||
this._instaService.invokeFunction(showMessageResponse, this._activeSession.lastExchange.prompt.value, this._activeSession.lastExchange.response.raw.message.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
private readonly _inlineDiffDecorations: IEditorDecorationsCollection;
|
||||
private _dim: Dimension | undefined;
|
||||
private _isVisible: boolean = false;
|
||||
private _isDiffLocked: boolean = false;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@@ -134,6 +135,8 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
override show(): void {
|
||||
assertType(this.editor.hasModel());
|
||||
this._sessionStore.clear();
|
||||
this._isDiffLocked = false;
|
||||
this._isVisible = true;
|
||||
|
||||
this._sessionStore.add(this._diffEditor.onDidUpdateDiff(() => {
|
||||
const result = this._diffEditor.getDiffComputationResult();
|
||||
@@ -148,12 +151,19 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
}
|
||||
}));
|
||||
this._updateFromChanges(this._session.wholeRange.value, this._session.lastTextModelChanges);
|
||||
this._isVisible = true;
|
||||
}
|
||||
|
||||
lockToDiff(): void {
|
||||
this._isDiffLocked = true;
|
||||
}
|
||||
|
||||
private _updateFromChanges(range: Range, changes: readonly LineRangeMapping[]): void {
|
||||
assertType(this.editor.hasModel());
|
||||
|
||||
if (this._isDiffLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) {
|
||||
// no change or changes to an empty file
|
||||
this._logService.debug('[IE] livePreview-mode: no diff');
|
||||
|
||||
@@ -108,7 +108,7 @@ class SessionWholeRange {
|
||||
|
||||
export class Session {
|
||||
|
||||
private _lastInput: string | undefined;
|
||||
private _lastInput: SessionPrompt | undefined;
|
||||
private _lastExpansionState: ExpansionState | undefined;
|
||||
private _lastTextModelChanges: readonly LineRangeMapping[] | undefined;
|
||||
private _isUnstashed: boolean = false;
|
||||
@@ -139,10 +139,14 @@ export class Session {
|
||||
};
|
||||
}
|
||||
|
||||
addInput(input: string): void {
|
||||
addInput(input: SessionPrompt): void {
|
||||
this._lastInput = input;
|
||||
}
|
||||
|
||||
get lastInput() {
|
||||
return this._lastInput;
|
||||
}
|
||||
|
||||
get isUnstashed(): boolean {
|
||||
return this._isUnstashed;
|
||||
}
|
||||
@@ -151,10 +155,6 @@ export class Session {
|
||||
this._isUnstashed = true;
|
||||
}
|
||||
|
||||
get lastInput() {
|
||||
return this._lastInput;
|
||||
}
|
||||
|
||||
get lastExpansionState(): ExpansionState | undefined {
|
||||
return this._lastExpansionState;
|
||||
}
|
||||
@@ -229,7 +229,7 @@ export class Session {
|
||||
for (const exchange of this._exchange) {
|
||||
const response = exchange.response;
|
||||
if (response instanceof MarkdownResponse || response instanceof EditResponse) {
|
||||
result.exchanges.push({ prompt: exchange.prompt, res: response.raw });
|
||||
result.exchanges.push({ prompt: exchange.prompt.value, res: response.raw });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -237,9 +237,29 @@ export class Session {
|
||||
}
|
||||
|
||||
|
||||
export class SessionExchange {
|
||||
export class SessionPrompt {
|
||||
|
||||
private _attempt: number = 0;
|
||||
|
||||
constructor(
|
||||
readonly prompt: string,
|
||||
readonly value: string,
|
||||
) { }
|
||||
|
||||
get attempt() {
|
||||
return this._attempt;
|
||||
}
|
||||
|
||||
retry() {
|
||||
const result = new SessionPrompt(this.value);
|
||||
result._attempt = this._attempt + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export class SessionExchange {
|
||||
|
||||
constructor(
|
||||
readonly prompt: SessionPrompt,
|
||||
readonly response: MarkdownResponse | EditResponse | EmptyResponse | ErrorResponse
|
||||
) { }
|
||||
}
|
||||
@@ -275,7 +295,11 @@ export class EditResponse {
|
||||
readonly workspaceEdits: ResourceEdit[] | undefined;
|
||||
readonly workspaceEditsIncludeLocalEdits: boolean = false;
|
||||
|
||||
constructor(localUri: URI, readonly raw: IInlineChatBulkEditResponse | IInlineChatEditResponse) {
|
||||
constructor(
|
||||
localUri: URI,
|
||||
readonly modelAltVersionId: number,
|
||||
readonly raw: IInlineChatBulkEditResponse | IInlineChatEditResponse
|
||||
) {
|
||||
if (raw.type === 'editorEdit') {
|
||||
//
|
||||
this.localEdits = raw.edits;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
@@ -13,7 +14,7 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon';
|
||||
import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, IValidEditOperation } from 'vs/editor/common/model';
|
||||
import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -37,13 +38,15 @@ export abstract class EditModeStrategy {
|
||||
|
||||
abstract makeChanges(edits: ISingleEditOperation[]): Promise<void>;
|
||||
|
||||
abstract undoChanges(response: EditResponse): Promise<void>;
|
||||
|
||||
abstract renderChanges(response: EditResponse): Promise<void>;
|
||||
|
||||
abstract toggleDiff(): void;
|
||||
|
||||
abstract hasFocus(): boolean;
|
||||
|
||||
abstract getWidgetPosition(): Position | null;
|
||||
abstract getWidgetPosition(): Position | undefined;
|
||||
}
|
||||
|
||||
export class PreviewStrategy extends EditModeStrategy {
|
||||
@@ -112,6 +115,10 @@ export class PreviewStrategy extends EditModeStrategy {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
override async undoChanges(_response: EditResponse): Promise<void> {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
override async renderChanges(response: EditResponse): Promise<void> {
|
||||
if (response.localEdits.length > 0) {
|
||||
const edits = response.localEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text));
|
||||
@@ -131,8 +138,8 @@ export class PreviewStrategy extends EditModeStrategy {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
getWidgetPosition(): Position | null {
|
||||
return null;
|
||||
getWidgetPosition(): Position | undefined {
|
||||
return;
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
@@ -281,9 +288,7 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
return;
|
||||
}
|
||||
const targetAltVersion = textModelNSnapshotAltVersion ?? textModelNAltVersion;
|
||||
while (targetAltVersion < modelN.getAlternativeVersionId() && modelN.canUndo()) {
|
||||
modelN.undo();
|
||||
}
|
||||
LiveStrategy._undoModelUntil(modelN, targetAltVersion);
|
||||
}
|
||||
|
||||
override async makeChanges(edits: ISingleEditOperation[], ignoreInlineDiff?: boolean): Promise<void> {
|
||||
@@ -303,6 +308,11 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
this._editor.executeEdits('inline-chat-live', edits, ignoreInlineDiff ? undefined : cursorStateComputerAndInlineDiffCollection);
|
||||
}
|
||||
|
||||
override async undoChanges(response: EditResponse): Promise<void> {
|
||||
const { textModelN } = this._session;
|
||||
LiveStrategy._undoModelUntil(textModelN, response.modelAltVersionId);
|
||||
}
|
||||
|
||||
override async renderChanges(response: EditResponse) {
|
||||
|
||||
this._inlineDiffDecorations.update();
|
||||
@@ -315,6 +325,12 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
private static _undoModelUntil(model: ITextModel, targetAltVersion: number): void {
|
||||
while (targetAltVersion < model.getAlternativeVersionId() && model.canUndo()) {
|
||||
model.undo();
|
||||
}
|
||||
}
|
||||
|
||||
protected _updateSummaryMessage() {
|
||||
let linesChanged = 0;
|
||||
for (const change of this._session.lastTextModelChanges) {
|
||||
@@ -331,7 +347,7 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
this._widget.updateStatus(message);
|
||||
}
|
||||
|
||||
private _lastLineOfLocalEdits(): number | undefined {
|
||||
override getWidgetPosition(): Position | undefined {
|
||||
const lastTextModelChanges = this._session.lastTextModelChanges;
|
||||
let lastLineOfLocalEdits: number | undefined;
|
||||
for (const change of lastTextModelChanges) {
|
||||
@@ -340,16 +356,7 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
lastLineOfLocalEdits = changeEndLineNumber;
|
||||
}
|
||||
}
|
||||
return lastLineOfLocalEdits;
|
||||
}
|
||||
|
||||
override getWidgetPosition(): Position | null {
|
||||
const isEditResponse = this._session.lastExchange?.response instanceof EditResponse;
|
||||
if (isEditResponse) {
|
||||
const lastLineOfLocalEdits = this._lastLineOfLocalEdits();
|
||||
return lastLineOfLocalEdits ? new Position(lastLineOfLocalEdits, 1) : null;
|
||||
}
|
||||
return null;
|
||||
return lastLineOfLocalEdits ? new Position(lastLineOfLocalEdits, 1) : undefined;
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
@@ -359,8 +366,8 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
|
||||
export class LivePreviewStrategy extends LiveStrategy {
|
||||
|
||||
private readonly _diffZone: InlineChatLivePreviewWidget;
|
||||
private readonly _previewZone: InlineChatFileCreatePreviewWidget;
|
||||
private readonly _diffZone: Lazy<InlineChatLivePreviewWidget>;
|
||||
private readonly _previewZone: Lazy<InlineChatFileCreatePreviewWidget>;
|
||||
|
||||
constructor(
|
||||
session: Session,
|
||||
@@ -374,15 +381,15 @@ export class LivePreviewStrategy extends LiveStrategy {
|
||||
) {
|
||||
super(session, editor, widget, contextKeyService, storageService, bulkEditService, editorWorkerService, instaService);
|
||||
|
||||
this._diffZone = instaService.createInstance(InlineChatLivePreviewWidget, editor, session);
|
||||
this._previewZone = instaService.createInstance(InlineChatFileCreatePreviewWidget, editor);
|
||||
this._diffZone = new Lazy(() => instaService.createInstance(InlineChatLivePreviewWidget, editor, session));
|
||||
this._previewZone = new Lazy(() => instaService.createInstance(InlineChatFileCreatePreviewWidget, editor));
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this._diffZone.hide();
|
||||
this._diffZone.dispose();
|
||||
this._previewZone.hide();
|
||||
this._previewZone.dispose();
|
||||
this._diffZone.rawValue?.hide();
|
||||
this._diffZone.rawValue?.dispose();
|
||||
this._previewZone.rawValue?.hide();
|
||||
this._previewZone.rawValue?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -390,36 +397,33 @@ export class LivePreviewStrategy extends LiveStrategy {
|
||||
|
||||
this._updateSummaryMessage();
|
||||
if (this._diffEnabled) {
|
||||
this._diffZone.show();
|
||||
this._diffZone.value.show();
|
||||
}
|
||||
|
||||
if (response.singleCreateFileEdit) {
|
||||
this._previewZone.showCreation(this._session.wholeRange.value, response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits));
|
||||
this._previewZone.value.showCreation(this._session.wholeRange.value, response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits));
|
||||
} else {
|
||||
this._previewZone.hide();
|
||||
this._previewZone.value.hide();
|
||||
}
|
||||
}
|
||||
|
||||
override async undoChanges(response: EditResponse): Promise<void> {
|
||||
this._diffZone.value.lockToDiff();
|
||||
super.undoChanges(response);
|
||||
}
|
||||
|
||||
protected override _doToggleDiff(): void {
|
||||
const scrollState = StableEditorScrollState.capture(this._editor);
|
||||
if (this._diffEnabled) {
|
||||
this._diffZone.show();
|
||||
this._diffZone.value.show();
|
||||
} else {
|
||||
this._diffZone.hide();
|
||||
this._diffZone.value.hide();
|
||||
}
|
||||
scrollState.restore(this._editor);
|
||||
}
|
||||
|
||||
override getWidgetPosition(): Position | null {
|
||||
const isEditResponse = this._session.lastExchange?.response instanceof EditResponse;
|
||||
if (isEditResponse) {
|
||||
return this._session.wholeRange.value.getEndPosition();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
override hasFocus(): boolean {
|
||||
return super.hasFocus() || this._diffZone.hasFocus() || this._previewZone.hasFocus();
|
||||
return super.hasFocus() || this._diffZone.value.hasFocus() || this._previewZone.value.hasFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -321,7 +321,7 @@ class TimerCellStatusBarItem extends Disposable {
|
||||
return <INotebookCellStatusBarItem>{
|
||||
text: formatCellDuration(duration, false),
|
||||
alignment: CellStatusbarAlignment.Left,
|
||||
priority: Number.MAX_SAFE_INTEGER - 1,
|
||||
priority: Number.MAX_SAFE_INTEGER - 5,
|
||||
tooltip
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { isWorkspaceFolder, IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { settingsEditIcon, settingsScopeDropDownIcon } from 'vs/workbench/contrib/preferences/browser/preferencesIcons';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { CONTEXT_SETTINGS_EDITOR_IN_USER_TAB } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
|
||||
@@ -52,7 +51,6 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem {
|
||||
action: IAction,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
) {
|
||||
super(null, action);
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
@@ -142,14 +140,14 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
private async update(): Promise<void> {
|
||||
private update(): void {
|
||||
let total = 0;
|
||||
this._folderSettingCounts.forEach(n => total += n);
|
||||
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
if (this._folder) {
|
||||
this.labelElement.textContent = this._folder.name;
|
||||
this.anchorElement.title = (await this.preferencesService.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, this._folder.uri))?.fsPath || '';
|
||||
this.anchorElement.title = this._folder.name;
|
||||
const detailsText = this.labelWithCount(this._action.label, total);
|
||||
this.detailsElement.textContent = detailsText;
|
||||
this.dropDownElement.classList.toggle('hide', workspace.folders.length === 1 || !this._action.checked);
|
||||
@@ -233,7 +231,6 @@ export class SettingsTargetsWidget extends Widget {
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
@ILanguageService private readonly languageService: ILanguageService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
) {
|
||||
@@ -265,15 +262,12 @@ export class SettingsTargetsWidget extends Widget {
|
||||
}));
|
||||
|
||||
this.userLocalSettings = new Action('userSettings', '', '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL));
|
||||
this.preferencesService.getEditableSettingsURI(ConfigurationTarget.USER_LOCAL).then(uri => {
|
||||
// Don't wait to create UI on resolving remote
|
||||
this.userLocalSettings.tooltip = uri?.fsPath ?? '';
|
||||
});
|
||||
this.userLocalSettings.tooltip = localize('userSettings', "User");
|
||||
|
||||
this.userRemoteSettings = new Action('userSettingsRemote', '', '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE));
|
||||
this.preferencesService.getEditableSettingsURI(ConfigurationTarget.USER_REMOTE).then(uri => {
|
||||
this.userRemoteSettings.tooltip = uri?.fsPath ?? '';
|
||||
});
|
||||
const remoteAuthority = this.environmentService.remoteAuthority;
|
||||
const hostLabel = remoteAuthority && this.labelService.getHostLabel(Schemas.vscodeRemote, remoteAuthority);
|
||||
this.userRemoteSettings.tooltip = localize('userSettingsRemote', "Remote") + (hostLabel ? ` [${hostLabel}]` : '');
|
||||
|
||||
this.workspaceSettings = new Action('workspaceSettings', '', '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE));
|
||||
|
||||
@@ -368,7 +362,7 @@ export class SettingsTargetsWidget extends Widget {
|
||||
this.workspaceSettings.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY;
|
||||
this.folderSettings.action.enabled = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.contextService.getWorkspace().folders.length > 0;
|
||||
|
||||
this.workspaceSettings.tooltip = (await this.preferencesService.getEditableSettingsURI(ConfigurationTarget.WORKSPACE))?.fsPath || '';
|
||||
this.workspaceSettings.tooltip = localize('workspaceSettings', "Workspace");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user