[vte/wip/fedora-0-64: 10/10] Support tracking the active container inside the terminal




commit 2928a4fe80f7de085743697add509c17306b0c56
Author: Debarshi Ray <debarshir gnome org>
Date:   Mon Mar 22 19:02:31 2021 +0100

    Support tracking the active container inside the terminal
    
    Add sequences
    
      OSC 777 ; container ; push ; NAME ; RUNTIME ; UID BEL
      OSC 777 ; container ; push ; NAME ; RUNTIME ; UID ST
      OSC 777 ; container ; pop ; NAME ; RUNTIME ; UID BEL
      OSC 777 ; container ; pop ; NAME ; RUNTIME ; UID ST
    
      OSC 777 ; container ; push ; NAME ; RUNTIME BEL
      OSC 777 ; container ; push ; NAME ; RUNTIME ST
      OSC 777 ; container ; pop ; NAME ; RUNTIME BEL
      OSC 777 ; container ; pop ; NAME ; RUNTIME ST
    
    that let container tools notify the terminal emulator when entering and
    leaving a container environment. The RUNTIME argument namespaces the
    NAME and identifies the container tooling being used. eg., docker,
    flatpak, podman, toolbox, etc.. The UID argument is the real UID of the
    container tools. Only those containers that are used with the same real
    UID as the VTE process are tracked.
    
    The OSC 777 escape sequence is taken from Enlightenment's Terminology:
    https://phab.enlightenment.org/T1765
    
    It's a VTE-specific extension until a standard escape sequence is
    agreed upon across multiple different terminal emulators [1].
    
    [1] https://gitlab.freedesktop.org/terminal-wg/specifications/issues/17

 src/vte.cc            |  8 +++++
 src/vte/vteterminal.h |  4 +++
 src/vtegtk.cc         | 77 +++++++++++++++++++++++++++++++++++++++++++++
 src/vtegtk.hh         |  2 ++
 src/vteinternal.hh    | 16 ++++++++++
 src/vteseq.cc         | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 193 insertions(+)
---
diff --git a/src/vte.cc b/src/vte.cc
index 90488beb..b7f48fcd 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -10176,6 +10176,14 @@ Terminal::emit_pending_signals()
                 g_signal_emit(freezer.get(), signals[SIGNAL_SHELL_PRECMD], 0);
         }
 
+       if (m_pending_changes & vte::to_integral(PendingChanges::CONTAINERS)) {
+                _vte_debug_print(VTE_DEBUG_SIGNALS,
+                                 "Notifying `current-container-name' and `current-container-runtime'.\n");
+
+                g_object_notify_by_pspec(freezer.get(), pspecs[PROP_CURRENT_CONTAINER_NAME]);
+                g_object_notify_by_pspec(freezer.get(), pspecs[PROP_CURRENT_CONTAINER_RUNTIME]);
+        }
+
         m_pending_changes = 0;
 
        /* Flush any pending "inserted" signals. */
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 0b77566a..540fd25a 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -488,6 +488,10 @@ glong vte_terminal_get_column_count(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VT
 _VTE_PUBLIC
 const char *vte_terminal_get_window_title(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
 _VTE_PUBLIC
+const char *vte_terminal_get_current_container_name(VteTerminal *terminal) _VTE_CXX_NOEXCEPT 
_VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
+const char *vte_terminal_get_current_container_runtime(VteTerminal *terminal) _VTE_CXX_NOEXCEPT 
_VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
 const char *vte_terminal_get_current_directory_uri(VteTerminal *terminal) _VTE_CXX_NOEXCEPT 
_VTE_GNUC_NONNULL(1);
 _VTE_PUBLIC
 const char *vte_terminal_get_current_file_uri(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1);
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 4b71437d..1446f3c7 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -707,6 +707,12 @@ try
                 case PROP_CURSOR_BLINK_MODE:
                         g_value_set_enum (value, vte_terminal_get_cursor_blink_mode (terminal));
                         break;
+                case PROP_CURRENT_CONTAINER_NAME:
+                        g_value_set_string (value, vte_terminal_get_current_container_name (terminal));
+                        break;
+                case PROP_CURRENT_CONTAINER_RUNTIME:
+                        g_value_set_string (value, vte_terminal_get_current_container_runtime (terminal));
+                        break;
                 case PROP_CURRENT_DIRECTORY_URI:
                         g_value_set_string (value, vte_terminal_get_current_directory_uri (terminal));
                         break;
@@ -2099,6 +2105,27 @@ vte_terminal_class_init(VteTerminalClass *klass)
                                      NULL,
                                      (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY));
 
+        /**
+         * VteTerminal:current-container-name:
+         *
+         * The name of the current container, or %NULL if unset.
+         */
+        pspecs[PROP_CURRENT_CONTAINER_NAME] =
+                g_param_spec_string ("current-container-name", NULL, NULL,
+                                     NULL,
+                                     (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY));
+
+        /**
+         * VteTerminal:current-container-runtime:
+         *
+         * The name of the runtime toolset used to set up the current
+         * container, or %NULL if unset.
+         */
+        pspecs[PROP_CURRENT_CONTAINER_RUNTIME] =
+                g_param_spec_string ("current-container-runtime", NULL, NULL,
+                                     NULL,
+                                     (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY));
+
         /**
          * VteTerminal:current-directory-uri:
          *
@@ -4574,6 +4601,56 @@ catch (...)
         return -1;
 }
 
+/**
+ * vte_terminal_get_current_container_name:
+ * @terminal: a #VteTerminal
+ *
+ * Returns: (nullable) (transfer none): the name of the current
+ *   container, or %NULL
+ */
+const char *
+vte_terminal_get_current_container_name(VteTerminal *terminal) noexcept
+try
+{
+        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+        auto impl = IMPL(terminal);
+        if (impl->m_containers.empty())
+                return NULL;
+
+        const VteContainer &container = impl->m_containers.top();
+        return container.m_name.c_str();
+}
+catch (...)
+{
+        vte::log_exception();
+        return NULL;
+}
+
+/**
+ * vte_terminal_get_current_container_runtime:
+ * @terminal: a #VteTerminal
+ *
+ * Returns: (nullable) (transfer none): the name of the runtime
+ *   toolset used to set up the current container, or %NULL
+ */
+const char *
+vte_terminal_get_current_container_runtime(VteTerminal *terminal) noexcept
+try
+{
+        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+        auto impl = IMPL(terminal);
+        if (impl->m_containers.empty())
+                return NULL;
+
+        const VteContainer &container = impl->m_containers.top();
+        return container.m_runtime.c_str();
+}
+catch (...)
+{
+        vte::log_exception();
+        return NULL;
+}
+
 /**
  * vte_terminal_get_current_directory_uri:
  * @terminal: a #VteTerminal
diff --git a/src/vtegtk.hh b/src/vtegtk.hh
index 93a6dde3..65196143 100644
--- a/src/vtegtk.hh
+++ b/src/vtegtk.hh
@@ -76,6 +76,8 @@ enum {
         PROP_CJK_AMBIGUOUS_WIDTH,
         PROP_CURSOR_BLINK_MODE,
         PROP_CURSOR_SHAPE,
+        PROP_CURRENT_CONTAINER_NAME,
+        PROP_CURRENT_CONTAINER_RUNTIME,
         PROP_CURRENT_DIRECTORY_URI,
         PROP_CURRENT_FILE_URI,
         PROP_DELETE_BINDING,
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 25253c0a..570c70b0 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -59,6 +59,7 @@
 #include <list>
 #include <queue>
 #include <optional>
+#include <stack>
 #include <string>
 #include <variant>
 #include <vector>
@@ -97,6 +98,18 @@ typedef enum _VteCharacterReplacement {
         VTE_CHARACTER_REPLACEMENT_LINE_DRAWING
 } VteCharacterReplacement;
 
+struct VteContainer {
+public:
+        VteContainer(const std::string &name, const std::string &runtime) :
+                m_name{name},
+                m_runtime{runtime}
+        {
+        }
+
+        std::string m_name;
+        std::string m_runtime;
+};
+
 typedef struct _VtePaletteColor {
        struct {
                vte::color::rgb color;
@@ -622,6 +635,8 @@ public:
         gboolean m_cursor_moved_pending;
         gboolean m_contents_changed_pending;
 
+        std::stack<VteContainer> m_containers;
+
         /* desktop notification */
         std::string m_notification_summary;
         std::string m_notification_body;
@@ -642,6 +657,7 @@ public:
                 NOTIFICATION = 1u << 3,
                 SHELL_PREEXEC = 1u << 4,
                 SHELL_PRECMD = 1u << 5,
+                CONTAINERS = 1u << 6,
         };
         unsigned m_pending_changes{0};
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 10b494bd..2a2ba4b4 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -19,10 +19,14 @@
 
 #include "config.h"
 
+#include <string>
+
 #include <search.h>
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
 #ifdef HAVE_SYS_SYSLIMITS_H
 #include <sys/syslimits.h>
 #endif
@@ -1385,6 +1389,88 @@ Terminal::handle_urxvt_extension(vte::parser::Sequence const& seq,
         if (token == endtoken)
                 return;
 
+        if (*token == "container") {
+                ++token;
+
+                if (token == endtoken)
+                        return;
+
+                const std::string sub_command = *token;
+                ++token;
+
+                if (sub_command == "pop") {
+                        if (token == endtoken)
+                                return;
+
+                        ++token;
+
+                        if (token == endtoken)
+                                return;
+
+                        ++token;
+
+                        if (token == endtoken) {
+                                if (!m_containers.empty()) {
+                                        m_containers.pop();
+                                        m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                }
+
+                                return;
+                        }
+
+                        const std::string uid_token = *token;
+                        ++token;
+
+                        const uid_t uid = getuid();
+                        const std::string uid_str = std::to_string(uid);
+
+                        if (uid_token == uid_str) {
+                                if (!m_containers.empty()) {
+                                        m_containers.pop();
+                                        m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                }
+
+                                return;
+                        }
+
+                        return;
+                } else if (sub_command == "push") {
+                        if (token == endtoken)
+                                return;
+
+                        const std::string name = *token;
+                        ++token;
+
+                        if (token == endtoken)
+                                return;
+
+                        const std::string runtime = *token;
+                        ++token;
+
+                        if (token == endtoken) {
+                                m_containers.emplace(name, runtime);
+                                m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                return;
+                        }
+
+                        const std::string uid_token = *token;
+                        ++token;
+
+                        const uid_t uid = getuid();
+                        const std::string uid_str = std::to_string(uid);
+
+                        if (uid_token == uid_str) {
+                                m_containers.emplace(name, runtime);
+                                m_pending_changes |= vte::to_integral(PendingChanges::CONTAINERS);
+                                return;
+                        }
+
+                        return;
+                }
+
+                return;
+        }
+
         if (*token == "notify") {
                 ++token;
 


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