feat(waybar): use slider, not gtk

This commit is contained in:
Barrett Ruth 2026-03-03 00:00:57 -05:00
parent db7edb13b8
commit 58d0d818dc
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
14 changed files with 285 additions and 294 deletions

30
README.html Normal file
View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>README</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<style type="text/css">Couldn't find the requested file /github.css in pixelbrackets/gfm-stylesheet.</style>
</head>
<body>
<h1 id="nix">nix</h1>
<p>my nix configuration</p>
</body>
</html>

6
config/cp/template.py Normal file
View file

@ -0,0 +1,6 @@
def main() -> None:
<++>
if __name__ == '__main__':
main()

View file

@ -0,0 +1,58 @@
#include <bits/stdc++.h> // {{{
#include <version>
#ifdef __cpp_lib_ranges_enumerate
#include <ranges>
namespace rv = std::views;
namespace rs = std::ranges;
#endif
#pragma GCC optimize("O2,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
using namespace std;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using f64 = double;
using f128 = long double;
#if __cplusplus >= 202002L
template <typename T>
constexpr T MIN = std::numeric_limits<T>::min();
template <typename T>
constexpr T MAX = std::numeric_limits<T>::max();
#endif
#ifdef LOCAL
#define db(...) std::print(__VA_ARGS__)
#define dbln(...) std::println(__VA_ARGS__)
#else
#define db(...)
#define dbln(...)
#endif
// }}}
void solve() {
<++>
}
int main() { // {{{
std::cin.exceptions(std::cin.failbit);
#ifdef LOCAL
std::cerr.rdbuf(std::cout.rdbuf());
std::cout.setf(std::ios::unitbuf);
std::cerr.setf(std::ios::unitbuf);
#else
std::cin.tie(nullptr)->sync_with_stdio(false);
#endif
u32 tc = 1;
std::cin >> tc;
for (u32 t = 0; t < tc; ++t) {
solve();
}
return 0;
} // }}}

View file

@ -0,0 +1,54 @@
#include <bits/stdc++.h> // {{{
#include <version>
#ifdef __cpp_lib_ranges_enumerate
#include <ranges>
namespace rv = std::views;
namespace rs = std::ranges;
#endif
#pragma GCC optimize("O2,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
using namespace std;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using f64 = double;
using f128 = long double;
#if __cplusplus >= 202002L
template <typename T>
constexpr T MIN = std::numeric_limits<T>::min();
template <typename T>
constexpr T MAX = std::numeric_limits<T>::max();
#endif
#ifdef LOCAL
#define db(...) std::print(__VA_ARGS__)
#define dbln(...) std::println(__VA_ARGS__)
#else
#define db(...)
#define dbln(...)
#endif
// }}}
void solve() {
<++>
}
int main() { // {{{
std::cin.exceptions(std::cin.failbit);
#ifdef LOCAL
std::cerr.rdbuf(std::cout.rdbuf());
std::cout.setf(std::ios::unitbuf);
std::cerr.setf(std::ios::unitbuf);
#else
std::cin.tie(nullptr)->sync_with_stdio(false);
#endif
solve();
return 0;
} // }}}

View file

@ -128,7 +128,7 @@ bind = ALT SHIFT, E, exec, hypr spawnfocus --ws 8 element-desktop
bind = , XF86Tools, submap, scripts
submap = scripts
bind = , A, exec, hyprctl dispatch submap reset; ctl audio out
bind = , A, exec, hyprctl dispatch submap reset; ctl audio sink
bind = , C, exec, hyprctl dispatch submap reset; sh -lc 'cliphist list | fuzzel --width 65 --dmenu --prompt="copy: " | cliphist decode | wl-copy'
bind = , I, exec, hyprctl dispatch submap reset; ctl idle
bind = , K, exec, hyprctl dispatch submap reset; ctl keyboard next
@ -192,7 +192,5 @@ windowrule = match:class ^(xdg-desktop-portal-kde)$, size monitor_w * 0.5 monito
windowrule = match:class ^(xdg-desktop-portal-hyprland)$, float on
windowrule = match:class ^(xdg-desktop-portal-hyprland)$, size monitor_w * 0.5 monitor_h * 0.6
windowrule = match:class ^(org.pulseaudio.pavucontrol)$, float on
windowrule = match:class ^(org.pulseaudio.pavucontrol)$, size 600 450
windowrule = match:class ^([Ss]ioyek)$, tile on

View file

@ -1,33 +1,2 @@
vim.o.conceallevel = 1
vim.o.textwidth = 80
local buf = vim.api.nvim_get_current_buf()
local opened = false
vim.api.nvim_create_autocmd('User', {
pattern = 'RenderCompileSuccess',
callback = function(args)
if args.data.bufnr ~= buf then
return
end
local html = args.data.output
if not opened and html and html ~= '' then
opened = true
vim.system({ 'xdg-open', html })
end
end,
})
vim.api.nvim_create_autocmd('BufWritePost', {
buffer = buf,
callback = function()
local ok, render = pcall(require, 'render')
if ok then
render.compile(buf)
end
end,
})
vim.keymap.set('n', '<leader>t', function()
require('render').compile(buf)
end, { buffer = true })

View file

@ -1,17 +0,0 @@
vim.keymap.set('n', '<leader>t', function()
require('render').compile()
vim.api.nvim_create_autocmd('User', {
pattern = 'RenderCompileSuccess',
once = true,
callback = function(args)
local pdf = args.data.output
if not pdf or pdf == '' then
return
end
if vim.fn.executable('sioyek') ~= 1 then
return vim.notify('sioyek not found', vim.log.levels.ERROR)
end
vim.system({ 'sioyek', '--new-instance', pdf })
end,
})
end, { buffer = true })

View file

@ -1,12 +1,12 @@
local dev_plugins = {
'midnight.nvim',
'live-server.nvim',
'nonicons.nvim',
'canola.nvim',
'pending.nvim',
'cp.nvim',
'diffs.nvim',
'render.nvim',
'preview.nvim',
'fzf-lua',
}
local opt_dir = vim.fn.stdpath('data') .. '/site/pack/dev/opt/'
@ -76,116 +76,6 @@ AlignAfterOpenBracket: Align
BinPackArguments: false
BinPackParameters: false]]
local cpp_base = [[#include <bits/stdc++.h> // {{{
#include <version>
#ifdef __cpp_lib_ranges_enumerate
#include <ranges>
namespace rv = std::views;
namespace rs = std::ranges;
#endif
#pragma GCC optimize("O2,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
using namespace std;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using f64 = double;
using f128 = long double;
#if __cplusplus >= 202002L
template <typename T>
constexpr T MIN = std::numeric_limits<T>::min();
template <typename T>
constexpr T MAX = std::numeric_limits<T>::max();
#endif
#ifdef LOCAL
#define db(...) std::print(__VA_ARGS__)
#define dbln(...) std::println(__VA_ARGS__)
#else
#define db(...)
#define dbln(...)
#endif
// }}}
void solve() {
<++>
}
int main() { // {{{
std::cin.exceptions(std::cin.failbit);
#ifdef LOCAL
std::cerr.rdbuf(std::cout.rdbuf());
std::cout.setf(std::ios::unitbuf);
std::cerr.setf(std::ios::unitbuf);
#else
std::cin.tie(nullptr)->sync_with_stdio(false);
#endif
]]
local cpp_single = cpp_base .. [[ solve();
return 0;
} // }}}]]
local cpp_multi = cpp_base
.. [[ u32 tc = 1;
std::cin >> tc;
for (u32 t = 0; t < tc; ++t) {
solve();
}
return 0;
} // }}}]]
local templates = {
cpp = {
default = cpp_multi,
codeforces = cpp_multi,
atcoder = cpp_single,
cses = cpp_single,
},
python = {
default = [[def main() -> None:
<++>
if __name__ == '__main__':
main()]],
},
}
local function insert_template(buf, lang, platform)
local lang_templates = templates[lang]
if not lang_templates then
return false
end
local template = lang_templates[platform] or lang_templates.default
if not template then
return false
end
local lines = vim.split(template, '\n')
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
for lnum, line in ipairs(lines) do
local col = line:find('<++>', 1, true)
if col then
local new_line = line:sub(1, col - 1) .. line:sub(col + 4)
vim.api.nvim_buf_set_lines(buf, lnum - 1, lnum, false, { new_line })
vim.api.nvim_win_set_cursor(0, { lnum, col - 1 })
break
end
end
return true
end
return {
{
'barrettruth/midnight.nvim',
@ -196,7 +86,7 @@ return {
},
{
'barrettruth/live-server.nvim',
enabled = false,
enabled = true,
before = function()
vim.g.live_server = {
debug = false,
@ -204,10 +94,6 @@ return {
end,
keys = { { '<leader>l', '<cmd>LiveServerToggle<cr>' } },
},
{
'barrettruth/nonicons.nvim',
enabled = true,
},
{
'barrettruth/canola.nvim',
enabled = true,
@ -281,7 +167,7 @@ return {
before = function()
vim.g.pending = { debug = true }
end,
keys = { { '<leader>p', '<cmd>Pending<cr>' } },
keys = { { '<leader>P', '<cmd>Pending<cr>' } },
},
{
'barrettruth/cp.nvim',
@ -301,6 +187,7 @@ return {
languages = {
cpp = {
extension = 'cc',
template = '~/.config/nix/config/cp/template_multi.cc',
commands = {
build = {
'g++',
@ -338,6 +225,7 @@ return {
},
python = {
extension = 'py',
template = '~/.config/nix/config/cp/template.py',
commands = {
run = { 'python', '{source}' },
debug = { 'python', '{source}' },
@ -352,8 +240,15 @@ return {
atcoder = {
enabled_languages = { 'cpp', 'python' },
default_language = 'cpp',
overrides = {
cpp = { template = '~/.config/nix/config/cp/template_single.cc' },
},
},
cses = {
overrides = {
cpp = { template = '~/.config/nix/config/cp/template_single.cc' },
},
},
cses = {},
},
ui = {
picker = 'fzf-lua',
@ -372,7 +267,7 @@ return {
before_debug = function(_)
require('config.lsp').format()
end,
setup_code = function(state)
setup_code = function(_)
vim.opt_local.winbar = ''
vim.opt_local.foldlevel = 0
vim.opt_local.foldmethod = 'marker'
@ -381,18 +276,18 @@ return {
vim.diagnostic.enable(false)
local buf = vim.api.nvim_get_current_buf()
local lines =
vim.api.nvim_buf_get_lines(buf, 0, 1, true)
if #lines > 1 or (#lines == 1 and lines[1] ~= '') then
return
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
for lnum, line in ipairs(lines) do
local col = line:find('<++>', 1, true)
if col then
local new_line = line:sub(1, col - 1) .. line:sub(col + 4)
vim.api.nvim_buf_set_lines(buf, lnum - 1, lnum, false, { new_line })
vim.api.nvim_win_set_cursor(0, { lnum, col - 1 })
break
end
end
local lang = state.get_language()
local platform = state.get_platform()
insert_template(buf, lang, platform)
local clang_format_path = vim.fn.getcwd()
.. '/.clang-format'
local clang_format_path = vim.fn.getcwd() .. '/.clang-format'
if vim.fn.filereadable(clang_format_path) == 0 then
vim.fn.writefile(
vim.split(clang_format, '\n'),
@ -408,55 +303,20 @@ return {
end,
},
{
'barrettruth/render.nvim',
'barrettruth/preview.nvim',
ft = { 'typst', 'tex', 'markdown' },
before = function()
vim.g.render = {
providers = {
typst = {
cmd = { 'typst', 'compile' },
args = function(ctx)
return { ctx.file }
end,
output = function(ctx)
return ctx.file:gsub('%.typ$', '.pdf')
end,
},
latexmk = {
cmd = { 'latexmk' },
args = function(ctx)
return { '-pdf', '-interaction=nonstopmode', ctx.file }
end,
output = function(ctx)
return ctx.file:gsub('%.tex$', '.pdf')
end,
clean = { 'latexmk', '-c' },
},
pandoc = {
cmd = { 'pandoc' },
args = function(ctx)
local output = ctx.file:gsub('%.md$', '.html')
return { ctx.file, '-s', '--embed-resources', '-o', output }
end,
output = function(ctx)
return ctx.file:gsub('%.md$', '.html')
end,
clean = function(ctx)
return { 'rm', '-f', ctx.file:gsub('%.md$', '.html') }
end,
},
},
providers_by_ft = {
typst = 'typst',
tex = 'latexmk',
markdown = 'pandoc',
},
}
after = function()
local presets = require('preview.presets')
require('preview').setup({
'github',
typst = vim.tbl_deep_extend('force', presets.typst, {
open = { 'sioyek', '--new-instance' },
}),
tex = vim.tbl_deep_extend('force', presets.latex, {
open = { 'sioyek', '--new-instance' },
}),
})
end,
keys = {
{ '<leader>rr', '<cmd>Render compile<cr>' },
{ '<leader>rs', '<cmd>Render stop<cr>' },
{ '<leader>rc', '<cmd>Render clean<cr>' },
},
keys = { { '<leader>p', '<cmd>Preview toggle<cr>' } },
},
}

View file

@ -1,12 +1,8 @@
vim.pack.add({
'https://github.com/ibhagwan/fzf-lua',
}, { load = function() end })
return {
'ibhagwan/fzf-lua',
'barrettruth/fzf-lua',
after = function()
local fzf = require('fzf-lua')
local has_icons = pcall(require, 'nonicons')
local has_nonicons = pcall(require, 'nonicons')
local opts = {
file_icon_padding = ' ',
@ -85,8 +81,8 @@ return {
},
}
opts.files.file_icons = has_icons
opts.grep.file_icons = has_icons
opts.files.file_icons = has_nonicons and 'nonicons' or false
opts.grep.file_icons = has_nonicons and 'nonicons' or false
opts.grep.rg_opts =
fzf.defaults.grep.rg_opts:gsub('%-e$', "--glob='!.git/' -e")

View file

@ -242,25 +242,4 @@ return {
}
end,
},
{
'lewis6991/gitsigns.nvim',
enabled = false,
event = 'DeferredUIEnter',
after = function()
require('gitsigns').setup({
signs = {
add = { text = '' },
change = { text = '' },
delete = { text = '_' },
topdelete = { text = '' },
changedelete = { text = '' },
},
})
end,
keys = {
{ ']g', '<cmd>Gitsigns next_hunk<cr>' },
{ '[g', '<cmd>Gitsigns prev_hunk<cr>' },
{ '<leader>gB', '<cmd>Gitsigns toggle_current_line_blame<cr>' },
},
},
}

View file

@ -32,10 +32,6 @@
"rev": "f2634758455cfa52a8acea6f142dcd6271a1bf57",
"src": "https://github.com/monaqa/dial.nvim"
},
"fzf-lua": {
"rev": "d637241b34f2cb012309baebb2e35e440a946d8b",
"src": "https://github.com/ibhagwan/fzf-lua"
},
"gitsigns.nvim": {
"rev": "9f3c6dd7868bcc116e9c1c1929ce063b978fa519",
"src": "https://github.com/lewis6991/gitsigns.nvim"

View file

@ -17,6 +17,8 @@ let
#workspaces button:hover { background: ${palette.bgAlt}; }
#window { color: ${palette.fgAlt}; }
tooltip { background: ${palette.bgAlt}; color: ${palette.fg}; border: 1px solid ${palette.border}; }
#pulseaudio-slider trough { background: ${palette.bgAlt}; }
#pulseaudio-slider highlight { background: ${palette.accent}; }
'';
hexToFuzzel = hex: "${builtins.substring 1 6 hex}ff";
@ -91,7 +93,6 @@ in
glib.bin
gsettings-desktop-schemas
(python3.withPackages (ps: [ ps.pillow ]))
pavucontrol
];
programs.waybar = {
@ -158,7 +159,7 @@ in
return-type = "json";
interval = 1;
signal = 2;
on-click = "pgrep pavucontrol && pkill pavucontrol || pavucontrol --tab=4";
on-click = "ctl audio source";
on-click-middle = "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle";
on-scroll-up = "wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%+ --limit 1.0";
on-scroll-down = "wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%-";
@ -177,7 +178,8 @@ in
signal = 1;
tooltip = true;
tooltip-format = "Volume: {volume}%\nOutput: {desc}";
on-click = "pgrep pavucontrol && pkill pavucontrol || pavucontrol --tab=3";
on-click = "ctl audio sink";
on-click-right = "pgrep -f 'waybar.*slider' && pkill -f 'waybar.*slider' || (waybar -c ${config.xdg.configHome}/waybar/slider.json &)";
on-click-middle = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
on-scroll-up = "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ --limit 1.0";
on-scroll-down = "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-";
@ -289,6 +291,22 @@ in
#custom-power {
padding: 0 16px 0 10px;
}
#pulseaudio-slider {
padding: 0 10px;
}
#pulseaudio-slider trough {
min-width: 150px;
min-height: 4px;
}
#pulseaudio-slider slider {
min-width: 0;
min-height: 0;
background: transparent;
border: none;
}
'';
};
@ -326,6 +344,20 @@ in
xdg.configFile."waybar/themes/midnight.css".text = mkWaybarTheme config.palettes.midnight;
xdg.configFile."waybar/themes/daylight.css".text = mkWaybarTheme config.palettes.daylight;
xdg.configFile."waybar/slider.json".text = builtins.toJSON {
position = "top";
layer = "top";
height = 38;
"margin-top" = 38;
exclusive = false;
"modules-right" = [ "pulseaudio/slider" ];
"pulseaudio/slider" = {
min = 0;
max = 100;
orientation = "horizontal";
};
};
xdg.configFile."fuzzel/fuzzel.ini".text = ''
include=${config.xdg.configHome}/fuzzel/themes/theme.ini

View file

@ -42,7 +42,19 @@ keyboard)
;;
pick)
require fuzzel
choice=$(printf 'QWERTY\nDvorak\nColemak' | fuzzel --dmenu --prompt="keyboard: " --lines=3 --no-icons)
variant=$(hyprctl getoption input:kb_variant 2>/dev/null | awk '/^str:/{print $2}' | cut -d, -f2)
case "$variant" in
dvorak) current="Dvorak" ;;
colemak) current="Colemak" ;;
*) current="QWERTY" ;;
esac
choice=$(printf 'QWERTY\nDvorak\nColemak' | \
awk -v cur="$current" '{
prefix = ($0 == cur) ? " > " : " "
printf "%s%s\t%s\n", prefix, $0, $0
}' | \
fuzzel --dmenu --prompt="kbd: " --no-icons --lines=3 \
--with-nth=1 --accept-nth=2 --width=24)
[ -z "$choice" ] && exit 0
case "$choice" in
QWERTY) variant="" ;;
@ -62,32 +74,52 @@ keyboard)
esac
;;
audio)
require wpctl pw-dump jq
require wpctl pw-dump jq fuzzel
case "$2" in
out)
sinks="$(pw-dump | jq -r '.[] | select(.info.props."media.class" == "Audio/Sink") | "\(.id)\t\(.info.props."node.description" // .info.props."node.name" // "unknown")"')"
[ -z "$sinks" ] && exit 0
if [ "$XDG_SESSION_TYPE" = x11 ]; then
choice="$(printf "%s\n" "$sinks" | awk -F'\t' '{print $1": "$2}' | dmenu -i -p "select sink:" | cut -d: -f1)"
sink|source)
if [ "$2" = sink ]; then
class="Audio/Sink"
prompt="sink: "
default_meta="default.audio.sink"
pad=7
else
count=$(printf "%s\n" "$sinks" | wc -l)
choice="$(printf "%s\n" "$sinks" | awk -F'\t' '{print $1": "$2}' | fuzzel --dmenu --prompt="sink: " --lines="$count" | cut -d: -f1)"
class="Audio/Source"
prompt="source: "
default_meta="default.audio.source"
pad=8
fi
[ "$choice" ] && wpctl set-default "$choice"
;;
in)
sources="$(pw-dump | jq -r '.[] | select(.info.props."media.class" == "Audio/Source") | "\(.id)\t\(.info.props."node.description" // .info.props."node.name" // "unknown")"')"
[ -z "$sources" ] && exit 0
if [ "$XDG_SESSION_TYPE" = x11 ]; then
choice="$(printf "%s\n" "$sources" | awk -F'\t' '{print $1": "$2}' | dmenu -i -p "select source:" | cut -d: -f1)"
else
count=$(printf "%s\n" "$sources" | wc -l)
choice="$(printf "%s\n" "$sources" | awk -F'\t' '{print $1": "$2}' | fuzzel --dmenu --prompt="source: " --lines="$count" | cut -d: -f1)"
fi
[ "$choice" ] && wpctl set-default "$choice"
dump=$(pw-dump)
devices=$(printf '%s' "$dump" | jq -r --arg class "$class" \
'.[] | select(.info.props."media.class" == $class) | "\(.id)\t\(.info.props."node.description" // .info.props."node.name" // "unknown")\t\(.info.props."node.name" // "")"')
[ -z "$devices" ] && exit 0
default_name=$(printf '%s' "$dump" | jq -r --arg key "$default_meta" \
'.[] | select(.type == "PipeWire:Interface:Metadata" and .info.props."metadata.name" == "default") | .info.metadata[] | select(.key == $key) | .value | fromjson | .name')
rows=$(printf '%s\n' "$devices" | while IFS="$(printf '\t')" read -r id name node_name; do
active=$([ "$node_name" = "$default_name" ] && echo ">" || echo "")
printf '%s\t%s\t%s\n' "$id" "$name" "$active"
done)
[ -z "$rows" ] && exit 0
w1=$(printf '%s\n' "$rows" | awk -F'\t' 'BEGIN{m=11}{l=length($2);if(l>m)m=l}END{print m}')
fw=$((w1 + pad + 10))
sep=$(awk -v n="$w1" 'BEGIN{for(i=0;i<n;i++)printf "─";print ""}')
indent=$(printf "%${pad}s" "")
active_prefix=$(printf " >%$((pad - 3))s" "")
header=$(printf "%s%s\n%s%s" "$indent" "Device name" "$indent" "$sep")
count=$(printf '%s\n' "$rows" | wc -l)
choice=$(printf '%s\n' "$rows" | \
awk -F'\t' -v w1="$w1" -v indent="$indent" -v active_prefix="$active_prefix" '{
prefix = ($3 == ">") ? active_prefix : indent
printf "%s%-*s\t%s\n", prefix, w1, $2, $1
}' | \
fuzzel --dmenu --prompt="$prompt" --no-icons --lines="$count" \
--with-nth=1 --accept-nth=2 \
--mesg="$header" --mesg-mode=expand \
--font="monospace:size=12" --width="$fw")
[ -z "$choice" ] && exit 0
wpctl set-default "$choice"
;;
*)
echo "Usage: ctl audio {in|out}" >&2
echo "Usage: ctl audio {sink|source}" >&2
exit 1
;;
esac
@ -143,8 +175,6 @@ wifi)
station=$(iwctl device list 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | awk '/station/{print $1}')
[ -z "$station" ] && { echo "ctl: no wifi device found" >&2; exit 1; }
while :; do
iwctl station "$station" scan 2>/dev/null
sleep 1
networks=$(iwctl station "$station" get-networks 2>/dev/null | \
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | \
awk 'NR>4 && /\S/ && !/^[[:space:]]*-/' | \
@ -176,13 +206,13 @@ wifi)
w1=$(printf '%s\n' "$networks" | awk -F'\t' 'BEGIN{m=12}{l=length($1);if(l>m)m=l}END{print m}')
w2=$(printf '%s\n' "$networks" | awk -F'\t' 'BEGIN{m=8}{l=length($2);if(l>m)m=l}END{print m}')
w3=$(printf '%s\n' "$networks" | awk -F'\t' 'BEGIN{m=6}{l=length($3);if(l>m)m=l}END{print m}')
fw=$((w1 + 4 + w2 + 4 + w3 + 14))
sep=$(awk -v n="$fw" 'BEGIN{for(i=0;i<n;i++)printf "─";print ""}')
header=$(printf " %-*s %-*s %s\n%s" "$w1" "Network name" "$w2" "Security" "Signal" "$sep")
fw=$((w1 + 4 + w2 + 4 + w3 + 17))
sep=$(awk -v n="$((w1 + w2 + w3 + 8))" 'BEGIN{for(i=0;i<n;i++)printf "─";print ""}')
header=$(printf " %-*s %-*s %s\n %s" "$w1" "Network name" "$w2" "Security" "Signal" "$sep")
count=$(printf '%s\n' "$networks" | wc -l)
ssid=$(printf '%s\n' "$networks" | \
awk -F'\t' -v w1="$w1" -v w2="$w2" '{
prefix = ($4 == ">") ? " > " : " "
prefix = ($4 == ">") ? " > " : " "
printf "%s%-*s %-*s %s\t%s\n", prefix, w1, $1, w2, $2, $3, $1
}' | \
fuzzel --dmenu --prompt="wifi: " --no-icons --lines="$count" \

View file

@ -172,7 +172,7 @@ cmd)
sed 's/ / /' |
fzf --reverse --prompt ':' --print-query \
--delimiter '\t' --with-nth '1,2' --accept-nth '1' \
--bind 'ctrl-y:transform-query(echo {1})+disable-search')
--bind 'ctrl-y:transform-query(echo {1})')
rc=$?
query=$(printf '%s' "$result" | head -1)
action=$(printf '%s' "$result" | sed -n '2p')