[Concept,05/24] console: Add bypass keypress to disable paging

Message ID 20250922180116.3088502-6-sjg@u-boot.org
State New
Headers
Series boot: efi: Various improvements to booting with the EFI app |

Commit Message

Simon Glass Sept. 22, 2025, 6 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add support for pressing 'Q' to put the pager into bypass mode,disabling
further paging for the current session.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/pager.c        | 36 +++++++++++++++++++++++++-----------
 doc/usage/console.rst |  3 +++
 include/pager.h       |  4 ++++
 test/common/pager.c   | 39 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 71 insertions(+), 11 deletions(-)
  

Patch

diff --git a/common/pager.c b/common/pager.c
index a16937768b6..c0a55b738b9 100644
--- a/common/pager.c
+++ b/common/pager.c
@@ -71,6 +71,10 @@  const char *pager_next(struct pager *pag, bool use_pager, int key)
 		pag->state = PAGERST_WAIT_USER;
 		return PAGER_PROMPT;
 	case PAGERST_WAIT_USER:
+		if (key == 'Q') {
+			pag->state = PAGERST_BYPASS;
+			return PAGER_BLANK;
+		}
 		if (key != ' ')
 			return PAGER_WAITING;
 		pag->state = PAGERST_CLEAR_PROMPT;
@@ -79,7 +83,7 @@  const char *pager_next(struct pager *pag, bool use_pager, int key)
 		pag->state = PAGERST_OK;
 		break;
 	case PAGERST_BYPASS:
-		return NULL;
+		break;
 	}
 
 	ret = membuf_getraw(&pag->mb, pag->buf.size - 1, false, &str);
@@ -93,17 +97,26 @@  const char *pager_next(struct pager *pag, bool use_pager, int key)
 		return NULL;
 	}
 
-	/* return lines until we reach the limit */
-	for (p = str, end = str + ret; p < end; p++) {
-		if (*p == '\n' && ++pag->line_count == pag->page_len - 1) {
-			/* remember to display the pager message next time */
-			pag->state = PAGERST_AT_LIMIT;
-			pag->line_count = 0;
-
-			/* skip the newline, since our prompt has one */
-			p++;
-			break;
+	end = str + ret;
+	if (pag->state != PAGERST_BYPASS) {
+		/* return lines until we reach the limit */
+		for (p = str; p < end; p++) {
+			if (*p == '\n' &&
+			    ++pag->line_count == pag->page_len - 1) {
+				/*
+				 * remember to display the pager message next
+				 * time
+				 */
+				pag->state = PAGERST_AT_LIMIT;
+				pag->line_count = 0;
+
+				/* skip the newline, since our prompt has one */
+				p++;
+				break;
+			}
 		}
+	} else {
+		p = end;
 	}
 
 	/* remove the used bytes from the membuf */
@@ -178,6 +191,7 @@  static int on_pager(const char *name, const char *value, enum env_op op,
 		if (value) {
 			new_page_len = simple_strtoul(value, NULL, 16);
 			pager_set_page_len(pag, new_page_len);
+			pager_set_bypass(pag, false);
 		}
 		break;
 	case env_op_delete:
diff --git a/doc/usage/console.rst b/doc/usage/console.rst
index 4a28ea95906..880a5b7b605 100644
--- a/doc/usage/console.rst
+++ b/doc/usage/console.rst
@@ -72,6 +72,9 @@  When activated, the pager pauses at the end of each 'page' (screenful) of
 output, shows a prompt ": Press SPACE to continue" and lets the user read the
 output. To continue to the next page, press the SPACE key.
 
+The pager can be bypassed by pressing 'Q' at the prompt. This disables the pager
+until the 'pager' environment variable is given a new value.
+
 Page Size Configuration
 ~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/include/pager.h b/include/pager.h
index b43b332a83c..887f5d1f639 100644
--- a/include/pager.h
+++ b/include/pager.h
@@ -110,6 +110,10 @@  const char *pager_post(struct pager *pag, bool use_pager, const char *s);
  * busy-wait for a keypress, if desired, since pager_next() will only ever
  * return PAGER_WAITING until @ch is non-zero.
  *
+ * When the pager prompts for user input, pressing SPACE continues to the next
+ * page, while pressing capital 'Q' puts the pager into bypass mode and
+ * disables further paging.
+ *
  * @pag: Pager to use
  * @use_pager: Whether or not to use the pager functionality
  * @ch: Key that the user has pressed, or 0 if none
diff --git a/test/common/pager.c b/test/common/pager.c
index 53902ab29a3..636069d5b37 100644
--- a/test/common/pager.c
+++ b/test/common/pager.c
@@ -579,3 +579,42 @@  static int pager_test_console(struct unit_test_state *uts)
 	return 0;
 }
 COMMON_TEST(pager_test_console, UTF_CONSOLE);
+
+/* Test bypass keypress ('Q') functionality */
+static int pager_test_bypass_keypress(struct unit_test_state *uts)
+{
+	struct pager *pag;
+	const char *out;
+	int ret;
+
+	ret = pager_init(&pag, 3, SZ_1K);
+	ut_assertok(ret);
+
+	/* Post text that will trigger paging */
+	out = pager_post(pag, true, "line1\nline2\nline3\nline4\n");
+	ut_assertnonnull(out);
+	ut_asserteq_str("line1\nline2", out);
+
+	/* Should be waiting for user input */
+	out = pager_next(pag, true, 0);
+	ut_asserteq_str(PAGER_PROMPT, out);
+
+	/* Press 'Q' to bypass */
+	out = pager_next(pag, true, 'Q');
+	ut_asserteq_str(PAGER_BLANK, out);
+
+	/* Verify pager is now in bypass mode */
+	ut_asserteq(PAGERST_BYPASS, pag->state);
+
+	/* Next call should return the remaining text without paging */
+	out = pager_next(pag, true, 0);
+	ut_asserteq_str("line3\nline4\n", out);
+
+	/* No more text should be available */
+	out = pager_next(pag, true, 0);
+	ut_asserteq_ptr(NULL, out);
+
+	pager_uninit(pag);
+	return 0;
+}
+COMMON_TEST(pager_test_bypass_keypress, 0);