Skip to content

Commit

Permalink
create problem markers from task output
Browse files Browse the repository at this point in the history
What's included in this PR:
- support taskDefinition, problemMatcher, & problemPattern contributed by Theia plugins.
- support customizing tasks by adding named & anonymous problem matchers and patterns in .theia/tasks.json.
- support parsing output from both "start - finish" tasks and "watch" tasks.
- support both single line and multi line patterns.
- create problem markers on parsing task output with the plugin-defined or user-defined problem matchers and patterns.

What's not included:
- prompt users to provide problem matcher and / or patterns before starting tasks
- remove problem markers automatically when problems are fixed

Signed-off-by: elaihau <[email protected]>
  • Loading branch information
elaihau committed May 22, 2019
1 parent 730afb4 commit 4b28701
Show file tree
Hide file tree
Showing 30 changed files with 2,094 additions and 71 deletions.
3 changes: 3 additions & 0 deletions packages/cpp/src/browser/cpp-build-configurations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { FileSystemNode } from '@theia/filesystem/lib/node/node-filesystem';
import { bindCppPreferences } from './cpp-preferences';
import { PreferenceService } from '@theia/core/lib/browser/preferences/preference-service';
import { MockPreferenceService } from '@theia/core/lib/browser/preferences/test/mock-preference-service';
import { TaskDefinitionRegistry } from '@theia/task/lib/common/task-protocol';
import { TaskDefinitionRegistryImpl } from '@theia/task/lib/browser/task-definition-registry';

let container: Container;

Expand All @@ -33,6 +35,7 @@ beforeEach(function () {
bind(CppBuildConfigurationManager).to(CppBuildConfigurationManagerImpl).inSingletonScope();
bind(StorageService).to(MockStorageService).inSingletonScope();
bind(FileSystem).to(FileSystemNode).inSingletonScope();
bind(TaskDefinitionRegistry).to(TaskDefinitionRegistryImpl).inSingletonScope();
bindCppPreferences(bind);
bind(PreferenceService).to(MockPreferenceService).inSingletonScope();
});
Expand Down
3 changes: 3 additions & 0 deletions packages/cpp/src/browser/cpp-task-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { Event } from '@theia/core';
import { expect } from 'chai';
import { TaskConfiguration } from '@theia/task/src/common';
import { ProcessTaskConfiguration } from '@theia/task/lib/common/process/task-protocol';
import { TaskDefinitionRegistry } from '@theia/task/lib/common/task-protocol';
import { TaskDefinitionRegistryImpl } from '@theia/task/lib/browser/task-definition-registry';

// The object under test.
let taskProvider: CppTaskProvider;
Expand Down Expand Up @@ -67,6 +69,7 @@ beforeEach(function () {
const container: Container = new Container();
container.bind(CppTaskProvider).toSelf().inSingletonScope();
container.bind(TaskResolverRegistry).toSelf().inSingletonScope();
container.bind(TaskDefinitionRegistry).to(TaskDefinitionRegistryImpl).inSingletonScope();
container.bind(CppBuildConfigurationManager).to(MockCppBuildConfigurationManager);
taskProvider = container.get(CppTaskProvider);

Expand Down
23 changes: 21 additions & 2 deletions packages/cpp/src/browser/cpp-task-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
********************************************************************************/

import parseArgv = require('string-argv');
import { inject, injectable } from 'inversify';
import { inject, injectable, postConstruct } from 'inversify';
import { ProcessTaskConfiguration } from '@theia/task/lib/common/process/task-protocol';
import { TaskContribution, TaskProvider, TaskProviderRegistry, TaskResolver, TaskResolverRegistry } from '@theia/task/lib/browser/task-contribution';
import { CppBuildConfigurationManager, CppBuildConfiguration } from './cpp-build-configurations';
import { ContributedTaskConfiguration, TaskConfiguration } from '@theia/task/lib/common/task-protocol';
import { ContributedTaskConfiguration, TaskConfiguration, TaskDefinitionRegistry } from '@theia/task/lib/common/task-protocol';

/**
* Data required to define a C/C++ build task the user could run.
Expand All @@ -35,8 +35,14 @@ const CPP_BUILD_TASK_SOURCE: string = 'cpp';
export class CppTaskProvider implements TaskContribution, TaskProvider, TaskResolver {

@inject(TaskResolverRegistry) protected readonly taskResolverRegistry: TaskResolverRegistry;
@inject(TaskDefinitionRegistry) protected readonly taskDefinitionRegistry: TaskDefinitionRegistry;
@inject(CppBuildConfigurationManager) protected readonly cppBuildConfigurationManager: CppBuildConfigurationManager;

@postConstruct()
protected init(): void {
this.registerTaskDefinition();
}

registerProviders(registry: TaskProviderRegistry) {
registry.register(CPP_BUILD_TASK_SOURCE, this);
}
Expand Down Expand Up @@ -108,4 +114,17 @@ export class CppTaskProvider implements TaskContribution, TaskProvider, TaskReso

return taskConfigs;
}

private registerTaskDefinition(): void {
this.taskDefinitionRegistry.register({
type: CPP_BUILD_TASK_TYPE_KEY,
required: ['label'],
properties: {
label: {
type: 'string',
description: 'Lable of the cpp build configuration task'
}
}
}, CPP_BUILD_TASK_SOURCE);
}
}
7 changes: 7 additions & 0 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ExtPluginApi } from './plugin-ext-api-contribution';
import { IJSONSchema, IJSONSchemaSnippet } from '@theia/core/lib/common/json-schema';
import { RecursivePartial } from '@theia/core/lib/common/types';
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/common/preferences/preference-schema';
import { TaskDefinitionContribution, ProblemMatcherContribution, ProblemPatternContribution } from '@theia/task/lib/common';

export const hostedServicePath = '/services/hostedPlugin';

Expand Down Expand Up @@ -71,6 +72,9 @@ export interface PluginPackageContribution {
keybindings?: PluginPackageKeybinding[];
debuggers?: PluginPackageDebuggersContribution[];
snippets: PluginPackageSnippetsContribution[];
taskDefinitions?: TaskDefinitionContribution[];
problemMatchers?: ProblemMatcherContribution[];
problemPatterns?: ProblemPatternContribution[];
}

export interface PluginPackageViewContainer {
Expand Down Expand Up @@ -364,6 +368,9 @@ export interface PluginContribution {
keybindings?: Keybinding[];
debuggers?: DebuggerContribution[];
snippets?: SnippetContribution[];
taskDefinitions?: TaskDefinitionContribution[];
problemMatchers?: ProblemMatcherContribution[];
problemPatterns?: ProblemPatternContribution[];
}

export interface SnippetContribution {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export class HostedPluginSupport {
}

if (plugin.model.contributes) {
this.contributionHandler.handleContributions(plugin.model.contributes);
this.contributionHandler.handleContributions(plugin.model.contributes, plugin.model.id);
}
}

Expand Down
13 changes: 13 additions & 0 deletions packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { deepClone } from '@theia/core/lib/common/objects';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/common/preferences/preference-schema';
import { RecursivePartial } from '@theia/core/lib/common/types';
import { TaskDefinitionContribution, ProblemMatcherContribution, ProblemPatternContribution } from '@theia/task/lib/common/task-protocol';

namespace nls {
export function localize(key: string, _default: string) {
Expand Down Expand Up @@ -183,6 +184,18 @@ export class TheiaPluginScanner implements PluginScanner {
contributions.debuggers = debuggers;
}

if (rawPlugin.contributes!.taskDefinitions) {
contributions.taskDefinitions = rawPlugin.contributes!.taskDefinitions as TaskDefinitionContribution[];
}

if (rawPlugin.contributes!.problemMatchers) {
contributions.problemMatchers = rawPlugin.contributes!.problemMatchers as ProblemMatcherContribution[];
}

if (rawPlugin.contributes!.problemPatterns) {
contributions.problemPatterns = rawPlugin.contributes!.problemPatterns as ProblemPatternContribution[];
}

contributions.snippets = this.readSnippets(rawPlugin);
return contributions;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { KeybindingsContributionPointHandler } from './keybindings/keybindings-c
import { MonacoSnippetSuggestProvider } from '@theia/monaco/lib/browser/monaco-snippet-suggest-provider';
import { PluginSharedStyle } from './plugin-shared-style';
import { CommandRegistry } from '@theia/core';
import { TaskDefinitionRegistry, ProblemMatcherRegistry, ProblemPatternRegistry } from '@theia/task/lib/common';

@injectable()
export class PluginContributionHandler {
Expand Down Expand Up @@ -59,7 +60,16 @@ export class PluginContributionHandler {
@inject(PluginSharedStyle)
protected readonly style: PluginSharedStyle;

handleContributions(contributions: PluginContribution): void {
@inject(TaskDefinitionRegistry)
protected readonly taskDefinitionRegistry: TaskDefinitionRegistry;

@inject(ProblemMatcherRegistry)
protected readonly problemMatcherRegistry: ProblemMatcherRegistry;

@inject(ProblemPatternRegistry)
protected readonly problemPatternRegistry: ProblemPatternRegistry;

handleContributions(contributions: PluginContribution, modelId: string): void {
if (contributions.configuration) {
this.updateConfigurationSchema(contributions.configuration);
}
Expand Down Expand Up @@ -149,6 +159,18 @@ export class PluginContributionHandler {
});
}
}

if (contributions.taskDefinitions) {
contributions.taskDefinitions.forEach(def => this.taskDefinitionRegistry.register(def, modelId));
}

if (contributions.problemPatterns) {
contributions.problemPatterns.forEach(pattern => this.problemPatternRegistry.register(pattern.name!, pattern));
}

if (contributions.problemMatchers) {
contributions.problemMatchers.forEach(matcher => this.problemMatcherRegistry.register(matcher));
}
}

protected registerCommands(contribution: PluginContribution): void {
Expand Down
6 changes: 4 additions & 2 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1728,12 +1728,14 @@ export class Task {
if (this.taskExecution instanceof ProcessExecution) {
Object.assign(this.taskDefinition, {
type: 'process',
id: this.taskExecution.computeId()
id: this.taskExecution.computeId(),
taskType: this.taskDefinition!.type
});
} else if (this.taskExecution instanceof ShellExecution) {
Object.assign(this.taskDefinition, {
type: 'shell',
id: this.taskExecution.computeId()
id: this.taskExecution.computeId(),
taskType: this.taskDefinition!.type
});
}
}
Expand Down
1 change: 0 additions & 1 deletion packages/process/src/node/terminal-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,5 +286,4 @@ export class TerminalProcess extends Process {
throw new Error('pty process did not start correctly');
}
}

}
3 changes: 2 additions & 1 deletion packages/task/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"@theia/terminal": "^0.6.0",
"@theia/variable-resolver": "^0.6.0",
"@theia/workspace": "^0.6.0",
"jsonc-parser": "^2.0.2"
"jsonc-parser": "^2.0.2",
"vscode-uri": "^1.0.1"
},
"publishConfig": {
"access": "public"
Expand Down
45 changes: 27 additions & 18 deletions packages/task/src/browser/quick-open-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
QuickOpenGroupItem, QuickOpenMode, QuickOpenHandler, QuickOpenOptions, QuickOpenActionProvider, QuickOpenGroupItemOptions
} from '@theia/core/lib/browser/quick-open/';
import { TaskService } from './task-service';
import { ContributedTaskConfiguration, TaskInfo, TaskConfiguration } from '../common/task-protocol';
import { TaskInfo, TaskConfiguration, TaskDefinitionRegistry } from '../common/task-protocol';
import { TaskConfigurations } from './task-configurations';
import URI from '@theia/core/lib/common/uri';
import { TaskActionProvider } from './task-action-provider';
Expand Down Expand Up @@ -58,6 +58,9 @@ export class QuickOpenTask implements QuickOpenModel, QuickOpenHandler {
@inject(TaskConfigurations)
protected readonly taskConfigurations: TaskConfigurations;

@inject(TaskDefinitionRegistry)
protected readonly taskDefinitionRegistry: TaskDefinitionRegistry;

/** Initialize this quick open model with the tasks. */
async init(): Promise<void> {
const recentTasks = this.taskService.recentTasks;
Expand All @@ -69,29 +72,38 @@ export class QuickOpenTask implements QuickOpenModel, QuickOpenHandler {
const isMulti = stat ? !stat.isDirectory : false;
this.items = [];
this.items.push(
...filteredRecentTasks.map((task, index) =>
new TaskRunQuickOpenItem(task, this.taskService, isMulti, {
...filteredRecentTasks.map((task, index) => {
const item = new TaskRunQuickOpenItem(task, this.taskService, isMulti, {
groupLabel: index === 0 ? 'recently used tasks' : undefined,
showBorder: false
})),
...filteredConfiguredTasks.map((task, index) =>
new TaskRunQuickOpenItem(task, this.taskService, isMulti, {
});
item['taskDefinitionRegistry'] = this.taskDefinitionRegistry;
return item;
}),
...filteredConfiguredTasks.map((task, index) => {
const item = new TaskRunQuickOpenItem(task, this.taskService, isMulti, {
groupLabel: index === 0 ? 'configured tasks' : undefined,
showBorder: (
filteredRecentTasks.length <= 0
? false
: index === 0 ? true : false
)
})),
...filteredProvidedTasks.map((task, index) =>
new TaskRunQuickOpenItem(task, this.taskService, isMulti, {
});
item['taskDefinitionRegistry'] = this.taskDefinitionRegistry;
return item;
}),
...filteredProvidedTasks.map((task, index) => {
const item = new TaskRunQuickOpenItem(task, this.taskService, isMulti, {
groupLabel: index === 0 ? 'detected tasks' : undefined,
showBorder: (
filteredRecentTasks.length <= 0 && filteredConfiguredTasks.length <= 0
? false
: index === 0 ? true : false
)
}))
});
item['taskDefinitionRegistry'] = this.taskDefinitionRegistry;
return item;
})
);

this.actionProvider = this.items.length ? this.taskActionProvider : undefined;
Expand Down Expand Up @@ -221,6 +233,8 @@ export class QuickOpenTask implements QuickOpenModel, QuickOpenHandler {

export class TaskRunQuickOpenItem extends QuickOpenGroupItem {

protected taskDefinitionRegistry: TaskDefinitionRegistry;

constructor(
protected readonly task: TaskConfiguration,
protected taskService: TaskService,
Expand All @@ -235,7 +249,7 @@ export class TaskRunQuickOpenItem extends QuickOpenGroupItem {
}

getLabel(): string {
if (ContributedTaskConfiguration.is(this.task)) {
if (this.taskDefinitionRegistry && !!this.taskDefinitionRegistry.getDefinition(this.task)) {
return `${this.task._source}: ${this.task.label}`;
}
return `${this.task.type}: ${this.task.label}`;
Expand All @@ -249,7 +263,7 @@ export class TaskRunQuickOpenItem extends QuickOpenGroupItem {
if (!this.isMulti) {
return '';
}
if (ContributedTaskConfiguration.is(this.task)) {
if (this.taskDefinitionRegistry && !!this.taskDefinitionRegistry.getDefinition(this.task)) {
if (this.task._scope) {
return new URI(this.task._scope).path.toString();
}
Expand All @@ -265,12 +279,7 @@ export class TaskRunQuickOpenItem extends QuickOpenGroupItem {
return false;
}

if (ContributedTaskConfiguration.is(this.task)) {
this.taskService.run(this.task._source, this.task.label);
} else {
this.taskService.runConfiguredTask(this.task._source, this.task.label);
}

this.taskService.run(this.task._source, this.task.label);
return true;
}
}
Expand Down
Loading

0 comments on commit 4b28701

Please sign in to comment.