@theia/scm 1.53.0-next.55 → 1.53.0-next.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +31 -31
  2. package/lib/browser/scm-commit-widget.js +1 -1
  3. package/lib/browser/scm-contribution.js +5 -5
  4. package/package.json +6 -6
  5. package/src/browser/decorations/scm-decorations-service.ts +102 -102
  6. package/src/browser/decorations/scm-navigator-decorator.ts +121 -121
  7. package/src/browser/decorations/scm-tab-bar-decorator.ts +83 -83
  8. package/src/browser/dirty-diff/content-lines.spec.ts +42 -42
  9. package/src/browser/dirty-diff/content-lines.ts +121 -121
  10. package/src/browser/dirty-diff/diff-computer.spec.ts +455 -455
  11. package/src/browser/dirty-diff/diff-computer.ts +177 -177
  12. package/src/browser/dirty-diff/dirty-diff-decorator.ts +114 -114
  13. package/src/browser/dirty-diff/dirty-diff-module.ts +33 -33
  14. package/src/browser/dirty-diff/dirty-diff-navigator.ts +288 -288
  15. package/src/browser/dirty-diff/dirty-diff-widget.ts +364 -364
  16. package/src/browser/scm-amend-component.tsx +600 -600
  17. package/src/browser/scm-amend-widget.tsx +77 -77
  18. package/src/browser/scm-avatar-service.ts +27 -27
  19. package/src/browser/scm-colors.ts +21 -21
  20. package/src/browser/scm-commit-widget.tsx +215 -215
  21. package/src/browser/scm-context-key-service.ts +46 -46
  22. package/src/browser/scm-contribution.ts +452 -452
  23. package/src/browser/scm-frontend-module.ts +149 -149
  24. package/src/browser/scm-groups-tree-model.ts +78 -78
  25. package/src/browser/scm-input.ts +164 -164
  26. package/src/browser/scm-layout-migrations.ts +64 -64
  27. package/src/browser/scm-no-repository-widget.tsx +41 -41
  28. package/src/browser/scm-preferences.ts +63 -63
  29. package/src/browser/scm-provider.ts +91 -91
  30. package/src/browser/scm-quick-open-service.ts +48 -48
  31. package/src/browser/scm-repository.ts +52 -52
  32. package/src/browser/scm-service.ts +108 -108
  33. package/src/browser/scm-tree-label-provider.ts +44 -44
  34. package/src/browser/scm-tree-model.ts +405 -405
  35. package/src/browser/scm-tree-widget.tsx +838 -838
  36. package/src/browser/scm-widget.tsx +204 -204
  37. package/src/browser/style/dirty-diff-decorator.css +53 -53
  38. package/src/browser/style/dirty-diff.css +50 -50
  39. package/src/browser/style/index.css +271 -271
  40. package/src/browser/style/scm-amend-component.css +94 -94
  41. package/src/browser/style/scm.svg +4 -4
@@ -1,288 +1,288 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2023 1C-Soft LLC 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
- import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
18
- import { Disposable, DisposableCollection, URI } from '@theia/core';
19
- import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
20
- import { EditorManager, EditorMouseEvent, MouseTargetType, TextEditor } from '@theia/editor/lib/browser';
21
- import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
22
- import { Change, LineRange } from './diff-computer';
23
- import { DirtyDiffUpdate } from './dirty-diff-decorator';
24
- import { DirtyDiffWidget, DirtyDiffWidgetFactory } from './dirty-diff-widget';
25
-
26
- @injectable()
27
- export class DirtyDiffNavigator {
28
-
29
- protected readonly controllers = new Map<TextEditor, DirtyDiffController>();
30
-
31
- @inject(ContextKeyService)
32
- protected readonly contextKeyService: ContextKeyService;
33
-
34
- @inject(EditorManager)
35
- protected readonly editorManager: EditorManager;
36
-
37
- @inject(DirtyDiffWidgetFactory)
38
- protected readonly widgetFactory: DirtyDiffWidgetFactory;
39
-
40
- @postConstruct()
41
- protected init(): void {
42
- const dirtyDiffVisible: ContextKey<boolean> = this.contextKeyService.createKey('dirtyDiffVisible', false);
43
- this.editorManager.onActiveEditorChanged(editorWidget => {
44
- dirtyDiffVisible.set(editorWidget && this.controllers.get(editorWidget.editor)?.isShowingChange());
45
- });
46
- this.editorManager.onCreated(editorWidget => {
47
- const { editor } = editorWidget;
48
- if (editor.uri.scheme !== 'file') {
49
- return;
50
- }
51
- const controller = this.createController(editor);
52
- controller.widgetFactory = props => {
53
- const widget = this.widgetFactory(props);
54
- if (widget.editor === this.editorManager.activeEditor?.editor) {
55
- dirtyDiffVisible.set(true);
56
- }
57
- widget.onDidClose(() => {
58
- if (widget.editor === this.editorManager.activeEditor?.editor) {
59
- dirtyDiffVisible.set(false);
60
- }
61
- });
62
- return widget;
63
- };
64
- this.controllers.set(editor, controller);
65
- editorWidget.disposed.connect(() => {
66
- this.controllers.delete(editor);
67
- controller.dispose();
68
- });
69
- });
70
- }
71
-
72
- handleDirtyDiffUpdate(update: DirtyDiffUpdate): void {
73
- const controller = this.controllers.get(update.editor);
74
- controller?.handleDirtyDiffUpdate(update);
75
- }
76
-
77
- canNavigate(): boolean {
78
- return !!this.activeController?.canNavigate();
79
- }
80
-
81
- gotoNextChange(): void {
82
- this.activeController?.gotoNextChange();
83
- }
84
-
85
- gotoPreviousChange(): void {
86
- this.activeController?.gotoPreviousChange();
87
- }
88
-
89
- canShowChange(): boolean {
90
- return !!this.activeController?.canShowChange();
91
- }
92
-
93
- showNextChange(): void {
94
- this.activeController?.showNextChange();
95
- }
96
-
97
- showPreviousChange(): void {
98
- this.activeController?.showPreviousChange();
99
- }
100
-
101
- isShowingChange(): boolean {
102
- return !!this.activeController?.isShowingChange();
103
- }
104
-
105
- closeChangePeekView(): void {
106
- this.activeController?.closeWidget();
107
- }
108
-
109
- protected get activeController(): DirtyDiffController | undefined {
110
- const editor = this.editorManager.activeEditor?.editor;
111
- return editor && this.controllers.get(editor);
112
- }
113
-
114
- protected createController(editor: TextEditor): DirtyDiffController {
115
- return new DirtyDiffController(editor);
116
- }
117
- }
118
-
119
- export class DirtyDiffController implements Disposable {
120
-
121
- protected readonly toDispose = new DisposableCollection();
122
-
123
- widgetFactory?: DirtyDiffWidgetFactory;
124
- protected widget?: DirtyDiffWidget;
125
- protected dirtyDiff?: DirtyDiffUpdate;
126
-
127
- constructor(protected readonly editor: TextEditor) {
128
- editor.onMouseDown(this.handleEditorMouseDown, this, this.toDispose);
129
- }
130
-
131
- dispose(): void {
132
- this.closeWidget();
133
- this.toDispose.dispose();
134
- }
135
-
136
- handleDirtyDiffUpdate(dirtyDiff: DirtyDiffUpdate): void {
137
- if (dirtyDiff.editor === this.editor) {
138
- this.closeWidget();
139
- this.dirtyDiff = dirtyDiff;
140
- }
141
- }
142
-
143
- canNavigate(): boolean {
144
- return !!this.changes?.length;
145
- }
146
-
147
- gotoNextChange(): void {
148
- const { editor } = this;
149
- const index = this.findNextClosestChange(editor.cursor.line, false);
150
- const change = this.changes?.[index];
151
- if (change) {
152
- const position = LineRange.getStartPosition(change.currentRange);
153
- editor.cursor = position;
154
- editor.revealPosition(position, { vertical: 'auto' });
155
- }
156
- }
157
-
158
- gotoPreviousChange(): void {
159
- const { editor } = this;
160
- const index = this.findPreviousClosestChange(editor.cursor.line, false);
161
- const change = this.changes?.[index];
162
- if (change) {
163
- const position = LineRange.getStartPosition(change.currentRange);
164
- editor.cursor = position;
165
- editor.revealPosition(position, { vertical: 'auto' });
166
- }
167
- }
168
-
169
- canShowChange(): boolean {
170
- return !!(this.widget || this.widgetFactory && this.editor instanceof MonacoEditor && this.changes?.length && this.previousRevisionUri);
171
- }
172
-
173
- showNextChange(): void {
174
- if (this.widget) {
175
- this.widget.showNextChange();
176
- } else {
177
- (this.widget = this.createWidget())?.showChange(
178
- this.findNextClosestChange(this.editor.cursor.line, true));
179
- }
180
- }
181
-
182
- showPreviousChange(): void {
183
- if (this.widget) {
184
- this.widget.showPreviousChange();
185
- } else {
186
- (this.widget = this.createWidget())?.showChange(
187
- this.findPreviousClosestChange(this.editor.cursor.line, true));
188
- }
189
- }
190
-
191
- isShowingChange(): boolean {
192
- return !!this.widget;
193
- }
194
-
195
- closeWidget(): void {
196
- if (this.widget) {
197
- this.widget.dispose();
198
- this.widget = undefined;
199
- }
200
- }
201
-
202
- protected get changes(): readonly Change[] | undefined {
203
- return this.dirtyDiff?.changes;
204
- }
205
-
206
- protected get previousRevisionUri(): URI | undefined {
207
- return this.dirtyDiff?.previousRevisionUri;
208
- }
209
-
210
- protected createWidget(): DirtyDiffWidget | undefined {
211
- const { widgetFactory, editor, changes, previousRevisionUri } = this;
212
- if (widgetFactory && editor instanceof MonacoEditor && changes?.length && previousRevisionUri) {
213
- const widget = widgetFactory({ editor, previousRevisionUri, changes });
214
- widget.onDidClose(() => {
215
- this.widget = undefined;
216
- });
217
- return widget;
218
- }
219
- }
220
-
221
- protected findNextClosestChange(line: number, inclusive: boolean): number {
222
- const length = this.changes?.length;
223
- if (!length) {
224
- return -1;
225
- }
226
- for (let i = 0; i < length; i++) {
227
- const { currentRange } = this.changes![i];
228
-
229
- if (inclusive) {
230
- if (LineRange.getEndPosition(currentRange).line >= line) {
231
- return i;
232
- }
233
- } else {
234
- if (LineRange.getStartPosition(currentRange).line > line) {
235
- return i;
236
- }
237
- }
238
- }
239
- return 0;
240
- }
241
-
242
- protected findPreviousClosestChange(line: number, inclusive: boolean): number {
243
- const length = this.changes?.length;
244
- if (!length) {
245
- return -1;
246
- }
247
- for (let i = length - 1; i >= 0; i--) {
248
- const { currentRange } = this.changes![i];
249
-
250
- if (inclusive) {
251
- if (LineRange.getStartPosition(currentRange).line <= line) {
252
- return i;
253
- }
254
- } else {
255
- if (LineRange.getEndPosition(currentRange).line < line) {
256
- return i;
257
- }
258
- }
259
- }
260
- return length - 1;
261
- }
262
-
263
- protected handleEditorMouseDown({ event, target }: EditorMouseEvent): void {
264
- if (event.button !== 0) {
265
- return;
266
- }
267
- const { range, type, element } = target;
268
- if (!range || type !== MouseTargetType.GUTTER_LINE_DECORATIONS || !element || element.className.indexOf('dirty-diff-glyph') < 0) {
269
- return;
270
- }
271
- const gutterOffsetX = target.detail.offsetX - (element as HTMLElement).offsetLeft;
272
- if (gutterOffsetX < -3 || gutterOffsetX > 3) { // dirty diff decoration on hover is 6px wide
273
- return; // to avoid colliding with folding
274
- }
275
- const index = this.findNextClosestChange(range.start.line, true);
276
- if (index < 0) {
277
- return;
278
- }
279
- if (index === this.widget?.currentChangeIndex) {
280
- this.closeWidget();
281
- return;
282
- }
283
- if (!this.widget) {
284
- this.widget = this.createWidget();
285
- }
286
- this.widget?.showChange(index);
287
- }
288
- }
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 1C-Soft LLC 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
+ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
18
+ import { Disposable, DisposableCollection, URI } from '@theia/core';
19
+ import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
20
+ import { EditorManager, EditorMouseEvent, MouseTargetType, TextEditor } from '@theia/editor/lib/browser';
21
+ import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
22
+ import { Change, LineRange } from './diff-computer';
23
+ import { DirtyDiffUpdate } from './dirty-diff-decorator';
24
+ import { DirtyDiffWidget, DirtyDiffWidgetFactory } from './dirty-diff-widget';
25
+
26
+ @injectable()
27
+ export class DirtyDiffNavigator {
28
+
29
+ protected readonly controllers = new Map<TextEditor, DirtyDiffController>();
30
+
31
+ @inject(ContextKeyService)
32
+ protected readonly contextKeyService: ContextKeyService;
33
+
34
+ @inject(EditorManager)
35
+ protected readonly editorManager: EditorManager;
36
+
37
+ @inject(DirtyDiffWidgetFactory)
38
+ protected readonly widgetFactory: DirtyDiffWidgetFactory;
39
+
40
+ @postConstruct()
41
+ protected init(): void {
42
+ const dirtyDiffVisible: ContextKey<boolean> = this.contextKeyService.createKey('dirtyDiffVisible', false);
43
+ this.editorManager.onActiveEditorChanged(editorWidget => {
44
+ dirtyDiffVisible.set(editorWidget && this.controllers.get(editorWidget.editor)?.isShowingChange());
45
+ });
46
+ this.editorManager.onCreated(editorWidget => {
47
+ const { editor } = editorWidget;
48
+ if (editor.uri.scheme !== 'file') {
49
+ return;
50
+ }
51
+ const controller = this.createController(editor);
52
+ controller.widgetFactory = props => {
53
+ const widget = this.widgetFactory(props);
54
+ if (widget.editor === this.editorManager.activeEditor?.editor) {
55
+ dirtyDiffVisible.set(true);
56
+ }
57
+ widget.onDidClose(() => {
58
+ if (widget.editor === this.editorManager.activeEditor?.editor) {
59
+ dirtyDiffVisible.set(false);
60
+ }
61
+ });
62
+ return widget;
63
+ };
64
+ this.controllers.set(editor, controller);
65
+ editorWidget.disposed.connect(() => {
66
+ this.controllers.delete(editor);
67
+ controller.dispose();
68
+ });
69
+ });
70
+ }
71
+
72
+ handleDirtyDiffUpdate(update: DirtyDiffUpdate): void {
73
+ const controller = this.controllers.get(update.editor);
74
+ controller?.handleDirtyDiffUpdate(update);
75
+ }
76
+
77
+ canNavigate(): boolean {
78
+ return !!this.activeController?.canNavigate();
79
+ }
80
+
81
+ gotoNextChange(): void {
82
+ this.activeController?.gotoNextChange();
83
+ }
84
+
85
+ gotoPreviousChange(): void {
86
+ this.activeController?.gotoPreviousChange();
87
+ }
88
+
89
+ canShowChange(): boolean {
90
+ return !!this.activeController?.canShowChange();
91
+ }
92
+
93
+ showNextChange(): void {
94
+ this.activeController?.showNextChange();
95
+ }
96
+
97
+ showPreviousChange(): void {
98
+ this.activeController?.showPreviousChange();
99
+ }
100
+
101
+ isShowingChange(): boolean {
102
+ return !!this.activeController?.isShowingChange();
103
+ }
104
+
105
+ closeChangePeekView(): void {
106
+ this.activeController?.closeWidget();
107
+ }
108
+
109
+ protected get activeController(): DirtyDiffController | undefined {
110
+ const editor = this.editorManager.activeEditor?.editor;
111
+ return editor && this.controllers.get(editor);
112
+ }
113
+
114
+ protected createController(editor: TextEditor): DirtyDiffController {
115
+ return new DirtyDiffController(editor);
116
+ }
117
+ }
118
+
119
+ export class DirtyDiffController implements Disposable {
120
+
121
+ protected readonly toDispose = new DisposableCollection();
122
+
123
+ widgetFactory?: DirtyDiffWidgetFactory;
124
+ protected widget?: DirtyDiffWidget;
125
+ protected dirtyDiff?: DirtyDiffUpdate;
126
+
127
+ constructor(protected readonly editor: TextEditor) {
128
+ editor.onMouseDown(this.handleEditorMouseDown, this, this.toDispose);
129
+ }
130
+
131
+ dispose(): void {
132
+ this.closeWidget();
133
+ this.toDispose.dispose();
134
+ }
135
+
136
+ handleDirtyDiffUpdate(dirtyDiff: DirtyDiffUpdate): void {
137
+ if (dirtyDiff.editor === this.editor) {
138
+ this.closeWidget();
139
+ this.dirtyDiff = dirtyDiff;
140
+ }
141
+ }
142
+
143
+ canNavigate(): boolean {
144
+ return !!this.changes?.length;
145
+ }
146
+
147
+ gotoNextChange(): void {
148
+ const { editor } = this;
149
+ const index = this.findNextClosestChange(editor.cursor.line, false);
150
+ const change = this.changes?.[index];
151
+ if (change) {
152
+ const position = LineRange.getStartPosition(change.currentRange);
153
+ editor.cursor = position;
154
+ editor.revealPosition(position, { vertical: 'auto' });
155
+ }
156
+ }
157
+
158
+ gotoPreviousChange(): void {
159
+ const { editor } = this;
160
+ const index = this.findPreviousClosestChange(editor.cursor.line, false);
161
+ const change = this.changes?.[index];
162
+ if (change) {
163
+ const position = LineRange.getStartPosition(change.currentRange);
164
+ editor.cursor = position;
165
+ editor.revealPosition(position, { vertical: 'auto' });
166
+ }
167
+ }
168
+
169
+ canShowChange(): boolean {
170
+ return !!(this.widget || this.widgetFactory && this.editor instanceof MonacoEditor && this.changes?.length && this.previousRevisionUri);
171
+ }
172
+
173
+ showNextChange(): void {
174
+ if (this.widget) {
175
+ this.widget.showNextChange();
176
+ } else {
177
+ (this.widget = this.createWidget())?.showChange(
178
+ this.findNextClosestChange(this.editor.cursor.line, true));
179
+ }
180
+ }
181
+
182
+ showPreviousChange(): void {
183
+ if (this.widget) {
184
+ this.widget.showPreviousChange();
185
+ } else {
186
+ (this.widget = this.createWidget())?.showChange(
187
+ this.findPreviousClosestChange(this.editor.cursor.line, true));
188
+ }
189
+ }
190
+
191
+ isShowingChange(): boolean {
192
+ return !!this.widget;
193
+ }
194
+
195
+ closeWidget(): void {
196
+ if (this.widget) {
197
+ this.widget.dispose();
198
+ this.widget = undefined;
199
+ }
200
+ }
201
+
202
+ protected get changes(): readonly Change[] | undefined {
203
+ return this.dirtyDiff?.changes;
204
+ }
205
+
206
+ protected get previousRevisionUri(): URI | undefined {
207
+ return this.dirtyDiff?.previousRevisionUri;
208
+ }
209
+
210
+ protected createWidget(): DirtyDiffWidget | undefined {
211
+ const { widgetFactory, editor, changes, previousRevisionUri } = this;
212
+ if (widgetFactory && editor instanceof MonacoEditor && changes?.length && previousRevisionUri) {
213
+ const widget = widgetFactory({ editor, previousRevisionUri, changes });
214
+ widget.onDidClose(() => {
215
+ this.widget = undefined;
216
+ });
217
+ return widget;
218
+ }
219
+ }
220
+
221
+ protected findNextClosestChange(line: number, inclusive: boolean): number {
222
+ const length = this.changes?.length;
223
+ if (!length) {
224
+ return -1;
225
+ }
226
+ for (let i = 0; i < length; i++) {
227
+ const { currentRange } = this.changes![i];
228
+
229
+ if (inclusive) {
230
+ if (LineRange.getEndPosition(currentRange).line >= line) {
231
+ return i;
232
+ }
233
+ } else {
234
+ if (LineRange.getStartPosition(currentRange).line > line) {
235
+ return i;
236
+ }
237
+ }
238
+ }
239
+ return 0;
240
+ }
241
+
242
+ protected findPreviousClosestChange(line: number, inclusive: boolean): number {
243
+ const length = this.changes?.length;
244
+ if (!length) {
245
+ return -1;
246
+ }
247
+ for (let i = length - 1; i >= 0; i--) {
248
+ const { currentRange } = this.changes![i];
249
+
250
+ if (inclusive) {
251
+ if (LineRange.getStartPosition(currentRange).line <= line) {
252
+ return i;
253
+ }
254
+ } else {
255
+ if (LineRange.getEndPosition(currentRange).line < line) {
256
+ return i;
257
+ }
258
+ }
259
+ }
260
+ return length - 1;
261
+ }
262
+
263
+ protected handleEditorMouseDown({ event, target }: EditorMouseEvent): void {
264
+ if (event.button !== 0) {
265
+ return;
266
+ }
267
+ const { range, type, element } = target;
268
+ if (!range || type !== MouseTargetType.GUTTER_LINE_DECORATIONS || !element || element.className.indexOf('dirty-diff-glyph') < 0) {
269
+ return;
270
+ }
271
+ const gutterOffsetX = target.detail.offsetX - (element as HTMLElement).offsetLeft;
272
+ if (gutterOffsetX < -3 || gutterOffsetX > 3) { // dirty diff decoration on hover is 6px wide
273
+ return; // to avoid colliding with folding
274
+ }
275
+ const index = this.findNextClosestChange(range.start.line, true);
276
+ if (index < 0) {
277
+ return;
278
+ }
279
+ if (index === this.widget?.currentChangeIndex) {
280
+ this.closeWidget();
281
+ return;
282
+ }
283
+ if (!this.widget) {
284
+ this.widget = this.createWidget();
285
+ }
286
+ this.widget?.showChange(index);
287
+ }
288
+ }