|
@@ -3,6 +3,10 @@ import { inject, injectable } from '@theia/core/shared/inversify';
|
|
|
import {
|
|
import {
|
|
|
Command, CommandContribution, CommandRegistry, MessageService,
|
|
Command, CommandContribution, CommandRegistry, MessageService,
|
|
|
} from '@theia/core/lib/common';
|
|
} from '@theia/core/lib/common';
|
|
|
|
|
+import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
|
|
|
+import { codicon } from '@theia/core/lib/browser';
|
|
|
|
|
+import { Widget } from '@theia/core/lib/browser';
|
|
|
|
|
+import { EditorWidget } from '@theia/editor/lib/browser';
|
|
|
import { RemoteConnectionProvider, ServiceConnectionProvider } from '@theia/core/lib/browser/messaging/service-connection-provider';
|
|
import { RemoteConnectionProvider, ServiceConnectionProvider } from '@theia/core/lib/browser/messaging/service-connection-provider';
|
|
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
|
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
|
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
|
@@ -11,6 +15,7 @@ import { ProblemManager } from '@theia/markers/lib/browser/problem/problem-manag
|
|
|
import { Diagnostic, DiagnosticSeverity } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
import { Diagnostic, DiagnosticSeverity } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
|
import { PreferenceContribution } from '@theia/core/lib/common/preferences/preference-schema';
|
|
import { PreferenceContribution } from '@theia/core/lib/common/preferences/preference-schema';
|
|
|
import { PreferenceService } from '@theia/core/lib/common/preferences/preference-service';
|
|
import { PreferenceService } from '@theia/core/lib/common/preferences/preference-service';
|
|
|
|
|
+import { OutputChannelManager } from '@theia/output/lib/browser/output-channel';
|
|
|
import { TaskContribution } from '@theia/task/lib/browser/task-contribution';
|
|
import { TaskContribution } from '@theia/task/lib/browser/task-contribution';
|
|
|
import URI from '@theia/core/lib/common/uri';
|
|
import URI from '@theia/core/lib/common/uri';
|
|
|
import {
|
|
import {
|
|
@@ -52,6 +57,7 @@ class CompilerCommands implements CommandContribution {
|
|
|
@inject(MessageService) protected readonly messages: MessageService;
|
|
@inject(MessageService) protected readonly messages: MessageService;
|
|
|
@inject(ProblemManager) protected readonly problems: ProblemManager;
|
|
@inject(ProblemManager) protected readonly problems: ProblemManager;
|
|
|
@inject(PreferenceService) protected readonly prefs: PreferenceService;
|
|
@inject(PreferenceService) protected readonly prefs: PreferenceService;
|
|
|
|
|
+ @inject(OutputChannelManager) protected readonly outputChannels: OutputChannelManager;
|
|
|
/** URIs currently carrying our markers, so stale ones can be cleared. */
|
|
/** URIs currently carrying our markers, so stale ones can be cleared. */
|
|
|
protected readonly markedUris = new Set<string>();
|
|
protected readonly markedUris = new Set<string>();
|
|
|
|
|
|
|
@@ -132,12 +138,21 @@ class CompilerCommands implements CommandContribution {
|
|
|
return `${errors} error(s), ${warnings} warning(s). Command: ${result.command}`;
|
|
return `${errors} error(s), ${warnings} warning(s). Command: ${result.command}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** Append the exact command plus its output to the Modula-2 channel. */
|
|
|
|
|
+ protected logCommand(command: string, output: string): void {
|
|
|
|
|
+ const channel = this.outputChannels.getChannel('Modula-2');
|
|
|
|
|
+ channel.appendLine(`$ ${command}`);
|
|
|
|
|
+ if (output.length > 0) channel.append(output.endsWith('\n') ? output : output + '\n');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
protected async build(project: Modula2Project): Promise<void> {
|
|
protected async build(project: Modula2Project): Promise<void> {
|
|
|
const result = await this.compiler.build(project);
|
|
const result = await this.compiler.build(project);
|
|
|
this.setProblemMarkers(project, result.diagnostics);
|
|
this.setProblemMarkers(project, result.diagnostics);
|
|
|
|
|
+ this.logCommand(result.command, result.output);
|
|
|
if (result.success) {
|
|
if (result.success) {
|
|
|
this.messages.info(`Modula-2: build succeeded. ${this.summarize(result)}`);
|
|
this.messages.info(`Modula-2: build succeeded. ${this.summarize(result)}`);
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ this.outputChannels.getChannel('Modula-2').show();
|
|
|
const first = result.diagnostics.slice(0, 3)
|
|
const first = result.diagnostics.slice(0, 3)
|
|
|
.map(d => `${d.file}:${d.line + 1}:${d.character + 1}: ${d.message}`).join('\n');
|
|
.map(d => `${d.file}:${d.line + 1}:${d.character + 1}: ${d.message}`).join('\n');
|
|
|
this.messages.error(`Modula-2: build failed. ${this.summarize(result)}${first ? '\n' + first : ''}`);
|
|
this.messages.error(`Modula-2: build failed. ${this.summarize(result)}${first ? '\n' + first : ''}`);
|
|
@@ -167,14 +182,16 @@ class CompilerCommands implements CommandContribution {
|
|
|
protected async run(project: Modula2Project): Promise<void> {
|
|
protected async run(project: Modula2Project): Promise<void> {
|
|
|
const result = await this.compiler.run(project);
|
|
const result = await this.compiler.run(project);
|
|
|
this.setProblemMarkers(project, result.diagnostics);
|
|
this.setProblemMarkers(project, result.diagnostics);
|
|
|
|
|
+ // The build step already logged its command; log the run itself.
|
|
|
|
|
+ this.logCommand(result.command, result.output);
|
|
|
|
|
+ this.outputChannels.getChannel('Modula-2').show();
|
|
|
if (!result.success && result.diagnostics.length > 0) {
|
|
if (!result.success && result.diagnostics.length > 0) {
|
|
|
const first = result.diagnostics.slice(0, 3)
|
|
const first = result.diagnostics.slice(0, 3)
|
|
|
.map(d => `${d.file}:${d.line + 1}:${d.character + 1}: ${d.message}`).join('\n');
|
|
.map(d => `${d.file}:${d.line + 1}:${d.character + 1}: ${d.message}`).join('\n');
|
|
|
this.messages.error(`Modula-2: build failed.\n${first}`);
|
|
this.messages.error(`Modula-2: build failed.\n${first}`);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- const output = result.output.length > 2000 ? result.output.slice(0, 2000) + '\n…' : result.output;
|
|
|
|
|
- this.messages.info(`Modula-2: program exited with code ${result.exitCode}.\n${output}`);
|
|
|
|
|
|
|
+ this.messages.info(`Modula-2: program exited with code ${result.exitCode}.`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
protected async detect(): Promise<void> {
|
|
protected async detect(): Promise<void> {
|
|
@@ -188,6 +205,36 @@ class CompilerCommands implements CommandContribution {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+@injectable()
|
|
|
|
|
+class CompilerToolbar implements TabBarToolbarContribution {
|
|
|
|
|
+ registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
|
|
|
|
+ // Editor toolbar buttons, visible only for Modula-2 files in editors.
|
|
|
|
|
+ // The `when` clause follows the active file; `isVisible` additionally
|
|
|
|
|
+ // restricts to editor widgets so the buttons do not leak into the
|
|
|
|
|
+ // Outline and other side views sharing the same tab-bar toolbar.
|
|
|
|
|
+ const when = 'resourceExtname == .mod || resourceExtname == .def';
|
|
|
|
|
+ const editorsOnly = (widget?: Widget): boolean => widget instanceof EditorWidget;
|
|
|
|
|
+ registry.registerItem({
|
|
|
|
|
+ id: 'modula2.build.toolbar',
|
|
|
|
|
+ command: Commands.build.id,
|
|
|
|
|
+ icon: codicon('tools'),
|
|
|
|
|
+ tooltip: 'Modula-2: Build',
|
|
|
|
|
+ when,
|
|
|
|
|
+ isVisible: editorsOnly,
|
|
|
|
|
+ priority: 1,
|
|
|
|
|
+ });
|
|
|
|
|
+ registry.registerItem({
|
|
|
|
|
+ id: 'modula2.run.toolbar',
|
|
|
|
|
+ command: Commands.run.id,
|
|
|
|
|
+ icon: codicon('play'),
|
|
|
|
|
+ tooltip: 'Modula-2: Run',
|
|
|
|
|
+ when,
|
|
|
|
|
+ isVisible: editorsOnly,
|
|
|
|
|
+ priority: 2,
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export default new ContainerModule(bind => {
|
|
export default new ContainerModule(bind => {
|
|
|
bind(PreferenceContribution).toConstantValue({ schema: modula2PreferenceSchema });
|
|
bind(PreferenceContribution).toConstantValue({ schema: modula2PreferenceSchema });
|
|
|
bind(Modula2Compiler).toDynamicValue(ctx => {
|
|
bind(Modula2Compiler).toDynamicValue(ctx => {
|
|
@@ -195,6 +242,7 @@ export default new ContainerModule(bind => {
|
|
|
return provider.createProxy<Modula2Compiler>(Modula2CompilerServicePath);
|
|
return provider.createProxy<Modula2Compiler>(Modula2CompilerServicePath);
|
|
|
}).inSingletonScope();
|
|
}).inSingletonScope();
|
|
|
bind(CommandContribution).to(CompilerCommands).inSingletonScope();
|
|
bind(CommandContribution).to(CompilerCommands).inSingletonScope();
|
|
|
|
|
+ bind(TabBarToolbarContribution).to(CompilerToolbar).inSingletonScope();
|
|
|
bind(Modula2TaskProvider).toSelf().inSingletonScope();
|
|
bind(Modula2TaskProvider).toSelf().inSingletonScope();
|
|
|
bind(Modula2TaskResolver).toSelf().inSingletonScope();
|
|
bind(Modula2TaskResolver).toSelf().inSingletonScope();
|
|
|
bind(TaskContribution).to(Modula2TaskContribution).inSingletonScope();
|
|
bind(TaskContribution).to(Modula2TaskContribution).inSingletonScope();
|