kakniri.sh

· ficd's pastes · raw

expires: 2026-07-19

 1# First arg always left|right. No need for guards b/c this is private function.
 2direction=$1
 3shift
 4# create fifo for collecting event stream
 5temp=$(mktemp -d kak-niri-XXXXXX)
 6fifo="$temp/fifo"
 7mkfifo "$fifo"
 8# register func to cleanup fifo
 9cleanup() {
10	rm -rf "$temp"
11}
12trap cleanup EXIT INT TERM
13# read event stream to fifo
14niri msg -j event-stream >"$fifo" &
15stream_pid=$!
16# register timeout fallback
17(
18	sleep 3
19	kill "$!" 2>/dev/null
20	kill "$stream_pid" 2>/dev/null
21) >/dev/null 2>&1 </dev/null &
22watchdog_pid=$!
23
24# safely quote arguments for passing to new terminal
25kakquote() {
26	set -- "$*" ""
27	while [ "${1#*\'}" != "$1" ]; do
28		set -- "${1#*\'}" "$2${1%%\'*}''"
29	done
30	printf "'%s' " "$2$1"
31}
32# loop over args and quote all
33quoted_args=''
34for arg in "$@"; do
35	quoted_args="$quoted_args$(kakquote "$arg")"
36done
37# run this block async to avoid user-facing lag
38{
39    # track when new window is ready
40	ready=false
41	# read lines of event stream from fifo
42	#   Note: each line is one event.
43	#   We wait for the event that indicates stream is initialized,
44	#   then we spawn the new terminal window. The next WindowOpenedOrChanged
45	#   event immediately after running niri-terminal-window SHOULD be
46	#   the event for this window, but it's not guaranteed. There is a very,
47	#   very tiny window for a race condition here. Unfortunately, I don't
48	#   believe we have a good way to handle it because there's no way to
49	#   know the window's ID before it's spawned. This may be a good job for
50	#   the Ostrich algorithm (https://en.wikipedia.org/wiki/Ostrich_algorithm)
51	while IFS= read -r line; do
52	    # each line is a JSON object
53		case "$line" in
54		# this line means stream is initialized
55		*"OverviewOpenedOrClosed"*)
56		    # guard to avoid spawning terminal twice
57			if [ "$ready" = false ]; then
58				ready=true
59				# spawn terminal with command
60				printf 'niri-terminal-window %s' "$quoted_args" >"$kak_command_fifo"
61			fi
62			;;
63		# newly opened window is now available to act on
64		*"WindowOpenedOrChanged"*)
65		    # only operate if window isn't floating
66		    # This accursed incantation is to access the JSON field
67		    # without depending on jq.
68			if expr "${line}" : '.*"is_floating":[[:space:]]*false.*' \
69				>/dev/null; then
70				# handle new window being unfocused
71				if expr "${line}" : '.*"is_focused":[[:space:]]*false.*' \
72					>/dev/null; then
73					# extract the window ID
74					# (POSIX compliant JSON parsing is ugly, sorry)
75					id="$(echo "$line" | sed -n 's/.*"id":[[:space:]]*\([0-9][0-9]*\).*/\1/p')"
76					# focus the new window
77					niri msg action focus-window --id "$id"
78				fi
79				# consume the new window in specified direction
80				niri msg action consume-or-expel-window-${direction}
81			fi
82			# close the stream reader and timeout watchdog
83			kill "$stream_pid"
84			wait "$stream_pid" 2>/dev/null
85			kill "$watchdog_pid" 2>/dev/null
86			exit 0
87			;;
88		esac
89	done <"$fifo"
90} >/dev/null 2>&1 </dev/null &