From patchwork Fri Jan 30 03:58:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1787 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=f8d1JkW2; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 2CC96697DD for ; Thu, 29 Jan 2026 20:59:40 -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 DaEyZQ556s22 for ; Thu, 29 Jan 2026 20:59:40 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 17FB7697CB for ; Thu, 29 Jan 2026 20:59:40 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D861E697ED 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 rkyd7uSdJQbF for ; Thu, 29 Jan 2026 20:59:37 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.160.43; helo=mail-oa1-f43.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-oa1-f43.google.com (mail-oa1-f43.google.com [209.85.160.43]) by mail.u-boot.org (Postfix) with ESMTPS id 8E08569738 for ; Thu, 29 Jan 2026 20:59:32 -0700 (MST) Received: by mail-oa1-f43.google.com with SMTP id 586e51a60fabf-40974bf7781so1135409fac.0 for ; Thu, 29 Jan 2026 19:59:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1769745571; x=1770350371; 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=XgQf8W2szUm4TjIufcRntmhr50KKs/4EIfNFHnCxnPA=; b=f8d1JkW2P9bI8/dcuQydPfJuW1Yc2DI1LH0nRbQGM8Oi3KpkD9U8HdcEWQVNdXLBAX lscODcO9+0EJb/pacY8oxJ1aE1S9ubF2o3b8/7hg+aUqfyXhSSzM0RvMDA3xjwzyVnqI fMnRdML5JzwFFEYAMsKdL2B0qmQoNWV32Vj1s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769745571; x=1770350371; 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=XgQf8W2szUm4TjIufcRntmhr50KKs/4EIfNFHnCxnPA=; b=GVrEBVRv1Skkpxt0uFrVNuX5UhGz17fVNyG3Njwbl2uk6OkfKOG4G7UMp1RF4YNfIz i2xiyZhN+R0YTv5eK4Ycrt46wKVM5lp9hP8VAKdvNdHR1aHzVNVtBPkfBhaLZ+VZjPKJ oVlY7DeDWKpqZcVrhdEloQeUroAgi/BeU94l1fVEtMWDhyo9urlH0jRWkR9/HYQn3n76 DY/+gK1AxpZXe27O0laUZaq5GpsO7Za3cVF+BXv53EA8U3xk7Xv0jzMWJAxm/Xpn7t2v PqfAiyEt2gjuSaQvbLHsP7ZSqL1oHlwQG6faxgcUeENnxcuINO+njLGlqCsELcBiiMxi 714g== X-Gm-Message-State: AOJu0YyITsP/8wtiuvxoF3STRntl0g9uM266065kK3M5QAwfq/vRdij5 Z+1oC8bRqt2BqGSz/ZEMf/mWvDRB9Ae+Xl9R6QBBoP3Rt6i32mmRgkeiEKygfhHhALFzi2EPOjB vY2zrQg== X-Gm-Gg: AZuq6aLoNCjqFCQmePDUVDGkx6kX5qGmGTWd1OL6Tzh1e/sch7QvLVPHWduyF/OJ/8U P+tnecc384mKUqPyyI7X77EgcB4PS99LmYVBWa34pZN2KoC6A2NbWqBcVDQoTr3z1cPE8RpG3si D7azkB0+jbI6CJdCY0g1kGCJZFDEH4CiLJBt9Xw/v9HZRqebp1U2N1hJ6aBLOfaDWlUT2jYnnk3 W+wkIylwWNFgidovrHb7C4KWxE2NgaeWkHG1A4/QIiGO5V5o/klwmo5rYOFuUYI6s3K3iWqoqR8 5/TRUmt9x5HscqioxdghrydZS3oJqdtZwr0kk7XUxsQoRN4gAYvvRZutxkDnYZqG6FovZhcpbdJ ErgVXBDPpAFT2EeWwGINUYUnESzkvydyITVa0qG5INIjrfcsPcVFIegbP+Vtm1pTsA1nHfyyjQn lONyZYBJqLr0oGu3XG X-Received: by 2002:a05:6820:4510:b0:65c:faa7:7077 with SMTP id 006d021491bc7-6631037c91cmr585922eaf.23.1769745570908; Thu, 29 Jan 2026 19:59:30 -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.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Jan 2026 19:59:29 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Thu, 29 Jan 2026 20:58:35 -0700 Message-ID: <20260130035849.3580212-13-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: HBFW3KMGNCAOJK3D2K4SUOLEVXQ47UO5 X-Message-ID-Hash: HBFW3KMGNCAOJK3D2K4SUOLEVXQ47UO5 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 12/19] cmd: editenv: Add -e flag for expo-based 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 Kconfig option CMD_EDITENV_EXPO to enable graphical environment variable editing using the expo framework. When enabled, users can use 'editenv -e varname' to edit a variable using a textedit widget in a graphical interface. The expo-based editor creates a simple scene with a textedit object, allowing the user to edit the variable value with full cursor movement support. Press Enter to accept changes or Escape to cancel. The implementation is in boot/editenv.c controlled by EXPO_EDITENV, allowing it to be used without CONFIG_CMDLINE. The command support (CMD_EDITENV_EXPO) depends on EXPO_EDITENV. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- boot/Kconfig | 9 +++ boot/Makefile | 1 + boot/editenv.c | 191 ++++++++++++++++++++++++++++++++++++++++++++ cmd/Kconfig | 9 +++ cmd/nvedit.c | 50 ++++++++++-- include/expo.h | 64 +++++++++++++++ test/boot/Makefile | 1 + test/boot/editenv.c | 94 ++++++++++++++++++++++ 8 files changed, 411 insertions(+), 8 deletions(-) create mode 100644 boot/editenv.c create mode 100644 test/boot/editenv.c diff --git a/boot/Kconfig b/boot/Kconfig index 7a8f9862ba7..e117e5b0479 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1012,6 +1012,15 @@ config EXPO_LOG_FILTER Only objects whose name contains the filter string are logged. This is useful for debugging specific expo objects. +config EXPO_EDITENV + bool "Expo-based environment variable editor" + depends on EXPO + default y if SANDBOX + help + Enable a graphical environment variable editor using expo. This + provides a textedit widget for editing environment variables with + full cursor movement support. + config BOOTMETH_SANDBOX def_bool y depends on SANDBOX diff --git a/boot/Makefile b/boot/Makefile index b9129a174c7..b2a475d4917 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_$(PHASE_)LOAD_FIT) += common_fit.o obj-$(CONFIG_$(PHASE_)EXPO) += expo.o scene.o expo_build.o obj-$(CONFIG_$(PHASE_)EXPO_DUMP) += expo_dump.o obj-$(CONFIG_$(PHASE_)EXPO) += scene_menu.o scene_textline.o scene_textedit.o scene_txtin.o +obj-$(CONFIG_$(PHASE_)EXPO_EDITENV) += editenv.o obj-$(CONFIG_$(PHASE_)EXPO_TEST) += expo_test.o ifdef CONFIG_COREBOOT_SYSINFO obj-$(CONFIG_$(PHASE_)EXPO) += expo_build_cb.o diff --git a/boot/editenv.c b/boot/editenv.c new file mode 100644 index 00000000000..de7df6fe3fa --- /dev/null +++ b/boot/editenv.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Expo-based environment variable editor + * + * Copyright 2025 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include + +/* IDs for expo objects */ +enum { + EDITENV_SCENE = EXPOID_BASE_ID + 1, + EDITENV_OBJ_TEXTEDIT, + EDITENV_OBJ_LABEL, + EDITENV_OBJ_EDIT, +}; + +static int editenv_setup(struct expo *exp, struct udevice *dev, + const char *varname, const char *value, + struct editenv_info *info) +{ + struct scene_obj_txtedit *ted; + struct scene *scn; + const char *name; + uint font_size; + int ret; + + ret = expo_set_display(exp, dev); + if (ret) + return log_msg_ret("dis", ret); + + ret = vidconsole_get_font_size(exp->cons, NULL, &name, &font_size); + if (ret) + font_size = 16; + + exp->theme.font_size = font_size; + exp->theme.textline_label_margin_x = 10; + + ret = scene_new(exp, "edit", EDITENV_SCENE, &scn); + if (ret < 0) + return log_msg_ret("scn", ret); + + ret = scene_texted(scn, "textedit", EDITENV_OBJ_TEXTEDIT, 70, &ted); + if (ret < 0) + return log_msg_ret("ted", ret); + + ret = scene_obj_set_bbox(scn, EDITENV_OBJ_TEXTEDIT, 50, 200, 1300, 400); + if (ret < 0) + return log_msg_ret("sbb", ret); + + /* Create the label text object */ + ret = scene_txt_str(scn, "label", EDITENV_OBJ_LABEL, 0, varname, NULL); + if (ret < 0) + return log_msg_ret("lab", ret); + + ted->tin.label_id = EDITENV_OBJ_LABEL; + + /* Create the edit text object pointing to the textedit buffer */ + ret = scene_txt_str(scn, "edit", EDITENV_OBJ_EDIT, 0, + abuf_data(&ted->tin.buf), NULL); + if (ret < 0) + return log_msg_ret("edi", ret); + + ted->tin.edit_id = EDITENV_OBJ_EDIT; + + ret = expo_apply_theme(exp, true); + if (ret) + return log_msg_ret("thm", ret); + + /* Copy initial value into the textedit buffer */ + if (value) + strlcpy(abuf_data(&ted->tin.buf), value, + abuf_size(&ted->tin.buf)); + + ret = expo_set_scene_id(exp, EDITENV_SCENE); + if (ret) + return log_msg_ret("sid", ret); + + /* Set the textedit as highlighted and open for editing */ + scene_set_highlight_id(scn, EDITENV_OBJ_TEXTEDIT); + ret = scene_set_open(scn, EDITENV_OBJ_TEXTEDIT, true); + if (ret) + return log_msg_ret("ope", ret); + + expo_enter_mode(exp); + + info->exp = exp; + info->scn = scn; + info->ted = ted; + + ret = scene_arrange(scn); + if (ret) + return log_msg_ret("arr", ret); + + ret = expo_render(exp); + if (ret) + return log_msg_ret("ren", ret); + + return 0; +} + +int expo_editenv_init(const char *varname, const char *value, + struct editenv_info *info) +{ + struct udevice *dev; + struct expo *exp; + int ret; + + ret = uclass_first_device_err(UCLASS_VIDEO, &dev); + if (ret) + return log_msg_ret("vid", ret); + + ret = expo_new("editenv", NULL, &exp); + if (ret) + return log_msg_ret("exp", ret); + + ret = editenv_setup(exp, dev, varname, value, info); + if (ret) { + expo_destroy(exp); + return log_msg_ret("set", ret); + } + + return 0; +} + +int expo_editenv_poll(struct editenv_info *info) +{ + struct expo_action act; + int ret; + + ret = scene_arrange(info->scn); + if (ret) + return log_msg_ret("arr", ret); + + ret = expo_render(info->exp); + if (ret) + return log_msg_ret("ren", ret); + + ret = expo_poll(info->exp, &act); + if (ret == -EAGAIN) + return -EAGAIN; + if (ret) + return log_msg_ret("pol", ret); + + if (act.type == EXPOACT_QUIT) + return -ECANCELED; + + if (act.type == EXPOACT_CLOSE) + return 0; + + return -EAGAIN; +} + +void expo_editenv_uninit(struct editenv_info *info) +{ + expo_exit_mode(info->exp); + expo_destroy(info->exp); +} + +const char *expo_editenv_result(struct editenv_info *info) +{ + return abuf_data(&info->ted->tin.buf); +} + +int expo_editenv(const char *varname, const char *value, char *buf, int size) +{ + struct editenv_info info; + int ret; + + ret = expo_editenv_init(varname, value, &info); + if (ret) + return log_msg_ret("ini", ret); + + /* Render and process input */ + while (1) { + ret = expo_editenv_poll(&info); + if (ret != -EAGAIN) + break; + } + + if (!ret) + strlcpy(buf, expo_editenv_result(&info), size); + + expo_editenv_uninit(&info); + + return ret; +} diff --git a/cmd/Kconfig b/cmd/Kconfig index 448a6e9fe39..606a34f8869 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -707,6 +707,15 @@ config CMD_EDITENV help Edit environment variable. +config CMD_EDITENV_EXPO + bool "editenv expo support" + depends on CMD_EDITENV && EXPO_EDITENV + default y if EXPO_EDITENV + help + Enable the -e flag for the editenv command, which provides a + graphical editor using the expo framework. This requires a video + console. + config CMD_GREPENV bool "search env" help diff --git a/cmd/nvedit.c b/cmd/nvedit.c index f67c268da84..f62b4cca242 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -427,31 +428,55 @@ static int do_env_edit(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { char buffer[CONFIG_SYS_CBSIZE]; + bool use_expo = false; + const char *varname; char *init_val; + if (IS_ENABLED(CONFIG_CMD_EDITENV_EXPO) && + argc >= 2 && !strcmp(argv[1], "-e")) { + use_expo = true; + argc--; + argv++; + } + if (argc < 2) return CMD_RET_USAGE; + varname = argv[1]; + /* before import into hashtable */ if (!(gd->flags & GD_FLG_ENV_READY)) return 1; - /* Set read buffer to initial value or empty sting */ - init_val = env_get(argv[1]); + /* Set read buffer to initial value or empty string */ + init_val = env_get(varname); if (init_val) snprintf(buffer, CONFIG_SYS_CBSIZE, "%s", init_val); else buffer[0] = '\0'; - if (cli_readline_into_buffer("edit: ", buffer, 0) < 0) - return 1; + if (IS_ENABLED(CONFIG_CMD_EDITENV_EXPO) && use_expo) { + int ret; + + ret = expo_editenv(varname, init_val, buffer, + CONFIG_SYS_CBSIZE); + if (ret == -EAGAIN) + return 0; /* User cancelled, no change */ + if (ret) { + printf("Edit failed (err=%d)\n", ret); + return CMD_RET_FAILURE; + } + } else { + if (cli_readline_into_buffer("edit: ", buffer, 0) < 0) + return 1; + } if (buffer[0] == '\0') { - const char * const _argv[3] = { "setenv", argv[1], NULL }; + const char * const _argv[3] = { "setenv", varname, NULL }; return env_do_env_set(0, 2, (char * const *)_argv, H_INTERACTIVE); } else { - const char * const _argv[4] = { "setenv", argv[1], buffer, + const char * const _argv[4] = { "setenv", varname, buffer, NULL }; return env_do_env_set(0, 3, (char * const *)_argv, H_INTERACTIVE); @@ -1065,7 +1090,7 @@ static struct cmd_tbl cmd_env_sub[] = { U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""), U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""), #if defined(CONFIG_CMD_EDITENV) - U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""), + U_BOOT_CMD_MKENT(edit, 3, 0, do_env_edit, "", ""), #endif #if defined(CONFIG_CMD_ENV_CALLBACK) U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), @@ -1141,8 +1166,12 @@ U_BOOT_LONGHELP(env, " \"-k\": keep variables not defined in default environment\n" "env delete [-f] var [...] - [forcibly] delete variable(s)\n" #if defined(CONFIG_CMD_EDITENV) +#if defined(CONFIG_CMD_EDITENV_EXPO) + "env edit [-e] name - edit environment variable (-e for expo)\n" +#else "env edit name - edit environment variable\n" #endif +#endif #if defined(CONFIG_CMD_ENV_EXISTS) "env exists name - tests for existence of variable\n" #endif @@ -1208,9 +1237,14 @@ U_BOOT_CMD( #if defined(CONFIG_CMD_EDITENV) U_BOOT_CMD_COMPLETE( - editenv, 2, 0, do_env_edit, + editenv, 3, 0, do_env_edit, "edit environment variable", +#if defined(CONFIG_CMD_EDITENV_EXPO) + "[-e] name\n" + " -e - use expo (graphical editor)\n" +#else "name\n" +#endif " - edit environment variable 'name'", var_complete ); diff --git a/include/expo.h b/include/expo.h index d63fbd0c8ad..5a35d72c58f 100644 --- a/include/expo.h +++ b/include/expo.h @@ -1181,6 +1181,70 @@ int expo_setup_theme(struct expo *exp, ofnode node); */ int expo_apply_theme(struct expo *exp, bool do_objs); +/** + * struct editenv_info - Context for environment-variable editing + * + * @exp: Expo being used + * @scn: Scene in the expo + * @ted: Textedit object for editing + */ +struct editenv_info { + struct expo *exp; + struct scene *scn; + struct scene_obj_txtedit *ted; +}; + +/** + * expo_editenv_init() - Set up a new editenv expo + * + * @varname: Name of the variable to edit + * @value: Initial value (may be NULL) + * @info: Returns info about the editenv state + * Return: 0 if OK, -ve on error + */ +int expo_editenv_init(const char *varname, const char *value, + struct editenv_info *info); + +/** + * expo_editenv_poll() - Poll for user input + * + * @info: Editenv info + * Return: 0 if editing is complete, -EAGAIN if more polling is needed, + * -ECANCELED if user quit, other -ve on error + */ +int expo_editenv_poll(struct editenv_info *info); + +/** + * expo_editenv_uninit() - Free resources used by editenv + * + * @info: Editenv info + */ +void expo_editenv_uninit(struct editenv_info *info); + +/** + * expo_editenv_result() - Get the result string from editenv + * + * @info: Editenv info + * Return: Pointer to the edited string + */ +const char *expo_editenv_result(struct editenv_info *info); + +/** + * expo_editenv() - Edit an environment variable using expo + * + * Creates a simple expo with a textedit object to edit the variable. + * This is a convenience function that calls expo_editenv_init(), + * expo_editenv_poll() in a loop, and expo_editenv_uninit(). + * + * @varname: Name of the variable to edit + * @value: Initial value (may be NULL) + * @buf: Buffer to receive the edited text + * @size: Size of buf + * Return: 0 if OK and text was edited, -ECANCELED if cancelled, other -ve on + * error + */ +int expo_editenv(const char *varname, const char *value, char *buf, int size); + /** * expo_build() - Build an expo from an FDT description * diff --git a/test/boot/Makefile b/test/boot/Makefile index ceb863969dd..329f4acbd52 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_$(PHASE_)FIT_PRINT) += fit_print.o obj-$(CONFIG_BLK_LUKS) += luks.o obj-$(CONFIG_EXPO) += expo.o expo_common.o +obj-$(CONFIG_EXPO_EDITENV) += editenv.o obj-$(CONFIG_CEDIT) += cedit.o expo_common.o obj-$(CONFIG_UT_BOOTCTL) += bootctl/ endif diff --git a/test/boot/editenv.c b/test/boot/editenv.c new file mode 100644 index 00000000000..02bc025e216 --- /dev/null +++ b/test/boot/editenv.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for expo environment editor + * + * Copyright 2025 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" + +/* Check expo_editenv() basic functionality */ +static int editenv_test_base(struct unit_test_state *uts) +{ + char buf[256]; + int ret; + + /* + * Type "test" then press Enter to accept + * \x0d is Ctrl-M (Enter/carriage return) + */ + console_in_puts("test\x0d"); + ret = expo_editenv("myvar", NULL, buf, sizeof(buf)); + ut_assertok(ret); + ut_asserteq_str("test", buf); + + return 0; +} +BOOTSTD_TEST(editenv_test_base, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Check expo_editenv() with initial value - prepend text */ +static int editenv_test_initial(struct unit_test_state *uts) +{ + char buf[256]; + int ret; + + /* + * Start with "world", go to start with Ctrl-A, type "hello ", then + * press Enter + */ + console_in_puts("\x01hello \x0d"); + ret = expo_editenv("myvar", "world", buf, sizeof(buf)); + ut_assertok(ret); + ut_asserteq_str("hello world", buf); + + return 0; +} +BOOTSTD_TEST(editenv_test_initial, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Check expo_editenv() escape closes editor (accepts current value) */ +static int editenv_test_escape(struct unit_test_state *uts) +{ + char buf[256]; + int ret; + + /* + * Press Escape immediately - this closes the editor and accepts + * the current (initial) value + */ + console_in_puts("\x1b"); + ret = expo_editenv("myvar", "unchanged", buf, sizeof(buf)); + ut_assertok(ret); + ut_asserteq_str("unchanged", buf); + + return 0; +} +BOOTSTD_TEST(editenv_test_escape, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Check expo_editenv() renders correctly */ +static int editenv_test_video(struct unit_test_state *uts) +{ + struct udevice *dev; + char buf[256]; + int ret; + + ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev)); + + /* Type "abc" then press Enter */ + console_in_puts("abc\x0d"); + ret = expo_editenv("testvar", "initial", buf, sizeof(buf)); + ut_assertok(ret); + ut_asserteq_str("initialabc", buf); + + /* Check the framebuffer has expected content */ + ut_asserteq(1029, video_compress_fb(uts, dev, false)); + + return 0; +} +BOOTSTD_TEST(editenv_test_video, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);