Skip to content

Commit 2df3f46

Browse files
committed
Add a copy output button to serial monitor
If the arduino collects some data that you want to store on your computer, a rather simple way is to write it to the serial monitor and copy it to the clipboard. This commit introduces a button that copies the whole content of the serial monitor to the clipboard to make this rather simple. It is a new component added to the menu, and does not change the behaviour of other compontents.
1 parent 0f9f0d0 commit 2df3f46

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

arduino-ide-extension/src/browser/serial/monitor/monitor-utils.ts

+4
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,7 @@ export function truncateLines(
6767
}
6868
return [lines, charCount];
6969
}
70+
71+
export function linesToMergedStr(lines: Line[]) : string {
72+
return lines.map((line: Line) => {return line.message}).join("");
73+
}

arduino-ide-extension/src/browser/serial/monitor/monitor-view-contribution.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ export namespace SerialMonitor {
5252
},
5353
'vscode/output.contribution/clearOutput.label'
5454
);
55+
export const COPY_OUTPUT = Command.toLocalizedCommand(
56+
{
57+
id: 'serial-monitor-copy-output',
58+
label: 'Copy Output',
59+
iconClass: codicon('copy'),
60+
},
61+
'arduino/serial/copyOutput'
62+
);
5563
}
5664
}
5765

@@ -149,6 +157,14 @@ export class MonitorViewContribution
149157
'Clear Output'
150158
),
151159
});
160+
registry.registerItem({
161+
id: SerialMonitor.Commands.COPY_OUTPUT.id,
162+
command: SerialMonitor.Commands.COPY_OUTPUT.id,
163+
tooltip: nls.localize(
164+
'arduino/serial/copyOutput',
165+
'Copy Output'
166+
),
167+
});
152168
}
153169

154170
override registerCommands(commands: CommandRegistry): void {
@@ -161,6 +177,15 @@ export class MonitorViewContribution
161177
}
162178
},
163179
});
180+
commands.registerCommand(SerialMonitor.Commands.COPY_OUTPUT, {
181+
isEnabled: (widget) => widget instanceof MonitorWidget,
182+
isVisible: (widget) => widget instanceof MonitorWidget,
183+
execute: (widget) => {
184+
if (widget instanceof MonitorWidget) {
185+
widget.copyOutput();
186+
}
187+
},
188+
});
164189
if (this.toggleCommand) {
165190
commands.registerCommand(this.toggleCommand, {
166191
execute: () => this.toggle(),

arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
import { MonitorModel } from '../../monitor-model';
2929
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
3030
import { serialMonitorWidgetLabel } from '../../../common/nls';
31+
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
3132

3233
@injectable()
3334
export class MonitorWidget extends ReactWidget {
@@ -47,6 +48,7 @@ export class MonitorWidget extends ReactWidget {
4748
*/
4849
protected closing = false;
4950
protected readonly clearOutputEmitter = new Emitter<void>();
51+
protected readonly copyOutputEmitter = new Emitter<void>();
5052

5153
@inject(MonitorModel)
5254
private readonly monitorModel: MonitorModel;
@@ -56,6 +58,8 @@ export class MonitorWidget extends ReactWidget {
5658
private readonly boardsServiceProvider: BoardsServiceProvider;
5759
@inject(FrontendApplicationStateService)
5860
private readonly appStateService: FrontendApplicationStateService;
61+
@inject(ClipboardService)
62+
private readonly clipboardService: ClipboardService;
5963

6064
private readonly toDisposeOnReset: DisposableCollection;
6165

@@ -102,6 +106,11 @@ export class MonitorWidget extends ReactWidget {
102106
this.clearOutputEmitter.fire(undefined);
103107
this.update();
104108
}
109+
110+
copyOutput(): void {
111+
this.copyOutputEmitter.fire();
112+
this.update();
113+
}
105114

106115
override dispose(): void {
107116
this.toDisposeOnReset.dispose();
@@ -247,6 +256,8 @@ export class MonitorWidget extends ReactWidget {
247256
monitorModel={this.monitorModel}
248257
monitorManagerProxy={this.monitorManagerProxy}
249258
clearConsoleEvent={this.clearOutputEmitter.event}
259+
copyOutputEvent={this.copyOutputEmitter.event}
260+
clipboardService={this.clipboardService}
250261
height={Math.floor(this.widgetHeight - 50)}
251262
/>
252263
</div>

arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import { Event } from '@theia/core/lib/common/event';
33
import { DisposableCollection } from '@theia/core/lib/common/disposable';
44
import { areEqual, FixedSizeList as List } from 'react-window';
55
import dateFormat from 'dateformat';
6-
import { messagesToLines, truncateLines } from './monitor-utils';
6+
import { messagesToLines, truncateLines, linesToMergedStr } from './monitor-utils';
77
import { MonitorManagerProxyClient } from '../../../common/protocol';
88
import { MonitorModel } from '../../monitor-model';
9+
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
910

1011
export type Line = { message: string; timestamp?: Date; lineLen: number };
1112

@@ -74,6 +75,9 @@ export class SerialMonitorOutput extends React.Component<
7475
this.props.clearConsoleEvent(() =>
7576
this.setState({ lines: [], charCount: 0 })
7677
),
78+
this.props.copyOutputEvent(() =>
79+
this.props.clipboardService.writeText(linesToMergedStr(this.state.lines))
80+
),
7781
this.props.monitorModel.onChange(({ property }) => {
7882
if (property === 'timestamp') {
7983
const { timestamp } = this.props.monitorModel;
@@ -130,6 +134,8 @@ export namespace SerialMonitorOutput {
130134
readonly monitorModel: MonitorModel;
131135
readonly monitorManagerProxy: MonitorManagerProxyClient;
132136
readonly clearConsoleEvent: Event<void>;
137+
readonly copyOutputEvent: Event<void>;
138+
readonly clipboardService: ClipboardService;
133139
readonly height: number;
134140
}
135141

0 commit comments

Comments
 (0)