From patchwork Fri Jan 30 03:58:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1790 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=QNHX0+it; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D4878697F9 for ; Thu, 29 Jan 2026 20:59:47 -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 HakdLfs7ASLe for ; Thu, 29 Jan 2026 20:59:47 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D3D28697C0 for ; Thu, 29 Jan 2026 20:59:45 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E3D13697DF for ; Thu, 29 Jan 2026 20:59:42 -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 UzFLOuYYEcR0 for ; Thu, 29 Jan 2026 20:59:42 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.160.52; helo=mail-oa1-f52.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-oa1-f52.google.com (mail-oa1-f52.google.com [209.85.160.52]) by mail.u-boot.org (Postfix) with ESMTPS id 7480469738 for ; Thu, 29 Jan 2026 20:59:40 -0700 (MST) Received: by mail-oa1-f52.google.com with SMTP id 586e51a60fabf-4097b420ce0so1034040fac.2 for ; Thu, 29 Jan 2026 19:59:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1769745579; x=1770350379; 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=PedH6FkvczNA6vv11FqO02i1jDRoJ029ifROI8COUbo=; b=QNHX0+itpv0yyxVwBURUrVepH+1peBPkgZYHMbZTJpWRlLTfOp1fAVKO5jyFHebcN3 jxz84J1d927XODk2h/JHHwa4H4LtbMUx11PUzJIvH1L9jZS3g/eB6aHdDTfq6Yqr8/wa Z1fTL/0oG8Gaf9Ze52cT98Obg62IB4sQy2ZNM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769745579; x=1770350379; 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=PedH6FkvczNA6vv11FqO02i1jDRoJ029ifROI8COUbo=; b=VivVOGLd8sHJEgIi7VxNr26iAWFn68Lftl/mSlsDTedXIiG5vEUk87ynvYLfodD0+F bdkkfYRBxkJpSOFHuHhdsnsadxNznr04VNvWUrQA4aVb/y3OJ3G/WaHW7UDLnI8a4bcJ eY1ADPmCYXX2huAdiHYMQxkWbJhCxk2QQL4GLV4u+MyiF68HYwTT8EyJeWLWe1KNtXFv tOCl83PP6xjhIVHeQLOYSMf9FNtdtZmoOKxRBWVH335mgAKDCJvialIRiWX44edfbYr2 eytgifZoAsRfWW7N8ks6judfX/NrerEcjl+zIcIcq8AjisT5dmO5nC8NzdVn+JrDh1zl Xm6w== X-Gm-Message-State: AOJu0YwOEN/fPH68NTaJZaIdCrhv1DNek0mNb9ApWqJKn/18aQe9Xc4Q Qsm8fE6D8sAVwSWmzUyCG9V7ACvICm4KtjWN1ZZGSdKLkU2ekm5qMD8HfAZWuzTwTTOU2En6ON8 cInLHDw== X-Gm-Gg: AZuq6aKP/XO8QL/BRx8VUiUX2ZWFnthM9SfwWqSsIk9gBtv2e9sPRwTt3WVxN7CeSPl ZPkRD8MS4zuOTyOo8rWPpo2v3fVbUqWqVM8KIerlZlCJ7etyP7QqSP9ubqJ1wNevSoVLMdEN17q jJStnSzSYFazMik1Jdy4zrwA96pu98SpdoGEGzAvH1DJE+Qc1RWbploUKiRRWKAlyTIC7I7yFk9 Z4to3V5p7ZggFSwh+KDiKYXyUTT+NSWa6kHDFIiel2bcs0yz1yMQBSl9ziC7n7Q3m4swvVlT2G4 acSP7lg322N/3AOPsUGQFJ8mAJqN5PCr+56Et9iHQg8H0H34+yMsXRhXofH9iJVlA1BoYiaMPuO 7VtZrwcvCn+SxwxOSV85zdJf6p8/XVGCDaux6GmJv6ledOHbW+fft2I9Wk0AimB0V319t+ypnrr lHh9BEKXBwTkkIp6CR X-Received: by 2002:a05:6820:4dfb:b0:663:d21:9f2 with SMTP id 006d021491bc7-6630f004395mr788533eaf.8.1769745579091; Thu, 29 Jan 2026 19:59:39 -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.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Jan 2026 19:59:37 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Thu, 29 Jan 2026 20:58:38 -0700 Message-ID: <20260130035849.3580212-16-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: B2HYPPWDWQUHWZTFSJKJKF6CRD47C5Y2 X-Message-ID-Hash: B2HYPPWDWQUHWZTFSJKJKF6CRD47C5Y2 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 15/19] cli: Add Ctrl+Left/Right arrow support for word navigation 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 support for Ctrl+Left and Ctrl+Right arrow keys to move the cursor by word in the command line editor. Ctrl+Left moves backward to the start of the previous word, and Ctrl+Right moves forward to the end of the next word. Decode the escape sequences (ESC[1;5D and ESC[1;5C) arein cli_getch.c and convert then to CTL_CH('r') and CTL_CH('t') respectively. Handle the actual word-movement logic is then handled in cli_readline.c, guarded by CONFIG_CMDLINE_EDITOR Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- common/cli_getch.c | 25 +++++++++++++++++++++++++ common/cli_readline.c | 31 +++++++++++++++++++++++++++++++ test/boot/editenv.c | 8 ++++++++ 3 files changed, 64 insertions(+) diff --git a/common/cli_getch.c b/common/cli_getch.c index a5ed6eb6fcf..8df1997911a 100644 --- a/common/cli_getch.c +++ b/common/cli_getch.c @@ -114,6 +114,12 @@ static int cli_ch_esc(struct cli_ch_state *cch, int ichar, if (cch->esc_save[2] == '2') act = ESC_SAVE; break; + case ';': + /* Ctrl+arrow: ESC [ 1 ; */ + if (CONFIG_IS_ENABLED(CMDLINE_EDITOR) && + cch->esc_save[2] == '1') + act = ESC_SAVE; + break; } break; case 4: @@ -122,12 +128,31 @@ static int cli_ch_esc(struct cli_ch_state *cch, int ichar, case '1': act = ESC_SAVE; break; /* bracketed paste */ + case '5': + /* Ctrl+arrow: ESC [ 1 ; 5 */ + if (CONFIG_IS_ENABLED(CMDLINE_EDITOR) && + cch->esc_save[3] == ';') + act = ESC_SAVE; + break; } break; case 5: if (ichar == '~') { /* bracketed paste */ ichar = 0; act = ESC_CONVERTED; + } else if (CONFIG_IS_ENABLED(CMDLINE_EDITOR) && + cch->esc_save[4] == '5') { + /* Ctrl+arrow: ESC [ 1 ; 5 D/C */ + switch (ichar) { + case 'D': /* Ctrl+<- key */ + ichar = CTL_CH('r'); + act = ESC_CONVERTED; + break; /* pass to backward-word handler */ + case 'C': /* Ctrl+-> key */ + ichar = CTL_CH('t'); + act = ESC_CONVERTED; + break; /* pass to forward-word handler */ + } } } diff --git a/common/cli_readline.c b/common/cli_readline.c index d2b02933fd7..4c25e9a04ba 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -333,6 +333,37 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) cls->num--; } break; + case CTL_CH('r'): /* backward-word */ + if (CONFIG_IS_ENABLED(CMDLINE_EDITOR) && cls->num) { + uint pos = cls->num; + + /* skip spaces before word */ + while (pos > 0 && buf[pos - 1] == ' ') + pos--; + /* skip word characters */ + while (pos > 0 && buf[pos - 1] != ' ') + pos--; + cls_putchars(cls, cls->num - pos, CTL_BACKSPACE); + cls->num = pos; + } + break; + case CTL_CH('t'): /* forward-word */ + if (CONFIG_IS_ENABLED(CMDLINE_EDITOR) && cls->num < cls->eol_num) { + uint pos = cls->num; + + /* skip spaces after cursor */ + while (pos < cls->eol_num && buf[pos] == ' ') { + cls_putch(cls, buf[pos]); + pos++; + } + /* skip word characters */ + while (pos < cls->eol_num && buf[pos] != ' ') { + cls_putch(cls, buf[pos]); + pos++; + } + cls->num = pos; + } + break; case CTL_CH('d'): if (cls->num < cls->eol_num) { uint wlen; diff --git a/test/boot/editenv.c b/test/boot/editenv.c index 0f9db54474d..20273c53647 100644 --- a/test/boot/editenv.c +++ b/test/boot/editenv.c @@ -171,6 +171,14 @@ static int editenv_test_funcs(struct unit_test_state *uts) ut_assertok(expo_editenv_init("testvar", initial, &info)); ut_asserteq(16611, ut_check_video(uts, "init")); + /* Navigate up to previous line */ + ut_assertok(editenv_send(&info, BKEY_UP)); + ut_asserteq(16684, ut_check_video(uts, "up")); + + /* Navigate back down */ + ut_assertok(editenv_send(&info, BKEY_DOWN)); + ut_asserteq(16611, ut_check_video(uts, "down")); + /* Type a character and press Enter to accept */ ut_assertok(editenv_send(&info, '*')); ut_asserteq(16689, ut_check_video(uts, "insert"));