[tracker-miners/wip/carlosg/cli-improvements: 14/30] tracker: Add pager integration to "tracker3 status"




commit 3031a3c69a0a8c64133a02ceb26f1e65d7718219
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Aug 17 17:15:58 2020 +0200

    tracker: Add pager integration to "tracker3 status"
    
    Use the pager when listing errors, so the user can page through them
    if they overflow the terminal size.

 src/libtracker-miners-common/tracker-term-utils.c | 98 +++++++++++++++++++++++
 src/libtracker-miners-common/tracker-term-utils.h |  6 ++
 src/tracker/tracker-status.c                      | 12 +++
 3 files changed, 116 insertions(+)
---
diff --git a/src/libtracker-miners-common/tracker-term-utils.c 
b/src/libtracker-miners-common/tracker-term-utils.c
index 9de157cf8..96e90da5f 100644
--- a/src/libtracker-miners-common/tracker-term-utils.c
+++ b/src/libtracker-miners-common/tracker-term-utils.c
@@ -21,11 +21,18 @@
 
 #include "tracker-term-utils.h"
 
+#include <gio/gio.h>
+#include <glib-unix.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
 
 static guint n_columns = 0;
 static guint n_rows = 0;
+static GSubprocess *pager = NULL;
+static gint stdout_fd = 0;
+static guint signal_handler_id = 0;
 
 gchar *
 tracker_term_ellipsize (const gchar          *str,
@@ -87,3 +94,94 @@ tracker_term_dimensions (guint *columns,
        if (rows)
                *rows = n_rows;
 }
+
+gboolean
+tracker_term_is_tty (void)
+{
+       return isatty (STDOUT_FILENO) > 0;
+}
+
+static gboolean
+ignore_signal_cb (gpointer user_data)
+{
+       return G_SOURCE_CONTINUE;
+}
+
+static gchar *
+best_pager (void)
+{
+       guint i;
+       gchar *command;
+       const gchar *pagers[] = {
+               "pager",
+               "less",
+               "most",
+               "more",
+       };
+
+       for (i = 0; i < G_N_ELEMENTS (pagers); i++) {
+               command = g_find_program_in_path (pagers[i]);
+               if (command)
+                       return command;
+       }
+
+       return NULL;
+}
+
+gboolean
+tracker_term_pipe_to_pager (void)
+{
+       GSubprocessLauncher *launcher;
+       gchar *pager_command;
+       gint fds[2];
+
+       if (!tracker_term_is_tty ())
+               return FALSE;
+
+       if (pipe2 (fds, O_CLOEXEC) < 0)
+               return FALSE;
+
+       pager_command = best_pager ();
+       if (!pager_command)
+               return FALSE;
+
+       /* Ensure this is cached before we redirect to the pager */
+       tracker_term_dimensions (NULL, NULL);
+
+       launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
+       g_subprocess_launcher_take_stdin_fd (launcher, fds[0]);
+       g_subprocess_launcher_setenv (launcher, "LESS", "FRSXMK", TRUE);
+
+       pager = g_subprocess_launcher_spawn (launcher, NULL, pager_command, NULL);
+       g_free (pager_command);
+
+       stdout_fd = dup (STDOUT_FILENO);
+       close (fds[0]);
+
+       if (dup2(fds[1], STDOUT_FILENO) < 0)
+               return FALSE;
+
+       close (fds[1]);
+       signal_handler_id = g_unix_signal_add (SIGINT, ignore_signal_cb, NULL);
+
+       return TRUE;
+}
+
+gboolean
+tracker_term_pager_close (void)
+{
+       if (!pager)
+               return FALSE;
+
+       fflush (stdout);
+
+       /* Restore stdout */
+       dup2 (stdout_fd, STDOUT_FILENO);
+       close (stdout_fd);
+
+       g_subprocess_send_signal (pager, SIGCONT);
+       g_subprocess_wait (pager, NULL, NULL);
+       g_source_remove (signal_handler_id);
+
+       return TRUE;
+}
diff --git a/src/libtracker-miners-common/tracker-term-utils.h 
b/src/libtracker-miners-common/tracker-term-utils.h
index e572b454e..1a4547d0b 100644
--- a/src/libtracker-miners-common/tracker-term-utils.h
+++ b/src/libtracker-miners-common/tracker-term-utils.h
@@ -23,6 +23,7 @@
 #define __TRACKER_TERM_UTILS_H__
 
 #include <glib.h>
+#include <gio/gio.h>
 
 typedef enum {
        TRACKER_ELLIPSIZE_START,
@@ -36,4 +37,9 @@ gchar * tracker_term_ellipsize (const gchar          *str,
 void tracker_term_dimensions (guint *columns,
                               guint *lines);
 
+gboolean tracker_term_is_tty (void);
+
+gboolean tracker_term_pipe_to_pager (void);
+gboolean tracker_term_pager_close (void);
+
 #endif /* __TRACKER_TERM_UTILS_H__ */
diff --git a/src/tracker/tracker-status.c b/src/tracker/tracker-status.c
index 2b6e2d8ec..8e8ae8ff4 100644
--- a/src/tracker/tracker-status.c
+++ b/src/tracker/tracker-status.c
@@ -96,6 +96,8 @@ status_stat (void)
                return EXIT_FAILURE;
        }
 
+       tracker_term_pipe_to_pager ();
+
        cursor = statistics_query (connection, &error);
 
        g_object_unref (connection);
@@ -162,6 +164,8 @@ status_stat (void)
                g_object_unref (cursor);
        }
 
+       tracker_term_pager_close ();
+
        return EXIT_SUCCESS;
 }
 
@@ -611,6 +615,8 @@ get_no_args (void)
        gint files, folders;
        GList *keyfiles;
 
+       tracker_term_pipe_to_pager ();
+
        /* How many files / folders do we have? */
        if (get_file_and_folder_count (&files, &folders) != 0) {
                return EXIT_FAILURE;
@@ -673,6 +679,8 @@ get_no_args (void)
                g_list_free_full (keyfiles, (GDestroyNotify) g_key_file_unref);
        }
 
+       tracker_term_pager_close ();
+
        return EXIT_SUCCESS;
 }
 
@@ -684,6 +692,8 @@ show_errors (gchar **terms)
        guint i;
        gboolean found = FALSE;
 
+       tracker_term_pipe_to_pager ();
+
        keyfiles = get_error_keyfiles ();
 
        for (i = 0; terms[i] != NULL; i++) {
@@ -722,6 +732,8 @@ show_errors (gchar **terms)
        if (!found)
                g_print (BOLD_BEGIN "%s" BOLD_END "\n", _("No reports found"));
 
+       tracker_term_pager_close ();
+
        return EXIT_SUCCESS;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]