diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 1bd31804..7c72a3c4 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -140,6 +140,8 @@ import { bindArduinoPreferences } from './arduino-preferences' import { SettingsService, SettingsDialog, SettingsWidget, SettingsDialogProps } from './settings'; import { AddFile } from './contributions/add-file'; import { ArchiveSketch } from './contributions/archive-sketch'; +import { OutputToolbarContribution as TheiaOutputToolbarContribution } from '@theia/output/lib/browser/output-toolbar-contribution'; +import { OutputToolbarContribution } from './theia/output/output-toolbar-contribution'; const ElementQueries = require('css-element-queries/src/ElementQueries'); @@ -313,6 +315,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(ShellLayoutRestorer).toSelf().inSingletonScope(); rebind(TheiaShellLayoutRestorer).toService(ShellLayoutRestorer); + // No dropdown for the _Output_ view. + bind(OutputToolbarContribution).toSelf().inSingletonScope(); + rebind(TheiaOutputToolbarContribution).toService(OutputToolbarContribution); + bind(ArduinoDaemon).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ArduinoDaemonPath)).inSingletonScope(); // File-system extension diff --git a/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts b/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts index e04e06ad..1b19be40 100644 --- a/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts +++ b/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts @@ -53,7 +53,7 @@ export class BurnBootloader extends SketchContribution { this.preferences.get('arduino.upload.verify'), this.preferences.get('arduino.upload.verbose') ]); - this.outputChannelManager.getChannel('Arduino: bootloader').clear(); + this.outputChannelManager.getChannel('Arduino').clear(); await this.coreService.burnBootloader({ fqbn, programmer, diff --git a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts index 06a1fd6e..d8cb8c31 100644 --- a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts @@ -122,7 +122,7 @@ export class UploadSketch extends SketchContribution { verify }; } - this.outputChannelManager.getChannel('Arduino: upload').clear(); + this.outputChannelManager.getChannel('Arduino').clear(); if (usingProgrammer) { await this.coreService.uploadUsingProgrammer(options); } else { diff --git a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts index 606b4095..01bc2a1c 100644 --- a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts @@ -77,7 +77,7 @@ export class VerifySketch extends SketchContribution { const { boardsConfig } = this.boardsServiceClientImpl; const fqbn = await this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn); const verbose = this.preferences.get('arduino.compile.verbose'); - this.outputChannelManager.getChannel('Arduino: compile').clear(); + this.outputChannelManager.getChannel('Arduino').clear(); await this.coreService.compile({ sketchUri: uri, fqbn, diff --git a/arduino-ide-extension/src/browser/output-service-impl.ts b/arduino-ide-extension/src/browser/output-service-impl.ts index c0ebe34d..098db8b4 100644 --- a/arduino-ide-extension/src/browser/output-service-impl.ts +++ b/arduino-ide-extension/src/browser/output-service-impl.ts @@ -13,16 +13,10 @@ export class OutputServiceImpl implements OutputService { protected outputChannelManager: OutputChannelManager; append(message: OutputMessage): void { - const { name, chunk } = message; - const channel = this.outputChannelManager.getChannel(`Arduino: ${name}`); - // Zen-mode: we do not reveal the output for daemon messages. - const show: Promise = name === 'daemon' - // This will open and reveal the view but won't show it. You will see the toggle bottom panel on the status bar. - ? this.outputContribution.openView({ activate: false, reveal: false }) - // This will open, reveal but do not activate the Output view. - : Promise.resolve(channel.show({ preserveFocus: true })); - - show.then(() => channel.append(chunk)); + const { chunk } = message; + const channel = this.outputChannelManager.getChannel(`Arduino`); + channel.show({ preserveFocus: true }); + channel.append(chunk); } } diff --git a/arduino-ide-extension/src/browser/theia/output/output-toolbar-contribution.ts b/arduino-ide-extension/src/browser/theia/output/output-toolbar-contribution.ts new file mode 100644 index 00000000..54def619 --- /dev/null +++ b/arduino-ide-extension/src/browser/theia/output/output-toolbar-contribution.ts @@ -0,0 +1,15 @@ +import { injectable } from 'inversify'; +import { ReactTabBarToolbarItem, TabBarToolbarItem, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { OutputToolbarContribution as TheiaOutputToolbarContribution } from '@theia/output/lib/browser/output-toolbar-contribution'; + +@injectable() +export class OutputToolbarContribution extends TheiaOutputToolbarContribution { + + async registerToolbarItems(registry: TabBarToolbarRegistry): Promise { + await super.registerToolbarItems(registry); // Why is it async? + // It's a hack. Currently, it's not possible to unregister a toolbar contribution via API. + ((registry as any).items as Map).delete('channels'); + (registry as any).fireOnDidChange(); + } + +} diff --git a/arduino-ide-extension/src/common/protocol/output-service.ts b/arduino-ide-extension/src/common/protocol/output-service.ts index f8e0cba2..84509f67 100644 --- a/arduino-ide-extension/src/common/protocol/output-service.ts +++ b/arduino-ide-extension/src/common/protocol/output-service.ts @@ -1,5 +1,4 @@ export interface OutputMessage { - readonly name: string; readonly chunk: string; readonly severity?: 'error' | 'warning' | 'info'; // Currently not used! } diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index 27bee4d2..052e6ee1 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -271,7 +271,7 @@ export class BoardsServiceImpl implements BoardsService { resp.on('data', (r: PlatformInstallResp) => { const prog = r.getProgress(); if (prog && prog.getFile()) { - this.outputService.append({ name: 'board download', chunk: `downloading ${prog.getFile()}\n` }); + this.outputService.append({ chunk: `downloading ${prog.getFile()}\n` }); } }); await new Promise((resolve, reject) => { @@ -302,7 +302,7 @@ export class BoardsServiceImpl implements BoardsService { const resp = client.platformUninstall(req); resp.on('data', (_: PlatformUninstallResp) => { if (!logged) { - this.outputService.append({ name: 'board uninstall', chunk: `uninstalling ${item.id}\n` }); + this.outputService.append({ chunk: `uninstalling ${item.id}\n` }); logged = true; } }) diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index 801b869d..a2024c69 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -24,7 +24,7 @@ export class CoreServiceImpl implements CoreService { protected readonly notificationService: NotificationServiceServer; async compile(options: CoreService.Compile.Options & { exportBinaries: boolean }): Promise { - this.outputService.append({ name: 'compile', chunk: 'Compile...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' }); + this.outputService.append({ chunk: 'Compile...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' }); const { sketchUri, fqbn } = options; const sketchFilePath = FileUri.fsPath(sketchUri); const sketchpath = dirname(sketchFilePath); @@ -48,15 +48,15 @@ export class CoreServiceImpl implements CoreService { try { await new Promise((resolve, reject) => { result.on('data', (cr: CompileResp) => { - this.outputService.append({ name: 'compile', chunk: Buffer.from(cr.getOutStream_asU8()).toString() }); - this.outputService.append({ name: 'compile', chunk: Buffer.from(cr.getErrStream_asU8()).toString() }); + this.outputService.append({ chunk: Buffer.from(cr.getOutStream_asU8()).toString() }); + this.outputService.append({ chunk: Buffer.from(cr.getErrStream_asU8()).toString() }); }); result.on('error', error => reject(error)); result.on('end', () => resolve()); }); - this.outputService.append({ name: 'compile', chunk: '\n--------------------------\nCompilation complete.\n' }); + this.outputService.append({ chunk: '\n--------------------------\nCompilation complete.\n' }); } catch (e) { - this.outputService.append({ name: 'compile', chunk: `Compilation error: ${e}\n`, severity: 'error' }); + this.outputService.append({ chunk: `Compilation error: ${e}\n`, severity: 'error' }); throw e; } } @@ -77,7 +77,7 @@ export class CoreServiceImpl implements CoreService { await this.compile(Object.assign(options, { exportBinaries: false })); const chunk = firstToUpperCase(task) + '...\n'; - this.outputService.append({ name: 'upload', chunk: chunk + JSON.stringify(options, null, 2) + '\n--------------------------\n' }); + this.outputService.append({ chunk: chunk + JSON.stringify(options, null, 2) + '\n--------------------------\n' }); const { sketchUri, fqbn, port, programmer } = options; const sketchFilePath = FileUri.fsPath(sketchUri); const sketchpath = dirname(sketchFilePath); @@ -104,15 +104,15 @@ export class CoreServiceImpl implements CoreService { try { await new Promise((resolve, reject) => { result.on('data', (resp: UploadResp) => { - this.outputService.append({ name: task, chunk: Buffer.from(resp.getOutStream_asU8()).toString() }); - this.outputService.append({ name: task, chunk: Buffer.from(resp.getErrStream_asU8()).toString() }); + this.outputService.append({ chunk: Buffer.from(resp.getOutStream_asU8()).toString() }); + this.outputService.append({ chunk: Buffer.from(resp.getErrStream_asU8()).toString() }); }); result.on('error', error => reject(error)); result.on('end', () => resolve()); }); - this.outputService.append({ name: 'upload', chunk: '\n--------------------------\n' + firstToLowerCase(task) + ' complete.\n' }); + this.outputService.append({ chunk: '\n--------------------------\n' + firstToLowerCase(task) + ' complete.\n' }); } catch (e) { - this.outputService.append({ name: 'upload', chunk: `${firstToUpperCase(task)} error: ${e}\n`, severity: 'error' }); + this.outputService.append({ chunk: `${firstToUpperCase(task)} error: ${e}\n`, severity: 'error' }); throw e; } } @@ -138,14 +138,14 @@ export class CoreServiceImpl implements CoreService { try { await new Promise((resolve, reject) => { result.on('data', (resp: BurnBootloaderResp) => { - this.outputService.append({ name: 'bootloader', chunk: Buffer.from(resp.getOutStream_asU8()).toString() }); - this.outputService.append({ name: 'bootloader', chunk: Buffer.from(resp.getErrStream_asU8()).toString() }); + this.outputService.append({ chunk: Buffer.from(resp.getOutStream_asU8()).toString() }); + this.outputService.append({ chunk: Buffer.from(resp.getErrStream_asU8()).toString() }); }); result.on('error', error => reject(error)); result.on('end', () => resolve()); }); } catch (e) { - this.outputService.append({ name: 'bootloader', chunk: `Error while burning the bootloader: ${e}\n`, severity: 'error' }); + this.outputService.append({ chunk: `Error while burning the bootloader: ${e}\n`, severity: 'error' }); throw e; } } diff --git a/arduino-ide-extension/src/node/library-service-server-impl.ts b/arduino-ide-extension/src/node/library-service-server-impl.ts index 3142f9c9..2b6db3e6 100644 --- a/arduino-ide-extension/src/node/library-service-server-impl.ts +++ b/arduino-ide-extension/src/node/library-service-server-impl.ts @@ -177,7 +177,7 @@ export class LibraryServiceImpl implements LibraryService { resp.on('data', (r: LibraryInstallResp) => { const prog = r.getProgress(); if (prog) { - this.outputService.append({ name: 'library', chunk: `downloading ${prog.getFile()}: ${prog.getCompleted()}%\n` }); + this.outputService.append({ chunk: `downloading ${prog.getFile()}: ${prog.getCompleted()}%\n` }); } }); await new Promise((resolve, reject) => { @@ -209,7 +209,7 @@ export class LibraryServiceImpl implements LibraryService { const resp = client.libraryUninstall(req); resp.on('data', (_: LibraryUninstallResp) => { if (!logged) { - this.outputService.append({ name: 'library', chunk: `uninstalling ${item.name}:${item.installedVersion}%\n` }); + this.outputService.append({ chunk: `uninstalling ${item.name}:${item.installedVersion}%\n` }); logged = true; } });