# ExecDomain {{since('20220807-113146-c2fee766')}} An `ExecDomain` defines a local-execution multiplexer domain. In simple terms, rather than directly executing the requested program, an `ExecDomain` allows you wrap up that command invocation by passing it through some other process. For example, if you wanted to make it more convenient to work with tabs and panes inside a docker container, you might want to define an `ExecDomain` that causes the commands to be run via `docker exec`. While you could just ask wezterm to explicitly spawn a command that runs `docker exec`, you would also need to adjust the default key assignments for splitting panes to know about that preference. Using an `ExecDomain` allows that preference to be associated with the pane so that things work more intuitively. ## Defining an ExecDomain You must use the `wezterm.exec_domain` function to define a domain. It accepts the following parameters: ``` wezterm.exec_domain(NAME, FIXUP [, LABEL]) ``` * *name* - uniquely identifies the domain. Must be different from any other multiplexer domains. * *fixup* - a lua function that will be called to *fixup* the requested command and return the revised command * *label* - optional. Can be either a string to serve as a label in the [Launcher Menu](../launch.md#the-launcher-menu), or a lua function that will return the label. ### fixup The simplest fixup function looks like this: ```lua wezterm.exec_domain('myname', function(cmd) return cmd end) ``` The *cmd* parameter is a [SpawnCommand](SpawnCommand.md) that contains information about the command that is to be executed. This will either be something that the user configured as a key assignment or will be an equivalent generated in response to a request to spawn a new tab or split a pane. It is expected that your fixup function will adjust the various fields of the provided command and then return it. The adjusted command is what wezterm will execute in order to satisfy the user's request to spawn a new program. ### label The label is visible in the [Launcher Menu](../launch.md#the-launcher-menu). You may set it a static string or set it to a lua callback. The default behavior is equivalent to this callback function definition: ```lua -- domain_name is the same name you used as the first parameter to -- wezterm.exec_domain() wezterm.exec_domains(domain_name, fixup_func, function(domain_name) return domain_name end) ``` Using a callback function allows you to produce an amended label just in time for the launcher menu to be rendered. That is useful for example to adjust it to represent some status information. If you were defining an ExecDomain for a docker container or VM, then you could have the label reflect whether it is currently running. Both the static string and the generated string may include escape sequences that affect the styling of the text. You may wish to use [wezterm.format()](wezterm/format.md) to manage that. ## Example: Running commands in their own systemd scope ```lua local wezterm = require 'wezterm' local config = {} -- Equivalent to POSIX basename(3) -- Given "/foo/bar" returns "bar" -- Given "c:\\foo\\bar" returns "bar" local function basename(s) return string.gsub(s, '(.*[/\\])(.*)', '%2') end config.exec_domains = { -- Defines a domain called "scoped" that will run the requested -- command inside its own individual systemd scope. -- This defines a strong boundary for resource control and can -- help to avoid OOMs in one pane causing other panes to be -- killed. wezterm.exec_domain('scoped', function(cmd) -- The "cmd" parameter is a SpawnCommand object. -- You can log it to see what's inside: wezterm.log_info(cmd) -- Synthesize a human understandable scope name that is -- (reasonably) unique. WEZTERM_PANE is the pane id that -- will be used for the newly spawned pane. -- WEZTERM_UNIX_SOCKET is associated with the wezterm -- process id. local env = cmd.set_environment_variables local ident = 'wezterm-pane-' .. env.WEZTERM_PANE .. '-on-' .. basename(env.WEZTERM_UNIX_SOCKET) -- Generate a new argument array that will launch a -- program via systemd-run local wrapped = { '/usr/bin/systemd-run', '--user', '--scope', '--description=Shell started by wezterm', '--same-dir', '--collect', '--unit=' .. ident, } -- Append the requested command -- Note that cmd.args may be nil; that indicates that the -- default program should be used. Here we're using the -- shell defined by the SHELL environment variable. for _, arg in ipairs(cmd.args or { os.getenv 'SHELL' }) do table.insert(wrapped, arg) end -- replace the requested argument array with our new one cmd.args = wrapped -- and return the SpawnCommand that we want to execute return cmd end), } -- Making the domain the default means that every pane/tab/window -- spawned by wezterm will have its own scope config.default_domain = 'scoped' return config ``` ## Example: docker domains Fully working example is yet to be completely fleshed out (volunteers welcome!) but the gist of it is: {% raw %} ```lua local wezterm = require 'wezterm' local config = {} function docker_list() -- Use wezterm.run_child_process to run -- `docker container ls --format '{{.ID}}:{{.Names}}'` and parse -- the output and return a mapping from ID -> name end function make_docker_fixup_func(id) return function(cmd) cmd.args = cmd.args or { '/bin/bash' } local wrapped = { 'docker', 'exec', '-it', id, } for _, arg in ipairs(cmd.args) do table.insert(wrapped, arg) end cmd.args = wrapped return cmd end end function make_docker_label_func(id) return function(name) -- TODO: query the container state and show info about -- whether it is running or stopped. -- If it stopped, you may wish to change the color to red -- to make it stand out return wezterm.format { { Foreground = { AnsiColor = 'Red' } }, { Text = 'docker container named ' .. name }, } end end local exec_domains = {} for id, name in pairs(docker_list()) do table.insert( exec_domains, wezterm.exec_domain( 'docker: ' .. name, make_docker_fixup_func(id), make_docker_label_func(id) ) ) end config.exec_domains = exec_domains return config ``` {% endraw %} With something like the config above, each time the config is reloaded, the list of available domains will be updated. Opening the launcher menu will show them and their status and allow you to launch programs inside those containers.