how to execute a function in i3 config?

7.6k views Asked by At

I want to rename a workspace but retain the workspace number by default, in i3 user guide, I find the following script to do so.

bindsym $mod+r exec i3-input -F 'rename workspace to "%s"' -P 'New name: '

But the problem is that it doesn't keep workspace number by default, so I have to remember to type the workspace number.

I've found a way to get the number of the focused workspace number with following command, but I don't know how to concat the number to with the input name together in i3 config.

i3-msg -t get_workspaces | jq '.[] | select(.focused == true) | .num'

So, I'm wondering whether in i3 config file, I can execute some kind of function to concat the workspace number with user input to achieve my purpose?

2

There are 2 answers

1
plnx On BEST ANSWER

I don't think you can. But, you can always do whatever you want if you create a script and call it with exec in your i3-config. So, for example:

~/bin/i3-rename-workspace (or wherever is convenient for you):

N=$(i3-msg -t get_workspaces | jq '.[] | select(.focused == true).num')
i3-input -F "rename workspace to \"$N: %s\"" -P 'New name: '

Somewhere in your i3-config:

bindsym $mod+r exec i3-rename-workspace

Remember to provide the full path to your script, or put it somewhere in i3's $PATH.

1
dragon788 On

You can execute a function from the i3 config, it gets a bit hairy but it works out quite nicely. The key things to remember are any commands with a , or ; need quoted (i.e. every function you can possibly write as it is a required part of the syntax), and if you have additional quotes of the same type inside the command passed to exec you need to escape them with \\ per the i3 documentation.

Personally I wanted a simple shutdown menu without having to create a separate script to maintain and drag around outside my i3 config, I used an inline function definition and call. This is very similar to the recommended way to run external commands in git aliases (and is where I had the idea that it would work).

bindsym $mod+Shift+q exec "bash -c 'f () { res=$(rofi -dmenu < <(echo -en \\"logout\nrestart\nshutdown\\")); case $res in logout) i3-msg exit;; restart) sudo shutdown -r +2;; shutdown) sudo shutdown -P +2;; esac; }; f;'"

This is a bit dense to unpack, but I define the temporary function f () {...}; f;' and call it after. Inside the function I'm feeding in the options to the menu using process substitution and input redirection to capture the selection to a variable res=$(rofi -dmenu < <(echo -en \\"logout\nrestart\nshutdown\\")) and note the extra \\ to escape the inner double quotes.

Finally I'm evaluating the option the user selected via case and choosing an action based on that option, with a 2 minute timeout on the restart and shutdown commands so I can abort if somehow I hit the hard to accidentally hit modifiers required to trigger the menu AND select an item rather than just pressing Esc to exit the menu.

After writing this up and realizing how easy it might be to logout and loose all my current windows/layouts, I'm going to add a "no-op" option that appears first in the list and is evaluated last in the case statement that maybe will echo something funny via cowsay or notify-send.