From fd86a6def117a63140fa98f68ccd4c8598bda465 Mon Sep 17 00:00:00 2001 From: levkropp Date: Mon, 14 Jul 2025 14:19:38 -0400 Subject: [PATCH] [gui] add `Select All` option --- src/client/gui/lib/vm_details/terminal.dart | 53 +++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/client/gui/lib/vm_details/terminal.dart b/src/client/gui/lib/vm_details/terminal.dart index f4bf05a82d..fd02c80f0f 100644 --- a/src/client/gui/lib/vm_details/terminal.dart +++ b/src/client/gui/lib/vm_details/terminal.dart @@ -174,6 +174,10 @@ class ResetTerminalFontIntent extends Intent { const ResetTerminalFontIntent(); } +class SelectAllTerminalTextIntent extends Intent { + const SelectAllTerminalTextIntent(); +} + class _VmTerminalState extends ConsumerState { static const defaultFontSize = 13.0; static const minFontSize = 2.5; @@ -286,6 +290,16 @@ class _VmTerminalState extends ConsumerState { ); }, ), + ContextMenuButtonItem( + label: 'Select All', + onPressed: () { + ContextMenuController.removeAny(); + Actions.maybeInvoke( + context, + const SelectAllTerminalTextIntent(), + ); + }, + ), ]; final style = Theme.of(context).textButtonTheme.style?.copyWith( @@ -405,6 +419,45 @@ class _VmTerminalState extends ConsumerState { return null; }, ), + SelectAllTerminalTextIntent: CallbackAction( + onInvoke: (_) async { + // Select all text in the terminal buffer + final buffer = terminal.buffer; + + // Check if there's any content to select + if (buffer.height == 0) return null; + + // Find the last line with actual content + int lastContentLine = buffer.height - 1; + for (int i = buffer.height - 1; i >= 0; i--) { + final line = buffer.lines[i]; + // Check if the line has any non-empty content + bool hasContent = false; + for (int j = 0; j < line.length; j++) { + if (line.getCodePoint(j) != 0 && line.getCodePoint(j) != 32) { + // not null and not space + hasContent = true; + break; + } + } + if (hasContent) { + lastContentLine = i; + break; + } + } + + // Create a selection from the first line to the last line with content + // Start from the first line, first column + final start = buffer.createAnchor(0, 0); + // End at the last content line, last column + final end = + buffer.createAnchor(buffer.viewWidth - 1, lastContentLine); + + // Set the selection to cover all meaningful text + terminalController.setSelection(start, end); + return null; + }, + ), }; return Actions(actions: terminalActions, child: scrollableTerminal);