diff --git a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx index f96636455..163fdbafd 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx @@ -6,6 +6,53 @@ import { BoardsServiceProvider } from '../../boards/boards-service-provider'; import { MonitorModel } from '../../monitor-model'; import { Unknown } from '../../../common/nls'; +class HistoryList { + private readonly items: string[] = []; + private index = -1; + + constructor(private readonly size = 100) {} + + push(val: string): void { + if (val !== this.items[this.items.length - 1]) { + this.items.push(val); + } + while (this.items.length > this.size) { + this.items.shift(); + } + this.index = -1; + } + + previous(): string { + if (this.index === -1) { + this.index = this.items.length - 1; + return this.items[this.index]; + } + if (this.hasPrevious) { + return this.items[--this.index]; + } + return this.items[this.index]; + } + + private get hasPrevious(): boolean { + return this.index >= 1; + } + + next(): string { + if (this.index === this.items.length - 1) { + this.index = -1; + return ''; + } + if (this.hasNext) { + return this.items[++this.index]; + } + return ''; + } + + private get hasNext(): boolean { + return this.index >= 0 && this.index !== this.items.length - 1; + } +} + export namespace SerialMonitorSendInput { export interface Props { readonly boardsServiceProvider: BoardsServiceProvider; @@ -16,6 +63,7 @@ export namespace SerialMonitorSendInput { export interface State { text: string; connected: boolean; + history: HistoryList; } } @@ -27,7 +75,7 @@ export class SerialMonitorSendInput extends React.Component< constructor(props: Readonly) { super(props); - this.state = { text: '', connected: true }; + this.state = { text: '', connected: true, history: new HistoryList() }; this.onChange = this.onChange.bind(this); this.onSend = this.onSend.bind(this); this.onKeyDown = this.onKeyDown.bind(this); @@ -90,7 +138,7 @@ export class SerialMonitorSendInput extends React.Component< ); } - protected setRef = (element: HTMLElement | null) => { + protected setRef = (element: HTMLElement | null): void => { if (this.props.resolveFocus) { this.props.resolveFocus(element || undefined); } @@ -110,7 +158,17 @@ export class SerialMonitorSendInput extends React.Component< if (keyCode) { const { key } = keyCode; if (key === Key.ENTER) { + const { text } = this.state; this.onSend(); + if (text) { + this.state.history.push(text); + } + } else if (key === Key.ARROW_UP) { + this.setState({ text: this.state.history.previous() }); + } else if (key === Key.ARROW_DOWN) { + this.setState({ text: this.state.history.next() }); + } else if (key === Key.ESCAPE) { + this.setState({ text: '' }); } } }