mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-04-26 16:27:19 +00:00

* backend structure WIP * Scaffold interfaces and classes for pluggable monitors * Implement MonitorService to handle pluggable monitor lifetime * Rename WebSocketService to WebSocketProvider and uninjected it * Moved some interfaces * Changed upload settings * Enhance MonitorManager APIs * Fixed WebSocketChange event signature * Add monitor proxy functions for the frontend * Moved settings to MonitorService * Remove several unnecessary serial monitor classes * Changed how connection is handled on upload * Proxied more monitor methods to frontend * WebSocketProvider is not injectable anymore * Add generic monitor settings storaging * More serial classes removal * Remove unused file * Changed plotter contribution to use new manager proxy * Changed MonitorWidget and children to use new monitor proxy * Updated MonitorWidget to use new monitor proxy * Fix backend logger bindings * Delete unnecessary Symbol * coreClientProvider is now set when constructing MonitorService * Add missing binding * Fix `MonitorManagerProxy` DI issue * fix monitor connection * delete duplex when connection is closed * update arduino-cli to 0.22.0 * fix upload when monitor is open * add MonitorSettingsProvider interface * monitor settings provider stub * updated pseudo code * refactor monitor settings interfaces * monitor service provider singleton * add unit tests * change MonitorService providers to injectable deps * fix monitor settings client communication * refactor monitor commands protocol * use monitor settings provider properly * add settings to monitor model * add settings to monitor model * reset serial monitor when port changes * fix serial plotter opening * refine monitor connection settings * fix hanging web socket connections * add serial plotter reset command * send port to web socket clients * monitor service wait for success serial port open * fix reset loop * update serial plotter version * update arduino-cli version to 0.23.0-rc1 and regenerate grpc protocol * remove useless plotter protocol file * localize web socket errors * clean-up code * update translation file * Fix duplicated editor tabs (#1012) * Save dialog for closing temporary sketch and unsaved files (#893) * Use normal `OnWillStop` event * Align `CLOSE` command to rest of app * Fixed FS path vs encoded URL comparision when handling stop request. Ref: https://github.com/eclipse-theia/theia/issues/11226 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * Fixed the translations. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * Fixed the translations again. Removed `electron` from the `nls-extract`. It does not contain app code. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * Aligned the stop handler code to Theia. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> Co-authored-by: Akos Kitta <a.kitta@arduino.cc> * fix serial monitor send line ending * refactor monitor-service poll for test/readability * localize web socket errors * update translation file * Fix duplicated editor tabs (#1012) * i18n:check rerun * Speed up IDE startup time. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * override coreClientProvider in monitor-service * cleanup merged code Co-authored-by: Francesco Stasi <f.stasi@me.com> Co-authored-by: Silvano Cerza <silvanocerza@gmail.com> Co-authored-by: Mark Sujew <mark.sujew@typefox.io> Co-authored-by: David Simpson <45690499+davegarthsimpson@users.noreply.github.com> Co-authored-by: Akos Kitta <a.kitta@arduino.cc>
254 lines
7.7 KiB
TypeScript
254 lines
7.7 KiB
TypeScript
import * as React from '@theia/core/shared/react';
|
|
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
import { OptionsType } from 'react-select/src/types';
|
|
import { Emitter } from '@theia/core/lib/common/event';
|
|
import { Disposable } from '@theia/core/lib/common/disposable';
|
|
import {
|
|
ReactWidget,
|
|
Message,
|
|
Widget,
|
|
MessageLoop,
|
|
} from '@theia/core/lib/browser/widgets';
|
|
import { ArduinoSelect } from '../../widgets/arduino-select';
|
|
import { SerialMonitorSendInput } from './serial-monitor-send-input';
|
|
import { SerialMonitorOutput } from './serial-monitor-send-output';
|
|
import { BoardsServiceProvider } from '../../boards/boards-service-provider';
|
|
import { nls } from '@theia/core/lib/common';
|
|
import { MonitorManagerProxyClient } from '../../../common/protocol';
|
|
import { MonitorModel } from '../../monitor-model';
|
|
import { MonitorSettings } from '../../../node/monitor-settings/monitor-settings-provider';
|
|
|
|
@injectable()
|
|
export class MonitorWidget extends ReactWidget {
|
|
static readonly LABEL = nls.localize(
|
|
'arduino/common/serialMonitor',
|
|
'Serial Monitor'
|
|
);
|
|
static readonly ID = 'serial-monitor';
|
|
|
|
protected settings: MonitorSettings = {};
|
|
|
|
protected widgetHeight: number;
|
|
|
|
/**
|
|
* Do not touch or use it. It is for setting the focus on the `input` after the widget activation.
|
|
*/
|
|
protected focusNode: HTMLElement | undefined;
|
|
/**
|
|
* Guard against re-rendering the view after the close was requested.
|
|
* See: https://github.com/eclipse-theia/theia/issues/6704
|
|
*/
|
|
protected closing = false;
|
|
protected readonly clearOutputEmitter = new Emitter<void>();
|
|
|
|
constructor(
|
|
@inject(MonitorModel)
|
|
protected readonly monitorModel: MonitorModel,
|
|
|
|
@inject(MonitorManagerProxyClient)
|
|
protected readonly monitorManagerProxy: MonitorManagerProxyClient,
|
|
|
|
@inject(BoardsServiceProvider)
|
|
protected readonly boardsServiceProvider: BoardsServiceProvider
|
|
) {
|
|
super();
|
|
this.id = MonitorWidget.ID;
|
|
this.title.label = MonitorWidget.LABEL;
|
|
this.title.iconClass = 'monitor-tab-icon';
|
|
this.title.closable = true;
|
|
this.scrollOptions = undefined;
|
|
this.toDispose.push(this.clearOutputEmitter);
|
|
this.toDispose.push(
|
|
Disposable.create(() => this.monitorManagerProxy.disconnect())
|
|
);
|
|
}
|
|
|
|
protected override onBeforeAttach(msg: Message): void {
|
|
this.update();
|
|
this.toDispose.push(this.monitorModel.onChange(() => this.update()));
|
|
this.getCurrentSettings().then(this.onMonitorSettingsDidChange.bind(this));
|
|
this.monitorManagerProxy.onMonitorSettingsDidChange(
|
|
this.onMonitorSettingsDidChange.bind(this)
|
|
);
|
|
|
|
this.monitorManagerProxy.startMonitor();
|
|
}
|
|
|
|
onMonitorSettingsDidChange(settings: MonitorSettings): void {
|
|
this.settings = {
|
|
...this.settings,
|
|
pluggableMonitorSettings: {
|
|
...this.settings.pluggableMonitorSettings,
|
|
...settings.pluggableMonitorSettings,
|
|
},
|
|
};
|
|
this.update();
|
|
}
|
|
|
|
clearConsole(): void {
|
|
this.clearOutputEmitter.fire(undefined);
|
|
this.update();
|
|
}
|
|
|
|
override dispose(): void {
|
|
super.dispose();
|
|
}
|
|
|
|
protected override onCloseRequest(msg: Message): void {
|
|
this.closing = true;
|
|
super.onCloseRequest(msg);
|
|
}
|
|
|
|
protected override onUpdateRequest(msg: Message): void {
|
|
// TODO: `this.isAttached`
|
|
// See: https://github.com/eclipse-theia/theia/issues/6704#issuecomment-562574713
|
|
if (!this.closing && this.isAttached) {
|
|
super.onUpdateRequest(msg);
|
|
}
|
|
}
|
|
|
|
protected override onResize(msg: Widget.ResizeMessage): void {
|
|
super.onResize(msg);
|
|
this.widgetHeight = msg.height;
|
|
this.update();
|
|
}
|
|
|
|
protected override onActivateRequest(msg: Message): void {
|
|
super.onActivateRequest(msg);
|
|
(this.focusNode || this.node).focus();
|
|
}
|
|
|
|
protected onFocusResolved = (element: HTMLElement | undefined) => {
|
|
if (this.closing || !this.isAttached) {
|
|
return;
|
|
}
|
|
this.focusNode = element;
|
|
requestAnimationFrame(() =>
|
|
MessageLoop.sendMessage(this, Widget.Msg.ActivateRequest)
|
|
);
|
|
};
|
|
|
|
protected get lineEndings(): OptionsType<
|
|
SerialMonitorOutput.SelectOption<MonitorModel.EOL>
|
|
> {
|
|
return [
|
|
{
|
|
label: nls.localize('arduino/serial/noLineEndings', 'No Line Ending'),
|
|
value: '',
|
|
},
|
|
{
|
|
label: nls.localize('arduino/serial/newLine', 'New Line'),
|
|
value: '\n',
|
|
},
|
|
{
|
|
label: nls.localize('arduino/serial/carriageReturn', 'Carriage Return'),
|
|
value: '\r',
|
|
},
|
|
{
|
|
label: nls.localize(
|
|
'arduino/serial/newLineCarriageReturn',
|
|
'Both NL & CR'
|
|
),
|
|
value: '\r\n',
|
|
},
|
|
];
|
|
}
|
|
|
|
private getCurrentSettings(): Promise<MonitorSettings> {
|
|
const board = this.boardsServiceProvider.boardsConfig.selectedBoard;
|
|
const port = this.boardsServiceProvider.boardsConfig.selectedPort;
|
|
if (!board || !port) {
|
|
return Promise.resolve(this.settings || {});
|
|
}
|
|
return this.monitorManagerProxy.getCurrentSettings(board, port);
|
|
}
|
|
|
|
protected render(): React.ReactNode {
|
|
const baudrate = this.settings?.pluggableMonitorSettings
|
|
? this.settings.pluggableMonitorSettings.baudrate
|
|
: undefined;
|
|
|
|
const baudrateOptions = baudrate?.values.map((b) => ({
|
|
label: b + ' baud',
|
|
value: b,
|
|
}));
|
|
const baudrateSelectedOption = baudrateOptions?.find(
|
|
(b) => b.value === baudrate?.selectedValue
|
|
);
|
|
|
|
const lineEnding =
|
|
this.lineEndings.find(
|
|
(item) => item.value === this.monitorModel.lineEnding
|
|
) || this.lineEndings[1]; // Defaults to `\n`.
|
|
|
|
return (
|
|
<div className="serial-monitor">
|
|
<div className="head">
|
|
<div className="send">
|
|
<SerialMonitorSendInput
|
|
boardsServiceProvider={this.boardsServiceProvider}
|
|
monitorModel={this.monitorModel}
|
|
resolveFocus={this.onFocusResolved}
|
|
onSend={this.onSend}
|
|
/>
|
|
</div>
|
|
<div className="config">
|
|
<div className="select">
|
|
<ArduinoSelect
|
|
maxMenuHeight={this.widgetHeight - 40}
|
|
options={this.lineEndings}
|
|
value={lineEnding}
|
|
onChange={this.onChangeLineEnding}
|
|
/>
|
|
</div>
|
|
{baudrateOptions && baudrateSelectedOption && (
|
|
<div className="select">
|
|
<ArduinoSelect
|
|
className="select"
|
|
maxMenuHeight={this.widgetHeight - 40}
|
|
options={baudrateOptions}
|
|
value={baudrateSelectedOption}
|
|
onChange={this.onChangeBaudRate}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="body">
|
|
<SerialMonitorOutput
|
|
monitorModel={this.monitorModel}
|
|
monitorManagerProxy={this.monitorManagerProxy}
|
|
clearConsoleEvent={this.clearOutputEmitter.event}
|
|
height={Math.floor(this.widgetHeight - 50)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
protected readonly onSend = (value: string) => this.doSend(value);
|
|
protected async doSend(value: string): Promise<void> {
|
|
this.monitorManagerProxy.send(value);
|
|
}
|
|
|
|
protected readonly onChangeLineEnding = (
|
|
option: SerialMonitorOutput.SelectOption<MonitorModel.EOL>
|
|
): void => {
|
|
this.monitorModel.lineEnding = option.value;
|
|
};
|
|
|
|
protected readonly onChangeBaudRate = ({
|
|
value,
|
|
}: {
|
|
value: string;
|
|
}): void => {
|
|
this.getCurrentSettings().then(({ pluggableMonitorSettings }) => {
|
|
if (!pluggableMonitorSettings || !pluggableMonitorSettings['baudrate'])
|
|
return;
|
|
const baudRateSettings = pluggableMonitorSettings['baudrate'];
|
|
baudRateSettings.selectedValue = value;
|
|
this.monitorManagerProxy.changeSettings({ pluggableMonitorSettings });
|
|
});
|
|
};
|
|
}
|