@theia/scm 1.53.0-next.4 → 1.53.0-next.55
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.
- package/README.md +31 -31
- package/lib/browser/scm-commit-widget.js +1 -1
- package/lib/browser/scm-contribution.js +5 -5
- package/package.json +7 -7
- package/src/browser/decorations/scm-decorations-service.ts +102 -102
- package/src/browser/decorations/scm-navigator-decorator.ts +121 -121
- package/src/browser/decorations/scm-tab-bar-decorator.ts +83 -83
- package/src/browser/dirty-diff/content-lines.spec.ts +42 -42
- package/src/browser/dirty-diff/content-lines.ts +121 -121
- package/src/browser/dirty-diff/diff-computer.spec.ts +455 -455
- package/src/browser/dirty-diff/diff-computer.ts +177 -177
- package/src/browser/dirty-diff/dirty-diff-decorator.ts +114 -114
- package/src/browser/dirty-diff/dirty-diff-module.ts +33 -33
- package/src/browser/dirty-diff/dirty-diff-navigator.ts +288 -288
- package/src/browser/dirty-diff/dirty-diff-widget.ts +364 -364
- package/src/browser/scm-amend-component.tsx +600 -600
- package/src/browser/scm-amend-widget.tsx +77 -77
- package/src/browser/scm-avatar-service.ts +27 -27
- package/src/browser/scm-colors.ts +21 -21
- package/src/browser/scm-commit-widget.tsx +215 -215
- package/src/browser/scm-context-key-service.ts +46 -46
- package/src/browser/scm-contribution.ts +452 -452
- package/src/browser/scm-frontend-module.ts +149 -149
- package/src/browser/scm-groups-tree-model.ts +78 -78
- package/src/browser/scm-input.ts +164 -164
- package/src/browser/scm-layout-migrations.ts +64 -64
- package/src/browser/scm-no-repository-widget.tsx +41 -41
- package/src/browser/scm-preferences.ts +63 -63
- package/src/browser/scm-provider.ts +91 -91
- package/src/browser/scm-quick-open-service.ts +48 -48
- package/src/browser/scm-repository.ts +52 -52
- package/src/browser/scm-service.ts +108 -108
- package/src/browser/scm-tree-label-provider.ts +44 -44
- package/src/browser/scm-tree-model.ts +405 -405
- package/src/browser/scm-tree-widget.tsx +838 -838
- package/src/browser/scm-widget.tsx +204 -204
- package/src/browser/style/dirty-diff-decorator.css +53 -53
- package/src/browser/style/dirty-diff.css +50 -50
- package/src/browser/style/index.css +271 -271
- package/src/browser/style/scm-amend-component.css +94 -94
- package/src/browser/style/scm.svg +4 -4
package/README.md
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
<div align='center'>
|
|
2
|
-
|
|
3
|
-
<br />
|
|
4
|
-
|
|
5
|
-
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
|
6
|
-
|
|
7
|
-
<h2>ECLIPSE THEIA - SCM EXTENSION</h2>
|
|
8
|
-
|
|
9
|
-
<hr />
|
|
10
|
-
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
## Description
|
|
14
|
-
|
|
15
|
-
The `@theia/scm` extension adds support for handling multiple source control managers, and includes a `SCM` (Source Control Manager) View which different source control providers (such as `Git` and `Mercurial`) can contribute to.
|
|
16
|
-
|
|
17
|
-
## Additional Information
|
|
18
|
-
|
|
19
|
-
- [API documentation for `@theia/scm`](https://eclipse-theia.github.io/theia/docs/next/modules/scm.html)
|
|
20
|
-
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
|
21
|
-
- [Theia - Website](https://theia-ide.org/)
|
|
22
|
-
- [VS Code SCM Documentation](https://code.visualstudio.com/docs/editor/versioncontrol)
|
|
23
|
-
|
|
24
|
-
## License
|
|
25
|
-
|
|
26
|
-
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
|
27
|
-
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
|
28
|
-
|
|
29
|
-
## Trademark
|
|
30
|
-
"Theia" is a trademark of the Eclipse Foundation
|
|
31
|
-
https://www.eclipse.org/theia
|
|
1
|
+
<div align='center'>
|
|
2
|
+
|
|
3
|
+
<br />
|
|
4
|
+
|
|
5
|
+
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
|
6
|
+
|
|
7
|
+
<h2>ECLIPSE THEIA - SCM EXTENSION</h2>
|
|
8
|
+
|
|
9
|
+
<hr />
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
The `@theia/scm` extension adds support for handling multiple source control managers, and includes a `SCM` (Source Control Manager) View which different source control providers (such as `Git` and `Mercurial`) can contribute to.
|
|
16
|
+
|
|
17
|
+
## Additional Information
|
|
18
|
+
|
|
19
|
+
- [API documentation for `@theia/scm`](https://eclipse-theia.github.io/theia/docs/next/modules/scm.html)
|
|
20
|
+
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
|
21
|
+
- [Theia - Website](https://theia-ide.org/)
|
|
22
|
+
- [VS Code SCM Documentation](https://code.visualstudio.com/docs/editor/versioncontrol)
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
|
|
26
|
+
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
|
27
|
+
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
|
28
|
+
|
|
29
|
+
## Trademark
|
|
30
|
+
"Theia" is a trademark of the Eclipse Foundation
|
|
31
|
+
https://www.eclipse.org/theia
|
|
@@ -121,7 +121,7 @@ let ScmCommitWidget = ScmCommitWidget_1 = class ScmCommitWidget extends browser_
|
|
|
121
121
|
React.createElement(react_autosize_textarea_1.default, { className: `${ScmCommitWidget_1.Styles.INPUT_MESSAGE} theia-input theia-scm-input-message-${validationStatus}`, id: ScmCommitWidget_1.Styles.INPUT_MESSAGE, placeholder: message, spellCheck: false, autoFocus: true, value: input.value, disabled: !input.enabled, onChange: this.setInputValue, ref: this.inputRef, rows: 1, maxRows: 6 });
|
|
122
122
|
return React.createElement("div", { className: ScmCommitWidget_1.Styles.INPUT_MESSAGE_CONTAINER },
|
|
123
123
|
textArea,
|
|
124
|
-
React.createElement("div", { className: `${ScmCommitWidget_1.Styles.VALIDATION_MESSAGE} ${ScmCommitWidget_1.Styles.NO_SELECT}
|
|
124
|
+
React.createElement("div", { className: `${ScmCommitWidget_1.Styles.VALIDATION_MESSAGE} ${ScmCommitWidget_1.Styles.NO_SELECT}
|
|
125
125
|
theia-scm-validation-message-${validationStatus} theia-scm-input-message-${validationStatus}`, style: {
|
|
126
126
|
display: !!input.issue ? 'block' : 'none'
|
|
127
127
|
} }, validationMessage));
|
|
@@ -380,11 +380,11 @@ let ScmContribution = class ScmContribution extends browser_1.AbstractViewContri
|
|
|
380
380
|
registerThemeStyle(theme, collector) {
|
|
381
381
|
const contrastBorder = theme.getColor('contrastBorder');
|
|
382
382
|
if (contrastBorder && (0, theme_1.isHighContrast)(theme.type)) {
|
|
383
|
-
collector.addRule(`
|
|
384
|
-
.theia-scm-input-message-container textarea {
|
|
385
|
-
outline: var(--theia-border-width) solid ${contrastBorder};
|
|
386
|
-
outline-offset: -1px;
|
|
387
|
-
}
|
|
383
|
+
collector.addRule(`
|
|
384
|
+
.theia-scm-input-message-container textarea {
|
|
385
|
+
outline: var(--theia-border-width) solid ${contrastBorder};
|
|
386
|
+
outline-offset: -1px;
|
|
387
|
+
}
|
|
388
388
|
`);
|
|
389
389
|
}
|
|
390
390
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/scm",
|
|
3
|
-
"version": "1.53.0-next.
|
|
3
|
+
"version": "1.53.0-next.55+d1a989a68c",
|
|
4
4
|
"description": "Theia - Source control Extension",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/core": "1.53.0-next.
|
|
7
|
-
"@theia/editor": "1.53.0-next.
|
|
8
|
-
"@theia/filesystem": "1.53.0-next.
|
|
9
|
-
"@theia/monaco": "1.53.0-next.
|
|
6
|
+
"@theia/core": "1.53.0-next.55+d1a989a68c",
|
|
7
|
+
"@theia/editor": "1.53.0-next.55+d1a989a68c",
|
|
8
|
+
"@theia/filesystem": "1.53.0-next.55+d1a989a68c",
|
|
9
|
+
"@theia/monaco": "1.53.0-next.55+d1a989a68c",
|
|
10
10
|
"@theia/monaco-editor-core": "1.83.101",
|
|
11
11
|
"@types/diff": "^5.2.1",
|
|
12
12
|
"diff": "^5.2.0",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"watch": "theiaext watch"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@theia/ext-scripts": "1.
|
|
52
|
+
"@theia/ext-scripts": "1.53.0"
|
|
53
53
|
},
|
|
54
54
|
"nyc": {
|
|
55
55
|
"extends": "../../configs/nyc.json"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "d1a989a68c1b5ec1f9098e9126653c6346844769"
|
|
58
58
|
}
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
// *****************************************************************************
|
|
2
|
-
// Copyright (C) 2019 Red Hat, Inc. 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 { injectable, inject } from '@theia/core/shared/inversify';
|
|
18
|
-
import { DisposableCollection, Emitter, Event, ResourceProvider } from '@theia/core';
|
|
19
|
-
import { DirtyDiffDecorator, DirtyDiffUpdate } from '../dirty-diff/dirty-diff-decorator';
|
|
20
|
-
import { DiffComputer } from '../dirty-diff/diff-computer';
|
|
21
|
-
import { ContentLines } from '../dirty-diff/content-lines';
|
|
22
|
-
import { EditorManager, EditorWidget, TextEditor } from '@theia/editor/lib/browser';
|
|
23
|
-
import { ScmService } from '../scm-service';
|
|
24
|
-
|
|
25
|
-
import throttle = require('@theia/core/shared/lodash.throttle');
|
|
26
|
-
|
|
27
|
-
@injectable()
|
|
28
|
-
export class ScmDecorationsService {
|
|
29
|
-
private readonly diffComputer = new DiffComputer();
|
|
30
|
-
|
|
31
|
-
protected readonly onDirtyDiffUpdateEmitter = new Emitter<DirtyDiffUpdate>();
|
|
32
|
-
readonly onDirtyDiffUpdate: Event<DirtyDiffUpdate> = this.onDirtyDiffUpdateEmitter.event;
|
|
33
|
-
|
|
34
|
-
constructor(
|
|
35
|
-
@inject(DirtyDiffDecorator) protected readonly decorator: DirtyDiffDecorator,
|
|
36
|
-
@inject(ScmService) protected readonly scmService: ScmService,
|
|
37
|
-
@inject(EditorManager) protected readonly editorManager: EditorManager,
|
|
38
|
-
@inject(ResourceProvider) protected readonly resourceProvider: ResourceProvider
|
|
39
|
-
) {
|
|
40
|
-
const updateTasks = new Map<EditorWidget, { (): void; cancel(): void }>();
|
|
41
|
-
this.editorManager.onCreated(editorWidget => {
|
|
42
|
-
const { editor } = editorWidget;
|
|
43
|
-
if (!this.supportsDirtyDiff(editor)) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const toDispose = new DisposableCollection();
|
|
47
|
-
const updateTask = this.createUpdateTask(editor);
|
|
48
|
-
updateTasks.set(editorWidget, updateTask);
|
|
49
|
-
toDispose.push(editor.onDocumentContentChanged(() => updateTask()));
|
|
50
|
-
editorWidget.disposed.connect(() => {
|
|
51
|
-
updateTask.cancel();
|
|
52
|
-
updateTasks.delete(editorWidget);
|
|
53
|
-
toDispose.dispose();
|
|
54
|
-
});
|
|
55
|
-
updateTask();
|
|
56
|
-
});
|
|
57
|
-
const runUpdateTasks = () => {
|
|
58
|
-
for (const updateTask of updateTasks.values()) {
|
|
59
|
-
updateTask();
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
this.scmService.onDidAddRepository(({ provider }) => {
|
|
63
|
-
provider.onDidChange(runUpdateTasks);
|
|
64
|
-
provider.onDidChangeResources?.(runUpdateTasks);
|
|
65
|
-
});
|
|
66
|
-
this.scmService.onDidChangeSelectedRepository(runUpdateTasks);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async applyEditorDecorations(editor: TextEditor): Promise<void> {
|
|
70
|
-
const currentRepo = this.scmService.selectedRepository;
|
|
71
|
-
if (currentRepo) {
|
|
72
|
-
try {
|
|
73
|
-
// Currently, the uri used here is specific to vscode.git; other SCM providers are thus not supported.
|
|
74
|
-
// See https://github.com/eclipse-theia/theia/pull/13104#discussion_r1494540628 for a detailed discussion.
|
|
75
|
-
const query = { path: editor.uri['codeUri'].fsPath, ref: '~' };
|
|
76
|
-
const uri = editor.uri.withScheme(currentRepo.provider.id).withQuery(JSON.stringify(query));
|
|
77
|
-
const previousResource = await this.resourceProvider(uri);
|
|
78
|
-
try {
|
|
79
|
-
const previousContent = await previousResource.readContents();
|
|
80
|
-
const previousLines = ContentLines.fromString(previousContent);
|
|
81
|
-
const currentLines = ContentLines.fromTextEditorDocument(editor.document);
|
|
82
|
-
const dirtyDiff = this.diffComputer.computeDirtyDiff(ContentLines.arrayLike(previousLines), ContentLines.arrayLike(currentLines));
|
|
83
|
-
const update = <DirtyDiffUpdate>{ editor, previousRevisionUri: uri, ...dirtyDiff };
|
|
84
|
-
this.decorator.applyDecorations(update);
|
|
85
|
-
this.onDirtyDiffUpdateEmitter.fire(update);
|
|
86
|
-
} finally {
|
|
87
|
-
previousResource.dispose();
|
|
88
|
-
}
|
|
89
|
-
} catch (e) {
|
|
90
|
-
// Scm resource may not be found, do nothing.
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
protected supportsDirtyDiff(editor: TextEditor): boolean {
|
|
96
|
-
return editor.shouldDisplayDirtyDiff();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
protected createUpdateTask(editor: TextEditor): { (): void; cancel(): void; } {
|
|
100
|
-
return throttle(() => this.applyEditorDecorations(editor), 500);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2019 Red Hat, Inc. 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 { injectable, inject } from '@theia/core/shared/inversify';
|
|
18
|
+
import { DisposableCollection, Emitter, Event, ResourceProvider } from '@theia/core';
|
|
19
|
+
import { DirtyDiffDecorator, DirtyDiffUpdate } from '../dirty-diff/dirty-diff-decorator';
|
|
20
|
+
import { DiffComputer } from '../dirty-diff/diff-computer';
|
|
21
|
+
import { ContentLines } from '../dirty-diff/content-lines';
|
|
22
|
+
import { EditorManager, EditorWidget, TextEditor } from '@theia/editor/lib/browser';
|
|
23
|
+
import { ScmService } from '../scm-service';
|
|
24
|
+
|
|
25
|
+
import throttle = require('@theia/core/shared/lodash.throttle');
|
|
26
|
+
|
|
27
|
+
@injectable()
|
|
28
|
+
export class ScmDecorationsService {
|
|
29
|
+
private readonly diffComputer = new DiffComputer();
|
|
30
|
+
|
|
31
|
+
protected readonly onDirtyDiffUpdateEmitter = new Emitter<DirtyDiffUpdate>();
|
|
32
|
+
readonly onDirtyDiffUpdate: Event<DirtyDiffUpdate> = this.onDirtyDiffUpdateEmitter.event;
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
@inject(DirtyDiffDecorator) protected readonly decorator: DirtyDiffDecorator,
|
|
36
|
+
@inject(ScmService) protected readonly scmService: ScmService,
|
|
37
|
+
@inject(EditorManager) protected readonly editorManager: EditorManager,
|
|
38
|
+
@inject(ResourceProvider) protected readonly resourceProvider: ResourceProvider
|
|
39
|
+
) {
|
|
40
|
+
const updateTasks = new Map<EditorWidget, { (): void; cancel(): void }>();
|
|
41
|
+
this.editorManager.onCreated(editorWidget => {
|
|
42
|
+
const { editor } = editorWidget;
|
|
43
|
+
if (!this.supportsDirtyDiff(editor)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const toDispose = new DisposableCollection();
|
|
47
|
+
const updateTask = this.createUpdateTask(editor);
|
|
48
|
+
updateTasks.set(editorWidget, updateTask);
|
|
49
|
+
toDispose.push(editor.onDocumentContentChanged(() => updateTask()));
|
|
50
|
+
editorWidget.disposed.connect(() => {
|
|
51
|
+
updateTask.cancel();
|
|
52
|
+
updateTasks.delete(editorWidget);
|
|
53
|
+
toDispose.dispose();
|
|
54
|
+
});
|
|
55
|
+
updateTask();
|
|
56
|
+
});
|
|
57
|
+
const runUpdateTasks = () => {
|
|
58
|
+
for (const updateTask of updateTasks.values()) {
|
|
59
|
+
updateTask();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
this.scmService.onDidAddRepository(({ provider }) => {
|
|
63
|
+
provider.onDidChange(runUpdateTasks);
|
|
64
|
+
provider.onDidChangeResources?.(runUpdateTasks);
|
|
65
|
+
});
|
|
66
|
+
this.scmService.onDidChangeSelectedRepository(runUpdateTasks);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async applyEditorDecorations(editor: TextEditor): Promise<void> {
|
|
70
|
+
const currentRepo = this.scmService.selectedRepository;
|
|
71
|
+
if (currentRepo) {
|
|
72
|
+
try {
|
|
73
|
+
// Currently, the uri used here is specific to vscode.git; other SCM providers are thus not supported.
|
|
74
|
+
// See https://github.com/eclipse-theia/theia/pull/13104#discussion_r1494540628 for a detailed discussion.
|
|
75
|
+
const query = { path: editor.uri['codeUri'].fsPath, ref: '~' };
|
|
76
|
+
const uri = editor.uri.withScheme(currentRepo.provider.id).withQuery(JSON.stringify(query));
|
|
77
|
+
const previousResource = await this.resourceProvider(uri);
|
|
78
|
+
try {
|
|
79
|
+
const previousContent = await previousResource.readContents();
|
|
80
|
+
const previousLines = ContentLines.fromString(previousContent);
|
|
81
|
+
const currentLines = ContentLines.fromTextEditorDocument(editor.document);
|
|
82
|
+
const dirtyDiff = this.diffComputer.computeDirtyDiff(ContentLines.arrayLike(previousLines), ContentLines.arrayLike(currentLines));
|
|
83
|
+
const update = <DirtyDiffUpdate>{ editor, previousRevisionUri: uri, ...dirtyDiff };
|
|
84
|
+
this.decorator.applyDecorations(update);
|
|
85
|
+
this.onDirtyDiffUpdateEmitter.fire(update);
|
|
86
|
+
} finally {
|
|
87
|
+
previousResource.dispose();
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {
|
|
90
|
+
// Scm resource may not be found, do nothing.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
protected supportsDirtyDiff(editor: TextEditor): boolean {
|
|
96
|
+
return editor.shouldDisplayDirtyDiff();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
protected createUpdateTask(editor: TextEditor): { (): void; cancel(): void; } {
|
|
100
|
+
return throttle(() => this.applyEditorDecorations(editor), 500);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
// *****************************************************************************
|
|
2
|
-
// Copyright (C) 2019 Red Hat, Inc. 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 } from '@theia/core/shared/inversify';
|
|
18
|
-
import { ILogger } from '@theia/core/lib/common/logger';
|
|
19
|
-
import { Event, Emitter } from '@theia/core/lib/common/event';
|
|
20
|
-
import { Tree } from '@theia/core/lib/browser/tree/tree';
|
|
21
|
-
import { TreeDecorator, TreeDecoration } from '@theia/core/lib/browser/tree/tree-decorator';
|
|
22
|
-
import { DepthFirstTreeIterator } from '@theia/core/lib/browser';
|
|
23
|
-
import { FileStatNode } from '@theia/filesystem/lib/browser';
|
|
24
|
-
import URI from '@theia/core/lib/common/uri';
|
|
25
|
-
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
|
|
26
|
-
import { Decoration, DecorationsService } from '@theia/core/lib/browser/decorations-service';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated since 1.25.0
|
|
30
|
-
* URI-based decorators should implement `DecorationsProvider` and contribute decorations via the `DecorationsService`.
|
|
31
|
-
*/
|
|
32
|
-
@injectable()
|
|
33
|
-
export class ScmNavigatorDecorator implements TreeDecorator {
|
|
34
|
-
|
|
35
|
-
readonly id = 'theia-scm-decorator';
|
|
36
|
-
private decorationsMap: Map<string, Decoration> | undefined;
|
|
37
|
-
|
|
38
|
-
@inject(ILogger) protected readonly logger: ILogger;
|
|
39
|
-
|
|
40
|
-
@inject(ColorRegistry)
|
|
41
|
-
protected readonly colors: ColorRegistry;
|
|
42
|
-
|
|
43
|
-
constructor(@inject(DecorationsService) protected readonly decorationsService: DecorationsService) {
|
|
44
|
-
this.decorationsService.onDidChangeDecorations(data => {
|
|
45
|
-
this.decorationsMap = data;
|
|
46
|
-
this.fireDidChangeDecorations((tree: Tree) => this.collectDecorators(tree));
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
protected collectDecorators(tree: Tree): Map<string, TreeDecoration.Data> {
|
|
51
|
-
const result = new Map();
|
|
52
|
-
if (tree.root === undefined || !this.decorationsMap) {
|
|
53
|
-
return result;
|
|
54
|
-
}
|
|
55
|
-
const markers = this.appendContainerChanges(this.decorationsMap);
|
|
56
|
-
for (const treeNode of new DepthFirstTreeIterator(tree.root)) {
|
|
57
|
-
const uri = FileStatNode.getUri(treeNode);
|
|
58
|
-
if (uri) {
|
|
59
|
-
const marker = markers.get(uri);
|
|
60
|
-
if (marker) {
|
|
61
|
-
result.set(treeNode.id, marker);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return new Map(Array.from(result.entries()).map(m => [m[0], this.toDecorator(m[1])] as [string, TreeDecoration.Data]));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
protected toDecorator(change: Decoration): TreeDecoration.Data {
|
|
69
|
-
const colorVariable = change.colorId && this.colors.toCssVariableName(change.colorId);
|
|
70
|
-
return {
|
|
71
|
-
tailDecorations: [
|
|
72
|
-
{
|
|
73
|
-
data: change.letter ? change.letter : '',
|
|
74
|
-
fontData: {
|
|
75
|
-
color: colorVariable && `var(${colorVariable})`
|
|
76
|
-
},
|
|
77
|
-
tooltip: change.tooltip ? change.tooltip : ''
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
protected readonly emitter = new Emitter<(tree: Tree) => Map<string, TreeDecoration.Data>>();
|
|
84
|
-
|
|
85
|
-
async decorations(tree: Tree): Promise<Map<string, TreeDecoration.Data>> {
|
|
86
|
-
if (this.decorationsMap) {
|
|
87
|
-
return this.collectDecorators(tree);
|
|
88
|
-
} else {
|
|
89
|
-
return new Map();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
protected appendContainerChanges(decorationsMap: Map<string, Decoration>): Map<string, Decoration> {
|
|
94
|
-
const result: Map<string, Decoration> = new Map();
|
|
95
|
-
for (const [uri, data] of decorationsMap.entries()) {
|
|
96
|
-
const uriString = uri.toString();
|
|
97
|
-
result.set(uriString, data);
|
|
98
|
-
let parentUri: URI | undefined = new URI(uri).parent;
|
|
99
|
-
while (parentUri && !parentUri.path.isRoot) {
|
|
100
|
-
const parentUriString = parentUri.toString();
|
|
101
|
-
const existing = result.get(parentUriString);
|
|
102
|
-
if (existing === undefined) {
|
|
103
|
-
result.set(parentUriString, data);
|
|
104
|
-
parentUri = parentUri.parent;
|
|
105
|
-
} else {
|
|
106
|
-
parentUri = undefined;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
get onDidChangeDecorations(): Event<(tree: Tree) => Map<string, TreeDecoration.Data>> {
|
|
114
|
-
return this.emitter.event;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
fireDidChangeDecorations(event: (tree: Tree) => Map<string, TreeDecoration.Data>): void {
|
|
118
|
-
this.emitter.fire(event);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
}
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2019 Red Hat, Inc. 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 } from '@theia/core/shared/inversify';
|
|
18
|
+
import { ILogger } from '@theia/core/lib/common/logger';
|
|
19
|
+
import { Event, Emitter } from '@theia/core/lib/common/event';
|
|
20
|
+
import { Tree } from '@theia/core/lib/browser/tree/tree';
|
|
21
|
+
import { TreeDecorator, TreeDecoration } from '@theia/core/lib/browser/tree/tree-decorator';
|
|
22
|
+
import { DepthFirstTreeIterator } from '@theia/core/lib/browser';
|
|
23
|
+
import { FileStatNode } from '@theia/filesystem/lib/browser';
|
|
24
|
+
import URI from '@theia/core/lib/common/uri';
|
|
25
|
+
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
|
|
26
|
+
import { Decoration, DecorationsService } from '@theia/core/lib/browser/decorations-service';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated since 1.25.0
|
|
30
|
+
* URI-based decorators should implement `DecorationsProvider` and contribute decorations via the `DecorationsService`.
|
|
31
|
+
*/
|
|
32
|
+
@injectable()
|
|
33
|
+
export class ScmNavigatorDecorator implements TreeDecorator {
|
|
34
|
+
|
|
35
|
+
readonly id = 'theia-scm-decorator';
|
|
36
|
+
private decorationsMap: Map<string, Decoration> | undefined;
|
|
37
|
+
|
|
38
|
+
@inject(ILogger) protected readonly logger: ILogger;
|
|
39
|
+
|
|
40
|
+
@inject(ColorRegistry)
|
|
41
|
+
protected readonly colors: ColorRegistry;
|
|
42
|
+
|
|
43
|
+
constructor(@inject(DecorationsService) protected readonly decorationsService: DecorationsService) {
|
|
44
|
+
this.decorationsService.onDidChangeDecorations(data => {
|
|
45
|
+
this.decorationsMap = data;
|
|
46
|
+
this.fireDidChangeDecorations((tree: Tree) => this.collectDecorators(tree));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected collectDecorators(tree: Tree): Map<string, TreeDecoration.Data> {
|
|
51
|
+
const result = new Map();
|
|
52
|
+
if (tree.root === undefined || !this.decorationsMap) {
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
const markers = this.appendContainerChanges(this.decorationsMap);
|
|
56
|
+
for (const treeNode of new DepthFirstTreeIterator(tree.root)) {
|
|
57
|
+
const uri = FileStatNode.getUri(treeNode);
|
|
58
|
+
if (uri) {
|
|
59
|
+
const marker = markers.get(uri);
|
|
60
|
+
if (marker) {
|
|
61
|
+
result.set(treeNode.id, marker);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return new Map(Array.from(result.entries()).map(m => [m[0], this.toDecorator(m[1])] as [string, TreeDecoration.Data]));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected toDecorator(change: Decoration): TreeDecoration.Data {
|
|
69
|
+
const colorVariable = change.colorId && this.colors.toCssVariableName(change.colorId);
|
|
70
|
+
return {
|
|
71
|
+
tailDecorations: [
|
|
72
|
+
{
|
|
73
|
+
data: change.letter ? change.letter : '',
|
|
74
|
+
fontData: {
|
|
75
|
+
color: colorVariable && `var(${colorVariable})`
|
|
76
|
+
},
|
|
77
|
+
tooltip: change.tooltip ? change.tooltip : ''
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
protected readonly emitter = new Emitter<(tree: Tree) => Map<string, TreeDecoration.Data>>();
|
|
84
|
+
|
|
85
|
+
async decorations(tree: Tree): Promise<Map<string, TreeDecoration.Data>> {
|
|
86
|
+
if (this.decorationsMap) {
|
|
87
|
+
return this.collectDecorators(tree);
|
|
88
|
+
} else {
|
|
89
|
+
return new Map();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
protected appendContainerChanges(decorationsMap: Map<string, Decoration>): Map<string, Decoration> {
|
|
94
|
+
const result: Map<string, Decoration> = new Map();
|
|
95
|
+
for (const [uri, data] of decorationsMap.entries()) {
|
|
96
|
+
const uriString = uri.toString();
|
|
97
|
+
result.set(uriString, data);
|
|
98
|
+
let parentUri: URI | undefined = new URI(uri).parent;
|
|
99
|
+
while (parentUri && !parentUri.path.isRoot) {
|
|
100
|
+
const parentUriString = parentUri.toString();
|
|
101
|
+
const existing = result.get(parentUriString);
|
|
102
|
+
if (existing === undefined) {
|
|
103
|
+
result.set(parentUriString, data);
|
|
104
|
+
parentUri = parentUri.parent;
|
|
105
|
+
} else {
|
|
106
|
+
parentUri = undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get onDidChangeDecorations(): Event<(tree: Tree) => Map<string, TreeDecoration.Data>> {
|
|
114
|
+
return this.emitter.event;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fireDidChangeDecorations(event: (tree: Tree) => Map<string, TreeDecoration.Data>): void {
|
|
118
|
+
this.emitter.fire(event);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|