-
-
Notifications
You must be signed in to change notification settings - Fork 801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamically determine command for new pane? Make default_prog a function? #1776
Comments
This is a neat idea! There's some plumbing to facilitate this sort of thing; on Windows, we have a Lines 176 to 212 in 4cd8933
When I wrote that, I had in mind the idea that we could extend it to also spawn into eg: docker containers, so it's not a huge stretch to consider also the container/isolation provided by systemd-run as part of this. In terms of implementation, rather than making That event would be synchronous, which means that some of the more powerful asynchronous helpers provided in the Note that in that context the pane_id is part of the environment set in the command builder. |
Here's an example of triggering a synchronous lua event; it emits the Lines 383 to 397 in 4cd8933
If you wanted to try making a PR for what I suggested above, I think the steps would be:
wezterm/config/src/keyassignment.rs Lines 157 to 183 in 4cd8933
wezterm/wezterm-gui/src/termwindow/spawn.rs Lines 83 to 102 in 4cd8933
Then in your wezterm config, you might have something like: wezterm.on("mux-local-domain-local-fixup-command", function(cmd)
local args = {"systemd-run", table.unpack(cmd.args)}
cmd.args = args
return cmd
end) |
@wez Oh that escalated quickly 😆 But a new event is a nice idea; I see if I can make a PR about this. Will take a while though, I'm pretty busy currently. |
An ExecDomain is a variation on WslDomain with the key difference being that you can control how to map the command that would be executed. The idea is that the user can define eg: a domain for a docker container, or a domain that chooses to run every command in its own cgroup. The example below shows a really crappy implementation as a demonstration: ``` local wezterm = require 'wezterm' return { exec_domains = { -- Commands executed in the woot domain have "WOOT" echoed -- first and are then run via bash. -- `cmd` is a SpawnCommand wezterm.exec_domain("woot", function(cmd) if cmd.args then cmd.args = { "bash", "-c", "echo WOOT && " .. wezterm.shell_join_args(cmd.args) } end -- you must return the SpawnCommand that will be run return cmd end), }, default_domain = "woot", } ``` This commit unfortunately does more than should go into a single commit, but I'm a bit too lazy to wrangle splitting it up. * Reverts the nil/null stuff from #2177 and makes the `ExtendSelectionToMouseCursor` parameter mandatory to dodge a whole load of urgh around nil in table values. That is necessary because SpawnCommand uses optional fields and the userdata proxy was making that a PITA. * Adds some shell quoting helper functions * Adds ExecDomain itself, which is really just a way to to run a callback to fixup the command that will be run. That command is converted to a SpawnCommand for the callback to process in lua and return an adjusted version of it, then converted back to a command builder for execution. refs: #1776
In local wezterm = require 'wezterm'
return {
exec_domains = {
wezterm.exec_domain("woot", function(cmd)
wezterm.log_info(cmd)
if cmd.args then
cmd.args = {
"bash",
"-c",
"echo WOOT && " .. wezterm.shell_join_args(cmd.args)
}
end
return cmd
end),
},
default_domain = "woot",
} You can define multiple The callback is passed a There are a couple of helper functions that can make some things more convenient: |
Here's a version of your original request: local wezterm = require 'wezterm'
-- 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
return {
exec_domains = {
wezterm.exec_domain("scoped", function(cmd)
wezterm.log_info(cmd)
local env = cmd.set_environment_variables
local ident = "wezterm-pane-" .. env.WEZTERM_PANE .. "-on-" .. basename(env.WEZTERM_UNIX_SOCKET)
local wrapped = {
'/usr/bin/systemd-run',
'--user',
'--scope',
'--description=Shell started by wezterm',
'--same-dir',
'--collect',
'--unit=' .. ident,
}
for _, arg in ipairs(cmd.args or {os.getenv("SHELL")}) do
table.insert(wrapped, arg)
end
cmd.args = wrapped
return cmd
end),
},
default_domain = "scoped",
}
|
@wez Woa, that's really great. 🤩 🎉 Can't wait to try it; when will this make it into a release? 😇 |
I want to get feedback on how well it works before I write up docs and then make a release; can you try a nightly build? |
Will do next week! ❤️ |
Docs should show up at https://wezfurlong.org/wezterm/config/lua/ExecDomain.html shortly |
@wez I tested nightly, and it works well. I had to alter the identifier slightly, though: I used a random string in place of the |
the pane id is unique for each tab created by a given wezterm process. If you are running multiple instances (processes!) of wezterm then it is important to include something that is derived from the wezterm pid in the identifier. The unix socket path I showed in the example above includes the pid. |
@wez That didn't work for me; in my test I've just tried to start it from another terminal, and now it doesn't start at all:
It looks as if I'm starting the App image with a custom Edit: The nightly version is |
This way we can ensure that it is set in the environment in time for the lua callback to see it. refs: #1776
Ah, I see; I pushed a fix for this! |
Thanks. I'll wait for tonight's nightly and test again 🙂
|
the nightly builds for linux are all pushed! |
@wez Tested again, now it works perfectly, thanks! |
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. |
Describe the solution you'd like
I'd like to use a function to determine the exact command to use for a new pane. Currently
default_prog
is just a static table, so all new tabs and panes spawn the same program. However I'd like to start a slightly different program for each new pane or tab.For this purpose I'd like
default_prog
to be a function, as an alternative to a fixed table. This function would receive a table with some information about the new tab/pane, and returns a table with the command to use.Would you accept a pull request which also allows a function for
default_prog
?See below for the why 🙂
Describe alternatives you've considered
Are there any other means to do this currently?
Additional context
I'd like to spawn every new shell into a dedicated systemd scope, to isolate tabs from each other and from the parent wezterm process.
This puts each pane under separate memory/CPU accounting, and makes it become a separate target for the userspace OOM killer. If some program running in wezterm consumes an excessive amount of system memory systemd will now take down just the offending pane instead of the entire wezterm process (which otherwise forms the parent scope).
In and by itself that's easy by wrapping
systemd-run
around my shell in inwezterm.lua
:However there's a minor nuisance: The scope name gets randomly generated by
systemd-run
itself and isn't exactly descriptive:I'd prefer if it was something like
wezterm-shell-$PID-$WINDOW-$TAB-$PANE-$RANDOM.scope
where$PID
is the PID of the current wezterm process,$RANDOM
some random string for uniqueness, and the other variables unique identifiers for the Wezterm window, tab and pane running this shell.I can pass a custom name for the new scope with the
--unit
option forsystemd-run
, but then systemd-run won't make that name unique. In other words I have to generate a unique name for each new shell.But I can't, because
default_prog
is a static table.The text was updated successfully, but these errors were encountered: