From patchwork Fri Jan 30 03:58:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1786 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org Authentication-Results: mail.u-boot.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=YAICvnQn; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9D86E697E8 for ; Thu, 29 Jan 2026 20:59:37 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id OBtvSxcXiDk4 for ; Thu, 29 Jan 2026 20:59:37 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 923A6697CE for ; Thu, 29 Jan 2026 20:59:35 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 68420697E6 for ; Thu, 29 Jan 2026 20:59:32 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id gJlBUiMBvB72 for ; Thu, 29 Jan 2026 20:59:32 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.161.43; helo=mail-oo1-f43.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-oo1-f43.google.com (mail-oo1-f43.google.com [209.85.161.43]) by mail.u-boot.org (Postfix) with ESMTPS id F35AF69738 for ; Thu, 29 Jan 2026 20:59:28 -0700 (MST) Received: by mail-oo1-f43.google.com with SMTP id 006d021491bc7-6611c3b147eso1183367eaf.2 for ; Thu, 29 Jan 2026 19:59:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1769745568; x=1770350368; darn=u-boot.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qJgH3z0FwmV2eXY3R2+ZGG0EcQn+eJVO2hcQlYjmUQw=; b=YAICvnQntVymvlxq35nGKssEg0GuyErFMphoRIRmU4A6CMFwRX4MLpRP+3MiTPSfg7 oyPNUP5b4Ughtsa+o774OMx/fVnNiM11vkFAvBHUQP2iG28WJeGL/N/3ZcZQ7d1adlhF dxZx7yexs/pSwzVZlXI/FxcAy9zk2RdHzXIUQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769745568; x=1770350368; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=qJgH3z0FwmV2eXY3R2+ZGG0EcQn+eJVO2hcQlYjmUQw=; b=C05PamJfj77XZgW4rlHJWyjYc7BhOmmbd2vorZZYDPXJdEEGDF1jEEfRjIn/pjanWO CM1IlzWIPjon1irBlEXVJ8qbWtAgtWkw0MBsQOLAKnGuRrbqTCvJA477JPPPhRJgutDS ny6ctS98xYX9Q9ebWnMR3q3wAigozmKpzTu7e45gOm7uaAV++U2spIAGjApD0VCgaW0E 7Xg7r5r2Epecjf/fWoS9+8LDLPwquiHtYJ69CY4gfl3aoLoO/fm+V62/uzK815LorqhY SzPI4jU4a+HVKGaJTEFC3aHBpbpT/oX2+PAWO/+qys2oGv8GfsdI/01OCUt/797DmmMt GPnQ== X-Gm-Message-State: AOJu0Yw19h9o53Wi7aednzFD0UH+vUcE0l45flVX/Z1t2cqDfXGYHDGl 3ZrmgiyQ1+G+Y3YPujZrvMByUvXBuaugUty7Zgko+Lxaw46r0UOBAs/XZkLlRC6+MqshD8+OeDn rUi58yQ== X-Gm-Gg: AZuq6aKiB5TdPNrvP+kaHxx0wXtTaA7lzWxJ3Vr7RkN+fRAJCr+J449lrf4QWQRRLGk 8CbvNVeDtMLS+O3i58mIHMbGxOrorBuXA4/5bGHfFQ1NBgwLhSR2LM5oEfapX3tseGNOTJDFLwW 26EJFpi8oL3E9kQhvrQM3uHx3LuduZa8zq0pQUx5MY2NPuBlcLKu1EthTQj2K1lewTAi6xrzE/X D0YiUhN43G/Mq+s2g2y8aIuYb7Lpjzp57PvKSuHO97RV6928h6+4P47NmGzOWOTAlbVW5Xb4lOf FA/p46Yt7ci+dEcJqjqpk0grvPO8jyIn3NzQ3hSYuQ+0U53ygTMFTep6/LwIaQOpGU+IB1hVbEH 1xzuVAqb6ocRsCPzYRZAf7Msa797CVlOvdBfDQKOzUBZYR6C9dgYfpgeLVAO/oXWD2sBE87JZ+r 6U3/gPYFCyty4cPJEa X-Received: by 2002:a05:6820:826:b0:662:f452:648f with SMTP id 006d021491bc7-6630f0043admr828061eaf.17.1769745567748; Thu, 29 Jan 2026 19:59:27 -0800 (PST) Received: from chromium.org ([73.34.74.121]) by smtp.gmail.com with ESMTPSA id 006d021491bc7-662f9a4e491sm4128687eaf.16.2026.01.29.19.59.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Jan 2026 19:59:26 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Thu, 29 Jan 2026 20:58:34 -0700 Message-ID: <20260130035849.3580212-12-simon.glass@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260130035849.3580212-1-simon.glass@canonical.com> References: <20260130035849.3580212-1-simon.glass@canonical.com> MIME-Version: 1.0 Message-ID-Hash: N3XIF6ZK7ZNYMFULABC6FBCE7GPRQDC4 X-Message-ID-Hash: N3XIF6ZK7ZNYMFULABC6FBCE7GPRQDC4 X-MailFrom: sjg@chromium.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 11/19] cli: Add a Kconfig for enhanced editing List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add a new Kconfig option CONFIG_CMDLINE_EDITOR to enable enhanced command-line editing features. This replaces CLI_READLINE_CALLBACK and is enabled by default when EXPO is enabled. Create struct cli_editor_state to hold state for enhanced editing features, initially containing: - putch: callback for character output redirection - line_nav: callback for multi-line navigation (Ctrl-P/N) - multiline: flag for multi-line input mode This struct is embedded in cli_line_state when CMDLINE_EDITOR is enabled. Add cli_editor() accessor function that returns a pointer to the editor state, or NULL if CMDLINE_EDITOR is not enabled. Update cli_readline.c and scene_txtin.c to use the new accessor. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- boot/scene_txtin.c | 10 ++++--- cmd/Kconfig | 16 +++++++---- common/cli_readline.c | 12 +++++--- include/cli.h | 66 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 81 insertions(+), 23 deletions(-) diff --git a/boot/scene_txtin.c b/boot/scene_txtin.c index cde9fdb8ccf..79814891cdc 100644 --- a/boot/scene_txtin.c +++ b/boot/scene_txtin.c @@ -112,6 +112,7 @@ int scene_txtin_render_deps(struct scene *scn, struct scene_obj *obj, struct scene_txtin *tin) { struct cli_line_state *cls = &tin->cls; + struct cli_editor_state *ed = cli_editor(cls); const bool open = obj->flags & SCENEOF_OPEN; struct udevice *cons = scn->expo->cons; void *ctx = tin->ctx; @@ -121,7 +122,7 @@ int scene_txtin_render_deps(struct scene *scn, struct scene_obj *obj, if (open) { scene_render_obj(scn, tin->edit_id, ctx); - if (cls->multiline) { + if (ed->multiline) { /* for multiline, set cursor position directly */ struct scene_obj_txt *txt; @@ -260,6 +261,7 @@ int scene_txtin_open(struct scene *scn, struct scene_obj *obj, struct scene_txtin *tin) { struct cli_line_state *cls = &tin->cls; + struct cli_editor_state *ed = cli_editor(cls); struct udevice *cons = scn->expo->cons; struct scene_obj_txt *txt; void *ctx; @@ -286,11 +288,11 @@ int scene_txtin_open(struct scene *scn, struct scene_obj *obj, vidconsole_entry_start(cons, ctx); cli_cread_init(cls, abuf_data(&tin->buf), abuf_size(&tin->buf)); cls->insert = true; - cls->putch = scene_txtin_putch; + ed->putch = scene_txtin_putch; cls->priv = scn; if (obj->type == SCENEOBJT_TEXTEDIT) { - cls->multiline = true; - cls->line_nav = scene_txtin_line_nav; + ed->multiline = true; + ed->line_nav = scene_txtin_line_nav; } cli_cread_add_initial(cls); diff --git a/cmd/Kconfig b/cmd/Kconfig index d8f57c446a5..448a6e9fe39 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -54,13 +54,17 @@ config CMDLINE_EDITING Enable editing and History functions for interactive command line input operations -config CLI_READLINE_CALLBACK - bool "Support a callback for character output" +config CMDLINE_EDITOR + bool "Enhanced command-line editing features" depends on CMDLINE_EDITING - help - Enable a callback for character output during line editing. This - allows redirection of output to a different destination, such as - a vidconsole. This is used by expo to support textline editing. + default y if EXPO + help + Enable enhanced editing features for the command line, including: + - Character-output callback for redirection to vidconsole + - Multi-line navigation callback (Ctrl-P/N) + - Ctrl+Left/Right arrow keys to move by words + - Undo/redo support (Ctrl+Z / Ctrl+Shift+Z) + - Yank/paste of killed text (Ctrl+Y) config CMDLINE_PS_SUPPORT bool "Enable support for changing the command prompt string at run-time" diff --git a/common/cli_readline.c b/common/cli_readline.c index 38f825184df..d2b02933fd7 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -79,8 +79,10 @@ static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen) */ static void cls_putch(struct cli_line_state *cls, int ch) { - if (CONFIG_IS_ENABLED(CLI_READLINE_CALLBACK) && cls->putch) - cls->putch(cls, ch); + struct cli_editor_state *ed = cli_editor(cls); + + if (ed && ed->putch) + ed->putch(cls, ch); else putc(ch); } @@ -299,6 +301,7 @@ static void cread_add_str(struct cli_line_state *cls, char *str, int strsize, int cread_line_process_ch(struct cli_line_state *cls, char ichar) { + struct cli_editor_state *ed; char *buf = cls->buf; /* ichar=0x0 when error occurs in U-Boot getc */ @@ -405,10 +408,11 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) break; case CTL_CH('p'): case CTL_CH('n'): - if (cls->multiline && cls->line_nav) { + ed = cli_editor(cls); + if (ed && ed->multiline && ed->line_nav) { int new_num; - new_num = cls->line_nav(cls, ichar == CTL_CH('p')); + new_num = ed->line_nav(cls, ichar == CTL_CH('p')); if (new_num < 0) { getcmd_cbeep(cls); break; diff --git a/include/cli.h b/include/cli.h index f1e5887fa56..b6a8a6be1dd 100644 --- a/include/cli.h +++ b/include/cli.h @@ -25,6 +25,43 @@ struct cli_ch_state { bool emitting; }; +struct cli_line_state; + +/** + * struct cli_editor_state - state for enhanced editing features + * + * This is only available when CONFIG_CMDLINE_EDITOR is enabled. + * + * @putch: Output a character (NULL to use putc()) + * @line_nav: Handle multi-line navigation (Ctrl-P/N) + * @multiline: true if input may contain multiple lines (enables + * Ctrl-P/N for line navigation instead of history) + */ +struct cli_editor_state { + /** + * @putch: Output a character (NULL to use putc()) + * + * @cls: CLI line state + * @ch: Character to output + */ + void (*putch)(struct cli_line_state *cls, int ch); + + /** + * @line_nav: Handle multi-line navigation (Ctrl-P/N) + * + * @cls: CLI line state + * @up: true for previous line, false for next + * Return: new cursor position, or -ve if at boundary + */ + int (*line_nav)(struct cli_line_state *cls, bool up); + + /** + * @multiline: true if input may contain multiple lines (enables + * Ctrl-P/N for line navigation instead of history) + */ + bool multiline; +}; + /** * struct cli_line_state - state of the line editor * @@ -34,15 +71,10 @@ struct cli_ch_state { * @history: true if history should be accessible * @cmd_complete: true if tab completion should be enabled (requires @prompt to * be set) - * @multiline: true if input may contain multiple lines (enables Ctrl-P/N for - * line navigation instead of history) * @buf: Buffer containing line * @prompt: Prompt for the line - * @putch: Function to call to output a character (NULL to use putc()) - * @line_nav: Function to call for multi-line navigation (Ctrl-P/N). Called with - * @up true for previous line, false for next. Returns new cursor position, - * or -ve if at boundary * @priv: Private data for callbacks + * @ed: Editor state for enhanced features (if CONFIG_CMDLINE_EDITOR) */ struct cli_line_state { uint num; @@ -51,14 +83,30 @@ struct cli_line_state { bool insert; bool history; bool cmd_complete; - bool multiline; char *buf; const char *prompt; - void (*putch)(struct cli_line_state *cls, int ch); - int (*line_nav)(struct cli_line_state *cls, bool up); void *priv; +#if CONFIG_IS_ENABLED(CMDLINE_EDITOR) + struct cli_editor_state ed; +#endif }; +/** + * cli_editor() - Get the editor state from a line state + * + * @cls: CLI line state + * Return: Pointer to editor state, or NULL if CONFIG_CMDLINE_EDITOR is not + * enabled + */ +static inline struct cli_editor_state *cli_editor(struct cli_line_state *cls) +{ +#if CONFIG_IS_ENABLED(CMDLINE_EDITOR) + return &cls->ed; +#else + return NULL; +#endif +} + /** * Go into the command loop *