From 57ee92051e5a2502e72d60cbf99d5c78718616a3 Mon Sep 17 00:00:00 2001 From: Andy Lee Date: Mon, 3 Aug 2026 19:35:49 +0800 Subject: [PATCH] feat(serial-console): add terminal search toolbar and highlight tuning Signed-off-by: Andy Lee --- .../components/SerialConsole/index.vue | 190 ++++++++++++++++-- 1 file changed, 177 insertions(+), 13 deletions(-) diff --git a/pkg/harvester/components/SerialConsole/index.vue b/pkg/harvester/components/SerialConsole/index.vue index 1d417387..077105cf 100644 --- a/pkg/harvester/components/SerialConsole/index.vue +++ b/pkg/harvester/components/SerialConsole/index.vue @@ -21,19 +21,35 @@ export default { data() { return { - socket: null, - terminal: null, - textDecoder: null, - fitAddon: null, - searchAddon: null, - webglAddon: null, - onResize: null, - isOpen: false, - isOpening: false, - backlog: [], - firstTime: true, - queue: [], - isDraining: false, + socket: null, + terminal: null, + textDecoder: null, + fitAddon: null, + searchAddon: null, + webglAddon: null, + onResize: null, + isOpen: false, + isOpening: false, + backlog: [], + firstTime: true, + queue: [], + isDraining: false, + showSearch: false, + searchQuery: '', + searchOptions: { + caseSensitive: false, + regex: false, + wholeWord: false, + incremental: true, + decorations: { + matchBackground: '#B45309', + matchBorder: '#FDBA74', + matchOverviewRuler: '#FDBA74', + activeMatchBackground: '#EA580C', + activeMatchBorder: '#FED7AA', + activeMatchColorOverviewRuler: '#FED7AA', + }, + }, }; }, @@ -137,9 +153,88 @@ export default { this.write(msg); }); + terminal.attachCustomKeyEventHandler((event) => { + const key = event.key?.toLowerCase(); + + if ((event.ctrlKey || event.metaKey) && key === 'f') { + event.preventDefault(); + this.openSearch(); + + return false; + } + + if (key === 'escape' && this.showSearch) { + event.preventDefault(); + this.closeSearch(); + + return false; + } + + return true; + }); + this.terminal = terminal; }, + openSearch() { + this.showSearch = true; + + this.$nextTick(() => { + const input = this.$refs.searchInput; + + if (input) { + input.focus(); + input.select(); + } + }); + }, + + closeSearch() { + this.showSearch = false; + this.terminal?.focus(); + }, + + findNext() { + if (!this.searchAddon || !this.searchQuery) { + return; + } + + this.searchAddon.findNext(this.searchQuery, this.searchOptions); + }, + + findPrevious() { + if (!this.searchAddon || !this.searchQuery) { + return; + } + + this.searchAddon.findPrevious(this.searchQuery, this.searchOptions); + }, + + onSearchInput() { + if (!this.searchQuery) { + return; + } + + this.findNext(); + }, + + onSearchKeydown(event) { + if (event.key === 'Enter') { + event.preventDefault(); + + if (event.shiftKey) { + this.findPrevious(); + } else { + this.findNext(); + } + } + + if (event.key === 'Escape') { + event.preventDefault(); + this.closeSearch(); + } + }, + scheduleFit() { this.$nextTick(() => { requestAnimationFrame(() => { @@ -348,6 +443,44 @@ export default {