Skip to content

Commit 3a2b682

Browse files
committed
[vscode] implement proposed.textEditorDiffInformation API
Resolves GH-16278 Contributed on behalf of STMicroelectronics
1 parent 2bbbe4e commit 3a2b682

File tree

6 files changed

+189
-2
lines changed

6 files changed

+189
-2
lines changed

packages/plugin-ext/src/plugin/plugin-context.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ import {
241241
TerminalCompletionList,
242242
McpHttpServerDefinition,
243243
McpStdioServerDefinition,
244-
InteractiveWindowInput
244+
InteractiveWindowInput,
245+
TextEditorChangeKind
245246
} from './types-impl';
246247
import { AuthenticationExtImpl } from './authentication-ext';
247248
import { SymbolKind } from '../common/plugin-api-rpc-model';
@@ -478,6 +479,9 @@ export function createAPIFactory(
478479
onDidChangeTextEditorSelection(listener, thisArg?, disposables?) {
479480
return editors.onDidChangeTextEditorSelection(listener, thisArg, disposables);
480481
},
482+
onDidChangeTextEditorDiffInformation(listener, thisArg?, disposables?) {
483+
return editors.onDidChangeTextEditorDiffInformation(listener, thisArg, disposables);
484+
},
481485
onDidChangeTextEditorOptions(listener, thisArg?, disposables?) {
482486
return editors.onDidChangeTextEditorOptions(listener, thisArg, disposables);
483487
},
@@ -1621,6 +1625,7 @@ export function createAPIFactory(
16211625
McpHttpServerDefinition,
16221626
McpStdioServerDefinition,
16231627
TabInputInteractiveWindow: InteractiveWindowInput,
1628+
TextEditorChangeKind
16241629
};
16251630
};
16261631
}

packages/plugin-ext/src/plugin/text-editor.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export class TextEditorExt implements theia.TextEditor {
2727
private _viewColumn: theia.ViewColumn | undefined;
2828
private _document: DocumentDataExt;
2929
private _options: TextEditorOptionsExt;
30+
private _diffInformation: theia.TextEditorDiffInformation[] | undefined;
31+
3032
private disposed = false;
3133
constructor(
3234
private readonly proxy: TextEditorsMain,
@@ -278,6 +280,15 @@ export class TextEditorExt implements theia.TextEditor {
278280
getDiffInformation(): Promise<theia.LineChange[]> {
279281
return this.proxy.$getDiffInformation(this.id);
280282
}
283+
284+
_acceptDiffInformation(diffInformation: theia.TextEditorDiffInformation[] | undefined): void {
285+
// ok(!this._disposed);
286+
this._diffInformation = diffInformation;
287+
}
288+
289+
get diffInformation(): theia.TextEditorDiffInformation[] | undefined {
290+
return this._diffInformation;
291+
}
281292
}
282293

283294
export class TextEditorOptionsExt implements theia.TextEditorOptions {

packages/plugin-ext/src/plugin/text-editors.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,23 @@ import { Emitter, Event } from '@theia/core/lib/common/event';
2121
import { EditorsAndDocumentsExtImpl } from './editors-and-documents';
2222
import { TextEditorExt } from './text-editor';
2323
import * as Converters from './type-converters';
24-
import { TextEditorSelectionChangeKind, URI } from './types-impl';
24+
import { TextEditorChangeKind, TextEditorSelectionChangeKind, URI } from './types-impl';
2525
import { IdGenerator } from '../common/id-generator';
2626

2727
export class TextEditorsExtImpl implements TextEditorsExt {
2828
private readonly _onDidChangeTextEditorSelection = new Emitter<theia.TextEditorSelectionChangeEvent>();
2929
private readonly _onDidChangeTextEditorOptions = new Emitter<theia.TextEditorOptionsChangeEvent>();
3030
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<theia.TextEditorVisibleRangesChangeEvent>();
3131
private readonly _onDidChangeTextEditorViewColumn = new Emitter<theia.TextEditorViewColumnChangeEvent>();
32+
private readonly _onDidChangeTextEditorDiffInformation = new Emitter<theia.TextEditorDiffInformationChangeEvent>();
3233
private readonly _onDidChangeActiveTextEditor = new Emitter<theia.TextEditor | undefined>();
3334
private readonly _onDidChangeVisibleTextEditors = new Emitter<theia.TextEditor[]>();
3435

3536
readonly onDidChangeTextEditorSelection: Event<theia.TextEditorSelectionChangeEvent> = this._onDidChangeTextEditorSelection.event;
3637
readonly onDidChangeTextEditorOptions = this._onDidChangeTextEditorOptions.event;
3738
readonly onDidChangeTextEditorVisibleRanges = this._onDidChangeTextEditorVisibleRanges.event;
3839
readonly onDidChangeTextEditorViewColumn = this._onDidChangeTextEditorViewColumn.event;
40+
readonly onDidChangeTextEditorDiffInformation = this._onDidChangeTextEditorDiffInformation.event;
3941
readonly onDidChangeActiveTextEditor = this._onDidChangeActiveTextEditor.event;
4042
readonly onDidChangeVisibleTextEditors = this._onDidChangeVisibleTextEditors.event;
4143

@@ -118,6 +120,73 @@ export class TextEditorsExtImpl implements TextEditorsExt {
118120
return activeEditor.getDiffInformation();
119121
}
120122

123+
$acceptEditorDiffInformation(id: string, diffInformation: theia.TextEditorDiffInformation[] | undefined): void {
124+
const textEditor = this.editorsAndDocuments.getEditor(id);
125+
if (!textEditor) {
126+
throw new Error('unknown text editor');
127+
}
128+
129+
if (!diffInformation) {
130+
textEditor._acceptDiffInformation(undefined);
131+
this._onDidChangeTextEditorDiffInformation.fire({
132+
textEditor: textEditor,
133+
diffInformation: undefined
134+
});
135+
return;
136+
}
137+
138+
const that = this;
139+
const result = diffInformation.map(diff => {
140+
const original = URI.revive(diff.original);
141+
const modified = URI.revive(diff.modified);
142+
143+
const changes = diff.changes.map(change => {
144+
const originalStartLineNumber = change.original.startLineNumber;
145+
const originalEndLineNumberExclusive = change.original.endLineNumberExclusive;
146+
const modifiedStartLineNumber = change.modified.startLineNumber;
147+
const modifiedEndLineNumberExclusive = change.modified.endLineNumberExclusive;
148+
149+
let kind: TextEditorChangeKind;
150+
if (change.original.startLineNumber === originalEndLineNumberExclusive) {
151+
kind = TextEditorChangeKind.Addition;
152+
} else if (modifiedStartLineNumber === modifiedEndLineNumberExclusive) {
153+
kind = TextEditorChangeKind.Deletion;
154+
} else {
155+
kind = TextEditorChangeKind.Modification;
156+
}
157+
158+
return {
159+
original: {
160+
startLineNumber: originalStartLineNumber,
161+
endLineNumberExclusive: originalEndLineNumberExclusive
162+
},
163+
modified: {
164+
startLineNumber: modifiedStartLineNumber,
165+
endLineNumberExclusive: modifiedEndLineNumberExclusive
166+
},
167+
kind
168+
} satisfies theia.TextEditorChange;
169+
});
170+
171+
return Object.freeze({
172+
documentVersion: diff.documentVersion,
173+
original,
174+
modified,
175+
changes,
176+
get isStale(): boolean {
177+
const document = that.editorsAndDocuments.getDocument(modified.toString());
178+
return document?.document.version !== diff.documentVersion;
179+
}
180+
});
181+
});
182+
183+
textEditor._acceptDiffInformation(result);
184+
this._onDidChangeTextEditorDiffInformation.fire({
185+
textEditor: textEditor,
186+
diffInformation: result
187+
});
188+
}
189+
121190
getVisibleTextEditors(): theia.TextEditor[] {
122191
return this.editorsAndDocuments.allEditors();
123192
}

packages/plugin-ext/src/plugin/types-impl.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4320,3 +4320,40 @@ export class McpHttpServerDefinition {
43204320
*/
43214321
export type McpServerDefinition = McpStdioServerDefinition | McpHttpServerDefinition;
43224322

4323+
// #region textEditorDiffInformation
4324+
4325+
export enum TextEditorChangeKind {
4326+
Addition = 1,
4327+
Deletion = 2,
4328+
Modification = 3
4329+
}
4330+
4331+
export interface TextEditorLineRange {
4332+
readonly startLineNumber: number;
4333+
readonly endLineNumberExclusive: number;
4334+
}
4335+
4336+
export interface TextEditorChange {
4337+
readonly original: TextEditorLineRange;
4338+
readonly modified: TextEditorLineRange;
4339+
readonly kind: TextEditorChangeKind;
4340+
}
4341+
4342+
export interface TextEditorDiffInformation {
4343+
readonly documentVersion: number;
4344+
readonly original: theia.Uri | undefined;
4345+
readonly modified: theia.Uri;
4346+
readonly changes: readonly TextEditorChange[];
4347+
readonly isStale: boolean;
4348+
}
4349+
4350+
export interface TextEditorDiffInformationChangeEvent {
4351+
readonly textEditor: TextEditor;
4352+
readonly diffInformation: TextEditorDiffInformation[] | undefined;
4353+
}
4354+
4355+
export interface TextEditor {
4356+
readonly diffInformation: TextEditorDiffInformation[] | undefined;
4357+
}
4358+
4359+
// #endregion

packages/plugin/src/theia.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import './theia.proposed.scmValidation';
4545
import './theia.proposed.shareProvider';
4646
import './theia.proposed.terminalCompletionProvider';
4747
import './theia.proposed.terminalQuickFixProvider';
48+
import './theia.proposed.textEditorDiffInformation';
4849
import './theia.proposed.textSearchProvider';
4950
import './theia.proposed.timeline';
5051

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2025 STMicroelectronics and others.
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License v. 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// This Source Code may also be made available under the following Secondary
9+
// Licenses when the conditions for such availability set forth in the Eclipse
10+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
// with the GNU Classpath Exception which is available at
12+
// https://www.gnu.org/software/classpath/license.html.
13+
//
14+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15+
// *****************************************************************************
16+
17+
/*---------------------------------------------------------------------------------------------
18+
* Copyright (c) Microsoft Corporation. All rights reserved.
19+
* Licensed under the MIT License. See License.txt in the project root for license information.
20+
*--------------------------------------------------------------------------------------------*/
21+
// code copied and modified from https://github.com/microsoft/vscode/blob/1.103.2/src/vscode-dts/vscode.proposed.textEditorDiffInformation.d.ts
22+
23+
declare module '@theia/plugin' {
24+
// https://github.com/microsoft/vscode/issues/84899
25+
26+
export enum TextEditorChangeKind {
27+
Addition = 1,
28+
Deletion = 2,
29+
Modification = 3
30+
}
31+
32+
export interface TextEditorLineRange {
33+
readonly startLineNumber: number;
34+
readonly endLineNumberExclusive: number;
35+
}
36+
37+
export interface TextEditorChange {
38+
readonly original: TextEditorLineRange;
39+
readonly modified: TextEditorLineRange;
40+
readonly kind: TextEditorChangeKind;
41+
}
42+
43+
export interface TextEditorDiffInformation {
44+
readonly documentVersion: number;
45+
readonly original: Uri | undefined;
46+
readonly modified: Uri;
47+
readonly changes: readonly TextEditorChange[];
48+
readonly isStale: boolean;
49+
}
50+
51+
export interface TextEditorDiffInformationChangeEvent {
52+
readonly textEditor: TextEditor;
53+
readonly diffInformation: TextEditorDiffInformation[] | undefined;
54+
}
55+
56+
export interface TextEditor {
57+
readonly diffInformation: TextEditorDiffInformation[] | undefined;
58+
}
59+
60+
export namespace window {
61+
export const onDidChangeTextEditorDiffInformation: Event<TextEditorDiffInformationChangeEvent>;
62+
}
63+
64+
}

0 commit comments

Comments
 (0)