FREE THOUGHT · FREE SOFTWARE · FREE WORLD

TMUX

TMUX == GNU Screen x 2.. here is a screenshot from my Arch Linux ThinkPenguin.com laptop back in 2014. That bg image, taken from the International Space Station is now one of my favorite grub boot bg images.

penguin-tmux

tmux usage

archlinux-on-mac

Note: This is primarily an article of my notes taken from reading the tmux source code. I'll add some good practical usage another time perhaps.

usage: %s [-2lquvV] [-c shell-command] [-f file] [-L socket-name] [-S socket-path] [command [flags]]

tmux.conf

Per my usual habit, I downloaded the tmux source code and poured over it for weeks. The purpose of that wasn't abstract, I work to find and build systems that once built will enable and empower my computing for a long time. In this case, for me that meant building a super optimized and understood tmux.conf -- here is the one I am using at the moment. tmux.conf

Tmux Command Aliases

grep -h 'const struct cmd_entry' -A1 cmd-*.c|nobb|grep -v '^const'|grep -v '^\-\-'|trs|nobb| sed 's,^"\([^"]\+\)"\, *"\([^"]\+\)"..*$,\2:
  • \2: \1
  • ,g'|grep -v NULL|sort -g|cut -d':' -f2-
    • attach: attach-session
    • bind: bind-key
    • breakp: break-pane
    • capturep: capture-pane
    • clearhist: clear-history
    • confirm: confirm-before
    • deleteb: delete-buffer
    • detach: detach-client
    • display: display-message
    • displayp: display-panes
    • findw: find-window
    • has: has-session
    • if: if-shell
    • joinp: join-pane
    • killp: kill-pane
    • killw: kill-window
    • last: last-window
    • lastp: last-pane
    • linkw: link-window
    • loadb: load-buffer
    • lock: lock-server
    • lockc: lock-client
    • locks: lock-session
    • ls: list-sessions
    • lsb: list-buffers
    • lsc: list-clients
    • lscm: list-commands
    • lsk: list-keys
    • lsp: list-panes
    • lsw: list-windows
    • movep: move-pane
    • movew: move-window
    • new: new-session
    • neww: new-window
    • next: next-window
    • nextl: next-layout
    • pasteb: paste-buffer
    • pipep: pipe-pane
    • prev: previous-window
    • prevl: previous-layout
    • refresh: refresh-client
    • rename: rename-session
    • renamew: rename-window
    • resizep: resize-pane
    • respawnp: respawn-pane
    • respawnw: respawn-window
    • rotatew: rotate-window
    • run: run-shell
    • saveb: save-buffer
    • selectl: select-layout
    • selectp: select-pane
    • selectw: select-window
    • send: send-keys
    • set: set-option
    • setb: set-buffer
    • setenv: set-environment
    • setw: set-window-option
    • show: show-options
    • showb: show-buffer
    • showenv: show-environment
    • showmsgs: show-messages
    • showw: show-window-options
    • source: source-file
    • splitw: split-window
    • start: start-server
    • suspendc: suspend-client
    • swapp: swap-pane
    • swapw: swap-window
    • switchc: switch-client
    • unbind: unbind-key
    • unlinkw: unlink-window
    • wait: wait-for
    • info: server-info

    Default Templates

    CHOOSE_BUFFER_TEMPLATE
    Default template for choose-buffer.
    "#{line}: #{buffer_size} bytes: #{buffer_sample}"
    CHOOSE_CLIENT_TEMPLATE
    Default template for choose-client.
    "#{client_tty}: #{session_name} [#{client_width}x#{client_height} #{client_termname}]#{?client_utf8, (utf8),}#{?client_readonly, (ro),} (last used #{client_activity_string})"
    CHOOSE_TREE_SESSION_TEMPLATE
    Default templates for choose-tree.
    "#{session_name}: #{session_windows} windows#{?session_grouped, (group ,}#{session_group}#{?session_grouped,),}#{?session_attached, (attached),}"
    CHOOSE_TREE_WINDOW_TEMPLATE
    "#{window_index}: #{window_name}#{window_flags} \"#{pane_title}\""
    DISPLAY_MESSAGE_TEMPLATE
    Default template for display-message.
    "[#{session_name}] #{window_index}:#{window_name}, current pane #{pane_index} - (%H:%M %d-%b-%y)"
    FIND_WINDOW_TEMPLATE
    Default template for find-window.
    "#{window_index}: #{window_name} [#{window_width}x#{window_height}] (#{window_panes} panes) #{window_find_matches}"
    LIST_BUFFERS_TEMPLATE
    Default template for list-buffers.
    "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\""
    LIST_CLIENTS_TEMPLATE
    Default template for list-clients.
    "#{client_tty}: #{session_name} [#{client_width}x#{client_height} #{client_termname}]#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
    LIST_SESSIONS_TEMPLATE
    Default template for list-sessions.
    "#{session_name}: #{session_windows} windows (created #{session_created_string}) [#{session_width}x#{session_height}]#{?session_grouped, (group ,}#{session_group}#{?session_grouped,),}#{?session_attached, (attached),}"
    LIST_WINDOWS_TEMPLATE
    Default templates for list-windows.
    "#{window_index}: #{window_name}#{window_flags} (#{window_panes} panes) [#{window_width}x#{window_height}] [layout #{window_layout}] #{window_id}#{?window_active, (active),}"
    LIST_WINDOWS_WITH_SESSION_TEMPLATE
    "#{session_name}:#{window_index}: #{window_name}#{window_flags} (#{window_panes} panes) [#{window_width}x#{window_height}] "
    NEW_SESSION_TEMPLATE
    "#{session_name}:"
    BREAK_PANE_TEMPLATE
    "#{session_name}:#{window_index}.#{pane_index}"
    NEW_WINDOW_TEMPLATE
    "#{session_name}:#{window_index}.#{pane_index}"
    SPLIT_WINDOW_TEMPLATE
    "#{session_name}:#{window_index}.#{pane_index}"

    tmux main() processing order:

    struct options	 global_options;	/* server options */
    struct options	 global_s_options;	/* session options */
    struct options	 global_w_options;	/* window options */
    struct environ	 global_environ;
    
    1. Parse cmd line options while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1)
    2. Setup global environment for (var = environ; *var != NULL; var++) environ_put(&global_environ, *var);
    3. Set PWD if (getcwd(tmp, sizeof tmp) != NULL) environ_set(&global_environ, "PWD", tmp);
    4. Populate Server Options options_table_populate_tree(server_options_table, &global_options)
    5. Populate Session Options options_table_populate_tree(session_options_table, &global_s_options);
    6. Set default-shell in global session option to the current shell options_set_string(&global_s_options, "default-shell", "%s", getshell());
    7. Populate Window Options options_table_populate_tree(window_options_table, &global_w_options);
    8. Enable UTF-8 if first client is on UTF-8 terminal
      if (flags & CLIENT_UTF8) {
      	options_set_number(&global_s_options, "status-utf8", 1);
      	options_set_number(&global_s_options, "mouse-utf8", 1);
      	options_set_number(&global_w_options, "utf8", 1);
      }
    9. Override keys to vi if VISUAL or EDITOR are set
      if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
      	if (strrchr(s, '/') != NULL) s = strrchr(s, '/') + 1;
      	if (strstr(s, "vi") != NULL) keys = MODEKEY_VI;
      	else keys = MODEKEY_EMACS;
      	options_set_number(&global_s_options, "status-keys", keys);
      	options_set_number(&global_w_options, "mode-keys", keys);
      }
    10. Locate the configuration file.
    11. Get path from environment
      s = getenv("TMUX");
      if (s != NULL && sscanf(s, "%255[^,],%lld,%d", in, &pid, &session) == 3) environ_path = xstrdup(in);
    12. Figure out the socket path and use.
    13. Set process title. #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", __progname, socket_path);
    14. Pass control to the client
      ev_base = osdep_event_init();
      exit(client_main(argc, argv, flags));

    tmux.c

    makesocketpath

    makesocketpath sets the socketpath in this order.

    1. TMUX_TMPDIR
    2. TMPDIR
    char *
    makesocketpath(const char *label)
    {
        char        base[MAXPATHLEN], realbase[MAXPATHLEN], *path, *s;
        struct stat sb;
        u_int       uid;
    
        uid = getuid();
        if ((s = getenv("TMUX_TMPDIR")) != NULL && *s != '\0')
            xsnprintf(base, sizeof base, "%s/", s);
        else if ((s = getenv("TMPDIR")) != NULL && *s != '\0')
            xsnprintf(base, sizeof base, "%s/tmux-%u", s, uid);
        else
            xsnprintf(base, sizeof base, "%s/tmux-%u", _PATH_TMP, uid);
    
        if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
            return (NULL);
    
        if (lstat(base, &sb) != 0)
            return (NULL);
        if (!S_ISDIR(sb.st_mode)) {
            errno = ENOTDIR;
            return (NULL);
        }
        if (sb.st_uid != uid || (!S_ISDIR(sb.st_mode) &&
            sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) {
            errno = EACCES;
            return (NULL);
        }
    
        if (realpath(base, realbase) == NULL)
            strlcpy(realbase, base, sizeof realbase);
    
        xasprintf(&path, "%s/%s", realbase, label);
        return (path);
    }
    

    shell_exec

    __dead void
    shell_exec(const char *shell, const char *shellcmd)
    {
        const char  *shellname, *ptr;
        char        *argv0;
    
        ptr = strrchr(shell, '/');
        if (ptr != NULL && *(ptr + 1) != '\0')
            shellname = ptr + 1;
        else
            shellname = shell;
        if (login_shell)
            xasprintf(&argv0, "-%s", shellname);
        else
            xasprintf(&argv0, "%s", shellname);
        setenv("SHELL", shell, 1);
    
        setblocking(STDIN_FILENO, 1);
        setblocking(STDOUT_FILENO, 1);
        setblocking(STDERR_FILENO, 1);
        closefrom(STDERR_FILENO + 1);
    
        execl(shell, argv0, "-c", shellcmd, (char *) NULL);
        fatal("execl failed");
    }
    

    tmux.h

    extern struct options global_options;
    extern struct options global_s_options;
    extern struct options global_w_options;
    extern struct environ global_environ;
    

    notify.c

    void	notify_enable(void);
    void	notify_disable(void);
    void	notify_input(struct window_pane *, struct evbuffer *);
    void	notify_window_layout_changed(struct window *);
    void	notify_window_unlinked(struct session *, struct window *);
    void	notify_window_linked(struct session *, struct window *);
    void	notify_window_renamed(struct window *);
    void	notify_attached_session_changed(struct client *);
    void	notify_session_renamed(struct session *);
    void	notify_session_created(struct session *);
    void	notify_session_closed(struct session *);
    

    options-table.c

    extern const struct options_table_entry server_options_table[];
    extern const struct options_table_entry session_options_table[];
    extern const struct options_table_entry window_options_table[];
    

    Default Templates

    key codes

    /* Special key codes. */
    #define KEYC_NONE 0xfff
    #define KEYC_BASE 0x1000
    
    /* Key modifier bits. */
    #define KEYC_ESCAPE 0x2000
    #define KEYC_CTRL 0x4000
    #define KEYC_SHIFT 0x8000
    #define KEYC_PREFIX 0x10000
    
    /* Mask to obtain key w/o modifiers. */
    #define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
    #define KEYC_MASK_KEY (~KEYC_MASK_MOD)
    
    /* Other key codes. */
    enum key_code {
    	/* Mouse key. */
    	KEYC_MOUSE = KEYC_BASE,
    
    	/* Backspace key. */
    	KEYC_BSPACE,
    
    	/* Function keys. */
    	KEYC_F1,
    	KEYC_F2,
    	KEYC_F3,
    	KEYC_F4,
    	KEYC_F5,
    	KEYC_F6,
    	KEYC_F7,
    	KEYC_F8,
    	KEYC_F9,
    	KEYC_F10,
    	KEYC_F11,
    	KEYC_F12,
    	KEYC_F13,
    	KEYC_F14,
    	KEYC_F15,
    	KEYC_F16,
    	KEYC_F17,
    	KEYC_F18,
    	KEYC_F19,
    	KEYC_F20,
    	KEYC_IC,
    	KEYC_DC,
    	KEYC_HOME,
    	KEYC_END,
    	KEYC_NPAGE,
    	KEYC_PPAGE,
    	KEYC_BTAB,
    
    	/* Arrow keys. */
    	KEYC_UP,
    	KEYC_DOWN,
    	KEYC_LEFT,
    	KEYC_RIGHT,
    
    	/* Numeric keypad. */
    	KEYC_KP_SLASH,
    	KEYC_KP_STAR,
    	KEYC_KP_MINUS,
    	KEYC_KP_SEVEN,
    	KEYC_KP_EIGHT,
    	KEYC_KP_NINE,
    	KEYC_KP_PLUS,
    	KEYC_KP_FOUR,
    	KEYC_KP_FIVE,
    	KEYC_KP_SIX,
    	KEYC_KP_ONE,
    	KEYC_KP_TWO,
    	KEYC_KP_THREE,
    	KEYC_KP_ENTER,
    	KEYC_KP_ZERO,
    	KEYC_KP_PERIOD,
    
    	KEYC_FOCUS_IN,
    	KEYC_FOCUS_OUT,
    };

    Termcap codes

    enum tty_code_code {
    	TTYC_AX = 0,
    	TTYC_ACSC,	/* acs_chars, ac */
    	TTYC_BEL,	/* bell, bl */
    	TTYC_BLINK,	/* enter_blink_mode, mb */
    	TTYC_BOLD,	/* enter_bold_mode, md */
    	TTYC_CIVIS,	/* cursor_invisible, vi */
    	TTYC_CLEAR,	/* clear_screen, cl */
    	TTYC_CNORM,	/* cursor_normal, ve */
    	TTYC_COLORS,	/* max_colors, Co */
    	TTYC_CR,	/* restore cursor colour, Cr */
    	TTYC_CS,	/* set cursor colour, Cs */
    	TTYC_CSR,	/* change_scroll_region, cs */
    	TTYC_CUB,	/* parm_left_cursor, LE */
    	TTYC_CUB1,	/* cursor_left, le */
    	TTYC_CUD,	/* parm_down_cursor, DO */
    	TTYC_CUD1,	/* cursor_down, do */
    	TTYC_CUF,	/* parm_right_cursor, RI */
    	TTYC_CUF1,	/* cursor_right, nd */
    	TTYC_CUP,	/* cursor_address, cm */
    	TTYC_CUU,	/* parm_up_cursor, UP */
    	TTYC_CUU1,	/* cursor_up, up */
    	TTYC_DCH,	/* parm_dch, DC */
    	TTYC_DCH1,	/* delete_character, dc */
    	TTYC_DIM,	/* enter_dim_mode, mh */
    	TTYC_DL,	/* parm_delete_line, DL */
    	TTYC_DL1,	/* delete_line, dl */
    	TTYC_E3,
    	TTYC_ECH,	/* erase_chars, ec */
    	TTYC_EL,	/* clr_eol, ce */
    	TTYC_EL1,	/* clr_bol, cb */
    	TTYC_ENACS,	/* ena_acs, eA */
    	TTYC_FSL,	/* from_status_line, fsl */
    	TTYC_HOME,	/* cursor_home, ho */
    	TTYC_HPA,	/* column_address, ch */
    	TTYC_ICH,	/* parm_ich, IC */
    	TTYC_ICH1,	/* insert_character, ic */
    	TTYC_IL,	/* parm_insert_line, IL */
    	TTYC_IL1,	/* insert_line, il */
    	TTYC_INVIS,	/* enter_secure_mode, mk */
    	TTYC_IS1,	/* init_1string, i1 */
    	TTYC_IS2,	/* init_2string, i2 */
    	TTYC_IS3,	/* init_3string, i3 */
    	TTYC_KCBT,	/* key_btab, kB */
    	TTYC_KCUB1,	/* key_left, kl */
    	TTYC_KCUD1,	/* key_down, kd */
    	TTYC_KCUF1,	/* key_right, kr */
    	TTYC_KCUU1,	/* key_up, ku */
    	TTYC_KDC2,
    	TTYC_KDC3,
    	TTYC_KDC4,
    	TTYC_KDC5,
    	TTYC_KDC6,
    	TTYC_KDC7,
    	TTYC_KDCH1,	/* key_dc, kD */
    	TTYC_KDN2,
    	TTYC_KDN3,
    	TTYC_KDN4,
    	TTYC_KDN5,
    	TTYC_KDN6,
    	TTYC_KDN7,
    	TTYC_KEND,	/* key_end, ke */
    	TTYC_KEND2,
    	TTYC_KEND3,
    	TTYC_KEND4,
    	TTYC_KEND5,
    	TTYC_KEND6,
    	TTYC_KEND7,
    	TTYC_KF1,	/* key_f1, k1 */
    	TTYC_KF10,	/* key_f10, k; */
    	TTYC_KF11,	/* key_f11, F1 */
    	TTYC_KF12,	/* key_f12, F2 */
    	TTYC_KF13,	/* key_f13, F3 */
    	TTYC_KF14,	/* key_f14, F4 */
    	TTYC_KF15,	/* key_f15, F5 */
    	TTYC_KF16,	/* key_f16, F6 */
    	TTYC_KF17,	/* key_f17, F7 */
    	TTYC_KF18,	/* key_f18, F8 */
    	TTYC_KF19,	/* key_f19, F9 */
    	TTYC_KF2,	/* key_f2, k2 */
    	TTYC_KF20,	/* key_f20, F10 */
    	TTYC_KF3,	/* key_f3, k3 */
    	TTYC_KF4,	/* key_f4, k4 */
    	TTYC_KF5,	/* key_f5, k5 */
    	TTYC_KF6,	/* key_f6, k6 */
    	TTYC_KF7,	/* key_f7, k7 */
    	TTYC_KF8,	/* key_f8, k8 */
    	TTYC_KF9,	/* key_f9, k9 */
    	TTYC_KHOM2,
    	TTYC_KHOM3,
    	TTYC_KHOM4,
    	TTYC_KHOM5,
    	TTYC_KHOM6,
    	TTYC_KHOM7,
    	TTYC_KHOME,	/* key_home, kh */
    	TTYC_KIC2,
    	TTYC_KIC3,
    	TTYC_KIC4,
    	TTYC_KIC5,
    	TTYC_KIC6,
    	TTYC_KIC7,
    	TTYC_KICH1,	/* key_ic, kI */
    	TTYC_KLFT2,
    	TTYC_KLFT3,
    	TTYC_KLFT4,
    	TTYC_KLFT5,
    	TTYC_KLFT6,
    	TTYC_KLFT7,
    	TTYC_KMOUS,	/* key_mouse, Km */
    	TTYC_KNP,	/* key_npage, kN */
    	TTYC_KNXT2,
    	TTYC_KNXT3,
    	TTYC_KNXT4,
    	TTYC_KNXT5,
    	TTYC_KNXT6,
    	TTYC_KNXT7,
    	TTYC_KPP,	/* key_ppage, kP */
    	TTYC_KPRV2,
    	TTYC_KPRV3,
    	TTYC_KPRV4,
    	TTYC_KPRV5,
    	TTYC_KPRV6,
    	TTYC_KPRV7,
    	TTYC_KRIT2,
    	TTYC_KRIT3,
    	TTYC_KRIT4,
    	TTYC_KRIT5,
    	TTYC_KRIT6,
    	TTYC_KRIT7,
    	TTYC_KUP2,
    	TTYC_KUP3,
    	TTYC_KUP4,
    	TTYC_KUP5,
    	TTYC_KUP6,
    	TTYC_KUP7,
    	TTYC_MS,	/* modify xterm(1) selection */
    	TTYC_OP,	/* orig_pair, op */
    	TTYC_REV,	/* enter_reverse_mode, mr */
    	TTYC_RI,	/* scroll_reverse, sr */
    	TTYC_RMACS,	/* exit_alt_charset_mode */
    	TTYC_RMCUP,	/* exit_ca_mode, te */
    	TTYC_RMKX,	/* keypad_local, ke */
    	TTYC_SE,	/* reset cursor style, Se */
    	TTYC_SETAB,	/* set_a_background, AB */
    	TTYC_SETAF,	/* set_a_foreground, AF */
    	TTYC_SGR0,	/* exit_attribute_mode, me */
    	TTYC_SITM,	/* enter_italics_mode, it */
    	TTYC_SMACS,	/* enter_alt_charset_mode, as */
    	TTYC_SMCUP,	/* enter_ca_mode, ti */
    	TTYC_SMKX,	/* keypad_xmit, ks */
    	TTYC_SMSO,	/* enter_standout_mode, so */
    	TTYC_SMUL,	/* enter_underline_mode, us */
    	TTYC_SS,	/* set cursor style, Ss */
    	TTYC_TSL,	/* to_status_line, tsl */
    	TTYC_VPA,	/* row_address, cv */
    	TTYC_XENL,	/* eat_newline_glitch, xn */
    	TTYC_XT,	/* xterm(1)-compatible title, XT */
    };
    #define NTTYCODE (TTYC_XT + 1)
    
    /* Termcap types. */
    enum tty_code_type {
    	TTYCODE_NONE = 0,
    	TTYCODE_STRING,
    	TTYCODE_NUMBER,
    	TTYCODE_FLAG,
    };

    Message codes

    enum msgtype {
    	MSG_VERSION = 12,
    
    	MSG_IDENTIFY_FLAGS = 100,
    	MSG_IDENTIFY_TERM,
    	MSG_IDENTIFY_TTYNAME,
    	MSG_IDENTIFY_CWD,
    	MSG_IDENTIFY_STDIN,
    	MSG_IDENTIFY_ENVIRON,
    	MSG_IDENTIFY_DONE,
    
    	MSG_COMMAND = 200,
    	MSG_DETACH,
    	MSG_DETACHKILL,
    	MSG_EXIT,
    	MSG_EXITED,
    	MSG_EXITING,
    	MSG_LOCK,
    	MSG_READY,
    	MSG_RESIZE,
    	MSG_SHELL,
    	MSG_SHUTDOWN,
    	MSG_STDERR,
    	MSG_STDIN,
    	MSG_STDOUT,
    	MSG_SUSPEND,
    	MSG_UNLOCK,
    	MSG_WAKEUP,
    };

    Mode key commands

    enum mode_key_cmd {
    	MODEKEY_NONE,
    	MODEKEY_OTHER,
    
    	/* Editing keys. */
    	MODEKEYEDIT_BACKSPACE,
    	MODEKEYEDIT_CANCEL,
    	MODEKEYEDIT_COMPLETE,
    	MODEKEYEDIT_CURSORLEFT,
    	MODEKEYEDIT_CURSORRIGHT,
    	MODEKEYEDIT_DELETE,
    	MODEKEYEDIT_DELETELINE,
    	MODEKEYEDIT_DELETETOENDOFLINE,
    	MODEKEYEDIT_DELETEWORD,
    	MODEKEYEDIT_ENDOFLINE,
    	MODEKEYEDIT_ENTER,
    	MODEKEYEDIT_HISTORYDOWN,
    	MODEKEYEDIT_HISTORYUP,
    	MODEKEYEDIT_NEXTSPACE,
    	MODEKEYEDIT_NEXTSPACEEND,
    	MODEKEYEDIT_NEXTWORD,
    	MODEKEYEDIT_NEXTWORDEND,
    	MODEKEYEDIT_PASTE,
    	MODEKEYEDIT_PREVIOUSSPACE,
    	MODEKEYEDIT_PREVIOUSWORD,
    	MODEKEYEDIT_STARTOFLINE,
    	MODEKEYEDIT_SWITCHMODE,
    	MODEKEYEDIT_SWITCHMODEAPPEND,
    	MODEKEYEDIT_SWITCHMODEAPPENDLINE,
    	MODEKEYEDIT_SWITCHMODEBEGINLINE,
    	MODEKEYEDIT_SWITCHMODECHANGELINE,
    	MODEKEYEDIT_SWITCHMODESUBSTITUTE,
    	MODEKEYEDIT_SWITCHMODESUBSTITUTELINE,
    	MODEKEYEDIT_TRANSPOSECHARS,
    
    	/* Menu (choice) keys. */
    	MODEKEYCHOICE_BACKSPACE,
    	MODEKEYCHOICE_BOTTOMLINE,
    	MODEKEYCHOICE_CANCEL,
    	MODEKEYCHOICE_CHOOSE,
    	MODEKEYCHOICE_DOWN,
    	MODEKEYCHOICE_ENDOFLIST,
    	MODEKEYCHOICE_PAGEDOWN,
    	MODEKEYCHOICE_PAGEUP,
    	MODEKEYCHOICE_SCROLLDOWN,
    	MODEKEYCHOICE_SCROLLUP,
    	MODEKEYCHOICE_STARTNUMBERPREFIX,
    	MODEKEYCHOICE_STARTOFLIST,
    	MODEKEYCHOICE_TOPLINE,
    	MODEKEYCHOICE_TREE_COLLAPSE,
    	MODEKEYCHOICE_TREE_COLLAPSE_ALL,
    	MODEKEYCHOICE_TREE_EXPAND,
    	MODEKEYCHOICE_TREE_EXPAND_ALL,
    	MODEKEYCHOICE_TREE_TOGGLE,
    	MODEKEYCHOICE_UP,
    
    	/* Copy keys. */
    	MODEKEYCOPY_APPENDSELECTION,
    	MODEKEYCOPY_BACKTOINDENTATION,
    	MODEKEYCOPY_BOTTOMLINE,
    	MODEKEYCOPY_CANCEL,
    	MODEKEYCOPY_CLEARSELECTION,
    	MODEKEYCOPY_COPYPIPE,
    	MODEKEYCOPY_COPYLINE,
    	MODEKEYCOPY_COPYENDOFLINE,
    	MODEKEYCOPY_COPYSELECTION,
    	MODEKEYCOPY_DOWN,
    	MODEKEYCOPY_ENDOFLINE,
    	MODEKEYCOPY_GOTOLINE,
    	MODEKEYCOPY_HALFPAGEDOWN,
    	MODEKEYCOPY_HALFPAGEUP,
    	MODEKEYCOPY_HISTORYBOTTOM,
    	MODEKEYCOPY_HISTORYTOP,
    	MODEKEYCOPY_JUMP,
    	MODEKEYCOPY_JUMPAGAIN,
    	MODEKEYCOPY_JUMPREVERSE,
    	MODEKEYCOPY_JUMPBACK,
    	MODEKEYCOPY_JUMPTO,
    	MODEKEYCOPY_JUMPTOBACK,
    	MODEKEYCOPY_LEFT,
    	MODEKEYCOPY_MIDDLELINE,
    	MODEKEYCOPY_NEXTPAGE,
    	MODEKEYCOPY_NEXTSPACE,
    	MODEKEYCOPY_NEXTSPACEEND,
    	MODEKEYCOPY_NEXTWORD,
    	MODEKEYCOPY_NEXTWORDEND,
    	MODEKEYCOPY_OTHEREND,
    	MODEKEYCOPY_PREVIOUSPAGE,
    	MODEKEYCOPY_PREVIOUSSPACE,
    	MODEKEYCOPY_PREVIOUSWORD,
    	MODEKEYCOPY_RECTANGLETOGGLE,
    	MODEKEYCOPY_RIGHT,
    	MODEKEYCOPY_SCROLLDOWN,
    	MODEKEYCOPY_SCROLLUP,
    	MODEKEYCOPY_SEARCHAGAIN,
    	MODEKEYCOPY_SEARCHDOWN,
    	MODEKEYCOPY_SEARCHREVERSE,
    	MODEKEYCOPY_SEARCHUP,
    	MODEKEYCOPY_SELECTLINE,
    	MODEKEYCOPY_STARTNUMBERPREFIX,
    	MODEKEYCOPY_STARTOFLINE,
    	MODEKEYCOPY_STARTSELECTION,
    	MODEKEYCOPY_TOPLINE,
    	MODEKEYCOPY_UP,
    };

    Modes

    #define MODE_CURSOR 0x1
    #define MODE_INSERT 0x2
    #define MODE_KCURSOR 0x4
    #define MODE_KKEYPAD 0x8	/* set = application, clear = number */
    #define MODE_WRAP 0x10		/* whether lines wrap */
    #define MODE_MOUSE_STANDARD 0x20
    #define MODE_MOUSE_BUTTON 0x40
    #define MODE_MOUSE_ANY 0x80
    #define MODE_MOUSE_UTF8 0x100
    #define MODE_MOUSE_SGR 0x200
    #define MODE_BRACKETPASTE 0x400
    #define MODE_FOCUSON 0x800
    
    #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)

    Grid attributes

    #define GRID_ATTR_BRIGHT 0x1
    #define GRID_ATTR_DIM 0x2
    #define GRID_ATTR_UNDERSCORE 0x4
    #define GRID_ATTR_BLINK 0x8
    #define GRID_ATTR_REVERSE 0x10
    #define GRID_ATTR_HIDDEN 0x20
    #define GRID_ATTR_ITALICS 0x40
    #define GRID_ATTR_CHARSET 0x80	/* alternative character set */

    Layout direction

    enum layout_type {
    	LAYOUT_LEFTRIGHT,
    	LAYOUT_TOPBOTTOM,
    	LAYOUT_WINDOWPANE
    };

    Mouse

    /* Mouse button masks. */
    #define MOUSE_MASK_BUTTONS 3
    #define MOUSE_MASK_SHIFT 4
    #define MOUSE_MASK_META 8
    #define MOUSE_MASK_CTRL 16
    #define MOUSE_MASK_DRAG 32
    #define MOUSE_MASK_WHEEL 64
    
    /* Mouse wheel states. */
    #define MOUSE_WHEEL_UP 0
    #define MOUSE_WHEEL_DOWN 1
    
    /* Mouse event bits. */
    #define MOUSE_EVENT_DOWN 0x1
    #define MOUSE_EVENT_DRAG 0x2
    #define MOUSE_EVENT_UP 0x4
    #define MOUSE_EVENT_CLICK 0x8
    #define MOUSE_EVENT_WHEEL 0x10
    
    /* Mouse flag bits. */
    #define MOUSE_RESIZE_PANE 0x1
    

    Option table entries

    /*
     * Option table entries. The option table is the user-visible part of the
     * option, as opposed to the internal options (struct option) which are just
     * number or string.
     */
    enum options_table_type {
        OPTIONS_TABLE_STRING,
        OPTIONS_TABLE_NUMBER,
        OPTIONS_TABLE_KEY,
        OPTIONS_TABLE_COLOUR,
        OPTIONS_TABLE_ATTRIBUTES,
        OPTIONS_TABLE_FLAG,
        OPTIONS_TABLE_CHOICE,
        OPTIONS_TABLE_STYLE
    };
    

    Common command usages

    /* Common command usages. */
    #define CMD_TARGET_PANE_USAGE "[-t target-pane]"
    #define CMD_TARGET_WINDOW_USAGE "[-t target-window]"
    #define CMD_TARGET_SESSION_USAGE "[-t target-session]"
    #define CMD_TARGET_CLIENT_USAGE "[-t target-client]"
    #define CMD_SRCDST_PANE_USAGE "[-s src-pane] [-t dst-pane]"
    #define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]"
    #define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]"
    #define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
    #define CMD_BUFFER_USAGE "[-b buffer-index]"
    

    colour.c

    Colour to string conversion functions. Bit 8 of the colour means it is one of the 256 colour palette.

    /* An RGB colour. */
    struct colour_rgb {
        u_char  r;
        u_char  g;
        u_char  b;
    };
    
    /* 256 colour RGB table, generated on first use. */
    struct colour_rgb *colour_rgb_256;
    
    void    colour_rgb_generate256(void);
    u_int   colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
    int colour_rgb_find(struct colour_rgb *);
    

    Generate 256 colour RGB table.

    void
    colour_rgb_generate256(void)
    {
        struct colour_rgb   *rgb;
        u_int            i, r, g, b;
    
        /*
         * Allocate the table. The first 16 colours are often changed by users
         * and terminals so don't include them.
         */
        colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256);
    
        /* Add the colours first. */
        r = g = b = 0;
        for (i = 240; i > 24; i--) {
            rgb = &colour_rgb_256[240 - i];
    
            if (r != 0)
                rgb->r = (r * 40) + 55;
            if (g != 0)
                rgb->g = (g * 40) + 55;
            if (b != 0)
                rgb->b = (b * 40) + 55;
    
            b++;
            if (b > 5) {
                b = 0;
                g++;
            }
            if (g > 5) {
                g = 0;
                r++;
            }
        }
    
        /* Then add the greys. */
        for (i = 24; i > 0; i--) {
            rgb = &colour_rgb_256[240 - i];
    
            rgb->r = 8 + (24 - i) * 10;
            rgb->g = 8 + (24 - i) * 10;
            rgb->b = 8 + (24 - i) * 10;
        }
    }

    Get colour RGB distance.

    u_int
    colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
    {
        int r, g, b;
    
        r = rgb1->r - rgb2->r;
        g = rgb1->g - rgb2->g;
        b = rgb1->b - rgb2->b;
        return (r * r + g * g + b * b);
    }

    Work out the nearest colour from the 256 colour set.

    int
    colour_rgb_find(struct colour_rgb *rgb)
    {
        u_int   distance, lowest, colour, i;
    
        if (colour_rgb_256 == NULL)
            colour_rgb_generate256();
    
        colour = 16;
        lowest = UINT_MAX;
        for (i = 0; i < 240; i++) {
            distance = colour_rgb_distance(&colour_rgb_256[i], rgb);
            if (distance < lowest) {
                lowest = distance;
                colour = 16 + i;
            }
        }
        return (colour);
    }

    Convert colour to a string.

    const char *
    colour_tostring(int c)
    {
        static char s[32];
    
        if (c & 0x100) {
            xsnprintf(s, sizeof s, "colour%u", c & ~0x100);
            return (s);
        }
    
        switch (c) {
        case 0:
            return ("black");
        case 1:
            return ("red");
        case 2:
            return ("green");
        case 3:
            return ("yellow");
        case 4:
            return ("blue");
        case 5:
            return ("magenta");
        case 6:
            return ("cyan");
        case 7:
            return ("white");
        case 8:
            return ("default");
        case 90:
            return ("brightblack");
        case 91:
            return ("brightred");
        case 92:
            return ("brightgreen");
        case 93:
            return ("brightyellow");
        case 94:
            return ("brightblue");
        case 95:
            return ("brightmagenta");
        case 96:
            return ("brightcyan");
        case 97:
            return ("brightwhite");
        }
        return (NULL);
    }

    Convert colour from string.

    int
    colour_fromstring(const char *s)
    {
        const char      *errstr;
        const char      *cp;
        struct colour_rgb    rgb;
        int          n;
    
        if (*s == '#' && strlen(s) == 7) {
            for (cp = s + 1; isxdigit((u_char) *cp); cp++)
                ;
            if (*cp != '\0')
                return (-1);
            n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b);
            if (n != 3)
                return (-1);
            return (colour_rgb_find(&rgb) | 0x100);
        }
    
        if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
            n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr);
            if (errstr != NULL)
                return (-1);
            return (n | 0x100);
        }
    
        if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0'))
            return (0);
        if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0'))
            return (1);
        if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0'))
            return (2);
        if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0'))
            return (3);
        if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0'))
            return (4);
        if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0'))
            return (5);
        if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0'))
            return (6);
        if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0'))
            return (7);
        if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0'))
            return (8);
        if (strcasecmp(s, "brightblack") == 0 ||
            (s[0] == '9' && s[1] == '0' && s[1] == '\0'))
            return (90);
        if (strcasecmp(s, "brightred") == 0 ||
            (s[0] == '9' && s[1] == '1' && s[1] == '\0'))
            return (91);
        if (strcasecmp(s, "brightgreen") == 0 ||
            (s[0] == '9' && s[1] == '2' && s[1] == '\0'))
            return (92);
        if (strcasecmp(s, "brightyellow") == 0 ||
            (s[0] == '9' && s[1] == '3' && s[1] == '\0'))
            return (93);
        if (strcasecmp(s, "brightblue") == 0 ||
            (s[0] == '9' && s[1] == '4' && s[1] == '\0'))
            return (94);
        if (strcasecmp(s, "brightmagenta") == 0 ||
            (s[0] == '9' && s[1] == '5' && s[1] == '\0'))
            return (95);
        if (strcasecmp(s, "brightcyan") == 0 ||
            (s[0] == '9' && s[1] == '6' && s[1] == '\0'))
            return (96);
        if (strcasecmp(s, "brightwhite") == 0 ||
            (s[0] == '9' && s[1] == '7' && s[1] == '\0'))
            return (97);
        return (-1);
    }
    

    Convert 256 colour palette to 16.

    u_char
    colour_256to16(u_char c)
    {
        static const u_char table[256] = {
             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
             0,  4,  4,  4, 12, 12,  2,  6,  4,  4, 12, 12,  2,  2,  6,  4,
            12, 12,  2,  2,  2,  6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
            10, 10, 10, 14,  1,  5,  4,  4, 12, 12,  3,  8,  4,  4, 12, 12,
             2,  2,  6,  4, 12, 12,  2,  2,  2,  6, 12, 12, 10, 10, 10, 10,
            14, 12, 10, 10, 10, 10, 10, 14,  1,  1,  5,  4, 12, 12,  1,  1,
             5,  4, 12, 12,  3,  3,  8,  4, 12, 12,  2,  2,  2,  6, 12, 12,
            10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,  1,  1,  1,  5,
            12, 12,  1,  1,  1,  5, 12, 12,  1,  1,  1,  5, 12, 12,  3,  3,
             3,  7, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,
             9,  9,  9,  9, 13, 12,  9,  9,  9,  9, 13, 12,  9,  9,  9,  9,
            13, 12,  9,  9,  9,  9, 13, 12, 11, 11, 11, 11,  7, 12, 10, 10,
            10, 10, 10, 14,  9,  9,  9,  9,  9, 13,  9,  9,  9,  9,  9, 13,
             9,  9,  9,  9,  9, 13,  9,  9,  9,  9,  9, 13,  9,  9,  9,  9,
             9, 13, 11, 11, 11, 11, 11, 15,  0,  0,  0,  0,  0,  0,  8,  8,
             8,  8,  8,  8,  7,  7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15
        };
    
        return (table[c]);
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    More Reading

    1. TMUX FAQ - Trunk
    2. TMUX Examples
    3. https://wiki.archlinux.org/index.php/Tmux
    4. http://mutelight.org/articles/practical-tmux
    5. Terminal ZEN

    JWR

    1. Copy and Paste
    2. tmux multiplexer
    3. tmux sessions

    tmux.conf examples

    1. jasonwryan tmux.conf

    URXVT

    1. http://linux.die.net/man/7/urxvt

    Hacking Linux linux.bash Screen shell tmux

     

     

    Comments