Browse Source

Added waybar config

master
chodak166 5 days ago
parent
commit
6dc56f4f12
  1. 1
      .config/nvim/lazy-lock.json
  2. 52
      .config/nvim/lua/plugins/colorscheme.lua
  3. 135
      .config/waybar/config.jsonc
  4. 157
      .config/waybar/disk.py
  5. 140
      .config/waybar/network.py
  6. 97
      .config/waybar/network.sh
  7. 77
      .config/waybar/style.css
  8. 30
      .config/waybar/top.sh
  9. 5
      .config/waybar/watch.sh

1
.config/nvim/lazy-lock.json

@ -12,7 +12,6 @@
"friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
"gitsigns.nvim": { "branch": "main", "commit": "25050e4ed39e628282831d4cbecb1850454ce915" },
"grug-far.nvim": { "branch": "main", "commit": "c995bbacf8229dc096ec1c3d60f8531059c86c1b" },
"hybrid-theme": { "branch": "main", "commit": "b131110fbe63481d7d263c71982206a70a04d236" },
"indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" },
"just-runner.nvim": { "branch": "main", "commit": "f29d405aa828900df242600720a2b0e57261489f" },
"lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },

52
.config/nvim/lua/plugins/colorscheme.lua

@ -13,39 +13,39 @@
-- }
-- Local development:
-- return {
-- dir = "/home/chodak/src/git/nvim-hybrid-theme",
-- name = "hybrid-theme",
-- lazy = false,
-- priority = 1000,
-- config = function()
-- require("hybrid-theme").setup({
-- theme = "dark",
-- transparent = false,
-- background_variant = "flat",
-- italics = {
-- comments = true,
-- keywords = false,
-- functions = false,
-- strings = false,
-- variables = false,
-- },
-- })
-- require("hybrid-theme").colorscheme()
-- end,
-- }
return {
{
"chodak166/nvim-hybrid-theme",
dir = "/home/chodak/src/git/nvim-hybrid-theme",
name = "hybrid-theme",
lazy = false,
priority = 1000,
config = function()
require("hybrid-theme").setup({
background_variant = "semi_flat",
theme = "dark",
transparent = false,
background_variant = "flat",
italics = {
comments = true,
keywords = false,
functions = false,
strings = false,
variables = false,
},
})
require("hybrid-theme").colorscheme()
end,
},
}
-- return {
-- {
-- "chodak166/nvim-hybrid-theme",
-- name = "hybrid-theme",
-- lazy = false,
-- priority = 1000,
-- config = function()
-- require("hybrid-theme").setup({
-- background_variant = "semi_flat",
-- })
-- require("hybrid-theme").colorscheme()
-- end,
-- },
-- }

135
.config/waybar/config.jsonc

@ -0,0 +1,135 @@
// -*- mode: json -*-
{
"layer": "top",
"position": "top",
"modules-left": [
"sway/workspaces",
"custom/right-arrow-dark"
],
"modules-center": [
"custom/left-arrow-dark",
"sway/window",
"custom/right-arrow-dark"
],
"modules-right": [
"custom/left-arrow-dark",
"pulseaudio",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"custom/network",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"custom/disk",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"memory",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"custom/top",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"battery",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"clock#0",
"custom/left-arrow-light",
"custom/left-arrow-dark",
"tray"
],
"custom/left-arrow-dark": {
"format": "<span size='x-large' rise='-1500'></span>",
"tooltip": false
},
"custom/left-arrow-light": {
"format": "<span size='x-large' rise='-1500'></span>",
"tooltip": false
},
"custom/right-arrow-dark": {
"format": "<span size='x-large' rise='-1500'></span>",
"tooltip": false
},
"sway/workspaces": {
"disable-scroll": true,
"format": "{name}"
},
"sway/window": {
"max-length": 70,
"format": "{title}"
},
"custom/network": {
"exec": "/home/chodak/.config/waybar/network.py",
"interval": 10,
"return-type": "json",
"tooltip": true
},
"clock#2": {
"format": "{:%H:%M}",
"tooltip": false
},
"clock#3": {
"format": "{:%d/%m}",
"tooltip": false
},
"clock#0": {
"format": "{:%H:%M %d/%m/%y}",
"tooltip": false
},
"pulseaudio": {
"format": "<span size='x-large' rise='-1500'>{icon}</span> {volume:2}%",
"format-bluetooth": "<span size='x-large' rise='-1500'>{icon}</span> {volume}%",
"format-muted": "MUTE",
"format-icons": {
"headphones": "",
"default": [
"",
""
]
},
"scroll-step": 5,
"on-click": "pamixer -t",
"on-click-right": "pavucontrol"
},
"memory": {
"interval": 5,
"format": "<span size='x-large' rise='-1500'></span> {}%"
},
"custom/top": {
"exec": "~/.config/waybar/top.sh",
"interval": 5,
"return-type": "json",
"tooltip": true
},
"battery": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"format": "<span size='x-large' rise='-1500'>{icon}</span> {capacity}%",
"format-icons": [
"",
"",
"",
"",
""
]
},
"custom/disk": {
"exec": "/home/chodak/.config/waybar/disk.py",
"interval": 30,
"return-type": "json",
"tooltip": true,
"escape": false
},
"tray": {
"icon-size": 24
}
}

157
.config/waybar/disk.py

@ -0,0 +1,157 @@
#!/usr/bin/env python3
"""Waybar disk module: shows disk usage across all mounted partitions."""
import json
import os
# Filesystem types to ignore (virtual / non-disk)
IGNORE_FSTYPES = {
"tmpfs", "devtmpfs", "proc", "sysfs", "cgroup", "cgroup2",
"pstore", "bpf", "debugfs", "tracefs", "securityfs", "configfs",
"hugetlbfs", "devpts", "ramfs", "fuse.gvfsd-fuse", "fusectl",
"mqueue", "rpc_pipefs", "overlay", "squashfs",
}
# Pango color thresholds
COLOR_LOW = "#a6e3a1" # green — < 70%
COLOR_MID = "#f9e2af" # yellow — 70–89%
COLOR_HIGH = "#f38ba8" # red — ≥ 90%
def _pct_color(pct: float) -> str:
"""Return a Pango color string for the given usage percentage."""
if pct >= 90:
return COLOR_HIGH
if pct >= 70:
return COLOR_MID
return COLOR_LOW
def _span(color: str, text: str) -> str:
"""Wrap text in a Pango <span> with the given foreground color."""
return f"<span foreground='{color}'>{text}</span>"
def get_partitions():
"""Return list of (device, mountpoint, fstype) for real partitions."""
partitions = []
seen_devices = set()
try:
with open("/proc/mounts") as f:
for line in f:
parts = line.split()
if len(parts) < 3:
continue
device, mountpoint, fstype = parts[:3]
if fstype in IGNORE_FSTYPES:
continue
if not device.startswith("/dev/"):
continue
if device in seen_devices:
continue
seen_devices.add(device)
partitions.append((device, mountpoint, fstype))
except OSError:
pass
return partitions
def get_usage(mountpoint):
"""Return (total_bytes, used_bytes, pct) for a mountpoint, or None."""
try:
st = os.statvfs(mountpoint)
total = st.f_frsize * st.f_blocks
free = st.f_frsize * st.f_bfree
used = total - free
pct = (used / total) * 100 if total > 0 else 0.0
return total, used, pct
except OSError:
return None
def fmt_size(bytes_val):
"""Format bytes as human-readable."""
if bytes_val >= 1 << 40:
return f"{bytes_val / (1 << 40):.1f}T"
if bytes_val >= 1 << 30:
return f"{bytes_val / (1 << 30):.1f}G"
if bytes_val >= 1 << 20:
return f"{bytes_val / (1 << 20):.1f}M"
if bytes_val >= 1 << 10:
return f"{bytes_val / (1 << 10):.1f}K"
return f"{bytes_val}B"
def main():
partitions = get_partitions()
if not partitions:
print(json.dumps(
{"text": "", "tooltip": "No disk partitions found"},
ensure_ascii=False))
return
tooltip_lines = []
root_pct = None
bar_parts = []
for device, mountpoint, fstype in partitions:
usage = get_usage(mountpoint)
if usage is None:
continue
total, used, pct = usage
total_str = fmt_size(total)
used_str = fmt_size(used)
color = _pct_color(pct)
# Icons per mountpoint
if mountpoint == "/":
icon = ""
elif mountpoint == "/home":
icon = ""
elif mountpoint == "/boot":
icon = ""
elif "/media/" in mountpoint or "/run/media/" in mountpoint:
icon = ""
else:
icon = ""
# Tooltip line with colored percentage
pct_span = _span(color, f"{pct:5.1f}%")
warn = "" if pct >= 90 else ""
tooltip_lines.append(
f"{icon} {mountpoint:20s} {used_str:>6s} / {total_str:>6s} ({pct_span}){warn}"
)
# Track root for bar display
if mountpoint == "/":
root_pct = pct
# Build bar text using Pango markup
if root_pct is not None:
bar_icon = "" if root_pct >= 90 else ""
bar_color = _pct_color(root_pct)
bar_text = (
f"<span size='x-large' rise='-1500'>{bar_icon}</span>"
f" {_span(bar_color, f'{root_pct:.0f}%')}"
)
elif tooltip_lines:
bar_text = f"<span size='x-large' rise='-1500'></span> —"
else:
bar_text = ""
tooltip = "\n".join(tooltip_lines) if tooltip_lines else "No partitions"
print(json.dumps(
{"text": bar_text, "tooltip": tooltip},
ensure_ascii=False))
if __name__ == "__main__":
main()

140
.config/waybar/network.py

@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""Waybar network module: shows interface, IP, and up/down transfer rate."""
import json
import os
import re
import subprocess
import time
STATE_FILE_TMPL = "/tmp/waybar-network-stats-{}"
ICON = "󰲝" # nerd font network icon
NO_NET_ICON = "󰖪"
def run(cmd: list[str]) -> str:
"""Run a command and return stdout, or empty string on failure."""
try:
return subprocess.check_output(
cmd, stderr=subprocess.DEVNULL, text=True
).strip()
except subprocess.CalledProcessError:
return ""
def get_default_interface() -> str | None:
"""Return the default route interface name."""
output = run(["ip", "route"])
for line in output.splitlines():
if line.startswith("default"):
parts = line.split()
# "default via X.X.X.X dev INTERFACE ..."
if len(parts) >= 5:
return parts[4]
return None
def get_ip(iface: str) -> str | None:
"""Return the IPv4 address of the given interface."""
output = run(["ip", "-4", "addr", "show", iface])
m = re.search(r"inet\s+(\d+\.\d+\.\d+\.\d+)", output)
return m.group(1) if m else None
def iface_type(iface: str) -> str:
"""Classify interface as WiFi, Ethernet, or generic."""
if re.match(r"^(wlan|wlp)", iface):
return "WiFi"
if re.match(r"^(eth|enp|eno|ens)", iface):
return "Ethernet"
return iface
def format_rate(bps: float) -> str:
"""Format bytes-per-second as human-readable with one decimal."""
bps = max(bps, 0)
if bps >= 1_073_741_824:
return f"{bps / 1_073_741_824:.1f}G"
if bps >= 1_048_576:
return f"{bps / 1_048_576:.1f}M"
if bps >= 1024:
return f"{bps / 1024:.1f}K"
return f"{bps:.1f}B"
def main() -> None:
iface = get_default_interface()
if iface is None:
print(json.dumps(
{"text": f"{NO_NET_ICON} No net",
"tooltip": "No network connection"},
ensure_ascii=False))
return
ip = get_ip(iface)
if ip is None:
print(json.dumps(
{"text": f"{NO_NET_ICON} No IP",
"tooltip": f"Interface {iface} has no IP"},
ensure_ascii=False))
return
itype = iface_type(iface)
# Read current byte counters
now_ts = time.time_ns()
rx_path = f"/sys/class/net/{iface}/statistics/rx_bytes"
tx_path = f"/sys/class/net/{iface}/statistics/tx_bytes"
try:
with open(rx_path) as f:
now_rx = int(f.read().strip())
with open(tx_path) as f:
now_tx = int(f.read().strip())
except (OSError, ValueError):
now_rx = now_tx = 0
# Transfer rate calculation
rate_down = ""
rate_up = ""
state_file = STATE_FILE_TMPL.format(iface)
if os.path.exists(state_file):
try:
with open(state_file) as f:
prev_rx, prev_tx, prev_ts = map(int, f.read().split())
delta_ns = now_ts - prev_ts
if delta_ns > 0:
delta_rx = now_rx - prev_rx
delta_tx = now_tx - prev_tx
rx_bps = delta_rx * 1e9 / delta_ns
tx_bps = delta_tx * 1e9 / delta_ns
rate_down = format_rate(rx_bps)
rate_up = format_rate(tx_bps)
except (OSError, ValueError):
pass
# Save current state for next run
with open(state_file, "w") as f:
f.write(f"{now_rx} {now_tx} {now_ts}")
# Build output
if rate_down and rate_up:
rate_str = f"{rate_down}{rate_up}"
tooltip_rate = f"{rate_down}/s ↑ {rate_up}/s"
else:
rate_str = ""
tooltip_rate = "↓ ?/s ↑ ?/s"
text = (
f"<span size='x-large' rise='-1500'>{ICON}</span>"
f" {iface} {ip}{rate_str}"
)
tooltip = f"{itype}: {iface}{ip} | {tooltip_rate}"
print(json.dumps({"text": text, "tooltip": tooltip}, ensure_ascii=False))
if __name__ == "__main__":
main()

97
.config/waybar/network.sh

@ -0,0 +1,97 @@
#!/usr/bin/env bash
# Get the default interface used for routing
INTERFACE=$(ip route 2>/dev/null | grep '^default' | awk '{print $5}' | head -1)
if [ -z "$INTERFACE" ]; then
echo '{"text": "󰖪 No net", "tooltip": "No network connection"}'
exit 0
fi
# Get IPv4 address of the interface
IP=$(ip -4 addr show "$INTERFACE" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
if [ -z "$IP" ]; then
echo '{"text": "󰖪 No IP", "tooltip": "Interface '"$INTERFACE"' has no IP"}'
exit 0
fi
# Determine interface type and set appropriate icon
if [[ "$INTERFACE" =~ ^(wlan|wlp) ]]; then
ICON="󰲝" # generic network icon (nerd font)
TYPE="WiFi"
elif [[ "$INTERFACE" =~ ^(eth|enp|eno|ens) ]]; then
ICON="󰲝" # generic network icon (nerd font)
TYPE="Ethernet"
else
ICON="󰲝" # generic network icon (nerd font)
TYPE="$INTERFACE"
fi
# --- Transfer rate calculation ---
# Path to sysfs statistics
RX_FILE="/sys/class/net/$INTERFACE/statistics/rx_bytes"
TX_FILE="/sys/class/net/$INTERFACE/statistics/tx_bytes"
STATE_FILE="/tmp/waybar-network-stats-$INTERFACE"
# Read current byte counters
NOW_RX=$(cat "$RX_FILE" 2>/dev/null)
NOW_TX=$(cat "$TX_FILE" 2>/dev/null)
NOW_TS=$(date +%s%N) # nanoseconds for precision
# Helper: format bytes/sec to human-readable
format_rate() {
local bytes_per_sec="$1"
if [ "$bytes_per_sec" -lt 0 ]; then
bytes_per_sec=0
fi
if [ "$bytes_per_sec" -ge 1073741824 ]; then
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fG", n / 1073741824 }'
elif [ "$bytes_per_sec" -ge 1048576 ]; then
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fM", n / 1048576 }'
elif [ "$bytes_per_sec" -ge 1024 ]; then
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fK", n / 1024 }'
else
awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fB", n }'
fi
}
RATE_DOWN=""
RATE_UP=""
if [ -f "$STATE_FILE" ]; then
# Read previous values: rx tx timestamp_ns
read -r PREV_RX PREV_TX PREV_TS < "$STATE_FILE"
if [ -n "$PREV_RX" ] && [ -n "$PREV_TX" ] && [ -n "$PREV_TS" ]; then
# Calculate time delta in seconds (nanosecond difference)
DELTA_NS=$((NOW_TS - PREV_TS))
if [ "$DELTA_NS" -gt 0 ]; then
DELTA_RX=$((NOW_RX - PREV_RX))
DELTA_TX=$((NOW_TX - PREV_TX))
# bytes per second = delta_bytes / (delta_ns / 1e9)
RX_BPS=$(awk -v rx="$DELTA_RX" -v ns="$DELTA_NS" 'BEGIN { printf "%.0f", rx * 1000000000 / ns }')
TX_BPS=$(awk -v tx="$DELTA_TX" -v ns="$DELTA_NS" 'BEGIN { printf "%.0f", tx * 1000000000 / ns }')
if [ -n "$RX_BPS" ] && [ -n "$TX_BPS" ]; then
RATE_DOWN=$(format_rate "$RX_BPS")
RATE_UP=$(format_rate "$TX_BPS")
fi
fi
fi
fi
# Save current state for next run
echo "$NOW_RX $NOW_TX $NOW_TS" > "$STATE_FILE"
# --- Build output ---
if [ -n "$RATE_DOWN" ] && [ -n "$RATE_UP" ]; then
RATE_STR="${RATE_DOWN}${RATE_UP}"
else
RATE_STR=""
fi
echo "{\"text\": \"<span size='x-large' rise='-1500'>$ICON</span> $INTERFACE $IP${RATE_STR}\", \"tooltip\": \"$TYPE: $INTERFACE$IP | ↓ ${RATE_DOWN:-?}/s ↑ ${RATE_UP:-?}/s\"}"

77
.config/waybar/style.css

@ -0,0 +1,77 @@
* {
font-size: 13px;
font-family: monospace;
}
window#waybar {
background: #282828;
color: #fbf1c7;
}
#custom-right-arrow-dark,
#custom-left-arrow-dark {
color: #1d2021;
}
#custom-right-arrow-light,
#custom-left-arrow-light {
color: #282828;
background: #1d2021;
}
#workspaces,
#window,
#clock.0,
#clock.2,
#clock.3,
#pulseaudio,
#memory,
#custom-top,
#battery,
#custom-disk,
#custom-network,
#tray {
background: #1d2021;
}
#workspaces button {
padding: 0 2px;
color: #a89984;
}
#workspaces button.focused {
color: #fabd2f;
font-weight: bold;
/* border-bottom: 2px solid #fabd2f; */
}
#workspaces button:hover {
box-shadow: inherit;
text-shadow: inherit;
}
#workspaces button:hover {
background: #1d2021;
border: #1d2021;
padding: 0 3px;
}
/* Right-side widgets: lighter sandy yellow */
#window,
#clock,
#pulseaudio,
#memory,
#custom-top,
#battery,
#custom-disk,
#custom-network,
#tray {
color: #f5d67b;
}
#window,
#clock,
#pulseaudio,
#memory,
#custom-top,
#battery,
#custom-disk,
#custom-network {
padding: 0 10px;
}

30
.config/waybar/top.sh

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Get the top CPU-consuming process, excluding kernel threads and this script
read -r NAME CPU < <(
ps -eo comm,pcpu --sort=-pcpu --no-headers 2>/dev/null |
awk '{
# Skip kernel threads (names in brackets)
if ($1 ~ /^\[/) next
# Skip this script and ps itself
if ($1 == "top.sh" || $1 == "ps") next
# Output the first matching line and exit
print $1, $2
exit
}'
)
if [ -z "$NAME" ]; then
echo '{"text": " --", "tooltip": "No process data"}'
exit 0
fi
# Round CPU to integer
CPU=$(printf "%.0f" "$CPU")
# Truncate long process names (keep bar readable)
if [ ${#NAME} -gt 10 ]; then
NAME="${NAME:0:9}"
fi
echo "{\"text\": \"<span size='x-large' rise='-1500'>󰍛</span> $NAME ${CPU}%\", \"tooltip\": \"Top CPU: $NAME${CPU}%\"}"

5
.config/waybar/watch.sh

@ -0,0 +1,5 @@
#!/usr/bin/env bash
while inotifywait -e close_write ~/.config/waybar; do
killall -SIGUSR2 waybar
done
Loading…
Cancel
Save