wezterm
wezterm copied to clipboard
Set title for tab and all its panes
Is your feature request related to a problem? Please describe.
Apologies if there's already a ticket for this that I didn't find. The problem is mentioned in https://github.com/wez/wezterm/issues/522#issuecomment-1000878325 but it was out of scope.
In a tab with more than one pane, I set the tab title in one pane (I have a set_title shell script that prints the title in an escape sequence), switch to the next, and the title changes again.
I'm not entirely sure, but I think none of the three escape codes at the beginning of this table cover this use case.
Describe the solution you'd like
An escape sequence that sets the title of a tab irrespective of the pane in which you are.
Describe alternatives you've considered
One could also write a hook for format-tab-title as mentioned in that other issue, but it feels more complicated (need to coordinate with an environment variable, etc).
Can you tell me more about the higher level workflow you want to achieve here?
It sort of sounds similar to the new Workspaces concept available in the nightly; there's some discussion on that here: https://github.com/wez/wezterm/discussions/1322#discussioncomment-1979578
You can display the workspace name in the status area: https://wezfurlong.org/wezterm/config/lua/window/active_workspace.html
Ah! I hadn't seen workspaces yet.
My workflow is, currently: for my job I work on six projects, and I have all of them in only one instance of wezterm, one tab per project (and typically, in each, one pane for vim, and one/two shells).When I was using Kitty, I had each of the tabs with the name of the project, to make it easier to switch to the one I want.
Currently, it's more difficult, because I need to set the name for all panes, and if I add a new split, it hides the name.
I haven't tried the nightly yet, but it sounds like workspaces along with sway could help replicate that (would I need one window per workspace?).
But still, I think being able to name a tab, even within a workspace, would be useful. Suppose I have a workspace per project: I might want to have three panes tailing logs in one tab, watch compiler and editor in another, ..., and being able to see where they are from the tab name.
If we take tmux analogy, one can name/rename a session, a window and even a pane (however I never used it, and displayed its name).
By default the window is named after the running binary of the current pane (what's already done in wezterm afaik, the tab is named after the running program). I'm guessing you want to be able to name the tabs arbitrarily?
(@wez I'd be interested to name/rename the tabs & workspace as well 🙃)
I haven't tried the nightly yet, but it sounds like workspaces along with sway could help replicate that (would I need one window per workspace?).
The model for workspaces is that a given window is associated with a single workspace.
So for the workflow you described, you could use workspaces instead of tabs: one for each of the projects. Then instead of switching between tabs, you would switch between workspaces. It would be similar to a tab based solution, except that you wouldn't see the workspaces lined up along the top of the window; you'd have to pop open a launcher to interactively select the one you wanted to activate, and likewise, set up key assignments if you want short cuts.
However, you could open a second window and have that map to a different (or even the same!) workspace as the other window if you wanted to see those projects in windows both at the same time.
But still, I think being able to name a tab, even within a workspace, would be useful. Suppose I have a workspace per project: I might want to have three panes
tailing logs in one tab,watchcompiler and editor in another, ..., and being able to see where they are from the tab name.
Yeah, I can see the utility. I'm just not 100% sure about what the UX should be. I think there are some things to figure out the overall semantics:
- The current OSC title sequences were originally intended to set the Window and Icon title in original xterm, which doesn't have tabs or panes. Those are currently interpreted by wezterm as the Window and Pane title, with the Pane title taking precedence over the Window title in the default tab/window titlebar logic. Both items are actually per-pane data!
- How does tab title fit into those? Should there be a separate OSC sequence for setting it, or should the existing items be reconsidered/reassigned? If we're allows tabs to be labelled, then we would route the window title to the Window in the model.
- There are extensions to those title OSC sequences that allow managing the titles as a stack. Probably should consider that as part of this
- The default window/tab title logic would need to be updated to reflect this new tab label
- Similarly, the lua API would need to be updated to accommodate getting and setting it
(@wez I'd be interested to name/rename the tabs & workspace as well 🙃)
Technically speaking, there's already some code that can rename workspaces, but nothing is attached to it today!
I'm going to close this as it sounds like workspaces is the right area for this.
@wez I don't think that workspaces really works for the use case described. This is absolutely something I would be interested in, I use it daily in tmux. I can try to make a PR but I would need some pointers to relevant files. Would it be bad to "break" OSC codes if it is extended specifically for wezterm?
Current workaround:
local tab_titles = { 'test1' }
wezterm.on('format-tab-title', function(tab)
local title = tab.tab_id .. ': ' .. tab.active_pane.title
if tab_titles[tab.tab_id + 1] ~= nil then
title = tab_titles[tab.tab_id + 1]
end
return title
end)
The only additional things to add for a hacky workaround would be 1) getting the current tab from the cli 2) setting a global in wezterm.GLOBAL through the cli. Then I could create an alias like $ tabtitle test, no OSC code hacks!
Another way to make this easier would be "arbitrary events/callbacks" that could be triggered from the cli like wezterm cli callback set_tab_title test. the event being set_tab_title and argument test
My hackish solution (got a lot of help from the matrix room):
local wezterm = require("wezterm")
wezterm.GLOBAL.tab_titles = {}
wezterm.on("format-tab-title", function(tab, _, panes)
local tab_id = tostring(tab.tab_id)
if tab.is_active then
for _, pane in ipairs(panes) do
local pane_title = pane.title
if pane_title:sub(1, 1) == ">" then
local title = pane_title:sub(2)
local current_titles = wezterm.GLOBAL.tab_titles
current_titles[tab_id] = title
wezterm.GLOBAL.tab_titles = current_titles
end
end
end
local pos = tab.tab_index + 1
local title = wezterm.GLOBAL.tab_titles[tab_id] or tab.active_pane.title
return " " .. pos .. ": " .. title .. " "
end)
return {}
I trigger it by setting the title of one of the panes to a value that starts with > (using title ">foo" or whatever alias you have to print the escape sequence). That value (without the leading >) becomes the "tab title".
I just pushed a commit that adds a title concept to both MuxWindow and MuxTab so you can get/set titles on those objects via eg: window:get_title(), window:set_title("something"), tab:get_title(), tab:set_title("something").
Escape sequences that change the window title (OSC 0 and OSC 2 are the most common) will cause the title of the containing MuxWindow to be changed to match.
There isn't yet an escape sequence to modify the MuxTab in a similar way.
TabInformation now exposes the corresponding window_id (which is helpful for some of the workarounds above), as well as window_title and tab_title fields for accessing the corresponding titles.
This should help a bit, but it's probably not 100% of what you need.
Things that I'd like to do as a follow up:
- Change the default
format-tab-titleandformat-window-titleto consider these new sources of title string - Define an escape sequence for setting the tab title (I don't think any other terminal has defined one yet: need to check)
- wezterm cli subcommand for getting/setting tab and window titles
With 2e9fe87e34fbd564617d1004b969a89f0c5aadad the API has been expanded a bit to make it easier to traverse the different windows, tabs and panes.
Notably, if you define a function like this in your wezterm.lua:
-- Sets the title of the active tab in the current window.
-- This method is intended to be called from the debug overlay repl
function set_tab_title(title)
-- The debug overlay defines a global `window` variable that is a Gui Window object; let's
-- access it via the special `_G` lua table that always references the global variables
local gui_window = _G.window
-- "Convert" the gui window into a mux window
local window = wezterm.mux.get_window(gui_window:window_id())
-- Locate the active tab
for _, tab_info in ipairs(window:tabs_with_info()) do
if tab_info.is_active then
-- Set the title and log something to indicate the changes that we made
tab_info.tab:set_title(title)
wezterm.log_info("Changed title for tab " .. tostring(tab_info.tab:tab_id()) .. " to " .. tab_info.tab:get_title())
break
end
end
end
Then activate the debug overlay via CTRL+SHIFT+L and type the following to call it:
> set_tab_title("woot")
nil
13:26:11.284 INFO logging > lua: Changed title for tab 0 to woot
>
This provides a way to make a kind of "alias" for performing more complex manipulations via the REPL.
@ovidiu I saw that you have:
wezterm.GLOBAL.tab_titles = {}
at the file scope in your config. I wouldn't recommend that, as it will clear tab_titles whenever the config is re-evaluated.
Instead, I would suggest doing something like this if you want to ensure that it initialized to an empty table:
wezterm.GLOBAL.tab_titles = wezterm.GLOBAL.tab_titles or {}
Oh, good catch! Thanks.
@wez hi, I've tried the set_tab_title function posted above, but neither Tab Navigator nor wezterm cli list picks up the new title. Any ideas where it might go wrong? Current version is 20220905-102802-7d4b8249 installed from Homebew tap (macOS 10.15).
@iwinux please file a separate issue with complete information on what you're trying and seeing
Hi Wez, I just started using wezterm today, I have found it to be amazing! Thank you for creating this!
Coming from tmux tab renaming is done quite often as things change with the tabs. I started using the function from your comment https://github.com/wez/wezterm/issues/1598#issuecomment-1167851819 and debug overlay. It is works great. However on a restart of wezterm the tab titles get wiped out, and they have to set again.

I am running wezterm with unix domains and auto connect:
unix_domains = {
{
name = 'unix',
},
},
default_gui_startup_args = { 'connect', 'unix' },
If you any workarounds or suggestions please let me know.
This is my hypothesis on why this happens, the titles are set on tabs of the window object. Once the window is closed the object is gone and so are the tab titles. When opening a new window a new object is created which does not have any titles set on the tabs.
I am wondering if there is a way to set the title on the tab objects of the daemon that is running in the background?
+1 to make it possible to set window and tab title throw the CLI.
Currently I use nvim in kitty along with this autogroup
augroup kitty_title
function! SetTitle(leaving)
let title = ''
let arg = argv(0)
if arg is v:null
let title = 'nvim'
elseif !a:leaving
if isdirectory(arg)
let title = 'nvim ~ ' . expand('%:p:h:t')
else
let title = 'nvim ~ ' . arg
endif
endif
call system('kitty @ set-window-title "' . title . '"')
call system('kitty @ set-tab-title "' . title . '"')
endfunction
autocmd VimEnter * ++once call SetTitle(0)
autocmd VimLeave * ++once call SetTitle(1)
augroup END
In addition, when kitty receives the title I change nvim for the vim icon (nerd fonts)
tab_title_template "{index}:{title[title.rfind('/')+1:].replace('nvim', ' ')} "
I know, too fancy.
For some reason escape sequences do not work. I have tried the followings having use_fancy_tab_bar true or false
echo "\x1b]1337;SetUserVar=tab_title=${title_b64}\007"
echo "\x1b]1337;SetUserVar=panetitle=$(echo -n $(basename $(pwd)) | base64)\x07"
printf "\033[48;5;226mTITLE\e[m\n"
Maybe I'm missing something?
This is probably the wrong place to ask this, but I was not sure, where else to put it:
I am trying to get the different workarounds running somehow - but how can I change a value in the GLOBAL-Table called tab_titles at runtime? it seems like, when doing it via the debug overlay, it won't be written?
This is the code in my wezterm.lua:
if wezterm.GLOBAL.tab_titles == nil then
wezterm.GLOBAL.tab_titles={}
end
wezterm.on("format-tab-title", function(tab)
local title = tab.tab_id .. ": " .. "something new"
if wezterm.GLOBAL.tab_titles["T" .. tab.tab_id] ~= nil then
title = wezterm.GLOBAL.tab_titles["T" .. tab.tab_id]
end
wezterm.log_info("Title: " .. title)
return title
end)
when opening the debug overlay, this happens:
> wezterm.GLOBAL.tab_titles["T0"]="Test"
> > wezterm.GLOBAL.tab_titles
{}
EDIT: the funktion set_tab_title from @wez did not work for me at all. This method at least changed the names
if there is a better solution to rename tabs, this is of course obsolete...
Also: can we call those methods from "extern" - like when opening a new Tab run that lua to change the tab name?
@sboesebeck please use either the discussions or file a separate issue so that this one can remain focused
@krafts I just pushed some changes to make the multiplexer aware of tab and window title changes, so that should resolve the issue you described.
Also, I added some shortcuts so that you can do:
window:active_tab():set_title("w00t!")
without having to write a complicated alias function.
I've also made the default format-tab-title logic take the tab title if it is non-empty, so you shouldn't need to write your own event just for tab titles.
Still missing is a a UI for setting the title, but this should at least tidy this feature up a bit for the moment.
And now there is wezterm cli set-tab-title for setting via the CLI
Thank you Wez!!
main now lets you do this:
local wezterm = require 'wezterm'
local act = wezterm.action
local config = wezterm.config_builder()
config.keys = {
{
key = 'E',
mods = 'CTRL|SHIFT',
action = act.PromptInputLine {
description = 'Enter new name for tab',
action = wezterm.action_callback(function(window, pane, line)
-- line will be `nil` if they hit escape without entering anything
-- An empty string if they just hit enter
-- Or the actual line of text they wrote
if line then
window:active_tab():set_title(line)
end
end),
},
},
}
return config
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.