Yabai: [Help] i need help using Yabai specially with multiple screens

Created on 15 Apr 2020  Β·  23Comments  Β·  Source: koekeishiya/yabai

Hey Mates, this is my very first time using tiling window manager and I am loving it.
I need help using Yabai using multiple screens, or maybe one deepened on the place maybe sometimes I am out with only laptop cuz it's awkward walking around with a 28-inch screen on my back 😜 (just kidding).

so, I need help setup my workspace like the following I need main 6 spaces

  • Desktop (for random apps) (space 1)
  • Chrome (space 2)
  • Emacs (space 3)
  • iTerm (space 4)
  • Slack and Discord (space 5)
  • Mail and ZohoMail (space 6)
    and whenever I press the key binding (cmd + alt - n) where [n] is the space number it navigates me to it that space wherever it is, right now if I change the space from the laptop screen to monitor screen the key binding gets missed up.
    also, can I make the app create its own space on lunching?
    I thought if creating 6 spacing on startup but it bloats it with empty spaces if I didn't open any of those app with an empty space.
    also, it would be great if Chrome, Emacs, and iTerm be in native fullscreen.

here are my current conf files stole some from @koekeishiya dotfiles πŸš€, thanks a lot to him.
yabairc

#!/usr/bin/env sh

# global settings
yabai -m config mouse_follows_focus          on
yabai -m config focus_follows_mouse          autoraise
yabai -m config window_placement             second_child
yabai -m config window_topmost               on
yabai -m config window_opacity               off
yabai -m config window_opacity_duration      0.0
yabai -m config window_shadow                on
yabai -m config window_border                on
yabai -m config window_border_placement      inset
yabai -m config window_border_width          2
yabai -m config window_border_radius         -1.0
yabai -m config active_window_border_topmost off
yabai -m config active_window_border_color   0xff61afef
yabai -m config normal_window_border_color   0xff282c34
yabai -m config insert_window_border_color   0xffe06c75
yabai -m config active_window_opacity        1.0
yabai -m config normal_window_opacity        0.75
yabai -m config split_ratio                  0.50
yabai -m config auto_balance                 on
yabai -m config mouse_modifier               fn
yabai -m config mouse_action1                move
yabai -m config mouse_action2                resize

# general space settings
yabai -m config layout                       bsp
yabai -m config top_padding                  32
yabai -m config bottom_padding               6
yabai -m config left_padding                 6
yabai -m config right_padding                6
yabai -m config window_gap                   6

# specific space settings
yabai -m config --space 7 layout             float

# window rules
yabai -m rule --add app=Chrome   space=2 native-fullscreen=true
yabai -m rule --add app=Emacs    space=3 native-fullscreen=true
yabai -m rule --add app=iTerm    space=4 native-fullscreen=true
yabai -m rule --add app=Discord  space=5
yabai -m rule --add app=Slack    space=5
yabai -m rule --add app=Mail     space=6
yabai -m rule --add app="^Zoho$" space=6
yabai -m rule --add app="^System Preferences$" manage=off

# signals
yabai -m signal --add event=window_destroyed action="yabai -m query --windows --window &> /dev/null || yabai -m window --focus mouse"
yabai -m signal --add event=application_terminated action="yabai -m query --windows --window &> /dev/null || yabai -m window --focus mouse"

echo "yabai configuration loaded.."

skhdrc

# Quickly restart the yabai launch agent
ctrl + alt + cmd - r : launchctl kickstart -k "gui/${UID}/homebrew.mxcl.yabai"

# open terminal
cmd - return : /Applications/iTerm.app/Contents/MacOS/iTerm2

# focus window
alt - h : yabai -m window --focus west
alt - j : yabai -m window --focus south
alt - k : yabai -m window --focus north
alt - l : yabai -m window --focus east

# swap window
shift + alt - h : yabai -m window --swap west
shift + alt - j : yabai -m window --swap south
shift + alt - k : yabai -m window --swap north
shift + alt - l : yabai -m window --swap east

# move window
shift + cmd - h : yabai -m window --warp west
shift + cmd - j : yabai -m window --warp south
shift + cmd - k : yabai -m window --warp north
shift + cmd - l : yabai -m window --warp east

# create desktop, move window and follow focus
shift + cmd - n : yabai -m space --create && \
                  index="$(yabai -m query --spaces --display | jq 'map(select(."native-fullscreen" == 0))[-1].index')" && \
                  yabai -m window --space "${index}" && \
                  yabai -m space --focus "${index}"

# create desktop and follow focus
shift + alt - n : yabai -m space --create && \
                  index="$(yabai -m query --spaces --display | jq 'map(select(."native-fullscreen" == 0))[-1].index')" && \
                  yabai -m space --focus "${index}"

# destroy desktop
cmd + alt - w : yabai -m space --destroy

# fast focus desktop
cmd + alt - x : yabai -m space --focus last
cmd + alt - z : yabai -m space --focus prev
cmd + alt - c : yabai -m space --focus next
cmd + alt - 1 : yabai -m space --focus 1
cmd + alt - 2 : yabai -m space --focus 2
cmd + alt - 3 : yabai -m space --focus 3
cmd + alt - 4 : yabai -m space --focus 4
cmd + alt - 5 : yabai -m space --focus 5
cmd + alt - 6 : yabai -m space --focus 6
cmd + alt - 7 : yabai -m space --focus 7
cmd + alt - 8 : yabai -m space --focus 8
cmd + alt - 9 : yabai -m space --focus 9
cmd + alt - 0 : yabai -m space --focus 10

# send window to desktop and follow focus
shift + cmd - x : yabai -m window --space last; yabai -m space --focus last
shift + cmd - z : yabai -m window --space prev; yabai -m space --focus prev
shift + cmd - c : yabai -m window --space next; yabai -m space --focus next
shift + cmd - 1 : yabai -m window --space  1; yabai -m space --focus 1
shift + cmd - 2 : yabai -m window --space  2; yabai -m space --focus 2
shift + cmd - 3 : yabai -m window --space  3; yabai -m space --focus 3
shift + cmd - 4 : yabai -m window --space  4; yabai -m space --focus 4
shift + cmd - 5 : yabai -m window --space  5; yabai -m space --focus 5
shift + cmd - 6 : yabai -m window --space  6; yabai -m space --focus 6
shift + cmd - 7 : yabai -m window --space  7; yabai -m space --focus 7
shift + cmd - 8 : yabai -m window --space  8; yabai -m space --focus 8
shift + cmd - 9 : yabai -m window --space  9; yabai -m space --focus 9
shift + cmd - 0 : yabai -m window --space 10; yabai -m space --focus 10

# focus monitor
ctrl + alt - x  : yabai -m display --focus last
ctrl + alt - z  : yabai -m display --focus prev
ctrl + alt - c  : yabai -m display --focus next
ctrl + alt - 1  : yabai -m display --focus 1
ctrl + alt - 2  : yabai -m display --focus 2
ctrl + alt - 3  : yabai -m display --focus 3

# send window to monitor and follow focus
ctrl + cmd - x  : yabai -m window --display last; yabai -m display --focus last
ctrl + cmd - z  : yabai -m window --display prev; yabai -m display --focus prev
ctrl + cmd - c  : yabai -m window --display next; yabai -m display --focus next
ctrl + cmd - 1  : yabai -m window --display 1; yabai -m display --focus 1
ctrl + cmd - 2  : yabai -m window --display 2; yabai -m display --focus 2
ctrl + cmd - 3  : yabai -m window --display 3; yabai -m display --focus 3

# move window
shift + ctrl - a : yabai -m window --move rel:-20:0
shift + ctrl - s : yabai -m window --move rel:0:20
shift + ctrl - w : yabai -m window --move rel:0:-20
shift + ctrl - d : yabai -m window --move rel:20:0

# increase window size
shift + alt - a : yabai -m window --resize left:-20:0
shift + alt - s : yabai -m window --resize bottom:0:20
shift + alt - w : yabai -m window --resize top:0:-20
shift + alt - d : yabai -m window --resize right:20:0

# decrease window size
shift + cmd - a : yabai -m window --resize left:20:0
shift + cmd - s : yabai -m window --resize bottom:0:-20
shift + cmd - w : yabai -m window --resize top:0:20
shift + cmd - d : yabai -m window --resize right:-20:0

# set insertion point in focused container
ctrl + alt - h : yabai -m window --insert west
ctrl + alt - j : yabai -m window --insert south
ctrl + alt - k : yabai -m window --insert north
ctrl + alt - l : yabai -m window --insert east

# rotate tree
alt - r : yabai -m space --rotate 90

# mirror tree y-axis
alt - y : yabai -m space --mirror y-axis

# mirror tree x-axis
alt - x : yabai -m space --mirror x-axis

# toggle desktop offset
alt - a : yabai -m space --toggle padding; yabai -m space --toggle gap

# toggle window parent zoom
alt - d : yabai -m window --toggle zoom-parent

# toggle window fullscreen zoom
alt - f : yabai -m window --toggle zoom-fullscreen

# toggle window native fullscreen
shift + alt - f : yabai -m window --toggle native-fullscreen

# toggle window border
shift + alt - b : yabai -m window --toggle border

# toggle window split type
alt - e : yabai -m window --toggle split

# float / unfloat window and center on screen
alt - t : yabai -m window --toggle float;\
          yabai -m window --grid 4:4:1:1:2:2

# toggle sticky
alt - s : yabai -m window --toggle sticky

# toggle sticky, float and resize to picture-in-picture size
alt - p : yabai -m window --toggle sticky;\
          yabai -m window --grid 5:5:4:0:1:1

# change layout of desktop
ctrl + alt - a : yabai -m space --layout bsp
ctrl + alt - d : yabai -m space --layout float

Thanks in advance mates πŸ˜„

help wanted question

Most helpful comment

yabai -m rule --add app=Chrome space=2 native-fullscreen=true
yabai -m rule --add app=Emacs space=3 native-fullscreen=true
yabai -m rule --add app=iTerm space=4 native-fullscreen=true

You should specify on, not true. If you check the log you will see an error for these: https://github.com/koekeishiya/yabai/wiki/Configuration#debug-output-and-error-reporting

Also when native-fullscreen is enabled the window will be moved into its own space (as per how macOS works), and so there is no reason to specify space in the rule.
If you want to always keep an app in a specific space, then you do want to specify space, but not fullscreen.

You can label spaces and use that to refer to specific spaces if that is more convenient than having to use indexes.

A very basic sample:

# assign alias to space 1
yabai -m space 1 --label code

# make sure Emacs is moved to space 'code' upon launch
yabai -m rule --add app="^Emacs$"    space=code

# focus space by name, bind this to a key using w/e software
yabai -m space --focus code

You can do more sophisticated things using the query and signal system, like querying the number of spaces currently on each monitor and label/destroy/create/move/whatever. See solution from https://github.com/koekeishiya/yabai/issues/365 for inspiration, or something.

All 23 comments

This is an issue board. Ask a specific question, and you'll likely get an answerβ€”asking for a complete configuration to be written according to your wishes is rude at best.

@dominiklohmann I never meant to be rude, and I don't anyone to write them for me, I won't learn anything then, and I will create dependency on those who wrote it from me and won't be able to customize it later.

I tried to explain what I want so you could help me better, also a small example would be greater so I can do the rest on my own, passing a place in the wiki that can help is also appreciated,
maybe what I want can't be done here then I will find another alternative to handle my workflow.

But to be honest, telling me you're rude without understanding my intention is kinda rude.
anyways thanks for your comment.

And my question is how to make space with a specific app that I can jump to with specific key binding.

yabai -m rule --add app=Chrome space=2 native-fullscreen=true
yabai -m rule --add app=Emacs space=3 native-fullscreen=true
yabai -m rule --add app=iTerm space=4 native-fullscreen=true

You should specify on, not true. If you check the log you will see an error for these: https://github.com/koekeishiya/yabai/wiki/Configuration#debug-output-and-error-reporting

Also when native-fullscreen is enabled the window will be moved into its own space (as per how macOS works), and so there is no reason to specify space in the rule.
If you want to always keep an app in a specific space, then you do want to specify space, but not fullscreen.

You can label spaces and use that to refer to specific spaces if that is more convenient than having to use indexes.

A very basic sample:

# assign alias to space 1
yabai -m space 1 --label code

# make sure Emacs is moved to space 'code' upon launch
yabai -m rule --add app="^Emacs$"    space=code

# focus space by name, bind this to a key using w/e software
yabai -m space --focus code

You can do more sophisticated things using the query and signal system, like querying the number of spaces currently on each monitor and label/destroy/create/move/whatever. See solution from https://github.com/koekeishiya/yabai/issues/365 for inspiration, or something.

@koekeishiya Thanks, that's actually useful, I will try the label approach it will do the thing for me.
I appreciate it so much.

Hey I am trying to get it working as I mentioned above but I have found the following signal:

space_changed
Triggered when the active space has changed.
Passes two arguments: $YABAI_SPACE_ID, $YABAI_RECENT_SPACE_ID

and made the following function to dynamic reassign the space every time I change its position
yabai -m query --windows --space ${YABAI_SPACE_ID} query the current position and pip it to jq

jq 'map(select(.app == \"${1}\"))[0].app' select the app name and compare it to the app I wanted to dynamically reading it's space

grep \"${1}\" this is just to make sure it found the app so to run the label assignment or not (and I couldn't find a better way)

yabai -m space ${YABAI_RECENT_SPACE_ID} --label ${2} assign the provided label to the new space

# functions
# Description:
#  Keep space name dymanic even while moving
#  the app from space to another one
#
# Usage:
#  $ dynamic_space_naming param1 param2
#  * param1: app name
#  * param2: space name you want to use
dynamic_space_naming() {
 yabai -m signal --add event=space_changed \
    action="yabai -m query --windows --space ${YABAI_RECENT_SPACE_ID} \
    | jq 'map(select(.app == \"${1}\"))[0].app' \
    | grep \"${1}\" \
    && yabai -m space ${YABAI_SPACE_ID} --label ${2}"
}

the problem I have:
YABAI_RECENT_SPACE_ID and YABAI_SPACE_ID doesn't return any value unfortunately
is there anything I can do about this !?

Screen Shot 2020-04-15 at 10 08 36 PM

You need to escape the variables because you are writing the script inline

dynamic_space_naming() {
 yabai -m signal --add event=space_changed \
    action="yabai -m query --windows --space \${YABAI_RECENT_SPACE_ID} \
    | jq 'map(select(.app == \"${1}\"))[0].app' \
    && grep \"${1}\" \
    && yabai -m space \${YABAI_SPACE_ID} --label ${2}"
}

@koekeishiya Sorry man still got no luck, the value of both bars seems to be missing here.
used the method you wrote above and the same style as the args both didn't work.
I have tried with static space value and the function worked really well.
I just had to pipe | grep instead of && grep and it worked, but with those 2 variables I keep getting these errors in the screenshot sorry for the debugging language, it just I keep doing this for a really long time now with no luck, the output on the left and the errors on the right:
Screen Shot 2020-04-16 at 12 23 55 AM

Try to understand when the variables are evaluated. As is, you're evaluating them when running the command to add the action.

Running with set -eu will help you a lot here, as this would actually return an error.

Assuming your shell is zsh, paste this into a terminal:

() {
  emulate -L zsh -o xtrace -o err_return -o nounset
  yabai -m signal --add event=space_changed action="
    echo $YABAI_RECENT_SPACE_ID"
}

You'll see this output:

(anon):2: YABAI_RECENT_SPACE_ID: parameter not set

But if you escape the variable, you'll see this:

() {
  emulate -L zsh -o xtrace -o err_return -o nounset
  yabai -m signal --add event=space_changed action="
    echo \$YABAI_RECENT_SPACE_ID"
}
+(anon):2> yabai -m signal --add 'event=space_changed' $'action=\n    echo $YABAI_RECENT_SPACE_ID'

@dominiklohmann Hey man, first of all, I would like to apologize about the confect and the misunderstanding that happened above, also thanks a lot on ur comment it helped me a lot for debugging, I think knew the problem here:
YABAI_RECENT_SPACE_ID and YABAI_SPACE_ID are the space id[obviously πŸ˜„]
and when I run the command yabai -m query --windows --space \${YABAI_RECENT_SPACE_ID}
it expects space index not ID that's why I keep getting that error :

Snowflake in ~
[I] ➜ yabai -m query --windows --space 25
could not locate the selected space.

cuz there's no space with the index 25, where 25 is the value of $YABAI_RECENT_SPACE_ID
so I will make 2 queries first to get the indexes then use those values for the query it should work.

You can convert between id and index with a simple query:

yabai -m query --spaces | jq -r ".[] | select(.id == \$YABAI_SPACE_ID).index"

@dominiklohmann Sorry but it seems like I can't skip $YABAI_SPACE_ID in jq phase and always getting that error:

jq: error: $YABAI_SPACE_ID is not defined at <top-level>, line 1:
.[] | select(.id == $YABAI_SPACE_ID).index
jq: 1 compile error

while the echo before it working well is there some special skipping that has to be done inside jq or something !?

snowflake in ~
[I] ➜ () {
  emulate -L zsh -o xtrace -o err_return -o nounset
    yabai -m signal --add event=space_changed \
      action="
        echo 'here' \$YABAI_SPACE_ID \
        && echo 'there' \$YABAI_RECENT_SPACE_ID \
        && YABAI_SPACE_INDEX=\$(yabai -m query --spaces | jq -r '.[] | select(.id == \$YABAI_SPACE_ID).index') \
        && YABAI_RECENT_SPACE_INDEX=\$(yabai -m query --spaces | jq -r '.[] | select(.id == \$YABAI_RECENT_SPACE_ID).index') \
        && echo 'YABAI_SPACE_INDEX' \$YABAI_SPACE_INDEX \
        && echo 'YABAI_RECENT_SPACE_INDEX' \$YABAI_RECENT_SPACE_INDEX \
        && yabai -m query --windows --space \$YABAI_RECENT_SPACE_INDEX \
        | jq 'map(select(.app == \$1))[0].app' \
        | grep \$1 \
        && yabai -m space \$YABAI_SPACE_INDEX --label \$2
    "
}
+(anon):2> yabai -m signal --add 'event=space_changed' $'action=\n        echo \'here\' $YABAI_SPACE_ID         && echo \'there\' $YABAI_RECENT_SPACE_ID         && YABAI_SPACE_INDEX=$(yabai -m query --spaces | jq -r \'.[] | select(.id == $YABAI_SPACE_ID).index\')         && YABAI_RECENT_SPACE_INDEX=$(yabai -m query --spaces | jq -r \'.[] | select(.id == $YABAI_RECENT_SPACE_ID).index\')         && echo \'YABAI_SPACE_INDEX\' $YABAI_SPACE_INDEX         && echo \'YABAI_RECENT_SPACE_INDEX\' $YABAI_RECENT_SPACE_INDEX         && yabai -m query --windows --space $YABAI_RECENT_SPACE_INDEX         | jq \'map(select(.app == $1))[0].app\'         | grep $1         && yabai -m space $YABAI_SPACE_INDEX --label $2\n    '

Screen Shot 2020-04-16 at 1 21 43 PM

Variables in single quotes are not evaluated. You need to be careful about using single or double quotes, as they are not freely interchangeable.

Hey mates, I managed to do it with another different method.
I realized by coincidence that yabai --message query --windows --space list the current space I am currently in, also yabai --message space --create --label <ARG> change the current space
which allows me to do the following:

# Apps Name
CHROME="Google\ Chrome"
EMACS="Emacs"
ITERM2="iTerm2"

yabai --message rule --add app="^${CHROME}$" native-fullscreen=on
yabai --message rule --add app="^${EMACS}$"   native-fullscreen=on
yabai --message rule --add app="^${ITERM2}$"   native-fullscreen=on

# Description:
#  Keep space name dymanic even while moving
#  the app from space to another one
#
# Usage:
#  $ dynamic_space_naming param1 param2
#  * param1: app name
#  * param2: space name you want to use
dynamic_space_naming() {
  yabai --message signal --add \
    event=space_changed \
    action="
      yabai --message query --windows --space \
      | jq -r \".[] | select(.app == \\\"\"$1\"\\\" and .\\\"\"native\-fullscreen\"\\\" == \"1\").app\" \
      | grep \"$1\" \
      && yabai --message space --label \"$2\"
    "
}

dynamic_space_naming "$CHROME" "$CHROME_SPACE"
dynamic_space_naming "$EMACS" "$EMACS_SPACE"
dynamic_space_naming "$ITERM2" "$ITERM2_SPACE"

this allows me to query the current space and make sure it contains the app I passed or not and make sure it's in native-fullscreen, if yes it will set the label if not it will not do anything,

the only drawback I have is if I switched multiple times so fast(like crazy which not happens normally) it lost track and unset all the labels however the current behavior is so satisfying for me, and I don't count this as a problem according to my usage.

@koekeishiya @dominiklohmann Thank you so much guys for helping me doing this πŸ˜„

I have also managed to make the second behavior I mentioned in my question by making some spaces for a specific type of apps by the following :

# Apps Name
DISCORD="Discord"
SLACK="Slack"
MAIL="Mail"
ZOHO="Zoho\ Mail\ \-\ Desktop"
WHATSAPP="WhatsApp"
TELEGRAM="Telegram"
MAC_SYSTEM="System\ Preferences"

#space Labels
WORK_SOCIAL_SPACE="workSocial"
MAIL_SPACE="mail"
SOCIAL_SPACE="social"

# Description:
# create spaces based on the app will be launched
#
# Usage:
#  $ create_space_with_spacfic_label param1 param2
#  * param1: app name
#  * param2: space name you want to create
create_space_with_spacfic_label() {
  yabai --message signal --add \
    event=application_launched \
    action="
      yabai --message query --spaces \
      | jq -r \".[] | select(.label == \\\"\"$2\"\\\")\" \
      | grep \"label\" \
      || \
      ( \
        yabai --message space --create \
        && index=\"\$(yabai --message query --spaces --display | jq \"map(select(.\\\"\"native\-fullscreen\"\\\" == 0))[-1].index\")\" \
        && yabai --message space \$index --label \"$2\"
      ) \
      && yabai --message rule --add app=\"^${1}$\" space=\"$2\"
    " \
    app="^${1}$"
}

create_space_with_spacfic_label "$DISCORD"  "$WORK_SOCIAL_SPACE"
create_space_with_spacfic_label "$SLACK"    "$WORK_SOCIAL_SPACE"
create_space_with_spacfic_label "$MAIL"     "$MAIL_SPACE"
create_space_with_spacfic_label "$ZOHO"     "$MAIL_SPACE"
create_space_with_spacfic_label "$WHATSAPP" "$SOCIAL_SPACE"
create_space_with_spacfic_label "$TELEGRAM" "$SOCIAL_SPACE"

this method search first in the spaces by title if the space exists it will apply the rule to send the app to its space, if not it will create it, then put a label on it[thanks for @koekeishiya I took the idea from his skhdrc] then apply the rule to send it to its space

Just a side note, this is how I write inline signals in my yabairc without having to do all this escaping nonsense.

#! /usr/bin/env zsh

function focus_under_cursor {
  if yabai -m query --windows --space |
      jq -er 'map(select(.focused == 1)) | length == 0' >/dev/null; then
    yabai -m window --focus mouse 2>/dev/null || true
  fi
}

# If no window on the current space is focused after a window is destroyed or
# minimized, or an application is hidden, focus the window under the cursor.
yabai -m signal --add event=window_destroyed \
  action="${functions[focus_under_cursor]}"
yabai -m signal --add event=window_minimized \
  action="${functions[focus_under_cursor]}"
yabai -m signal --add event=application_hidden \
  action="${functions[focus_under_cursor]}"

@dominiklohmann is there a way to do the same style but passing arguments to the functions
I can't do it, and if passed the function name like this focus_under_cursor ARG1 ARG2 it raises error focus_under_cursor not found

It's ugly, but this works:

function focus_under_cursor {
  () {
    if yabai -m query --windows --space |
        jq -er 'map(select(.focused == 1)) | length == 0' >/dev/null; then
      yabai -m window --focus mouse 2>/dev/null || true
    fi
  }
}

Now you can pass arguments to the inner anonymous functions.

I realized that ${functions[hello]} return the body of the function as a string that gets run by sh -c so I made the following workaround

snowflake in ~
[I] ➜ function hello { echo "Heeey" $1 "Hoooy" $2 }

snowflake in ~
[I] ➜ hello foo bar
Heeey foo Hoooy bar

snowflake in ~
[I] ➜ echo $functions[hello]
        echo "Heeey" $1 "Hoooy" $2

snowflake in ~
[I] ➜ sh -c "function hello { ${functions[hello]}; }; hello foo bar"
Heeey foo Hoooy bar

I am returning the body into a function then I called right away,
so passing function hello { ${functions[hello]}; }; hello foo bar to action should work,
but iI liked the way you made it, instead of returning just the body It be will be returning a whole function that takes arguments.

@dominiklohmann when i have tried the anonymous functions as you mentioned above i got the following error, is there something messing here ?

sh: -c: line 0: syntax error near unexpected token `)'
sh: -c: line 0: `       () {'

also when i try it on the terminal got the same error:

[I] ➜ function focus_under_cursor {
  () {
    if yabai -m query --windows --space |
        jq -er 'map(select(.focused == 1)) | length == 0' >/dev/null; then
      yabai -m window --focus mouse 2>/dev/null || true
    fi
  }
}

snowflake in ~
[I] ➜ echo $functions[focus_under_cursor]
        () {
                if yabai -m query --windows --space | jq -er 'map(select(.focused == 1)) | length == 0' > /dev/null
                then
                        yabai -m window --focus mouse 2> /dev/null || true
                fi
        }

snowflake in ~
[I] ➜ sh -c  "$functions[focus_under_cursor]"
sh: -c: line 0: syntax error near unexpected token `)'
sh: -c: line 0: `       () {'

After some straggling and some research, I find out that bash doesn't have anonymous function,
so i tried to make nasted function and call it right away like this, and it worked.

function dynamic_space_naming() {
  anonymous() {
    if yabai -m query --windows --space |
        jq -e "map(select(.app == \"$1\" and .\"native-fullscreen\" == 1)) | length > 0" >/dev/null
    then
      yabai --message space --label "$2";
    fi
  }
  anonymous
}

Glad to see you discovered the issue. I was wrongly assuming zsh to be your default shell. If you want to have it more portable, you can always just name the function as you've shown.

@dominiklohmann strangely zsh is my default shell, but it seems yabai prefer sh/bash over zsh, even that I am putting #!/usr/bin/env zsh at the start of yabairc file.
is there a way other chsh -s $(which zsh) or chsh -s $(brew --prefix zsh) to set zsh as my default shell.

From looking at the source code, yabai always runs sh -c, while skhd runs $SHELL -c. That's a slight difference, but nothing that can't be worked around. You can always prepend your signals with zsh -c.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eraserhd picture eraserhd  Β·  4Comments

stylerw picture stylerw  Β·  4Comments

eramdam picture eramdam  Β·  3Comments

haze picture haze  Β·  4Comments

imjma picture imjma  Β·  3Comments