Skip to content

Commit 9001508

Browse files
authoredAug 25, 2023
Ensure contributed problem patterns are found correctly (#12805)
- Resolve pattern names correctly by removing leading '$' - Introduce utility function for dealing with variable names - Ensure 'ready' promises are already available with object creation Fixes #12725
1 parent 5720724 commit 9001508

7 files changed

+69
-26
lines changed
 

‎packages/task/src/browser/task-configurations.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import {
2121
TaskDefinition,
2222
TaskOutputPresentation,
2323
TaskConfigurationScope,
24-
TaskScope
24+
TaskScope,
25+
asVariableName
2526
} from '../common';
2627
import { TaskDefinitionRegistry } from './task-definition-registry';
2728
import { ProvidedTaskConfigurations } from './provided-task-configurations';
@@ -349,7 +350,7 @@ export class TaskConfigurations implements Disposable {
349350
} else if (task.problemMatcher) {
350351
problemMatcher.push(task.problemMatcher.name!);
351352
}
352-
customization.problemMatcher = problemMatcher.map(name => name.startsWith('$') ? name : `$${name}`);
353+
customization.problemMatcher = problemMatcher.map(asVariableName);
353354
}
354355
if (task.group) {
355356
customization.group = task.group;

‎packages/task/src/browser/task-problem-matcher-registry.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ import { Event, Emitter } from '@theia/core/lib/common';
2424
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
2525
import {
2626
ApplyToKind, FileLocationKind, NamedProblemMatcher,
27-
ProblemPattern, ProblemMatcher, ProblemMatcherContribution, WatchingMatcher
27+
ProblemPattern, ProblemMatcher, ProblemMatcherContribution, WatchingMatcher,
28+
fromVariableName
2829
} from '../common';
2930
import { ProblemPatternRegistry } from './task-problem-pattern-registry';
3031
import { Severity } from '@theia/core/lib/common/severity';
32+
import { Deferred } from '@theia/core/lib/common/promise-util';
3133

3234
@injectable()
3335
export class ProblemMatcherRegistry {
3436

3537
private readonly matchers = new Map<string, NamedProblemMatcher>();
36-
private readyPromise: Promise<void>;
38+
private readyPromise = new Deferred<void>();
3739

3840
@inject(ProblemPatternRegistry)
3941
protected readonly problemPatternRegistry: ProblemPatternRegistry;
@@ -47,13 +49,13 @@ export class ProblemMatcherRegistry {
4749
protected init(): void {
4850
this.problemPatternRegistry.onReady().then(() => {
4951
this.fillDefaults();
50-
this.readyPromise = new Promise<void>((res, rej) => res(undefined));
52+
this.readyPromise.resolve();
5153
this.onDidChangeProblemMatcherEmitter.fire(undefined);
5254
});
5355
}
5456

5557
onReady(): Promise<void> {
56-
return this.readyPromise;
58+
return this.readyPromise.promise;
5759
}
5860

5961
/**
@@ -73,6 +75,7 @@ export class ProblemMatcherRegistry {
7375
this.doRegister(matcher, toDispose).then(() => this.onDidChangeProblemMatcherEmitter.fire(undefined));
7476
return toDispose;
7577
}
78+
7679
protected async doRegister(matcher: ProblemMatcherContribution, toDispose: DisposableCollection): Promise<void> {
7780
const problemMatcher = await this.getProblemMatcherFromContribution(matcher);
7881
if (toDispose.disposed) {
@@ -88,10 +91,7 @@ export class ProblemMatcherRegistry {
8891
* @return the problem matcher. If the task definition is not found, `undefined` is returned.
8992
*/
9093
get(name: string): NamedProblemMatcher | undefined {
91-
if (name.startsWith('$')) {
92-
return this.matchers.get(name.slice(1));
93-
}
94-
return this.matchers.get(name);
94+
return this.matchers.get(fromVariableName(name));
9595
}
9696

9797
/**
@@ -132,7 +132,7 @@ export class ProblemMatcherRegistry {
132132
if (matcher.pattern) {
133133
if (typeof matcher.pattern === 'string') {
134134
await this.problemPatternRegistry.onReady();
135-
const registeredPattern = this.problemPatternRegistry.get(matcher.pattern);
135+
const registeredPattern = this.problemPatternRegistry.get(fromVariableName(matcher.pattern));
136136
if (Array.isArray(registeredPattern)) {
137137
patterns.push(...registeredPattern);
138138
} else if (!!registeredPattern) {

‎packages/task/src/browser/task-problem-pattern-registry.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@
1919
* Licensed under the MIT License. See License.txt in the project root for license information.
2020
*--------------------------------------------------------------------------------------------*/
2121

22+
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
23+
import { Deferred } from '@theia/core/lib/common/promise-util';
2224
import { injectable, postConstruct } from '@theia/core/shared/inversify';
2325
import { NamedProblemPattern, ProblemLocationKind, ProblemPattern, ProblemPatternContribution } from '../common';
24-
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
2526

2627
@injectable()
2728
export class ProblemPatternRegistry {
2829
private readonly patterns = new Map<string, NamedProblemPattern | NamedProblemPattern[]>();
29-
private readyPromise: Promise<void>;
30+
private readyPromise = new Deferred<void>();
3031

3132
@postConstruct()
3233
protected init(): void {
3334
this.fillDefaults();
34-
this.readyPromise = new Promise<void>((res, rej) => res(undefined));
35+
this.readyPromise.resolve();
3536
}
3637

3738
onReady(): Promise<void> {
38-
return this.readyPromise;
39+
return this.readyPromise.promise;
3940
}
4041

4142
/**

‎packages/task/src/browser/task-schema-updater.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { inputsSchema } from '@theia/variable-resolver/lib/browser/variable-inpu
3030
import URI from '@theia/core/lib/common/uri';
3131
import { ProblemMatcherRegistry } from './task-problem-matcher-registry';
3232
import { TaskDefinitionRegistry } from './task-definition-registry';
33-
import { TaskServer } from '../common';
33+
import { TaskServer, asVariableName } from '../common';
3434
import { UserStorageUri } from '@theia/userstorage/lib/browser';
3535
import { WorkspaceService } from '@theia/workspace/lib/browser';
3636
import { JSONObject } from '@theia/core/shared/@phosphor/coreutils';
@@ -213,7 +213,7 @@ export class TaskSchemaUpdater implements JsonSchemaContribution {
213213

214214
/** Gets the most up-to-date names of problem matchers from the registry and update the task schema */
215215
private updateProblemMatcherNames(): void {
216-
const matcherNames = this.problemMatcherRegistry.getAll().map(m => m.name.startsWith('$') ? m.name : `$${m.name}`);
216+
const matcherNames = this.problemMatcherRegistry.getAll().map(m => asVariableName(m.name));
217217
problemMatcherNames.length = 0;
218218
problemMatcherNames.push(...matcherNames);
219219
this.update();

‎packages/task/src/browser/task-service.ts

+6-9
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ import {
4848
TaskInfo,
4949
TaskOutputPresentation,
5050
TaskOutputProcessedEvent,
51-
TaskServer
51+
TaskServer,
52+
asVariableName
5253
} from '../common';
5354
import { TaskWatcher } from '../common/task-watcher';
5455
import { ProvidedTaskConfigurations } from './provided-task-configurations';
@@ -908,13 +909,9 @@ export class TaskService implements TaskConfigurationClient {
908909
async updateTaskConfiguration(token: number, task: TaskConfiguration, update: { [name: string]: any }): Promise<void> {
909910
if (update.problemMatcher) {
910911
if (Array.isArray(update.problemMatcher)) {
911-
update.problemMatcher.forEach((name, index) => {
912-
if (!name.startsWith('$')) {
913-
update.problemMatcher[index] = `$${update.problemMatcher[index]}`;
914-
}
915-
});
916-
} else if (!update.problemMatcher.startsWith('$')) {
917-
update.problemMatcher = `$${update.problemMatcher}`;
912+
update.problemMatcher.forEach((_name, index) => update.problemMatcher[index] = asVariableName(update.problemMatcher[index]));
913+
} else {
914+
update.problemMatcher = asVariableName(update.problemMatcher);
918915
}
919916
}
920917
this.taskConfigurations.updateTaskConfig(token, task, update);
@@ -1041,7 +1038,7 @@ export class TaskService implements TaskConfigurationClient {
10411038
({
10421039
label: matcher.label,
10431040
value: { problemMatchers: [matcher] },
1044-
description: matcher.name.startsWith('$') ? matcher.name : `$${matcher.name}`
1041+
description: asVariableName(matcher.name)
10451042
})
10461043
));
10471044
return items;

‎packages/task/src/common/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
export * from './task-protocol';
1818
export * from './task-watcher';
1919
export * from './problem-matcher-protocol';
20+
export * from './task-util';

‎packages/task/src/common/task-util.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2023 EclipseSource 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+
* Converts the given standard name to a variable name starting with '$' if not already present.
19+
*
20+
* Variable names are used, for instance, to reference problem matchers, within task configurations.
21+
*
22+
* @param name standard name
23+
* @returns variable name with leading '$' if not already present.
24+
*
25+
* @see {@link fromVariableName} for the reverse conversion.
26+
*/
27+
export function asVariableName(name: string): string {
28+
return name.startsWith('$') ? name : `$${name}`;
29+
}
30+
31+
/**
32+
* Converts a given variable name to a standard name, effectively removing a leading '$' if present.
33+
*
34+
* Standard names are used, for instance, in registries to store variable objects
35+
*
36+
* @param name variable name
37+
* @returns variable name without leading '$' if present.
38+
*
39+
* @see {@link asVariableName} for the reverse conversion.
40+
*/
41+
export function fromVariableName(name: string): string {
42+
return name.startsWith('$') ? name.slice(1) : name;
43+
}

0 commit comments

Comments
 (0)
Please sign in to comment.