Skip to content

Instantly share code, notes, and snippets.

@codemedic
Last active July 30, 2024 17:13
Show Gist options
  • Save codemedic/fac3684bde0a4f7161e60deea9e0a887 to your computer and use it in GitHub Desktop.
Save codemedic/fac3684bde0a4f7161e60deea9e0a887 to your computer and use it in GitHub Desktop.
tmux styles for wezterm

Lua module for wezterm to convert tmux stylised text into Lua tables compatible with wezterm.format().

See wezterm/wezterm#5848 for details.

In addition to the tmux styles, it also supports wezterm.nerdfonts, allowing the use of any symbol name supported by wezterm.

Gitmux is an example of tmux utility that can be used with wezterm. See gitmux.yml for example config.

tmux:
# The symbols section defines the symbols printed before specific elements
# of Git status displayed in tmux status string.
symbols:
# current branch name.
branch: "#[nf=dev_git_branch] "
# Git SHA1 hash (in 'detached' state).
hashprefix: ":"
# 'ahead count' when local and remote branch diverged.
ahead: "#[nf=md_arrow_up_bold] "
# 'behind count' when local and remote branch diverged.
behind: "#[nf=md_arrow_down_bold] "
# count of files in the staging area.
staged: "#[nf=oct_file_added] "
# count of files in conflicts.
conflict: "#[nf=cod_error] "
# count of modified files.
modified: "#[nf=oct_file_diff] "
# count of untracked files.
untracked: "#[nf=oct_diff_ignored] "
# count of stash entries.
stashed: "#[nf=md_snowflake] "
# count of inserted lines (stats section).
insertions: "+"
# count of deleted lines (stats section).
deletions: "-"
# Shown when the working tree is clean.
clean: "#[nf=fa_check] "
# Styles are tmux format strings used to specify text colors and attributes
# of Git status elements. See the STYLES section of tmux man page.
# https://man7.org/linux/man-pages/man1/tmux.1.html#STYLES.
styles:
# Clear previous style.
clear: "#[none]"
# Special tree state strings such as [rebase], [merge], etc.
state: "#[fg=red,bold]"
# Local branch name
branch: "#[fg=#7B6823]"
# Remote branch name
remote: "#[fg=cyan]"
# 'divergence' counts
divergence: "#[fg=yellow]"
# 'staged' count
staged: "#[fg=green,bold]"
# 'conflicts' count
conflict: "#[fg=red,bold]"
# 'modified' count
modified: "#[fg=red,bold]"
# 'untracked' count
untracked: "#[fg=magenta,bold]"
# 'stash' count
stashed: "#[fg=cyan,bold]"
# 'insertions' count
insertions: "#[fg=green]"
# 'deletions' count
deletions: "#[fg=red]"
# 'clean' symbol
clean: "#[fg=green,bold]"
# The layout section defines what components gitmux shows and the order in
# which they appear on tmux status bar.
#
# Allowed components:
# - branch: local branch name. Examples: `⎇ main`, `⎇ :345e7a0` or `[rebase]`
# - remote-branch: remote branch name, for example: `origin/main`.
# - divergence: divergence between local and remote branch, if any. Example: `↓·2↑·1`
# - remote: alias for `remote-branch` followed by `divergence`, for example: `origin/main ↓·2↑·1`
# - flags: symbols representing the working tree state, for example `✚ 1 ⚑ 1 … 2`
# - stats: insertions/deletions (lines), for example`Σ56 Δ21`
# - some string `foo`: any other character of string is directly shown, for example `foo` or `|`
layout: [branch, divergence, " ", flags, stats]
# Additional configuration options.
options:
# Maximum displayed length for local and remote branch names.
branch_max_len: 50
# Trim left, right or from the center of the branch (`right`, `left` or `center`).
branch_trim: center
# Character indicating whether and where a branch was truncated.
ellipsis: …
# Hides the clean flag
hide_clean: false
# Swaps order of behind & ahead upstream counts - "↓·1↑·1" -> "↑·1↓·1".
swap_divergence: false
# Add a space between behind & ahead upstream counts.
divergence_space: false
function string:split(pat)
pat = pat or '%s+'
local st, g = 1, self:gmatch('()(' .. pat .. ')')
local function getter(segs, seps, sep, cap1, ...)
st = sep and seps + #sep
return self:sub(segs, (seps or 0) - 1), cap1 or sep, ...
end
return function()
if st then
return getter(st, g())
end
end
end
local function Text(text)
return { Text = text }
end
local function make_single_table(name, value)
local ret = {}
ret[name] = value
return ret
end
local function Attribute(name, value)
return make_single_table('Attribute', make_single_table(name, value))
end
local function Underline(type)
return Attribute('Underline', type)
end
local function Intensity(level)
return Attribute('Intensity', level)
end
local function Italic(on)
return Attribute('Italic', on)
end
local function ForegroundColour(colour)
return make_single_table('Foreground', make_single_table('Color', colour))
end
local function BackgroundColour(colour)
return make_single_table('Background', make_single_table('Color', colour))
end
local function NerdFont(text)
local wezterm = require 'wezterm'
local ok, nf = pcall(function()
return wezterm.nerdfonts[text]
end)
if ok then
return Text(nf)
else
wezterm.log_info(wezterm.to_string(nf))
end
return nil
end
local function MakeFormat(f)
f = f:sub(3, -2)
local ret = {}
for ff in f:split ',' do
if ff == 'none' then
table.insert(ret, 'ResetAttributes')
elseif ff:match '^fg=' then
table.insert(ret, ForegroundColour(ff:sub(4)))
elseif ff:match '^bg=' then
table.insert(ret, BackgroundColour(ff:sub(4)))
elseif ff:match '^nf=' then
table.insert(ret, NerdFont(ff:sub(4)))
elseif ff == 'bright' or ff == 'bold' then
table.insert(ret, Intensity 'Bold')
elseif ff == 'dim' then
table.insert(ret, Intensity 'Half')
elseif ff == 'italics' then
table.insert(ret, Italic(true))
elseif ff == 'underscore' then
table.insert(ret, Underline 'Single')
elseif ff == 'double-underscore' then
table.insert(ret, Underline 'Double')
elseif ff == 'curly-underscore' then
table.insert(ret, Underline 'Curly')
elseif ff == 'dotted-underscore' then
table.insert(ret, Underline 'Dotted')
elseif ff == 'dashed-underscore' then
table.insert(ret, Underline 'Dashed')
end
end
return ret
end
M = {}
function M.status_to_wezterm_format(text)
local rx = '(#%b[])'
local tokens = {}
-- Extract all formatting notations into tokens table as plain text
local pass1 = string.gsub(text, rx, function(f)
table.insert(tokens, f)
return '`'
end)
-- Capture all text, which remains in pass1 result, as Text objects
local i = 1
for ticks, txt in string.gmatch(pass1, '(`*)([^`]+)') do
i = i + ticks:len()
if txt:len() > 0 then
table.insert(tokens, i, Text(txt))
i = i + 1
end
end
-- Finalise wezterm.format input
local ret = {}
for _, v in pairs(tokens) do
if type(v) == 'table' then
table.insert(ret, v)
goto continue
end
local formats = MakeFormat(v)
for _, f in ipairs(formats) do
table.insert(ret, f)
end
::continue::
end
return ret
end
return M
@codemedic
Copy link
Author

I have added nerdfonts support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment