Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b14290fffe | |||
| b93b27e43a | |||
| a91c8cf8f2 | |||
| b220b21509 | |||
| a52cc3a427 | |||
| 67004150dc | |||
| ba9c351589 | |||
| a63724d4f1 | |||
| 00947d2410 | |||
| b5ce26f244 | |||
| 793a16b2fc | |||
| 1e2f869bf3 | |||
| 7e7c62ec42 | |||
| e6d69e1e45 | |||
| 514e284b16 | |||
| efa96077a5 | |||
| 734906d50e | |||
| 47ffa48678 | |||
| e7c33b6411 | |||
| 26cb98338a | |||
| 89e9b93222 | |||
| f04bde4ec5 |
@@ -0,0 +1,2 @@
|
||||
# Used by the Noctalia Pi Status Bridge adapter and the Hyprland launcher.
|
||||
PI_STATUS_UI_BINARY=/home/alex/.local/bin/pi-status-ui
|
||||
@@ -29,3 +29,6 @@ end
|
||||
# bun
|
||||
set --export BUN_INSTALL "$HOME/.bun"
|
||||
set --export PATH $BUN_INSTALL/bin $PATH
|
||||
|
||||
# opencode
|
||||
fish_add_path /home/alex/.opencode/bin
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Non-locking Wayland screen blanker. It covers every monitor in black and
|
||||
# dismisses itself on any key press or mouse click; it never changes DPMS.
|
||||
listener {
|
||||
timeout = 300
|
||||
on-timeout = /home/alex/.local/bin/wayshell-blanker
|
||||
}
|
||||
+40
-13
@@ -12,14 +12,19 @@ end
|
||||
local main_mod = "SUPER"
|
||||
local terminal = "alacritty"
|
||||
|
||||
local input = {
|
||||
kb_layout = "us",
|
||||
kb_variant = "intl",
|
||||
numlock_by_default = true,
|
||||
}
|
||||
for key, value in pairs(machine.input or {}) do
|
||||
input[key] = value
|
||||
end
|
||||
|
||||
hl.config({
|
||||
input = {
|
||||
kb_layout = "us",
|
||||
kb_variant = "intl",
|
||||
numlock_by_default = true,
|
||||
},
|
||||
input = input,
|
||||
general = {
|
||||
gaps_in = 8,
|
||||
gaps_in = 4,
|
||||
-- Keep a thin black perimeter so the bottom border remains on-screen.
|
||||
gaps_out = 2,
|
||||
border_size = 2,
|
||||
@@ -35,16 +40,35 @@ hl.config({
|
||||
animations = {
|
||||
enabled = false,
|
||||
},
|
||||
binds = {
|
||||
-- Selecting the current workspace again returns to the last workspace.
|
||||
workspace_back_and_forth = true,
|
||||
},
|
||||
})
|
||||
|
||||
-- Three-finger horizontal swipes change workspaces; touchscreens remain excluded
|
||||
-- by Hyprland's default workspace_swipe_touch = false behavior.
|
||||
hl.gesture({
|
||||
fingers = 3,
|
||||
direction = "horizontal",
|
||||
action = "workspace",
|
||||
})
|
||||
|
||||
-- Dynamically hide the border when a workspace has exactly one tiled app.
|
||||
hl.workspace_rule({
|
||||
workspace = "w[t1]",
|
||||
no_border = true,
|
||||
})
|
||||
|
||||
-- Application and session bindings.
|
||||
local noctalia_ipc = "noctalia msg "
|
||||
local pi_status_ui_toggle = 'ui="${PI_STATUS_UI_BINARY:-$HOME/.local/bin/pi-status-ui}"; if test -x "$ui"; then setsid -f env TMPDIR=/tmp "$ui" --toggle >/tmp/pi-status-ui.log 2>&1; fi'
|
||||
-- Tap and release Super on its own to open Noctalia's control-center home.
|
||||
hl.bind(main_mod .. " + SUPER_L", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"), { release = true })
|
||||
hl.bind(main_mod .. " + RETURN", hl.dsp.exec_cmd(terminal))
|
||||
hl.bind(main_mod .. " + CTRL + RETURN", hl.dsp.exec_cmd(terminal .. " -e zellij"))
|
||||
hl.bind(main_mod .. " + SHIFT + RETURN", hl.dsp.exec_cmd("rofi -show combi"))
|
||||
hl.bind(main_mod .. " + SPACE", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle launcher"))
|
||||
hl.bind(main_mod .. " + SPACE", hl.dsp.exec_cmd(pi_status_ui_toggle))
|
||||
hl.bind(main_mod .. " + S", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"))
|
||||
hl.bind(main_mod .. " + SHIFT + F", hl.dsp.exec_cmd(noctalia_ipc .. "bar-toggle main"))
|
||||
hl.bind(main_mod .. " + SHIFT + R", hl.dsp.exec_cmd("hyprctl reload"))
|
||||
@@ -52,7 +76,7 @@ hl.bind(main_mod .. " + CTRL + L", hl.dsp.exec_cmd("command -v hyprlock >/dev/nu
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + S", hl.dsp.exec_cmd("systemctl suspend"))
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + H", hl.dsp.exec_cmd("systemctl hibernate"))
|
||||
hl.bind(main_mod .. " + SHIFT + C", hl.dsp.window.close())
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + F", hl.dsp.exec_cmd("env LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 flameshot gui"))
|
||||
hl.bind(main_mod .. " + CTRL + SHIFT + F", hl.dsp.exec_cmd("/home/alex/.local/bin/screenshot-select"))
|
||||
|
||||
-- Audio, media, brightness, and calculator keys.
|
||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true })
|
||||
@@ -64,10 +88,10 @@ hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86AudioRaiseVolume", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86AudioLowerVolume", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd('light -A 5 && notify-send "Brightness set to $(light)"'), { locked = true })
|
||||
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd('light -U 5 && notify-send "Brightness set to $(light)"'), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86MonBrightnessDown", hl.dsp.exec_cmd('light -S 0.2 && notify-send "Brightness set to min"'), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86MonBrightnessUp", hl.dsp.exec_cmd('light -S 100 && notify-send "Brightness set to max"'), { locked = true })
|
||||
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd('light -A 5'), { locked = true })
|
||||
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd('light -U 5'), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86MonBrightnessDown", hl.dsp.exec_cmd('light -S 0.0'), { locked = true })
|
||||
hl.bind(main_mod .. " + XF86MonBrightnessUp", hl.dsp.exec_cmd('light -S 100'), { locked = true })
|
||||
hl.bind("XF86Calculator", hl.dsp.exec_cmd("qalculate-qt"), { locked = true })
|
||||
|
||||
-- Retain i3's hjkl and arrow-key directional workflow.
|
||||
@@ -88,7 +112,9 @@ for workspace = 1, 9 do
|
||||
hl.bind(main_mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = workspace }))
|
||||
hl.bind(main_mod .. " + CTRL + " .. key, hl.dsp.window.move({ workspace = workspace, follow = true }))
|
||||
end
|
||||
-- Hyprland has no direct i3-style back_and_forth dispatcher; use numbered workspaces.
|
||||
-- Match i3's back-and-forth workflow: Super+Tab switches to the last workspace;
|
||||
-- selecting the current numbered workspace also returns to it.
|
||||
hl.bind(main_mod .. " + TAB", hl.dsp.focus({ workspace = "previous" }))
|
||||
hl.bind(main_mod .. " + CTRL + RIGHT", hl.dsp.focus({ workspace = "+1" }))
|
||||
hl.bind(main_mod .. " + CTRL + LEFT", hl.dsp.focus({ workspace = "-1" }))
|
||||
|
||||
@@ -113,6 +139,7 @@ local function float_rule(name, match, border_size)
|
||||
end
|
||||
|
||||
hl.window_rule({ name = "thunderbird-workspace", match = { class = "^Thunderbird$" }, workspace = "9" })
|
||||
float_rule("pi-status-ui", { class = "^(pi-status-ui|Pi-status-ui)$" }, 1)
|
||||
float_rule("alsamixer", { title = "^alsamixer$" }, 1)
|
||||
float_rule("qalculate", { title = "^Qalculate!$" })
|
||||
float_rule("psensor", { class = "^Psensor$" })
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Minimal Hyprlock screen using the current desktop as a blurred backdrop.
|
||||
|
||||
$font = Sans
|
||||
|
||||
general {
|
||||
hide_cursor = true
|
||||
}
|
||||
|
||||
background {
|
||||
monitor =
|
||||
path = screenshot
|
||||
blur_passes = 3
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor =
|
||||
size = 20%, 5%
|
||||
outline_thickness = 2
|
||||
inner_color = rgba(0, 0, 0, 0.25)
|
||||
outer_color = rgba(eeeeeecc)
|
||||
check_color = rgba(8ec07ccc)
|
||||
fail_color = rgba(fb4934cc)
|
||||
|
||||
font_color = rgb(eeeeee)
|
||||
fade_on_empty = false
|
||||
rounding = 12
|
||||
font_family = $font
|
||||
placeholder_text = Input password...
|
||||
fail_text = $PAMFAIL
|
||||
|
||||
position = 0, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor =
|
||||
text = $TIME
|
||||
font_size = 72
|
||||
font_family = $font
|
||||
|
||||
position = 0, 120
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
@@ -10,6 +10,7 @@ return {
|
||||
},
|
||||
startup = {
|
||||
"noctalia",
|
||||
"hypridle",
|
||||
-- Electron's tray icon registers only when the SNI watcher already exists.
|
||||
"sh -c 'sleep 2; exec mullvad-vpn'",
|
||||
"thunderbird",
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
-- Laptop profile: leave monitor selection to Hyprland's hotplug support.
|
||||
-- Noctalia replaces the i3-era Redshift, Polybar, Blueman Applet, and Picom stack.
|
||||
return {
|
||||
input = {
|
||||
touchpad = {
|
||||
-- Standard laptop behavior: one/two/three-finger taps map to
|
||||
-- left/right/middle click, and a second tap held down starts a drag.
|
||||
tap_to_click = true,
|
||||
tap_button_map = "lrm",
|
||||
tap_and_drag = true,
|
||||
drag_lock = false,
|
||||
clickfinger_behavior = true,
|
||||
disable_while_typing = true,
|
||||
|
||||
-- Preserve natural two-finger scrolling at the default sensitivity.
|
||||
natural_scroll = true,
|
||||
scroll_factor = 1.0,
|
||||
},
|
||||
},
|
||||
monitors = {},
|
||||
startup = {
|
||||
"noctalia",
|
||||
|
||||
@@ -5,8 +5,75 @@ offline_mode = true
|
||||
external_ip_enabled = false
|
||||
telemetry_enabled = false
|
||||
|
||||
# Noctalia owns idle handling so ScreenSaver/Wayland idle inhibitors (such as
|
||||
# browser video playback) prevent these actions. Power displays down after five
|
||||
# minutes, lock after ten minutes, then suspend-then-hibernate after thirty.
|
||||
[idle]
|
||||
behavior_order = ["lock", "screen-off", "suspend-then-hibernate"]
|
||||
pre_action_fade_seconds = 2.0
|
||||
|
||||
[idle.behavior.lock]
|
||||
action = "lock"
|
||||
enabled = true
|
||||
timeout = 600
|
||||
|
||||
[idle.behavior.screen-off]
|
||||
action = "screen_off"
|
||||
enabled = true
|
||||
timeout = 300
|
||||
|
||||
[idle.behavior.suspend-then-hibernate]
|
||||
action = "command"
|
||||
command = "loginctl lock-session && systemctl suspend-then-hibernate"
|
||||
enabled = true
|
||||
timeout = 1800
|
||||
|
||||
[theme]
|
||||
mode = "dark"
|
||||
source = "custom"
|
||||
custom_palette = "Ember OLED"
|
||||
pure_black_dark = true
|
||||
|
||||
# Noctalia merges files alphabetically. Keep reusable modules here; machine-specific
|
||||
# layout and hardware settings live in 90-machine.toml, while 99-extend.toml is local.
|
||||
[plugins]
|
||||
enabled = ["alex/system-status"]
|
||||
|
||||
[widget.cpu]
|
||||
type = "alex/system-status:cpu"
|
||||
|
||||
[widget.ram]
|
||||
type = "alex/system-status:memory"
|
||||
|
||||
[widget.network-rate]
|
||||
type = "alex/system-status:network-rate"
|
||||
|
||||
[widget.idle-inhibitors]
|
||||
type = "alex/system-status:inhibitors"
|
||||
|
||||
[widget.temp]
|
||||
type = "sysmon"
|
||||
stat = "cpu_temp"
|
||||
display = "text"
|
||||
|
||||
[widget.disk]
|
||||
type = "sysmon"
|
||||
stat = "disk_pct"
|
||||
display = "text"
|
||||
path = "/"
|
||||
|
||||
[desktop_widgets]
|
||||
enabled = false
|
||||
|
||||
[wallpaper]
|
||||
enabled = true
|
||||
fill_color = "#000000"
|
||||
|
||||
[wallpaper.default]
|
||||
path = "color:#000000"
|
||||
|
||||
[nightlight]
|
||||
enabled = true
|
||||
force = false
|
||||
temperature_day = 6500
|
||||
temperature_night = 2500
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
# Desktop-specific shell layout and hardware telemetry.
|
||||
# Pi Status Bridge is installed locally from ~/projects/pi-gui.
|
||||
[plugins]
|
||||
enabled = ["alex/system-status", "alex/pi-status-bridge"]
|
||||
|
||||
[widget.pi-status]
|
||||
type = "alex/pi-status-bridge:bridge"
|
||||
|
||||
[bar.main]
|
||||
position = "bottom"
|
||||
layer = "overlay"
|
||||
layer = "top"
|
||||
scale = 0.95
|
||||
capsule_radius = 5
|
||||
center = ["group:g3", "notifications"]
|
||||
end = ["bluetooth", "volume", "control-center", "group:g1", "session"]
|
||||
end = ["group:g2", "group:g6", "group:g1", "session"]
|
||||
font_weight = 400
|
||||
margin_ends = 0
|
||||
padding = 0
|
||||
panel_overlap = 3
|
||||
radius = 0
|
||||
shadow = false
|
||||
smart_auto_hide = true
|
||||
# The bar may overlay the thin perimeter while visible; hidden bars release the space.
|
||||
reserve_space = false
|
||||
start = ["tray", "group:g4", "group:g2", "privacy"]
|
||||
# Keep the desktop status bar visible and reserve its screen edge.
|
||||
auto_hide = false
|
||||
smart_auto_hide = false
|
||||
reserve_space = true
|
||||
start = ["tray", "group:g4", "privacy"]
|
||||
thickness = 39
|
||||
widget_spacing = 10
|
||||
|
||||
@@ -22,7 +31,7 @@ widget_spacing = 10
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g1"
|
||||
members = ["caffeine", "date", "clock"]
|
||||
members = ["idle-inhibitors", "caffeine", "date", "clock"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
@@ -30,7 +39,7 @@ padding = 6.0
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g2"
|
||||
members = ["network_rx", "network_tx", "network"]
|
||||
members = ["network", "bluetooth"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
@@ -47,20 +56,18 @@ radius = 5.0
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g4"
|
||||
members = ["cpu", "temp", "ram", "gpu", "gpu_temp", "disk", "battery"]
|
||||
members = ["pi-status", "cpu", "temp", "ram", "gpu", "gpu_temp", "disk"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[widget.cpu]
|
||||
type = "alex/system-status:cpu"
|
||||
|
||||
[widget.ram]
|
||||
type = "alex/system-status:memory"
|
||||
|
||||
[widget.temp]
|
||||
type = "sysmon"
|
||||
stat = "cpu_temp"
|
||||
display = "text"
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g6"
|
||||
members = ["input_volume", "volume"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
radius = 5.0
|
||||
|
||||
[widget.gpu]
|
||||
type = "sysmon"
|
||||
@@ -72,39 +79,11 @@ type = "sysmon"
|
||||
stat = "gpu_temp"
|
||||
display = "text"
|
||||
|
||||
[widget.disk]
|
||||
type = "sysmon"
|
||||
stat = "disk_pct"
|
||||
display = "text"
|
||||
path = "/"
|
||||
|
||||
[battery.device."/org/freedesktop/UPower/devices/battery_hidpp_battery_0"]
|
||||
warning_threshold = 20
|
||||
|
||||
[control_center]
|
||||
sidebar = "full"
|
||||
sidebar_section = "full"
|
||||
width = 880
|
||||
|
||||
[desktop_widgets]
|
||||
enabled = false
|
||||
|
||||
[wallpaper]
|
||||
enabled = true
|
||||
fill_color = "#000000"
|
||||
|
||||
[wallpaper.default]
|
||||
path = "color:#000000"
|
||||
|
||||
[system.monitor]
|
||||
# GPU polling is disabled by Noctalia by default; enable it for the RTX 3090 widgets.
|
||||
gpu_poll_seconds = 2.0
|
||||
|
||||
[plugins]
|
||||
enabled = ["alex/system-status"]
|
||||
|
||||
[nightlight]
|
||||
enabled = true
|
||||
force = false
|
||||
temperature_day = 6500
|
||||
temperature_night = 2500
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Laptop-specific Noctalia layout. Shared privacy/theme defaults live in 10-base.toml.
|
||||
[bar.main]
|
||||
position = "top"
|
||||
layer = "overlay"
|
||||
layer = "top"
|
||||
scale = 0.95
|
||||
capsule_radius = 5
|
||||
center = ["group:g3", "notifications"]
|
||||
end = ["bluetooth", "volume", "control-center", "group:g1", "session"]
|
||||
end = ["group:g2", "group:g6", "group:g5", "group:g1", "session"]
|
||||
font_weight = 400
|
||||
margin_ends = 0
|
||||
padding = 0
|
||||
@@ -14,7 +15,8 @@ shadow = false
|
||||
auto_hide = false
|
||||
smart_auto_hide = false
|
||||
reserve_space = true
|
||||
start = ["tray", "group:g4", "group:g2", "privacy"]
|
||||
start = ["tray", "group:g4"]
|
||||
# Accommodate the battery-rate widget's wattage + ETA lines without clipping.
|
||||
thickness = 39
|
||||
widget_spacing = 10
|
||||
|
||||
@@ -22,7 +24,7 @@ widget_spacing = 10
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g1"
|
||||
members = ["caffeine", "date", "clock"]
|
||||
members = ["idle-inhibitors", "caffeine", "date", "clock"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
@@ -30,7 +32,7 @@ padding = 6.0
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g2"
|
||||
members = ["network_rx", "network_tx", "network"]
|
||||
members = ["network", "bluetooth"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
@@ -47,47 +49,35 @@ radius = 5.0
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g4"
|
||||
members = ["cpu", "temp", "ram", "disk", "battery"]
|
||||
members = ["cpu", "temp", "ram", "gpu-mode", "disk"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
|
||||
[widget.cpu]
|
||||
type = "alex/system-status:cpu"
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g5"
|
||||
members = ["battery-rate", "battery", "power_profile"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
radius = 5.0
|
||||
|
||||
[widget.ram]
|
||||
type = "alex/system-status:memory"
|
||||
[[bar.main.capsule_group]]
|
||||
enabled = true
|
||||
fill = "surface_variant"
|
||||
id = "g6"
|
||||
members = ["input_volume", "volume"]
|
||||
opacity = 1.0
|
||||
padding = 6.0
|
||||
radius = 5.0
|
||||
|
||||
[widget.temp]
|
||||
type = "sysmon"
|
||||
stat = "cpu_temp"
|
||||
display = "text"
|
||||
[widget.battery-rate]
|
||||
type = "alex/system-status:battery-rate"
|
||||
|
||||
[widget.disk]
|
||||
type = "sysmon"
|
||||
stat = "disk_pct"
|
||||
display = "text"
|
||||
path = "/"
|
||||
[widget.gpu-mode]
|
||||
type = "alex/system-status:gpu-mode"
|
||||
|
||||
[control_center]
|
||||
sidebar = "full"
|
||||
sidebar_section = "full"
|
||||
width = 720
|
||||
|
||||
[desktop_widgets]
|
||||
enabled = false
|
||||
|
||||
[wallpaper]
|
||||
enabled = true
|
||||
fill_color = "#000000"
|
||||
|
||||
[wallpaper.default]
|
||||
path = "color:#000000"
|
||||
|
||||
[plugins]
|
||||
enabled = ["alex/system-status"]
|
||||
|
||||
[nightlight]
|
||||
enabled = true
|
||||
force = false
|
||||
temperature_day = 6500
|
||||
temperature_night = 2500
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
[module/public_ip]
|
||||
type = custom/text
|
||||
content=
|
||||
click-left = curl -s ifconfig.co | while read OUTPUT; do notify-send "$OUTPUT"; done & curl -s ifconfig.co | xargs -I % sh -c "curl -s ipinfo.io/%/city" | while read OUTPUT; do notify-send "$OUTPUT"; done
|
||||
click-left = ip="$(curl -fsS --connect-timeout 3 --max-time 5 https://ifconfig.co/ip)" || exit; case "$ip" in ''|*[!0-9A-Fa-f.:]*) exit 1 ;; esac; notify-send "$ip"; city="$(curl -fsS --connect-timeout 3 --max-time 5 "https://ipinfo.io/${ip}/city")" || exit; notify-send "$city"
|
||||
|
||||
[module/mic_status]
|
||||
type = custom/script
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../idle-inhibitor-monitor.service
|
||||
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=Track session ScreenSaver idle inhibitors for Noctalia
|
||||
After=graphical-session.target
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=%h/.local/bin/idle-inhibitor-monitor
|
||||
Restart=on-failure
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Pi Status Bridge home agent
|
||||
After=graphical-session.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=PATH=/home/alex/.local/bin:/usr/local/bin:/usr/bin:/bin
|
||||
ExecStart=/home/alex/.local/bin/pi-status-bridge --session-root %h/.local/state/pi-status-bridge/sessions
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -33,10 +33,10 @@
|
||||
"interval": 1,
|
||||
"tooltip-format": "\n<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
|
||||
"calendar-weeks-pos": "right",
|
||||
"today-format": "<span color='#7645AD'><b><u>{}</u></b></span>",
|
||||
"format-calendar": "<span color='#aeaeae'><b>{}</b></span>",
|
||||
"format-calendar-weeks": "<span color='#aeaeae'><b>W{:%V}</b></span>",
|
||||
"format-calendar-weekdays": "<span color='#aeaeae'><b>{}</b></span>"
|
||||
"today-format": "<span color='#ff8800'><b><u>{}</u></b></span>",
|
||||
"format-calendar": "<span color='#f4c7a1'><b>{}</b></span>",
|
||||
"format-calendar-weeks": "<span color='#f4c7a1'><b>W{:%V}</b></span>",
|
||||
"format-calendar-weekdays": "<span color='#f4c7a1'><b>{}</b></span>"
|
||||
},
|
||||
|
||||
"disk": {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check the current state of the speaker
|
||||
state=$(amixer -D pulse sget Master | awk '/\[on\]/{print "unmute"; exit} /\[off\]/{print "mute"; exit}')
|
||||
|
||||
# Toggle the state of the speaker
|
||||
#
|
||||
if [ "$state" = "[on] "]; then
|
||||
amixer
|
||||
# amixer -D pulse sset Master "$state" > /dev/null
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Toggle the default PulseAudio sink's mute state.
|
||||
amixer -D pulse sset Master toggle >/dev/null
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
#!/bin/bash
|
||||
format() {
|
||||
if [ "$1" -eq 0 ]; then
|
||||
echo '-'
|
||||
else
|
||||
echo "$1"
|
||||
fi
|
||||
if [ "$1" -eq 0 ]; then
|
||||
echo '-'
|
||||
else
|
||||
echo "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
if ! updates_arch="$(checkupdates | wc -l)"; then
|
||||
updates_arch=0
|
||||
updates_arch=0
|
||||
fi
|
||||
|
||||
if ! updates_aur="$(yay -Qum 2>/dev/null | wc -l)"; then
|
||||
updates_aur=0
|
||||
updates_aur=0
|
||||
fi
|
||||
|
||||
updates="$((updates_arch + updates_aur))"
|
||||
|
||||
if [ "$updates" -gt 0 ]; then
|
||||
echo " ($(format $updates_arch)/$(format $updates_aur))"
|
||||
echo " ($(format $updates_arch)/$(format $updates_aur))"
|
||||
else
|
||||
echo
|
||||
fia
|
||||
echo
|
||||
fi
|
||||
|
||||
+41
-40
@@ -1,22 +1,14 @@
|
||||
/* Noctalia Ember OLED: near-black surfaces, warm amber focus. */
|
||||
* {
|
||||
font-family: "JetBrainsMono Nerd Font,JetBrainsMono NF" ;
|
||||
color: white;
|
||||
}
|
||||
|
||||
window#waybar {
|
||||
background: black;
|
||||
}
|
||||
|
||||
.modules-right {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.modules-center {
|
||||
background: #000000;
|
||||
font-family: "JetBrainsMono Nerd Font,JetBrainsMono NF";
|
||||
color: #fff1e6;
|
||||
}
|
||||
|
||||
window#waybar,
|
||||
.modules-right,
|
||||
.modules-center,
|
||||
.modules-left {
|
||||
background: #000000;
|
||||
background: #050403;
|
||||
}
|
||||
|
||||
#battery,
|
||||
@@ -38,50 +30,59 @@ window#waybar {
|
||||
#window,
|
||||
#workspaces,
|
||||
#clock {
|
||||
min-width: 1ex;
|
||||
min-width: 1ex;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#tray menu * {
|
||||
color: black;
|
||||
color: #050403;
|
||||
}
|
||||
|
||||
|
||||
#cpu {
|
||||
/* "100% " fits in this box; fixed width prevents sibling modules shifting. */
|
||||
min-width: 7ch;
|
||||
max-width: 7ch;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#temperature.critical,
|
||||
#pulseaudio {
|
||||
min-width: 5ex;
|
||||
}
|
||||
#pulseaudio.muted {
|
||||
color: #FF0000;
|
||||
}
|
||||
#pulseaudio.mic.muted {
|
||||
color: #ffffff;
|
||||
min-width: 5ex;
|
||||
}
|
||||
|
||||
#pulseaudio.muted,
|
||||
#pulseaudio.mic:not(.source-muted) {
|
||||
color: #fc0202;
|
||||
color: #ff6b4a;
|
||||
}
|
||||
#clock{
|
||||
color: #f9780e;
|
||||
|
||||
#pulseaudio.mic.muted {
|
||||
color: #6e4a31;
|
||||
}
|
||||
|
||||
#clock {
|
||||
color: #ff8800;
|
||||
}
|
||||
|
||||
#battery.charging {
|
||||
color: #ffffff;
|
||||
background-color: #26A65B;
|
||||
color: #1a0d00;
|
||||
background-color: #c98a45;
|
||||
}
|
||||
|
||||
#battery.warning:not(.charging) {
|
||||
background-color: #ffbe61;
|
||||
color: black;
|
||||
background-color: #ffb05c;
|
||||
color: #2b1600;
|
||||
}
|
||||
|
||||
#battery.critical:not(.charging) {
|
||||
background-color: #f53c3c;
|
||||
color: #ffffff;
|
||||
animation-name: blink;
|
||||
animation-duration: 0.5s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-direction: alternate;
|
||||
background-color: #ff6b4a;
|
||||
color: #2b0700;
|
||||
animation-name: blink;
|
||||
animation-duration: 0.5s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
|
||||
#network.speed {
|
||||
min-width: 30ex;
|
||||
min-width: 30ex;
|
||||
}
|
||||
|
||||
Executable
+189
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Track session ScreenSaver inhibitors and expose combined idle blockers as TSV.
|
||||
|
||||
logind exposes idle inhibitors through systemd-inhibit. Browser video wake locks
|
||||
use org.freedesktop.ScreenSaver instead, which has no list API, so this monitor
|
||||
observes Inhibit/UnInhibit calls and keeps their active state in a small JSON
|
||||
file for the Noctalia widget and panel.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
STATE_FILE = Path.home() / ".local/state/noctalia/idle-inhibitors.json"
|
||||
SCREEN_SAVER = "org.freedesktop.ScreenSaver"
|
||||
|
||||
|
||||
def write_state(inhibitors: dict[tuple[str, int], dict[str, str]]) -> None:
|
||||
STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = {"inhibitors": list(inhibitors.values())}
|
||||
with NamedTemporaryFile("w", dir=STATE_FILE.parent, delete=False) as file:
|
||||
json.dump(payload, file, separators=(",", ":"))
|
||||
file.write("\n")
|
||||
temporary_name = file.name
|
||||
os.replace(temporary_name, STATE_FILE)
|
||||
|
||||
|
||||
def read_screensaver_inhibitors() -> list[dict[str, str]]:
|
||||
try:
|
||||
payload = json.loads(STATE_FILE.read_text())
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return []
|
||||
inhibitors = payload.get("inhibitors", [])
|
||||
return [item for item in inhibitors if isinstance(item, dict)]
|
||||
|
||||
|
||||
def logind_inhibitors() -> list[dict[str, str]]:
|
||||
result = subprocess.run(
|
||||
["systemd-inhibit", "--list", "--no-pager"],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return []
|
||||
|
||||
inhibitors = []
|
||||
for line in result.stdout.splitlines()[1:]:
|
||||
fields = line.split(maxsplit=6)
|
||||
if len(fields) < 7 or "idle" not in fields[5].split(":"):
|
||||
continue
|
||||
reason_and_mode = fields[6].rsplit(maxsplit=1)
|
||||
inhibitors.append(
|
||||
{
|
||||
"source": "logind",
|
||||
"who": fields[0],
|
||||
"user": fields[2],
|
||||
"pid": fields[3],
|
||||
"comm": fields[4],
|
||||
"mode": reason_and_mode[-1],
|
||||
"why": reason_and_mode[0] if len(reason_and_mode) == 2 else "No reason supplied",
|
||||
}
|
||||
)
|
||||
return inhibitors
|
||||
|
||||
|
||||
def combined_inhibitors() -> list[dict[str, str]]:
|
||||
return logind_inhibitors() + read_screensaver_inhibitors()
|
||||
|
||||
|
||||
def print_inhibitors() -> None:
|
||||
for inhibitor in combined_inhibitors():
|
||||
values = [
|
||||
inhibitor.get("source", "screensaver"),
|
||||
inhibitor.get("who", ""),
|
||||
inhibitor.get("user", ""),
|
||||
inhibitor.get("pid", ""),
|
||||
inhibitor.get("comm", ""),
|
||||
inhibitor.get("mode", ""),
|
||||
inhibitor.get("why", ""),
|
||||
]
|
||||
print("\t".join(value.replace("\t", " ").replace("\n", " ") for value in values))
|
||||
|
||||
|
||||
def monitor() -> None:
|
||||
active: dict[tuple[str, int], dict[str, str]] = {}
|
||||
pending: dict[tuple[str, int], dict[str, str]] = {}
|
||||
write_state(active)
|
||||
|
||||
process = subprocess.Popen(
|
||||
["stdbuf", "-oL", "busctl", "--user", "--json=short", "monitor"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
)
|
||||
|
||||
def stop(_signal: int, _frame: object) -> None:
|
||||
process.terminate()
|
||||
write_state({})
|
||||
raise SystemExit(0)
|
||||
|
||||
signal.signal(signal.SIGTERM, stop)
|
||||
signal.signal(signal.SIGINT, stop)
|
||||
|
||||
assert process.stdout is not None
|
||||
for line in process.stdout:
|
||||
try:
|
||||
message = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
message_type = message.get("type")
|
||||
sender = message.get("sender", "")
|
||||
payload = message.get("payload", {}).get("data", [])
|
||||
|
||||
if (
|
||||
message_type == "method_call"
|
||||
and message.get("interface") == SCREEN_SAVER
|
||||
and message.get("member") == "Inhibit"
|
||||
and len(payload) >= 2
|
||||
):
|
||||
pending[(sender, int(message.get("cookie", 0)))] = {
|
||||
"source": "screensaver",
|
||||
"who": str(payload[0]),
|
||||
"user": "session",
|
||||
"pid": "",
|
||||
"comm": str(payload[0]),
|
||||
"mode": "block",
|
||||
"why": str(payload[1]),
|
||||
}
|
||||
elif (
|
||||
message_type == "method_return"
|
||||
and payload
|
||||
and isinstance(payload[0], int)
|
||||
):
|
||||
request = (message.get("destination", ""), int(message.get("reply_cookie", 0)))
|
||||
inhibitor = pending.pop(request, None)
|
||||
if inhibitor is not None:
|
||||
active[(request[0], int(payload[0]))] = inhibitor
|
||||
write_state(active)
|
||||
elif (
|
||||
message_type == "method_call"
|
||||
and message.get("interface") == SCREEN_SAVER
|
||||
and message.get("member") == "UnInhibit"
|
||||
and payload
|
||||
and isinstance(payload[0], int)
|
||||
):
|
||||
cookie = int(payload[0])
|
||||
active.pop((sender, cookie), None)
|
||||
# Some clients reconnect before releasing a cookie; the cookie is
|
||||
# globally unique for Noctalia, so clean up that fallback as well.
|
||||
for key in [key for key in active if key[1] == cookie]:
|
||||
active.pop(key, None)
|
||||
write_state(active)
|
||||
elif (
|
||||
message_type == "signal"
|
||||
and message.get("interface") == "org.freedesktop.DBus"
|
||||
and message.get("member") == "NameOwnerChanged"
|
||||
and len(payload) == 3
|
||||
and payload[2] == ""
|
||||
):
|
||||
vanished = str(payload[0])
|
||||
for key in [key for key in active if key[0] == vanished]:
|
||||
active.pop(key, None)
|
||||
for key in [key for key in pending if key[0] == vanished]:
|
||||
pending.pop(key, None)
|
||||
write_state(active)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--count", action="store_true", help="print combined inhibitor count")
|
||||
parser.add_argument("--list", action="store_true", help="print combined inhibitors as TSV")
|
||||
arguments = parser.parse_args()
|
||||
|
||||
if arguments.count:
|
||||
print(len(combined_inhibitors()))
|
||||
elif arguments.list:
|
||||
print_inhibitors()
|
||||
else:
|
||||
monitor()
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# The opaque release window runs natively on Wayland; disable WebKit DMABUF,
|
||||
# which is unreliable with this NVIDIA desktop's compositor path.
|
||||
exec env WEBKIT_DISABLE_DMABUF_RENDERER=1 "$HOME/projects/pi-gui/ui/src-tauri/target/release/pi-status-ui" "$@"
|
||||
@@ -0,0 +1 @@
|
||||
../../../../projects/pi-gui/noctalia-v5-plugin/pi-status-bridge
|
||||
@@ -0,0 +1,205 @@
|
||||
-- Show instantaneous battery power above an ETA based on a time-weighted,
|
||||
-- five-minute rolling average. Energy values are normalized to µWh so that
|
||||
-- both energy_* and charge_* battery drivers can produce an estimate.
|
||||
local command = [[
|
||||
bat=/sys/class/power_supply/BAT0
|
||||
|
||||
number() {
|
||||
if [ -r "$1" ]; then
|
||||
value=$(cat "$1" 2>/dev/null)
|
||||
case "$value" in
|
||||
''|*[!0-9]*) ;;
|
||||
*) printf '%s' "$value"; return 0 ;;
|
||||
esac
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
status=$(cat "$bat/status" 2>/dev/null) || exit 1
|
||||
power=$(number "$bat/power_now")
|
||||
voltage=$(number "$bat/voltage_now")
|
||||
|
||||
if [ -z "$power" ]; then
|
||||
current=$(number "$bat/current_now")
|
||||
if [ -n "$current" ] && [ -n "$voltage" ]; then
|
||||
power=$(awk -v current="$current" -v voltage="$voltage" \
|
||||
'BEGIN { printf "%.0f", current * voltage / 1000000 }')
|
||||
fi
|
||||
fi
|
||||
|
||||
energy_now=$(number "$bat/energy_now")
|
||||
energy_full=$(number "$bat/energy_full")
|
||||
|
||||
if [ -z "$energy_now" ] || [ -z "$energy_full" ]; then
|
||||
charge_now=$(number "$bat/charge_now")
|
||||
charge_full=$(number "$bat/charge_full")
|
||||
if [ -n "$charge_now" ] && [ -n "$charge_full" ] && [ -n "$voltage" ]; then
|
||||
energy_now=$(awk -v charge="$charge_now" -v voltage="$voltage" \
|
||||
'BEGIN { printf "%.0f", charge * voltage / 1000000 }')
|
||||
energy_full=$(awk -v charge="$charge_full" -v voltage="$voltage" \
|
||||
'BEGIN { printf "%.0f", charge * voltage / 1000000 }')
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '%s\t%s\t%s\t%s\n' "$status" "$power" "$energy_now" "$energy_full"
|
||||
]]
|
||||
|
||||
local sample_window_seconds = 5 * 60
|
||||
local power_samples = {}
|
||||
local sampled_state = nil
|
||||
local request_in_flight = false
|
||||
|
||||
local function renderLines(top, bottom)
|
||||
barWidget.render(ui.column({ gap = 0, align = "center" }, {
|
||||
ui.label({ text = top, fontSize = 10 }),
|
||||
ui.label({ text = bottom, fontSize = 9 }),
|
||||
}))
|
||||
end
|
||||
|
||||
local function resetSamples(state)
|
||||
if sampled_state ~= state then
|
||||
power_samples = {}
|
||||
sampled_state = state
|
||||
end
|
||||
end
|
||||
|
||||
local function addPowerSample(state, power, now)
|
||||
resetSamples(state)
|
||||
|
||||
local latest = power_samples[#power_samples]
|
||||
if latest ~= nil and latest.time == now then
|
||||
latest.power = power
|
||||
else
|
||||
table.insert(power_samples, { time = now, power = power })
|
||||
end
|
||||
|
||||
local cutoff = now - sample_window_seconds
|
||||
while #power_samples > 1 and power_samples[2].time <= cutoff do
|
||||
table.remove(power_samples, 1)
|
||||
end
|
||||
end
|
||||
|
||||
local function rollingAverage(now)
|
||||
if #power_samples == 0 then
|
||||
return nil, 0
|
||||
end
|
||||
|
||||
if #power_samples == 1 then
|
||||
return power_samples[1].power, 0
|
||||
end
|
||||
|
||||
local cutoff = now - sample_window_seconds
|
||||
local integral = 0
|
||||
local duration = 0
|
||||
|
||||
for index = 2, #power_samples do
|
||||
local earlier = power_samples[index - 1]
|
||||
local later = power_samples[index]
|
||||
local interval = later.time - earlier.time
|
||||
local start_time = math.max(earlier.time, cutoff)
|
||||
local end_time = math.min(later.time, now)
|
||||
|
||||
if interval > 0 and end_time > start_time then
|
||||
local start_fraction = (start_time - earlier.time) / interval
|
||||
local end_fraction = (end_time - earlier.time) / interval
|
||||
local start_power = earlier.power + (later.power - earlier.power) * start_fraction
|
||||
local end_power = earlier.power + (later.power - earlier.power) * end_fraction
|
||||
local elapsed = end_time - start_time
|
||||
|
||||
integral = integral + (start_power + end_power) * elapsed / 2
|
||||
duration = duration + elapsed
|
||||
end
|
||||
end
|
||||
|
||||
if duration == 0 then
|
||||
return power_samples[#power_samples].power, 0
|
||||
end
|
||||
|
||||
return integral / duration, duration
|
||||
end
|
||||
|
||||
local function formatDuration(hours)
|
||||
local minutes = math.max(1, math.floor(hours * 60 + 0.5))
|
||||
local whole_hours = math.floor(minutes / 60)
|
||||
local remaining_minutes = minutes % 60
|
||||
|
||||
if whole_hours > 0 then
|
||||
return string.format("%dh %02dm", whole_hours, remaining_minutes)
|
||||
end
|
||||
|
||||
return string.format("%dm", remaining_minutes)
|
||||
end
|
||||
|
||||
local function formatSampleDuration(seconds)
|
||||
local minutes = math.floor(seconds / 60)
|
||||
return string.format("%dm %02ds", minutes, seconds % 60)
|
||||
end
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(5000)
|
||||
|
||||
if request_in_flight then
|
||||
return
|
||||
end
|
||||
|
||||
request_in_flight = true
|
||||
noctalia.runAsync(command, function(result)
|
||||
request_in_flight = false
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
renderLines("—", "Unavailable")
|
||||
barWidget.setTooltip("Battery rate and remaining-time estimate unavailable")
|
||||
return
|
||||
end
|
||||
|
||||
local state, power, energy_now, energy_full = string.match(
|
||||
result.stdout,
|
||||
"^([^\t]+)\t([^\t]*)\t([^\t]*)\t([^\r\n]*)"
|
||||
)
|
||||
power = tonumber(power)
|
||||
energy_now = tonumber(energy_now)
|
||||
energy_full = tonumber(energy_full)
|
||||
|
||||
if state ~= "Discharging" and state ~= "Charging" then
|
||||
resetSamples(state)
|
||||
renderLines("—", state)
|
||||
barWidget.setTooltip("Battery: " .. state)
|
||||
return
|
||||
end
|
||||
|
||||
if power == nil or power <= 0 then
|
||||
renderLines("—", "Calculating…")
|
||||
barWidget.setTooltip("Battery: " .. state .. " · waiting for a power reading")
|
||||
return
|
||||
end
|
||||
|
||||
local now = os.time()
|
||||
addPowerSample(state, power, now)
|
||||
local average_power, sample_duration = rollingAverage(now)
|
||||
local label = "Calculating…"
|
||||
|
||||
if average_power ~= nil and average_power > 0 and energy_now ~= nil and energy_full ~= nil then
|
||||
local energy_remaining = energy_now
|
||||
if state == "Charging" then
|
||||
energy_remaining = energy_full - energy_now
|
||||
end
|
||||
|
||||
if energy_remaining >= 0 then
|
||||
local suffix = state == "Charging" and " to full" or " left"
|
||||
label = formatDuration(energy_remaining / average_power) .. suffix
|
||||
end
|
||||
end
|
||||
|
||||
local direction = state == "Charging" and "↑" or "↓"
|
||||
renderLines(string.format("%s %.1f W", direction, power / 1000000), label)
|
||||
barWidget.setTooltip(
|
||||
string.format(
|
||||
"Battery: %s · %.1f W now · %.1f W rolling average (%s sampled of 5m)",
|
||||
state,
|
||||
power / 1000000,
|
||||
average_power / 1000000,
|
||||
formatSampleDuration(sample_duration)
|
||||
)
|
||||
)
|
||||
end)
|
||||
end
|
||||
@@ -11,6 +11,26 @@ local command = [[awk '
|
||||
local previous = {}
|
||||
local request_in_flight = false
|
||||
|
||||
local function colorForUsage(percent)
|
||||
if percent >= 85 then
|
||||
return "#ff453a" -- red
|
||||
end
|
||||
if percent >= 70 then
|
||||
return "#ff8800" -- orange
|
||||
end
|
||||
if percent >= 50 then
|
||||
return "#ffd60a" -- yellow
|
||||
end
|
||||
return "#ffffff" -- white
|
||||
end
|
||||
|
||||
local function renderStatus(text, color)
|
||||
barWidget.render(ui.row({ gap = 4, align = "center" }, {
|
||||
ui.glyph({ name = "cpu", size = 14, color = color }),
|
||||
ui.label({ text = text, color = color }),
|
||||
}))
|
||||
end
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(2000)
|
||||
|
||||
@@ -23,7 +43,8 @@ function update()
|
||||
request_in_flight = false
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
barWidget.setText("CPU —")
|
||||
renderStatus("CPU —", "#fff1e6")
|
||||
barWidget.setTooltip("Unable to read CPU utilization")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -47,12 +68,19 @@ function update()
|
||||
previous[name] = { total = total, idle = idle }
|
||||
end
|
||||
|
||||
barWidget.setGlyph("cpu")
|
||||
if sampled > 0 then
|
||||
barWidget.setText(string.format("%.0f%%", utilization))
|
||||
barWidget.setTooltip("Aggregate CPU utilization (100% per logical CPU)")
|
||||
-- Keep the aggregate display, but base its heat color on average
|
||||
-- utilization per logical CPU so multicore systems do not stay red.
|
||||
local per_cpu_utilization = utilization / sampled
|
||||
renderStatus(string.format("%.0f%%", utilization), colorForUsage(per_cpu_utilization))
|
||||
barWidget.setTooltip(
|
||||
string.format(
|
||||
"Aggregate CPU utilization (100%% per logical CPU) · %.0f%% average per CPU",
|
||||
per_cpu_utilization
|
||||
)
|
||||
)
|
||||
else
|
||||
barWidget.setText("—")
|
||||
renderStatus("—", "#fff1e6")
|
||||
barWidget.setTooltip("Sampling CPU utilization…")
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
-- Query EnvyControl once when this widget starts; GPU mode changes require a restart.
|
||||
local command = "envycontrol --query"
|
||||
local labels = {
|
||||
integrated = "iGPU",
|
||||
dedicated = "dGPU",
|
||||
nvidia = "dGPU",
|
||||
hybrid = "hybrid",
|
||||
}
|
||||
|
||||
barWidget.setGlyph("device-desktop")
|
||||
barWidget.setText("GPU…")
|
||||
barWidget.setTooltip("Reading EnvyControl GPU mode…")
|
||||
|
||||
noctalia.runAsync(command, function(result)
|
||||
if result.exitCode ~= 0 then
|
||||
barWidget.setText("GPU?")
|
||||
barWidget.setTooltip("Unable to read EnvyControl GPU mode")
|
||||
return
|
||||
end
|
||||
|
||||
local mode = string.lower(string.match(result.stdout, "([%a_-]+)") or "")
|
||||
local label = labels[mode]
|
||||
if label == nil then
|
||||
barWidget.setText("GPU?")
|
||||
barWidget.setTooltip("Unknown EnvyControl GPU mode: " .. mode)
|
||||
return
|
||||
end
|
||||
|
||||
barWidget.setText(label)
|
||||
barWidget.setTooltip("EnvyControl GPU mode: " .. mode)
|
||||
end)
|
||||
@@ -0,0 +1,85 @@
|
||||
-- Click-through details for both logind idle inhibitors and session
|
||||
-- ScreenSaver requests such as browser video wake locks.
|
||||
local command = (noctalia.getenv("HOME") or "") .. "/.local/bin/idle-inhibitor-monitor --list"
|
||||
|
||||
local inhibitors = {}
|
||||
local status = "Loading idle inhibitors…"
|
||||
local request_in_flight = false
|
||||
|
||||
local function renderPanel()
|
||||
local children = {
|
||||
ui.column({ gap = 2 }, {
|
||||
ui.label({ text = "Idle inhibitors", fontSize = 18, fontWeight = "bold" }),
|
||||
ui.label({ text = status, color = "on_surface_variant" }),
|
||||
}),
|
||||
ui.button({ text = "Refresh", onClick = "onRefresh" }),
|
||||
}
|
||||
|
||||
if #inhibitors == 0 then
|
||||
table.insert(children, ui.label({ text = "No process currently blocks automatic idle." }))
|
||||
else
|
||||
for _, inhibitor in ipairs(inhibitors) do
|
||||
local title = inhibitor.comm ~= "" and inhibitor.comm or inhibitor.who
|
||||
table.insert(children, ui.column({ gap = 2 }, {
|
||||
ui.label({ text = string.format("%s · %s", inhibitor.source, title), fontWeight = "bold" }),
|
||||
ui.label({ text = inhibitor.why ~= "" and inhibitor.why or "No reason supplied", maxLines = 2 }),
|
||||
ui.label({
|
||||
text = string.format("%s · %s · PID %s", inhibitor.mode, inhibitor.user, inhibitor.pid),
|
||||
color = "on_surface_variant",
|
||||
fontSize = 11,
|
||||
}),
|
||||
}))
|
||||
end
|
||||
end
|
||||
|
||||
panel.render(ui.scroll({ padding = 20, gap = 12 }, children))
|
||||
end
|
||||
|
||||
local function refreshInhibitors()
|
||||
if request_in_flight then return end
|
||||
request_in_flight = true
|
||||
status = "Loading idle inhibitors…"
|
||||
renderPanel()
|
||||
|
||||
noctalia.runAsync(command, function(result)
|
||||
request_in_flight = false
|
||||
inhibitors = {}
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
status = "Unable to inspect logind inhibitors."
|
||||
renderPanel()
|
||||
return
|
||||
end
|
||||
|
||||
for line in string.gmatch(result.stdout, "[^\r\n]+") do
|
||||
local source, who, user, pid, comm, mode, why = string.match(
|
||||
line,
|
||||
"^([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t(.*)$"
|
||||
)
|
||||
if source ~= nil then
|
||||
table.insert(inhibitors, {
|
||||
source = source,
|
||||
who = who,
|
||||
user = user,
|
||||
pid = pid,
|
||||
comm = comm,
|
||||
mode = mode,
|
||||
why = why,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
status = #inhibitors == 0
|
||||
and "Automatic idle is eligible."
|
||||
or string.format("%d active idle inhibitor%s.", #inhibitors, #inhibitors == 1 and "" or "s")
|
||||
renderPanel()
|
||||
end)
|
||||
end
|
||||
|
||||
function onOpen()
|
||||
refreshInhibitors()
|
||||
end
|
||||
|
||||
function onRefresh()
|
||||
refreshInhibitors()
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
-- Show whether any process blocks automatic idle. The monitor combines logind
|
||||
-- idle inhibitors with session ScreenSaver requests such as browser video wake locks.
|
||||
local command = (noctalia.getenv("HOME") or "") .. "/.local/bin/idle-inhibitor-monitor --count"
|
||||
|
||||
local request_in_flight = false
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(5000)
|
||||
|
||||
if request_in_flight then return end
|
||||
request_in_flight = true
|
||||
noctalia.runAsync(command, function(result)
|
||||
request_in_flight = false
|
||||
|
||||
local count = tonumber(result.stdout)
|
||||
if result.exitCode ~= 0 or count == nil then
|
||||
barWidget.setGlyph("circle-help")
|
||||
barWidget.setText("Idle ?")
|
||||
barWidget.setTooltip("Unable to inspect idle inhibitors")
|
||||
return
|
||||
end
|
||||
|
||||
if count > 0 then
|
||||
barWidget.setGlyph("moon-off")
|
||||
barWidget.setText(string.format("Idle %d", count))
|
||||
barWidget.setTooltip(
|
||||
string.format("%d idle inhibitor%s active · click for details", count, count == 1 and "" or "s")
|
||||
)
|
||||
else
|
||||
barWidget.setGlyph("moon")
|
||||
barWidget.setText("Idle")
|
||||
barWidget.setTooltip("No active idle inhibitors · click for details")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function onClick()
|
||||
noctalia.runAsync("noctalia msg panel-toggle alex/system-status:inhibitors-panel")
|
||||
end
|
||||
@@ -8,16 +8,37 @@ $1 == "SwapFree:" { swap_free = $2 }
|
||||
END {
|
||||
if (!total || !available) exit 1
|
||||
used = total - available
|
||||
memory_used = used * 100 / total
|
||||
if (swap_total > 0) {
|
||||
swap_used = (swap_total - swap_free) * 100 / swap_total
|
||||
printf "RAM %.1f/%.1f GiB S %.0f%%\n", used / 1048576, total / 1048576, swap_used
|
||||
printf "%.1f/%.1f GiB S %.0f%%\t%.0f\t%.0f\n", used / 1048576, total / 1048576, swap_used, memory_used, swap_used
|
||||
} else {
|
||||
printf "RAM %.1f/%.1f GiB S —\n", used / 1048576, total / 1048576
|
||||
printf "%.1f/%.1f GiB S —\t%.0f\t0\n", used / 1048576, total / 1048576, memory_used
|
||||
}
|
||||
}' /proc/meminfo]]
|
||||
|
||||
local request_in_flight = false
|
||||
|
||||
local function colorForUsage(percent)
|
||||
if percent >= 85 then
|
||||
return "#ff453a" -- red
|
||||
end
|
||||
if percent >= 70 then
|
||||
return "#ff8800" -- orange
|
||||
end
|
||||
if percent >= 50 then
|
||||
return "#ffd60a" -- yellow
|
||||
end
|
||||
return "#ffffff" -- white
|
||||
end
|
||||
|
||||
local function renderStatus(text, color)
|
||||
barWidget.render(ui.row({ gap = 4, align = "center" }, {
|
||||
ui.glyph({ name = "memory", size = 14, color = color }),
|
||||
ui.label({ text = text, color = color }),
|
||||
}))
|
||||
end
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(5000)
|
||||
|
||||
@@ -30,14 +51,32 @@ function update()
|
||||
request_in_flight = false
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
barWidget.setText("RAM —")
|
||||
renderStatus("RAM —", "#fff1e6")
|
||||
barWidget.setTooltip("Unable to read /proc/meminfo")
|
||||
return
|
||||
end
|
||||
|
||||
local text = string.gsub(result.stdout, "%s+$", "")
|
||||
barWidget.setGlyph("memory")
|
||||
barWidget.setText(text)
|
||||
barWidget.setTooltip("RAM used / total · S = swap used")
|
||||
local text, memory_percent, swap_percent = string.match(
|
||||
result.stdout,
|
||||
"^([^\t]+)\t([%d.]+)\t([%d.]+)"
|
||||
)
|
||||
memory_percent = tonumber(memory_percent)
|
||||
swap_percent = tonumber(swap_percent)
|
||||
|
||||
if text == nil or memory_percent == nil or swap_percent == nil then
|
||||
renderStatus("RAM —", "#fff1e6")
|
||||
barWidget.setTooltip("Unable to parse memory utilization")
|
||||
return
|
||||
end
|
||||
|
||||
local highest_usage = math.max(memory_percent, swap_percent)
|
||||
renderStatus(text, colorForUsage(highest_usage))
|
||||
barWidget.setTooltip(
|
||||
string.format(
|
||||
"RAM used / total · %.0f%% RAM · %.0f%% swap",
|
||||
memory_percent,
|
||||
swap_percent
|
||||
)
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
-- Compact, two-line network throughput widget. It samples the interface used
|
||||
-- by the default route so virtual and physical interfaces are not double-counted.
|
||||
local command = [[
|
||||
iface=$(ip route show default 2>/dev/null | awk '$1 == "default" { for (i = 1; i <= NF; i++) if ($i == "dev") { print $(i + 1); exit } }')
|
||||
|
||||
if [ -z "$iface" ]; then
|
||||
for path in /sys/class/net/*; do
|
||||
candidate=${path##*/}
|
||||
[ "$candidate" = "lo" ] && continue
|
||||
[ "$(cat "$path/carrier" 2>/dev/null)" = "1" ] || continue
|
||||
iface=$candidate
|
||||
break
|
||||
done
|
||||
fi
|
||||
|
||||
[ -n "$iface" ] || exit 1
|
||||
awk -v iface="$iface" '$1 ~ ("^" iface ":") { sub(":", "", $1); print iface "\t" $2 "\t" $10; exit }' /proc/net/dev
|
||||
]]
|
||||
|
||||
local previous = nil
|
||||
local request_in_flight = false
|
||||
-- 82px accommodates the longest fixed field ("1023 KiB/s") at 10px while
|
||||
-- removing the excess side padding from the original 112px capsule.
|
||||
local label_width = 82
|
||||
|
||||
local function formatRate(bytes_per_second)
|
||||
local units = { "B/s", "KiB/s", "MiB/s", "GiB/s" }
|
||||
local value = bytes_per_second
|
||||
local unit_index = 1
|
||||
|
||||
while value >= 1024 and unit_index < #units do
|
||||
value = value / 1024
|
||||
unit_index = unit_index + 1
|
||||
end
|
||||
|
||||
if unit_index == 1 then
|
||||
return string.format("%d %s", math.floor(value + 0.5), units[unit_index])
|
||||
end
|
||||
|
||||
if value >= 100 then
|
||||
return string.format("%.0f %s", value, units[unit_index])
|
||||
end
|
||||
|
||||
return string.format("%.1f %s", value, units[unit_index])
|
||||
end
|
||||
|
||||
local function renderLines(download, upload)
|
||||
-- The explicit minimum width and fixed ten-character value field keep the
|
||||
-- capsule width stable while inheriting the bar font used by other modules.
|
||||
barWidget.render(ui.column({ gap = 0, align = "center", minWidth = label_width }, {
|
||||
ui.label({
|
||||
text = string.format("↓ %10s", download),
|
||||
maxLines = 1,
|
||||
fontSize = 10,
|
||||
}),
|
||||
ui.label({
|
||||
text = string.format("↑ %10s", upload),
|
||||
maxLines = 1,
|
||||
fontSize = 10,
|
||||
}),
|
||||
}))
|
||||
end
|
||||
|
||||
function update()
|
||||
noctalia.setUpdateInterval(2000)
|
||||
|
||||
if request_in_flight then
|
||||
return
|
||||
end
|
||||
|
||||
request_in_flight = true
|
||||
noctalia.runAsync(command, function(result)
|
||||
request_in_flight = false
|
||||
|
||||
if result.exitCode ~= 0 then
|
||||
previous = nil
|
||||
renderLines("—", "—")
|
||||
barWidget.setTooltip("Network throughput unavailable: no active interface")
|
||||
return
|
||||
end
|
||||
|
||||
local iface, received, sent = string.match(
|
||||
result.stdout,
|
||||
"^([^\t]+)\t(%d+)\t(%d+)"
|
||||
)
|
||||
received = tonumber(received)
|
||||
sent = tonumber(sent)
|
||||
|
||||
if iface == nil or received == nil or sent == nil then
|
||||
previous = nil
|
||||
renderLines("—", "—")
|
||||
barWidget.setTooltip("Network throughput unavailable")
|
||||
return
|
||||
end
|
||||
|
||||
local now = os.time()
|
||||
if previous == nil or previous.iface ~= iface or now <= previous.time then
|
||||
previous = { iface = iface, received = received, sent = sent, time = now }
|
||||
renderLines("Sampling…", "Sampling…")
|
||||
barWidget.setTooltip("Sampling network throughput on " .. iface)
|
||||
return
|
||||
end
|
||||
|
||||
local elapsed = now - previous.time
|
||||
local download = math.max(0, (received - previous.received) / elapsed)
|
||||
local upload = math.max(0, (sent - previous.sent) / elapsed)
|
||||
previous = { iface = iface, received = received, sent = sent, time = now }
|
||||
|
||||
renderLines(formatRate(download), formatRate(upload))
|
||||
barWidget.setTooltip(
|
||||
string.format(
|
||||
"%s · Download %s · Upload %s",
|
||||
iface,
|
||||
formatRate(download),
|
||||
formatRate(upload)
|
||||
)
|
||||
)
|
||||
end)
|
||||
end
|
||||
@@ -3,7 +3,7 @@ name = "System Status"
|
||||
version = "1.0.0"
|
||||
plugin_api = 3
|
||||
author = "alex"
|
||||
description = "Low-overhead memory and swap indicator for the bar."
|
||||
description = "Low-overhead system and network status indicators for the bar."
|
||||
|
||||
[[widget]]
|
||||
id = "cpu"
|
||||
@@ -12,3 +12,23 @@ entry = "cpu.luau"
|
||||
[[widget]]
|
||||
id = "memory"
|
||||
entry = "memory.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "battery-rate"
|
||||
entry = "battery-rate.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "network-rate"
|
||||
entry = "network-rate.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "gpu-mode"
|
||||
entry = "gpu-mode.luau"
|
||||
|
||||
[[widget]]
|
||||
id = "inhibitors"
|
||||
entry = "inhibitors.luau"
|
||||
|
||||
[[panel]]
|
||||
id = "inhibitors-panel"
|
||||
entry = "inhibitors-panel.luau"
|
||||
|
||||
@@ -12,6 +12,19 @@
|
||||
"contextWindow": 1050000
|
||||
}
|
||||
}
|
||||
},
|
||||
"openai-codex": {
|
||||
"modelOverrides": {
|
||||
"gpt-5.6-sol": {
|
||||
"contextWindow": 1050000
|
||||
},
|
||||
"gpt-5.6-terra": {
|
||||
"contextWindow": 1050000
|
||||
},
|
||||
"gpt-5.6-luna": {
|
||||
"contextWindow": 1050000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"quietStartup": true,
|
||||
"lastChangelogVersion": "0.80.10",
|
||||
"defaultProvider": "openai-codex",
|
||||
"defaultModel": "gpt-5.6-sol",
|
||||
"defaultModel": "gpt-5.6-terra",
|
||||
"defaultThinkingLevel": "high",
|
||||
"packages": [
|
||||
"npm:pi-subagents",
|
||||
@@ -18,11 +18,11 @@
|
||||
"npm:bigpowers",
|
||||
"npm:@gotgenes/pi-permission-system",
|
||||
"npm:pi-intercom",
|
||||
"npm:gentle-engram",
|
||||
"npm:gentle-engram@0.1.8",
|
||||
"npm:pi-lens",
|
||||
"npm:@juicesharp/rpiv-todo",
|
||||
"npm:@majorgilles/pi-grill-me",
|
||||
"git:git.commumedia.org/alex/pi-map"
|
||||
"npm:pi-mcp-adapter"
|
||||
],
|
||||
"powerline": "full",
|
||||
"hideThinkingBlock": false,
|
||||
|
||||
+107
-173
@@ -1,186 +1,120 @@
|
||||
# -- general -------------------------------------------------------------------
|
||||
# ~/.tmux.conf — Vim-centric tmux configuration (tmux 3.7+)
|
||||
# Reload with: prefix + r
|
||||
|
||||
set -g extended-keys on
|
||||
|
||||
set -g default-terminal "screen-256color" # colors!
|
||||
setw -g xterm-keys on
|
||||
set -s escape-time 10 # faster command sequences
|
||||
set -sg repeat-time 600 # increase repeat timeout
|
||||
# --- Terminal and responsiveness ---------------------------------------------
|
||||
set -g default-terminal "tmux-256color"
|
||||
set -as terminal-features ",xterm-256color:RGB,screen-256color:RGB,tmux-256color:RGB"
|
||||
set -sg escape-time 10
|
||||
set -sg repeat-time 600
|
||||
set -s focus-events on
|
||||
set -g allow-passthrough on
|
||||
set -g history-limit 100000
|
||||
set -g set-clipboard on
|
||||
|
||||
set -g prefix2 C-a # GNU-Screen compatible prefix
|
||||
bind C-a send-prefix -2
|
||||
# --- Prefix and defaults ------------------------------------------------------
|
||||
unbind C-b
|
||||
set -g prefix C-a
|
||||
bind C-a send-prefix
|
||||
|
||||
set -q -g status-utf8 on # expect UTF-8 (tmux < 2.2)
|
||||
set -q -g utf8 on
|
||||
setw -g mode-keys vi
|
||||
set -g status-keys vi
|
||||
set -g mouse on
|
||||
set -g base-index 1
|
||||
setw -g pane-base-index 1
|
||||
set -g renumber-windows on
|
||||
set -g detach-on-destroy off
|
||||
set -g display-panes-time 800
|
||||
set -g display-time 1500
|
||||
|
||||
set -g history-limit 5000 # boost history
|
||||
# --- Reload and editing -------------------------------------------------------
|
||||
bind r source-file ~/.tmux.conf \; display-message "tmux config reloaded"
|
||||
bind e new-window -n tmux.conf "exec \${EDITOR:-nvim} ~/.tmux.conf"
|
||||
|
||||
# edit configuration
|
||||
bind e new-window -n "~/.tmux.conf.local" "sh -c '\${EDITOR:-vim} ~/.tmux.conf.local && tmux source ~/.tmux.conf && tmux display \"~/.tmux.conf sourced\"'"
|
||||
# --- Vim-style panes ----------------------------------------------------------
|
||||
# Keep the familiar split keys and always inherit the active pane's directory.
|
||||
bind m split-window -v -c "#{pane_current_path}"
|
||||
bind n split-window -h -c "#{pane_current_path}"
|
||||
bind c new-window -c "#{pane_current_path}"
|
||||
# Re-tile the current window using Ctrl-a, Ctrl-h / Ctrl-a, Ctrl-k.
|
||||
bind C-h select-layout even-vertical
|
||||
bind C-k select-layout even-horizontal
|
||||
|
||||
# reload configuration
|
||||
bind r source-file ~/.tmux.conf \; display '~/.tmux.conf sourced'
|
||||
bind -r h select-pane -L
|
||||
bind -r j select-pane -D
|
||||
bind -r k select-pane -U
|
||||
bind -r l select-pane -R
|
||||
bind -r H resize-pane -L 5
|
||||
bind -r J resize-pane -D 5
|
||||
bind -r K resize-pane -U 5
|
||||
bind -r L resize-pane -R 5
|
||||
bind -r \{ swap-pane -U
|
||||
bind -r \} swap-pane -D
|
||||
bind z resize-pane -Z
|
||||
bind w confirm-before -p "kill pane #P? (y/n)" kill-pane
|
||||
|
||||
# run the powerline daemon
|
||||
run-shell "powerline-daemon -q"
|
||||
# source powerline tmux bindings
|
||||
source "/usr/lib/python3.14/site-packages/powerline/bindings/tmux/powerline.conf"
|
||||
# --- Windows, sessions, and buffers ------------------------------------------
|
||||
bind -r f next-window
|
||||
bind -r b previous-window
|
||||
bind Tab last-window
|
||||
bind d choose-tree -Zw
|
||||
bind s choose-tree -Zs
|
||||
bind g command-prompt -p "switch to session:" "switch-client -t '%%'"
|
||||
bind [ choose-buffer
|
||||
bind P paste-buffer # tmux buffer fallback; prefix + ] pastes the system clipboard
|
||||
bind C-l send-keys C-l \; clear-history
|
||||
|
||||
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -in -selection clipboard'
|
||||
# --- Copy mode ----------------------------------------------------------------
|
||||
bind Enter copy-mode
|
||||
bind -T copy-mode-vi v send -X begin-selection
|
||||
bind -T copy-mode-vi C-v send -X rectangle-toggle
|
||||
bind -T copy-mode-vi y send -X copy-selection-and-cancel
|
||||
bind -T copy-mode-vi Escape send -X cancel
|
||||
bind -T copy-mode-vi q send -X cancel
|
||||
bind -T copy-mode-vi H send -X start-of-line
|
||||
bind -T copy-mode-vi L send -X end-of-line
|
||||
bind -T copy-mode-vi C-u send -X halfpage-up
|
||||
bind -T copy-mode-vi C-d send -X halfpage-down
|
||||
|
||||
# Prevent random characters from appearing during yank
|
||||
set -s set-clipboard off
|
||||
# Keep tmux and the desktop clipboard in sync by default. `set-clipboard on`
|
||||
# handles OSC 52-capable terminals; these bindings cover local Wayland/X11.
|
||||
# Copy-mode y writes to the system clipboard. Prefix + ] reads it back and
|
||||
# pastes it; prefix + P remains available for the most recent tmux buffer.
|
||||
bind -T copy-mode-vi y send -X copy-pipe-and-cancel 'if command -v wl-copy >/dev/null 2>&1; then wl-copy; elif command -v xclip >/dev/null 2>&1; then xclip -in -selection clipboard; fi'
|
||||
bind ] run-shell 'if command -v wl-paste >/dev/null 2>&1; then wl-paste --no-newline | tmux load-buffer - && tmux paste-buffer; elif command -v xclip >/dev/null 2>&1; then xclip -out -selection clipboard | tmux load-buffer - && tmux paste-buffer; fi'
|
||||
|
||||
# -- display -------------------------------------------------------------------
|
||||
# --- Status line --------------------------------------------------------------
|
||||
set -g status on
|
||||
set -g status-position bottom
|
||||
set -g status-interval 5
|
||||
set -g status-justify left
|
||||
set -g status-left-length 40
|
||||
set -g status-right-length 100
|
||||
# Noctalia "Ember OLED" palette: deep near-black with restrained amber focus.
|
||||
set -g status-style "bg=#050403,fg=#fff1e6"
|
||||
set -g message-style "bg=#ff8800,fg=#1a0d00"
|
||||
set -g message-command-style "bg=#ff8800,fg=#1a0d00"
|
||||
set -g pane-border-style "fg=#6e4a31"
|
||||
set -g pane-active-border-style "fg=#ff8800"
|
||||
set -g mode-style "bg=#ffb05c,fg=#2b1600"
|
||||
# The left segment switches to a large amber cue while tmux waits for the
|
||||
# key following C-a, so prefix mode is visible rather than implicit.
|
||||
# Keep each style attribute in its own sequence: conditional-format commas then
|
||||
# cannot be mistaken for part of a #[fg=…,bg=…] style specification.
|
||||
set -g status-left "#{?client_prefix,#[bg=#ffb05c]#[fg=#2b1600]#[bold] C-a COMMAND ,#[bg=#ff8800]#[fg=#1a0d00]#[bold] #S }#[bg=#050403]#[fg=#ff8800]"
|
||||
set -g status-right "#[fg=#f4c7a1]#(whoami)@#H #[fg=#ff8800]| #[fg=#fff1e6]%Y-%m-%d %H:%M "
|
||||
setw -g window-status-format " #[fg=#f4c7a1]#I:#W "
|
||||
setw -g window-status-current-format "#[bg=#1a110c,fg=#fff1e6,bold] #I:#W "
|
||||
|
||||
set -g base-index 1 # start windows numbering at 1
|
||||
setw -g pane-base-index 1 # make pane numbering consistent with windows
|
||||
# --- Optional TPM plugins -----------------------------------------------------
|
||||
# Install TPM once: git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
|
||||
# Then reload and press prefix + I to install these plugins.
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
set -g @plugin 'tmux-plugins/tmux-sensible'
|
||||
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
||||
set -g @plugin 'tmux-plugins/tmux-continuum'
|
||||
set -g @resurrect-capture-pane-contents 'on'
|
||||
set -g @continuum-restore 'on'
|
||||
if-shell '[ -f ~/.tmux/plugins/tpm/tpm ]' 'run ~/.tmux/plugins/tpm/tpm'
|
||||
|
||||
#setw -g automatic-rename on # rename window to reflect current program
|
||||
set -g renumber-windows on # renumber windows when a window is closed
|
||||
|
||||
#set -g set-titles on # set terminal title
|
||||
|
||||
set -g display-panes-time 800 # slightly longer pane indicators display time
|
||||
set -g display-time 1000 # slightly longer status messages display time
|
||||
|
||||
set-option -g status on
|
||||
set-option -g status-interval 2
|
||||
set-option -g status-justify "centre"
|
||||
set-option -g status-left-length 60
|
||||
set-option -g status-right-length 90
|
||||
|
||||
|
||||
|
||||
# clear both screen and history
|
||||
bind -n C-l send-keys C-l \; run 'sleep 0.1' \; clear-history
|
||||
|
||||
# activity
|
||||
set -g monitor-activity on
|
||||
set -g visual-activity off
|
||||
|
||||
# set border color for panes
|
||||
set -g pane-active-border-style bg=colour130,fg=colour250
|
||||
|
||||
|
||||
# -- navigation ----------------------------------------------------------------
|
||||
|
||||
# create session
|
||||
bind C-c new-session
|
||||
|
||||
# find session
|
||||
bind C-f command-prompt -p find-session 'switch-client -t %%'
|
||||
|
||||
# split current window horizontally
|
||||
bind s split-window -v
|
||||
# split current window vertically
|
||||
bind v split-window -h
|
||||
|
||||
# close pane
|
||||
bind w kill-pane
|
||||
|
||||
# pane navigation
|
||||
bind -r h select-pane -L # move left
|
||||
bind -r j select-pane -D # move down
|
||||
bind -r k select-pane -U # move up
|
||||
bind -r l select-pane -R # move right
|
||||
bind > swap-pane -D # swap current pane with the next one
|
||||
bind < swap-pane -U # swap current pane with the previous one
|
||||
|
||||
# maximize current pane
|
||||
bind + run 'cut -c3- ~/.tmux.conf | sh -s _maximize_pane "#{session_name}" #D'
|
||||
|
||||
# pane resizing
|
||||
bind -r H resize-pane -L 2
|
||||
bind -r J resize-pane -D 2
|
||||
bind -r K resize-pane -U 2
|
||||
bind -r L resize-pane -R 2
|
||||
|
||||
# window navigation
|
||||
unbind n
|
||||
unbind p
|
||||
bin -r C-n new-window
|
||||
bind -r C-h previous-window # select previous window
|
||||
bind -r C-l next-window # select next window
|
||||
bind Tab last-window # move to last active window
|
||||
|
||||
# toggle mouse
|
||||
bind m run "cut -c3- ~/.tmux.conf | sh -s _toggle_mouse"
|
||||
|
||||
|
||||
# -- urlview -------------------------------------------------------------------
|
||||
|
||||
bind U run "cut -c3- ~/.tmux.conf | sh -s _urlview #{pane_id}"
|
||||
|
||||
|
||||
# -- facebook pathpicker -------------------------------------------------------
|
||||
|
||||
bind F run "cut -c3- ~/.tmux.conf | sh -s _fpp #{pane_id}"
|
||||
|
||||
|
||||
# -- list choice (tmux < 2.4) --------------------------------------------------
|
||||
|
||||
# vi-choice is gone in tmux >= 2.4
|
||||
run -b 'tmux bind -t vi-choice h tree-collapse 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-choice l tree-expand 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-choice K start-of-list 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-choice J end-of-list 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-choice H tree-collapse-all 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-choice L tree-expand-all 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-choice Escape cancel 2> /dev/null || true'
|
||||
|
||||
|
||||
# -- edit mode (tmux < 2.4) ----------------------------------------------------
|
||||
|
||||
# vi-edit is gone in tmux >= 2.4
|
||||
run -b 'tmux bind -ct vi-edit H start-of-line 2> /dev/null || true'
|
||||
run -b 'tmux bind -ct vi-edit L end-of-line 2> /dev/null || true'
|
||||
run -b 'tmux bind -ct vi-edit q cancel 2> /dev/null || true'
|
||||
run -b 'tmux bind -ct vi-edit Escape cancel 2> /dev/null || true'
|
||||
|
||||
|
||||
# -- copy mode -----------------------------------------------------------------
|
||||
|
||||
bind Enter copy-mode # enter copy mode
|
||||
|
||||
run -b 'tmux bind -t vi-copy v begin-selection 2> /dev/null || true'
|
||||
run -b 'tmux bind -T copy-mode-vi v send -X begin-selection 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-copy C-v rectangle-toggle 2> /dev/null || true'
|
||||
run -b 'tmux bind -T copy-mode-vi C-v send -X rectangle-toggle 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-copy y copy-selection 2> /dev/null || true'
|
||||
run -b 'tmux bind -T copy-mode-vi y send -X copy-selection-and-cancel 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-copy Escape cancel 2> /dev/null || true'
|
||||
run -b 'tmux bind -T copy-mode-vi Escape send -X cancel 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-copy H start-of-line 2> /dev/null || true'
|
||||
run -b 'tmux bind -T copy-mode-vi H send -X start-of-line 2> /dev/null || true'
|
||||
run -b 'tmux bind -t vi-copy L end-of-line 2> /dev/null || true'
|
||||
run -b 'tmux bind -T copy-mode-vi L send -X end-of-line 2> /dev/null || true'
|
||||
|
||||
# copy to macOS clipboard
|
||||
if -b 'command -v pbcopy > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | pbcopy"'
|
||||
if -b 'command -v reattach-to-user-namespace > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | reattach-to-user-namespace pbcopy"'
|
||||
# copy to X11 clipboard
|
||||
if -b 'command -v xsel > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | xsel -i -b"'
|
||||
if -b '! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | xclip -i -selection clipboard >/dev/null 2>&1"'
|
||||
# copy to Windows clipboard
|
||||
if -b 'command -v clip.exe > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | clip.exe"'
|
||||
if -b '[ -c /dev/clipboard ]' 'bind y run -b "tmux save-buffer - > /dev/clipboard"'
|
||||
|
||||
|
||||
# -- buffers -------------------------------------------------------------------
|
||||
|
||||
bind b list-buffers # list paste buffers
|
||||
bind p paste-buffer # paste from the top paste buffer
|
||||
bind P choose-buffer # choose which buffer to paste from
|
||||
|
||||
|
||||
# -- user defined overrides ----------------------------------------------------
|
||||
|
||||
if '[ -f ~/.tmux.conf.local ]' 'source ~/.tmux.conf.local'
|
||||
|
||||
|
||||
# -- 8< ------------------------------------------------------------------------
|
||||
|
||||
run 'cut -c3- ~/.tmux.conf | sh -s _apply_configuration'
|
||||
run -b '[ -z "#{window_active}" ] && [ -z "#{version}" ] && tmux set display-time 3000 \; display "This configuration will soon require tmux >= 2.4" \; set -u display-time || true'
|
||||
# Keep machine-specific bindings and experiments out of this tracked base file.
|
||||
if-shell '[ -f ~/.tmux.conf.local ]' 'source-file ~/.tmux.conf.local'
|
||||
|
||||
+6
-67
@@ -1,68 +1,7 @@
|
||||
# -- navigation ----------------------------------------------------------------
|
||||
# ~/.tmux.conf.local
|
||||
# Personal or machine-specific overrides for ~/.tmux.conf.
|
||||
# This file is deliberately small; its previous version was saved beside it.
|
||||
|
||||
# if you're running tmux within iTerm2
|
||||
# - and tmux is 1.9 or 1.9a
|
||||
# - and iTerm2 is configured to let option key act as +Esc
|
||||
# - and iTerm2 is configured to send [1;9A -> [1;9D for option + arrow keys
|
||||
# then uncomment the following line to make Meta + arrow keys mapping work
|
||||
#set -ga terminal-overrides "*:kUP3=\e[1;9A,*:kDN3=\e[1;9B,*:kRIT3=\e[1;9C,*:kLFT3=\e[1;9D"
|
||||
|
||||
|
||||
# -- windows & pane creation ---------------------------------------------------
|
||||
|
||||
# new window retains current path, possible values are:
|
||||
# - true
|
||||
# - false (default)
|
||||
tmux_conf_new_window_retain_current_path=false
|
||||
|
||||
# new pane retains current path, possible values are:
|
||||
# - true (default)
|
||||
# - false
|
||||
tmux_conf_new_pane_retain_current_path=true
|
||||
|
||||
# new pane tries to reconnect ssh sessions (experimental), possible values are:
|
||||
# - true
|
||||
# - false (default)
|
||||
tmux_conf_new_pane_reconnect_ssh=false
|
||||
|
||||
# prompt for session name when creating a new session, possible values are:
|
||||
# - true
|
||||
# - false (default)
|
||||
tmux_conf_new_session_prompt=false
|
||||
|
||||
|
||||
# -- display -------------------------------------------------------------------
|
||||
|
||||
# -- clipboard -----------------------------------------------------------------
|
||||
|
||||
# in copy mode, copying selection also copies to the OS clipboard
|
||||
# - true
|
||||
# - false (default)
|
||||
# on macOS, this requires installing reattach-to-user-namespace, see README.md
|
||||
# on Linux, this requires xsel or xclip
|
||||
tmux_conf_copy_to_os_clipboard=true
|
||||
|
||||
|
||||
# -- user customizations -------------------------------------------------------
|
||||
# this is the place to override or undo settings
|
||||
|
||||
# increase history size
|
||||
#set -g history-limit 10000
|
||||
|
||||
# start with mouse mode enabled
|
||||
set -g mouse on
|
||||
|
||||
# force Vi mode
|
||||
# really you should export VISUAL or EDITOR environment variable, see manual
|
||||
#set -g status-keys vi
|
||||
#set -g mode-keys vi
|
||||
|
||||
# replace C-b by C-a instead of using both prefixes
|
||||
set -gu prefix2
|
||||
unbind C-a
|
||||
unbind C-b
|
||||
set -g prefix C-a
|
||||
bind C-a send-prefix
|
||||
|
||||
# move status line to top
|
||||
#set -g status-position top
|
||||
# Examples:
|
||||
# set -g status-position top
|
||||
# bind -n M-Left select-pane -L
|
||||
|
||||
@@ -156,437 +156,15 @@ alias sudo='sudo '
|
||||
export EDITOR=nvim
|
||||
export VISUAL=nvim
|
||||
|
||||
# add the custom functions from the .custom_functions file
|
||||
# Load the known shell helpers; do not source foreign-shell files.
|
||||
custom_func_dir=$HOME/.scripts
|
||||
for f in $custom_func_dir/*; do source $f; done
|
||||
for f in "$custom_func_dir"/*.sh(N) "$custom_func_dir"/get_ip(N); do
|
||||
source "$f"
|
||||
done
|
||||
|
||||
# add pyenv to the path
|
||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
|
||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
|
||||
echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
if (( $+commands[pyenv] )); then
|
||||
export PYENV_ROOT="${PYENV_ROOT:-$HOME/.pyenv}"
|
||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init - zsh)"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Dotfiles
|
||||
|
||||
Personal, Arch-oriented user dotfiles and support scripts for shells, window management, applications, and package lists. This repository is a collection of machine-specific configuration, not a general-purpose installer.
|
||||
|
||||
## Status and scope
|
||||
|
||||
There is no authoritative root installation, linking, backup, overwrite, or rollback script. Do not infer one: review and apply only the individual files appropriate to a machine. Some filenames use `##class.arch_*` suffixes to distinguish machine classes. The repository also includes a nested README for the custom/vendored `st` terminal under `.config/st/`; it documents that component, not installation of this repository.
|
||||
|
||||
Several scripts assume paths below `~/.setup`, Arch tooling, and root access. Some repository scripts contain machine-specific connection details; do not publish, copy, or document such values. Use local, private configuration for hosts, addresses, accounts, and credentials.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An Arch-based system for the supplied `pacman`/`yay` package workflows.
|
||||
- The package manager or helper required by the script being considered (`pacman` and/or `yay`).
|
||||
- Desktop/session tools matching the chosen configuration (for example X11/XMonad-related files where applicable).
|
||||
- Root access only for the system-changing scripts described below.
|
||||
|
||||
Package lists in `.setup/packages/` are inputs for a user-managed installation; no repository command defines how to install an entire list. Inspect package names and select lists for the intended machine before installing anything.
|
||||
|
||||
## Safe review and user-level configuration
|
||||
|
||||
Start by reviewing the intended files and any machine-class variants. Typical areas are:
|
||||
|
||||
- `.zshrc`, `.bashrc`, `.terminal_aliases`, `.tmux.conf`, and `.p10k.zsh` — shell and terminal setup.
|
||||
- `.xmonad/`, `.Xresources##class.*`, `.xprofile##class.*`, and `.config/` — desktop/window-manager and application configuration.
|
||||
- `.scripts/` — optional shell, network, virtual-environment, and update helpers.
|
||||
- `.setup/packages/` — package lists grouped by purpose.
|
||||
|
||||
Back up existing configuration before manually placing or linking a file. No test suite is provided; validate a change in the relevant shell/session or application and keep a rollback copy of the previous configuration.
|
||||
|
||||
## Package updates
|
||||
|
||||
`.scripts/updating.sh` defines, but does not invoke, two functions. It expects `~/.setup/packages/exclude_from_updating.list`:
|
||||
|
||||
```sh
|
||||
source .scripts/updating.sh
|
||||
update_system
|
||||
# or
|
||||
update_pacman_packages
|
||||
```
|
||||
|
||||
> **Warning: system-wide, potentially disruptive operation.** `update_system` runs `yay -Syu` and `update_pacman_packages` runs `sudo pacman -Syu`, both non-interactively and with the exclusion list. Review the exclusion list and pending package changes first. These functions update the running system; they are not tests.
|
||||
|
||||
## System-changing scripts
|
||||
|
||||
The following scripts mutate files outside this repository and must be inspected before use:
|
||||
|
||||
- `.setup/config/setup_touchpad.sh` copies an X11 configuration into `/etc/X11/xorg.conf.d/` when absent.
|
||||
- `.setup/config/exclude_from_update.sh` edits `/etc/pacman.conf` with `sudo` based on `~/.setup/packages/exclude_from_updating.list`.
|
||||
- `.setup/config/dinit_add_logs_to_all_services.sh` edits files in `/etc/dinit.d` and writes log specifications under `/var/log/dinit`; its `-o` option removes existing logfile lines before adding them.
|
||||
|
||||
> **Warning: destructive/system-wide operations.** These scripts can alter system package policy, service definitions, or input configuration. They have no repository-provided dry run or rollback. Run only on a machine you control after backups and after checking paths, permissions, and the script contents.
|
||||
|
||||
`.setup/config/set_default_programs.sh` sets the default HTTP/HTTPS handler through `xdg-mime`; review the desktop entry before using it.
|
||||
|
||||
## Custom `st` terminal
|
||||
|
||||
The nested `.config/st/README.md` documents its own `make` and `sudo make install` workflow. Those commands build/install only that terminal component, may modify the system, and are not a bootstrap procedure for all dotfiles.
|
||||
Reference in New Issue
Block a user