Linux bluetooth development
 help / color / mirror / Atom feed
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 5/6] monitor: Prefer fzf as the pager when one is not set
Date: Thu, 17 Sep 2026 16:45:40 -0400	[thread overview]
Message-ID: <20260917204541.2176720-6-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260917204541.2176720-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

A trace is a poor fit for a plain pager. Every frame spans several lines
and what identifies one is spread between its header and its contents, so
finding something means paging through by hand.

Use fzf when PAGER is not set and it is installed, asking it for whole
frames and for the colours to be rendered rather than shown as escape
sequences:

  fzf --ansi --read0

PAGER is still honoured when set, and setting it to cat or leaving it
empty still turns the pager off. The choice is shared with the frames
seen so far being handed over while capturing, so both arrive at the same
pager.

Frames are separated only when a pager that reads records is going to
read them, so redirected output and a pager that reads lines are both
left exactly as they were.

The model wrote this, which the author reviewed and verified by checking
which pager is started for each setting of PAGER, that the colours are
rendered rather than shown, and that redirected output is unchanged.

Assisted-by: opencode:claude-opus-5
---
 monitor/display.c | 73 +++++++++++++++++++++++++++++++++++++++++++----
 monitor/display.h |  3 ++
 monitor/find.c    | 20 +++++++++----
 monitor/find.h    |  2 +-
 monitor/main.c    |  4 +--
 5 files changed, 88 insertions(+), 14 deletions(-)

diff --git a/monitor/display.c b/monitor/display.c
index b540155319a0..8d767e77e464 100644
--- a/monitor/display.c
+++ b/monitor/display.c
@@ -20,6 +20,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #include <signal.h>
 #include <sys/wait.h>
 #include <sys/prctl.h>
@@ -117,6 +118,69 @@ static void wait_for_terminate(pid_t pid)
 	}
 }
 
+/* Look for a command in PATH, so that it can be preferred if present */
+static bool have_command(const char *name)
+{
+	const char *path = getenv("PATH");
+	char *dirs, *dir, *save = NULL;
+	bool found = false;
+
+	if (!path)
+		return false;
+
+	dirs = strdup(path);
+	if (!dirs)
+		return false;
+
+	for (dir = strtok_r(dirs, ":", &save); dir;
+					dir = strtok_r(NULL, ":", &save)) {
+		char file[PATH_MAX];
+
+		if (snprintf(file, sizeof(file), "%s/%s", dir, name) < 0)
+			continue;
+
+		if (!access(file, X_OK)) {
+			found = true;
+			break;
+		}
+	}
+
+	free(dirs);
+
+	return found;
+}
+
+bool pager_disabled(void)
+{
+	const char *pager = getenv("PAGER");
+
+	return pager && (!*pager || !strcmp(pager, "cat"));
+}
+
+/*
+ * A fuzzy finder is a far better fit for a trace than a plain pager, so
+ * prefer it when one is installed and nothing was asked for. Wherever it
+ * is used it is told to take whole frames rather than lines, and to
+ * render the colours instead of showing the escape sequences.
+ */
+const char *pager_command(void)
+{
+	static char cmd[256];
+	const char *pager = getenv("PAGER");
+
+	if (!pager || !*pager)
+		return have_command("fzf") ? "fzf --ansi --read0" : NULL;
+
+	if (!strstr(pager, "fzf"))
+		return pager;
+
+	snprintf(cmd, sizeof(cmd), "%s%s%s", pager,
+			strstr(pager, "--ansi") ? "" : " --ansi",
+			strstr(pager, "--read0") ? "" : " --read0");
+
+	return cmd;
+}
+
 void open_pager(void)
 {
 	const char *pager;
@@ -126,11 +190,10 @@ void open_pager(void)
 	if (pager_pid > 0)
 		return;
 
-	pager = getenv("PAGER");
-	if (pager) {
-		if (!*pager || strcmp(pager, "cat") == 0)
-			return;
-	}
+	if (pager_disabled())
+		return;
+
+	pager = pager_command();
 
 	if (!(isatty(STDOUT_FILENO) > 0))
 		return;
diff --git a/monitor/display.h b/monitor/display.h
index 93773e651ef1..cad182f77c94 100644
--- a/monitor/display.h
+++ b/monitor/display.h
@@ -135,5 +135,8 @@ static inline void print_hex_field(const char *label, const uint8_t *data,
 void set_default_pager_num_columns(int num_columns);
 int num_columns(void);
 
+bool pager_disabled(void);
+const char *pager_command(void);
+
 void open_pager(void);
 void close_pager(void);
diff --git a/monitor/find.c b/monitor/find.c
index 32600964faf1..58c4f51d8bfb 100644
--- a/monitor/find.c
+++ b/monitor/find.c
@@ -60,6 +60,7 @@ static bool store;	/* Keep the frames for handing to the pager */
 static bool records;	/* Separate the frames with a NUL */
 static bool printed;	/* Something has been written out already */
 static bool print0;
+static bool use_pager;
 static bool raw_mode;
 static int poll_id = -1;
 static struct termios saved_term;
@@ -312,16 +313,14 @@ static void pager_open(void)
 	const char *pager;
 	int fd;
 
-	if (pager_pid || !num_frames)
+	if (pager_pid || !num_frames || !use_pager || pager_disabled())
 		return;
 
 	fd = frames_to_file();
 	if (fd < 0)
 		return;
 
-	pager = getenv("PAGER");
-	if (pager && (!*pager || !strcmp(pager, "cat")))
-		pager = NULL;
+	pager = pager_command();
 
 	fflush(stdout);
 
@@ -427,13 +426,22 @@ static bool want_records(void)
 	if (print0)
 		return true;
 
-	pager = getenv("PAGER");
+	/*
+	 * Only separate the frames if something is actually going to read
+	 * them as records. Nothing does when the output is redirected or
+	 * the pager has been turned off.
+	 */
+	if (!use_pager || pager_disabled() || !isatty(STDOUT_FILENO))
+		return false;
+
+	pager = pager_command();
 
 	return pager && strstr(pager, "--read0");
 }
 
-void find_setup(bool live)
+void find_setup(bool live, bool pager)
 {
+	use_pager = pager;
 	records = want_records();
 
 	if (live && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
diff --git a/monitor/find.h b/monitor/find.h
index 3048ab69e4c9..e7dad7aaf25c 100644
--- a/monitor/find.h
+++ b/monitor/find.h
@@ -11,7 +11,7 @@
 #include <stdbool.h>
 
 void find_set_print0(void);
-void find_setup(bool live);
+void find_setup(bool live, bool pager);
 
 void find_frame_begin(void);
 void find_frame_end(void);
diff --git a/monitor/main.c b/monitor/main.c
index 25de945446a9..1a7a25713de1 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -286,7 +286,7 @@ int main(int argc, char *argv[])
 		if (ellisys_server)
 			ellisys_enable(ellisys_server, ellisys_port);
 
-		find_setup(false);
+		find_setup(false, use_pager);
 
 		control_reader(reader_path, use_pager);
 		return EXIT_SUCCESS;
@@ -310,7 +310,7 @@ int main(int argc, char *argv[])
 		return EXIT_FAILURE;
 
 	/* Watch for the key that brings the pager up */
-	find_setup(true);
+	find_setup(true, use_pager);
 
 	exit_status = mainloop_run_with_signal(signal_callback, NULL);
 
-- 
2.55.0


  parent reply	other threads:[~2026-09-17 20:45 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function Luiz Augusto von Dentz
2026-09-17 23:55   ` monitor: Search the frames with a pager bluez.test.bot
2026-09-17 20:45 ` [PATCH BlueZ v1 2/6] monitor: Separate the frames for a pager reading records Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 3/6] monitor: Hand the captured frames to the pager on Ctrl-R Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 4/6] doc/btmon: Document searching the frames Luiz Augusto von Dentz
2026-09-17 20:45 ` Luiz Augusto von Dentz [this message]
2026-09-17 20:45 ` [PATCH BlueZ v1 6/6] doc/btmon: Document the pager choice Luiz Augusto von Dentz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260917204541.2176720-6-luiz.dentz@gmail.com \
    --to=luiz.dentz@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox