Script: tmux_env.py

Update WeeChat environment from tmux.
Author: agriffis — Version: 3.1 — License: GPL-3.0-or-later
For WeeChat ≥ 0.3.0.
Tags: tmux, py3
Added: 2013-10-22 — Updated: 2021-03-06

Download GitHub Repository

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
tmux_env.py -- update weechat environment from tmux

Copyright 2013 Aron Griffis <agriffis@n01se.net>
Released under the terms of the GNU General Public License v3

Description:

    This script propagates environment updates from tmux into the weechat
    process, including the script interpreters.  This allows the process
    environment to follow the tmux client, such as the X DISPLAY variable,
    and the DBUS_SESSION_BUS_ADDRESS used for desktop notifications.

    See https://github.com/agriffis/weechat-tmux-env for full usage
    instructions.

History:

    2013-09-30 Aron Griffis <agriffis@n01se.net>
      version 1: initial release

    2014-02-03 Aron Griffis <agriffis@n01se.net>
      version 2: python 2.6 compatible subprocess.check_output()

    2020-01-03 dobbymoodge <john.w.lamb [at] gmail . com> ( https://github.com/dobbymoodge/ )
      version 3: python 3.x compatibility

    2020-10-30 Friedrich Delgado <taupan [at] gmail . com>
      version 3.1: fix python 3.6 compatibility and remove python 2 support
"""

from __future__ import absolute_import, unicode_literals

import weechat as w

import fnmatch
import os
import subprocess

SCRIPT_NAME = "tmux_env"
SCRIPT_AUTHOR = "Aron Griffis <agriffis@n01se.net>"
SCRIPT_VERSION = "3.1"
SCRIPT_LICENSE = "GPL3"
SCRIPT_DESC = "Update weechat environment from tmux"

settings = {
    'interval': '30',  # How often in seconds to check for updates

    # For include/exclude, the bare variable name only refers to
    # environment updates, not removals. For removals, include the variable
    # name prefixed by a minus sign. For example, to add/remove exclusively
    # the DISPLAY variable, include="DISPLAY,-DISPLAY"
    #
    # Globs are also accepted, so you can ignore all variable removals with
    # exclude="-*"

    'include': '*,-*',  # Env vars to include, default all
    'exclude': '',      # Env vars to exclude, default all
    }

TIMER = None


def set_timer():
    """Update timer hook with new interval"""

    global TIMER
    if TIMER:
        w.unhook(TIMER)
    TIMER = w.hook_timer(int(w.config_get_plugin('interval')) * 1000,
                         0, 0, 'timer_cb', '')


def config_cb(data, option, value):
    """Reset timer when interval option is updated"""

    if option.endswith('.interval'):
        set_timer()
    return w.WEECHAT_RC_OK


def timer_cb(buffer, args):
    """Check if tmux is attached, update environment"""

    attached = os.access(SOCK, os.X_OK)  # X bit indicates attached
    if attached:
        update_environment()
    return w.WEECHAT_RC_OK


def update_environment():
    """Updates environment from tmux showenv"""

    env = subprocess.check_output(['tmux', 'showenv']).decode()
    for line in env.splitlines():
        name = line.split('=', 1)[0]
        if check_include(name) and not check_exclude(name):
            if name.startswith('-'):
                remove_env(name[1:])
            else:
                add_env(name, line.split('=', 1)[1])


def check_include(name):
    globs = comma_split_config('include')
    return check_match(name, globs)


def check_exclude(name):
    globs = comma_split_config('exclude')
    return check_match(name, globs)


def check_match(name, globs):
    for g in globs:
        if fnmatch.fnmatch(name, g):
            return True


def comma_split_config(name):
    config = w.config_get_plugin(name)
    return filter(None, (s.strip() for s in config.split(',')))


def add_env(name, value):
    old = os.environ.get(name)
    if old != value:
        w.prnt("", "%s: add %s=%r (was %r)" % (SCRIPT_NAME, name, value, old))
        os.environ[name] = value


def remove_env(name):
    old = os.environ.get(name)
    if old is not None:
        w.prnt("", "%s: remove %s (was %r)" % (SCRIPT_NAME, name, old))
        del os.environ[name]


if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
              SCRIPT_DESC, '', ''):
    for option, default_value in settings.items():
        if not w.config_is_set_plugin(option):
            w.config_set_plugin(option, default_value)

    global SOCK
    SOCK = None

    if 'TMUX' in os.environ:
        # We are running under tmux
        socket_data = os.environ['TMUX']
        SOCK = socket_data.rsplit(',', 2)[0]

    if SOCK:
        w.hook_config("plugins.var.python.{}.*".format(SCRIPT_NAME), "config_cb", "")
        set_timer()