Skip to content

Commit

Permalink
Finalize status conversion to JSON
Browse files Browse the repository at this point in the history
- add flag to dkcmd `-p` to prettify status output
- update README and manpage
- add example for scratchpad terminal at startup to dkrc
- rewrite bar script to use new status and better performance
- simple window info for `ws` and `bar` type status
  • Loading branch information
natemaia committed Apr 5, 2024
1 parent b8899f5 commit 9fff894
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 256 deletions.
28 changes: 19 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ Most of your interaction with the window manager will be using `dkcmd`
which writes one or more commands into the socket where it is then read
and parsed by the window manager *(see Commands section below)*.

dkcmd accepts one flag with an optional file argument
- `-p` Pretty format JSON input from passed file or STDIN and print on STDOUT.


```bash
dkcmd status type=bar num=1 | dkcmd -p

# or
dkcmd -p output.json
```

### Syntax Outline
The commands have a very basic syntax and parsing, the input is broken
down into smaller pieces *(tokens)* which are then passed to the matching
Expand Down Expand Up @@ -645,21 +656,20 @@ win [CLIENT] resize x=center y=center w=1280 h=720 bw=1
---

#### Status
`status` print status information to a file or stdout.
`status` print status information as JSON to a file or stdout.

``` bash
status [TYPE] [FILE] [NUM]
```

###### Subcommands
`type` (string) the type of status info to output.

- `ws` output workspace info.
- `win` output current window title.
- `layout` output current workspace layout name.
- `bar` output simple info for use in bars *(win, layout, and ws combined)*.
- `full` output the full wm and managed client state.
- `json` same as full but output in JSON format.
`type` (string) the type of status info to output and when to trigger.

- `ws` output full workspace info - triggers on workspace change.
- `win` output current window title - triggers on window or title change.
- `layout` output current layout name - triggers on layout change.
- `bar` identical output to `ws` except - triggers on all changes.
- `full` output full wm and client state - triggers on all changes.

``` bash
status type=ws [FILE] [NUM]
Expand Down
5 changes: 5 additions & 0 deletions doc/dkrc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ if hash sxhkd >/dev/null 2>&1; then
sxhkd -c "$HOME/.config/dk/sxhkdrc" &
fi

# spawn a scratchpad terminal if not already (see sxhkdrc and rules for bind and setup)
# if ! pgrep -f "st -c scratchpad" >/dev/null 2>&1; then
# st -c scratchpad &
# fi

# adjust border widths based on the DPI of the monitor
px=$(xrandr | grep ' connected' | tail -n1 | grep -o '[0-9]\+x[0-9]\+' | cut -d'x' -f2)
mm=$(xrandr | grep ' connected' | tail -n1 | grep -o '[0-9]\+mm' | tail -n1 | sed 's/mm//')
Expand Down
199 changes: 144 additions & 55 deletions doc/scripts/bar.sh
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
#!/bin/bash
# shellcheck disable=SC2059,SC2064,SC2086
# shellcheck disable=SC2059,SC2064,SC2086,SC2001,SC2016

# simple lightweight lemonbar script for use with dk

set -eE -o pipefail

bg="#111111"
fg="#666666"
highlight="#6699ee"
underline=3
separator=""

# xfonts
font0="-xos4-terminus-medium-r-normal--24-240-72-72-c-120-iso10646-1"
font1=""
font2=""
font3=""

# xft fonts
# font0="monospace:pixelsize=24"
# font1="Font Awesome 5 Brands:pixelsize=20"
# font2="icomoon:pixelsize=18"
# font3="Anonymice Nerd Font Mono:pixelsize=18"

bg="#111111" # background colour
fg="#666666" # foreground colour
hi="#6699ee" # highlight colour
ul=3 # underline thickness
sep="" # separator text
font="-xos4-terminus-medium-r-normal--12-240-72-72-c-120-iso10646-1"
fifo="/tmp/bar.fifo"

# adjust font size based on resolution DPI
px=$(xrandr | grep ' connected' | tail -n1 | grep -o '[0-9]\+x[0-9]\+' | cut -d'x' -f2)
mm=$(xrandr | grep ' connected' | tail -n1 | grep -o '[0-9]\+mm' | tail -n1 | sed 's/mm//')
dpi=$(( (px / mm) * 25 ))
if (( dpi >= 140 )); then
font="-xos4-terminus-medium-r-normal--24-240-72-72-c-120-iso10646-1"
elif (( dpi >= 120 )); then
font="-xos4-terminus-medium-r-normal--18-240-72-72-c-120-iso10646-1"
elif (( dpi >= 100 )); then
font="-xos4-terminus-medium-r-normal--14-240-72-72-c-120-iso10646-1"
fi

# mimic dwm style layout symbols
typeset -A layouts=(
[tile]="[]="
[rtile]="=[]"
[mono]="[M]"
[none]="><>"
[grid]="###"
Expand All @@ -37,30 +39,48 @@ typeset -A layouts=(

clock()
{
# sync up the clock to the minute mark
now="$(date +"T %a %H:%M ")"
printf "%s\n" "$now"
while [[ $(date +"T %a %H:%M ") != "$now" ]]; do
sleep 1
done

if [[ $1 ]]; then
while :; do
date +"T%%{A1:$1:} %a %H:%M %%{A}"
sleep 10
sleep 60
done
else
while :; do
date +"T %a %H:%M "
sleep 10
sleep 60
done
fi
}

battery()
{
lvl=$(acpi --battery 2>/dev/null | grep -v 'Unknown\| 0%' | cut -d, -f2 | tr -d '[:space:]')
[[ ! $lvl ]] && return # no battery so we don't need to continue

if [[ $1 ]]; then
while :; do
printf 'B%s\n' "%{A1:$1:} $(acpi --battery 2>/dev/null | cut -d, -f2 | tr -d '[:space:]') %{A}"
sleep 10
bat="$(acpi --battery 2>/dev/null | grep -v 'Unknown\| 0%' | cut -d, -f2 | tr -d '[:space:]')"
if [[ $lastb != "$bat" ]]; then
lastb="$bat"
printf 'B%s\n' "%{A1:$1:} Bat: ${bat} %{A}${sep}"
fi
sleep 120
done
else
while :; do
printf 'B%s\n' " $(acpi --battery 2>/dev/null | cut -d, -f2 | tr -d '[:space:]') "
sleep 10
bat="$(acpi --battery 2>/dev/null | grep -v 'Unknown\| 0%' | cut -d, -f2 | tr -d '[:space:]')"
if [[ $lastb != "$bat" ]]; then
lastb="$bat"
printf 'B%s\n' " Bat: ${bat} ${sep}"
fi
sleep 120
done
fi
}
Expand All @@ -69,70 +89,139 @@ volume()
{
if [[ $1 ]]; then
while :; do
printf 'V%s\n' "%{A1:$1:} $(pamixer --get-volume-human) %{A}"
sleep 0.2
vol="$(pamixer --get-volume-human)"
if [[ $lastv != "$vol" ]]; then
lastv=$vol
printf 'V%s\n' "%{A1:$1:} Vol: $vol %{A}${sep}"
fi
sleep 1
done
else
while :; do
vol="$(pamixer --get-volume-human)"
if [[ $lastv != "$vol" ]]; then
lastv=${vol}
printf 'V%s\n' " Vol: ${vol} ${sep}"
fi
sleep 1
done
fi
}

network()
{
check()
{
if hash nm-online > /dev/null 2>&1 && [[ $(systemctl is-active NetworkManager.service) == "active" ]]; then
nm-online > /dev/null 2>&1
else
ping -qc1 'archlinux.org' > /dev/null 2>&1
fi
}

if [[ $1 ]]; then
while :; do
printf 'N%s\n' "%{A1:$1:} disconnected %{A}${sep}"
until check; do
sleep 30
done
printf 'N%s\n' "%{A1:$1:} connected %{A}${sep}"
while :; do
sleep 300
check || break
done
done
else
while :; do
printf 'V%s\n' " $(pamixer --get-volume-human) "
sleep 0.2
printf 'N%s\n' " disconnected ${sep}"
until check; do
sleep 30
done
printf 'N%s\n' " connected ${sep}"
while :; do
sleep 300
check || break
done
done
fi
}

workspaces()
{
# these will be filled out once we eval each line
typeset name="" title="" layout="" focused=false active=false

WS=""
OFS=$IFS
while IFS=$'\n' read -r ws; do
if [[ $ws ]]; then
eval "$ws"
# default foreground, background, and underline colours
# changing the foreground and underline based on
# the active and focused state
f="$fg" b="$bg" u="$fg";
$active && u="$hi"
if $focused; then
# clicking the layout symbol will cycle the layout
lyt="%{A:dkcmd set layout cycle:}${layouts[$layout]}%{A}"
WIN="${title:0:50}"
f="$hi"
fi
# clicking on a workspace name will view it
WS="$WS%{F$f}%{B$b}%{+u}%{U$u}%{A:dkcmd ws $name:} $name %{A}%{-u}%{B-}%{F-}"
fi
# turn the dk JSON output into lines that can be `eval`ed one by one,
# filling out the following fields: name, focused, active, layout, title
done < <(sed 's/.*:\[\|\].*\|},\?\|$(.*)//g;
s/{/\n/g;
s/,"/ "/g;
s/"\([a-zA-Z0-9_]*\)":/\1=/g' <<< "$1")
IFS=$OFS
WS="$WS $sep $lyt"
}

parsefifo()
{
typeset f='' b='' u='' wm='' time='' bat='' vol='' title='' layout='' s="$separator"
# globals to simplify the workspaces call
declare -g WS WIN

local time vol bat net

while read -r line; do
case $line in
T*) time="${line#?}" ;;
V*) vol="${line#?}" ;;
B*) bat="${line#?}" ;;
A*) title="${line#?}" ;;
L*) l="${line#?}"; layout="${layouts[$l]}" ;;
W*)
wm='' IFS=':' # set the internal field separator to ':'
set -- ${line#?} # split the line into arguments ($@) based on the field separator
for item in "$@"; do
name=${item#?}
case $item in
A*) f="$highlight" b="$bg" u="$highlight" ;; # occupied - focused
a*) f="$fg" b="$bg" u="$highlight" ;; # occupied - unfocused
I*) f="$highlight" b="$bg" u="$fg" ;; # unoccupied - focused
i*) f="$fg" b="$bg" u="$fg" ;; # unoccupied - unfocused
esac
wm="$wm%{F$f}%{B$b}%{+u}%{U$u}%{A:dkcmd ws $name:} $name %{A}%{-u}%{B-}%{F-}"
done
;;
N*) net="${line#?}" ;;
'{'*) workspaces "$line" ;;
esac
printf "%s\n" "%{l}$wm $s $layout%{c}$title%{r}${bat}${s}${vol}${s}${time}"
printf "%s\n" "%{l}${WS}%{c}${WIN}%{r}${net}${bat}${vol}${time}"
done
}


# kill the process and cleanup if we exit or get killed
trap "trap - TERM; kill 0; rm -f '$fifo'" INT TERM QUIT EXIT
trap "trap - TERM; rm -f '$fifo'; kill 0" INT TERM QUIT EXIT PIPE

# make the fifo
[ -e "$fifo" ] && rm "$fifo"
mkfifo "$fifo"


# here we dump info into the FIFO, order does not matter things are parsed
# out using the first character of the line. Click commands for left button
# can be added by passing an argument containing the command (like volume below)
clock '' > "$fifo" &
# can be added by passing an argument containing the command (like below)
#
# comment a line to remove the "module"
network '' > "$fifo" &
clock 'gsimplecal' > "$fifo" &
battery '' > "$fifo" &
volume 'pavucontrol' > "$fifo" &
dkcmd status type=bar > "$fifo" &


# run the pipeline
if [[ $1 == '-b' ]]; then
parsefifo < "$fifo" | lemonbar -b -a 32 -u $underline -B "$bg" -F "$fg" -f "$font0" -f "$font1" -f "$font2" -f "$font3" | sh
parsefifo < "$fifo" | lemonbar -b -a 32 -u $ul -B "$bg" -F "$fg" -f "$font" | sh;
else
parsefifo < "$fifo" | lemonbar -a 32 -u $underline -B "$bg" -F "$fg" -f "$font0" -f "$font1" -f "$font2" -f "$font3" | sh
parsefifo < "$fifo" | lemonbar -a 32 -u $ul -B "$bg" -F "$fg" -f "$font" | sh
fi

# vim:ft=sh:fdm=marker:fmr={,}
22 changes: 13 additions & 9 deletions man/dk.1
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ dk \- A tiling window manager in the vein of dwm, bspwm, and xmonad.
.SH SYNOPSIS
.B dk
.RB [ \-vh ]
.PP
.B dkcmd
.RB [ \-vh ]\ [ \-p\ [ FILE ] ]\ [ COMMAND ]
.SH DESCRIPTION
.PP
Windows are managed in various layouts, and are grouped by workspaces.
Expand Down Expand Up @@ -41,6 +44,9 @@ Prints usage information to stdout and exits.
.TP
.B \-v
Prints version information to stdout and exits.
.TP
.B \-p
Pretty format JSON input from FILE or STDIN and print on STDOUT.
.SH CUSTOMIZATION
For basic changes dk can be customized by running commands through the
.B dkcmd
Expand Down Expand Up @@ -814,7 +820,7 @@ win [CLIENT] resize x=center y=center w=1280 h=720 bw=1
\l'60'
.SS Status
.PP
\fI\fCstatus\fR operates on windows.
\fI\fCstatus\fR print status information as JSON to a file or stdout.
.IP
.nf
\fI\fC
Expand All @@ -823,19 +829,17 @@ status [TYPE] [FILE] [NUM]
.fi
.SS Settings
.PP
\fI\fCtype\fR the type of status to output.
.IP \[bu] 2
\fI\fCws\fR output workspace info.
\fI\fCtype\fR the type of status to output and when to trigger.
.IP \[bu] 2
\fI\fCwin\fR output current window title.
\fI\fCws\fR output full workspace info - triggers on workspace change.
.IP \[bu] 2
\fI\fClayout\fR output current workspace layout name.
\fI\fCwin\fR output current window title - triggers on window or title change.
.IP \[bu] 2
\fI\fCbar\fR output simple info for use in bars (win, layout, and ws combined).
\fI\fClayout\fR output current layout name - triggers on layout change.
.IP \[bu] 2
\fI\fCfull\fR output the full wm and managed client state.
\fI\fCbar\fR identical output to `ws` except - triggers on all changes.
.IP \[bu] 2
\fI\fCjson\fR same as full but output in JSON format.
\fI\fCfull\fR output full wm and client state - triggers on all changes.
.IP
.nf
\fI\fC
Expand Down
Loading

0 comments on commit 9fff894

Please sign in to comment.