aboutsummaryrefslogtreecommitdiffstats
path: root/language-web/src/main/js/xtext
diff options
context:
space:
mode:
Diffstat (limited to 'language-web/src/main/js/xtext')
-rw-r--r--language-web/src/main/js/xtext/HighlightingService.ts43
-rw-r--r--language-web/src/main/js/xtext/ValidationService.ts17
-rw-r--r--language-web/src/main/js/xtext/XtextClient.ts10
-rw-r--r--language-web/src/main/js/xtext/xtextServiceResults.ts26
4 files changed, 87 insertions, 9 deletions
diff --git a/language-web/src/main/js/xtext/HighlightingService.ts b/language-web/src/main/js/xtext/HighlightingService.ts
new file mode 100644
index 00000000..b8ceed20
--- /dev/null
+++ b/language-web/src/main/js/xtext/HighlightingService.ts
@@ -0,0 +1,43 @@
1import { Decoration } from '@codemirror/view';
2import { Range, RangeSet } from '@codemirror/rangeset';
3
4import type { EditorStore } from '../editor/EditorStore';
5import type { UpdateService } from './UpdateService';
6import { getLogger } from '../utils/logger';
7import { isHighlightingResult } from './xtextServiceResults';
8
9const log = getLogger('xtext.ValidationService');
10
11export class HighlightingService {
12 private store: EditorStore;
13
14 private updateService: UpdateService;
15
16 constructor(store: EditorStore, updateService: UpdateService) {
17 this.store = store;
18 this.updateService = updateService;
19 }
20
21 onPush(push: unknown): void {
22 if (!isHighlightingResult(push)) {
23 log.error('Invalid highlighting result', push);
24 return;
25 }
26 const allChanges = this.updateService.computeChangesSinceLastUpdate();
27 const decorations: Range<Decoration>[] = [];
28 push.regions.forEach(({ offset, length, styleClasses }) => {
29 if (styleClasses.length === 0) {
30 return;
31 }
32 const from = allChanges.mapPos(offset);
33 const to = allChanges.mapPos(offset + length);
34 if (to <= from) {
35 return;
36 }
37 decorations.push(Decoration.mark({
38 class: styleClasses.map((c) => `cmt-problem-${c}`).join(' '),
39 }).range(from, to));
40 });
41 this.store.updateSemanticHighlighting(RangeSet.of(decorations, true));
42 }
43}
diff --git a/language-web/src/main/js/xtext/ValidationService.ts b/language-web/src/main/js/xtext/ValidationService.ts
index 163b5535..31c8f716 100644
--- a/language-web/src/main/js/xtext/ValidationService.ts
+++ b/language-web/src/main/js/xtext/ValidationService.ts
@@ -24,15 +24,20 @@ export class ValidationService {
24 } 24 }
25 const allChanges = this.updateService.computeChangesSinceLastUpdate(); 25 const allChanges = this.updateService.computeChangesSinceLastUpdate();
26 const diagnostics: Diagnostic[] = []; 26 const diagnostics: Diagnostic[] = [];
27 push.issues.forEach((issue) => { 27 push.issues.forEach(({
28 if (issue.severity === 'ignore') { 28 offset,
29 length,
30 severity,
31 description,
32 }) => {
33 if (severity === 'ignore') {
29 return; 34 return;
30 } 35 }
31 diagnostics.push({ 36 diagnostics.push({
32 from: allChanges.mapPos(issue.offset), 37 from: allChanges.mapPos(offset),
33 to: allChanges.mapPos(issue.offset + issue.length), 38 to: allChanges.mapPos(offset + length),
34 severity: issue.severity, 39 severity,
35 message: issue.description, 40 message: description,
36 }); 41 });
37 }); 42 });
38 this.store.updateDiagnostics(diagnostics); 43 this.store.updateDiagnostics(diagnostics);
diff --git a/language-web/src/main/js/xtext/XtextClient.ts b/language-web/src/main/js/xtext/XtextClient.ts
index 7683a8ef..ccb58ab4 100644
--- a/language-web/src/main/js/xtext/XtextClient.ts
+++ b/language-web/src/main/js/xtext/XtextClient.ts
@@ -6,6 +6,7 @@ import type { Transaction } from '@codemirror/state';
6 6
7import type { EditorStore } from '../editor/EditorStore'; 7import type { EditorStore } from '../editor/EditorStore';
8import { ContentAssistService } from './ContentAssistService'; 8import { ContentAssistService } from './ContentAssistService';
9import { HighlightingService } from './HighlightingService';
9import { UpdateService } from './UpdateService'; 10import { UpdateService } from './UpdateService';
10import { getLogger } from '../utils/logger'; 11import { getLogger } from '../utils/logger';
11import { ValidationService } from './ValidationService'; 12import { ValidationService } from './ValidationService';
@@ -20,6 +21,8 @@ export class XtextClient {
20 21
21 private contentAssistService: ContentAssistService; 22 private contentAssistService: ContentAssistService;
22 23
24 private highlightingService: HighlightingService;
25
23 private validationService: ValidationService; 26 private validationService: ValidationService;
24 27
25 constructor(store: EditorStore) { 28 constructor(store: EditorStore) {
@@ -29,6 +32,7 @@ export class XtextClient {
29 ); 32 );
30 this.updateService = new UpdateService(store, this.webSocketClient); 33 this.updateService = new UpdateService(store, this.webSocketClient);
31 this.contentAssistService = new ContentAssistService(this.updateService); 34 this.contentAssistService = new ContentAssistService(this.updateService);
35 this.highlightingService = new HighlightingService(store, this.updateService);
32 this.validationService = new ValidationService(store, this.updateService); 36 this.validationService = new ValidationService(store, this.updateService);
33 } 37 }
34 38
@@ -50,12 +54,12 @@ export class XtextClient {
50 await this.updateService.updateFullText(); 54 await this.updateService.updateFullText();
51 } 55 }
52 switch (service) { 56 switch (service) {
57 case 'highlight':
58 this.highlightingService.onPush(push);
59 return;
53 case 'validate': 60 case 'validate':
54 this.validationService.onPush(push); 61 this.validationService.onPush(push);
55 return; 62 return;
56 case 'highlight':
57 // TODO
58 return;
59 default: 63 default:
60 log.error('Unknown push service:', service); 64 log.error('Unknown push service:', service);
61 break; 65 break;
diff --git a/language-web/src/main/js/xtext/xtextServiceResults.ts b/language-web/src/main/js/xtext/xtextServiceResults.ts
index 6c3d9daf..e32d49c3 100644
--- a/language-web/src/main/js/xtext/xtextServiceResults.ts
+++ b/language-web/src/main/js/xtext/xtextServiceResults.ts
@@ -198,3 +198,29 @@ export function isContentAssistResult(result: unknown): result is IContentAssist
198 return isDocumentStateResult(result) 198 return isDocumentStateResult(result)
199 && isArrayOfType(contentAssistResult.entries, isContentAssistEntry); 199 && isArrayOfType(contentAssistResult.entries, isContentAssistEntry);
200} 200}
201
202export interface IHighlightingRegion {
203 offset: number;
204
205 length: number;
206
207 styleClasses: string[];
208}
209
210export function isHighlightingRegion(value: unknown): value is IHighlightingRegion {
211 const region = value as IHighlightingRegion;
212 return typeof region === 'object'
213 && typeof region.offset === 'number'
214 && typeof region.length === 'number'
215 && isArrayOfType(region.styleClasses, (s): s is string => typeof s === 'string');
216}
217
218export interface IHighlightingResult {
219 regions: IHighlightingRegion[];
220}
221
222export function isHighlightingResult(result: unknown): result is IHighlightingResult {
223 const highlightingResult = result as IHighlightingResult;
224 return typeof highlightingResult === 'object'
225 && isArrayOfType(highlightingResult.regions, isHighlightingRegion);
226}