Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f99cfeae79 | |||
| 34acd648c9 | |||
| 9647feebfa | |||
| f30bf8a3bd | |||
| 11d8e9542a | |||
| 751432fbb1 | |||
| fd50b7deb9 | |||
| ba75f3c7f7 | |||
| 03fbcb735a | |||
| 04a89118bc | |||
| f9007e3225 | |||
| b14290fffe | |||
| b93b27e43a | |||
| a91c8cf8f2 | |||
| b220b21509 | |||
| a52cc3a427 | |||
| 67004150dc | |||
| ba9c351589 | |||
| a63724d4f1 | |||
| 00947d2410 | |||
| b5ce26f244 | |||
| 793a16b2fc | |||
| 1e2f869bf3 | |||
| 7e7c62ec42 | |||
| e6d69e1e45 | |||
| 514e284b16 | |||
| efa96077a5 | |||
| 734906d50e | |||
| 47ffa48678 | |||
| e7c33b6411 | |||
| 26cb98338a | |||
| 89e9b93222 | |||
| f04bde4ec5 |
@@ -1,11 +0,0 @@
|
|||||||
-- Laptop profile: leave monitor selection to Hyprland's hotplug support.
|
|
||||||
-- Noctalia replaces the i3-era Redshift, Polybar, Blueman Applet, and Picom stack.
|
|
||||||
return {
|
|
||||||
monitors = {},
|
|
||||||
startup = {
|
|
||||||
"noctalia",
|
|
||||||
-- Start after Noctalia has claimed the StatusNotifier watcher.
|
|
||||||
"sh -c 'sleep 2; exec mullvad-vpn'",
|
|
||||||
"nextcloud",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Shared Noctalia defaults. Keep GUI experiments in state; promote durable choices here.
|
|
||||||
[shell]
|
|
||||||
setup_wizard_enabled = false
|
|
||||||
offline_mode = true
|
|
||||||
external_ip_enabled = false
|
|
||||||
telemetry_enabled = false
|
|
||||||
|
|
||||||
[theme]
|
|
||||||
mode = "dark"
|
|
||||||
source = "custom"
|
|
||||||
custom_palette = "Ember OLED"
|
|
||||||
pure_black_dark = true
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# Laptop-specific Noctalia layout. Shared privacy/theme defaults live in 10-base.toml.
|
|
||||||
[bar.main]
|
|
||||||
position = "top"
|
|
||||||
layer = "overlay"
|
|
||||||
capsule_radius = 5
|
|
||||||
center = ["group:g3", "notifications"]
|
|
||||||
end = ["bluetooth", "volume", "control-center", "group:g1", "session"]
|
|
||||||
font_weight = 400
|
|
||||||
margin_ends = 0
|
|
||||||
padding = 0
|
|
||||||
panel_overlap = 3
|
|
||||||
radius = 0
|
|
||||||
shadow = false
|
|
||||||
auto_hide = false
|
|
||||||
smart_auto_hide = false
|
|
||||||
reserve_space = true
|
|
||||||
start = ["tray", "group:g4", "group:g2", "privacy"]
|
|
||||||
thickness = 39
|
|
||||||
widget_spacing = 10
|
|
||||||
|
|
||||||
[[bar.main.capsule_group]]
|
|
||||||
enabled = true
|
|
||||||
fill = "surface_variant"
|
|
||||||
id = "g1"
|
|
||||||
members = ["caffeine", "date", "clock"]
|
|
||||||
opacity = 1.0
|
|
||||||
padding = 6.0
|
|
||||||
|
|
||||||
[[bar.main.capsule_group]]
|
|
||||||
enabled = true
|
|
||||||
fill = "surface_variant"
|
|
||||||
id = "g2"
|
|
||||||
members = ["network_rx", "network_tx", "network"]
|
|
||||||
opacity = 1.0
|
|
||||||
padding = 6.0
|
|
||||||
|
|
||||||
[[bar.main.capsule_group]]
|
|
||||||
enabled = true
|
|
||||||
fill = "surface_variant"
|
|
||||||
id = "g3"
|
|
||||||
members = ["launcher", "media", "control-center", "clipboard"]
|
|
||||||
opacity = 1.0
|
|
||||||
padding = 6.0
|
|
||||||
radius = 5.0
|
|
||||||
|
|
||||||
[[bar.main.capsule_group]]
|
|
||||||
enabled = true
|
|
||||||
fill = "surface_variant"
|
|
||||||
id = "g4"
|
|
||||||
members = ["cpu", "temp", "ram", "disk", "battery"]
|
|
||||||
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"
|
|
||||||
|
|
||||||
[widget.disk]
|
|
||||||
type = "sysmon"
|
|
||||||
stat = "disk_pct"
|
|
||||||
display = "text"
|
|
||||||
path = "/"
|
|
||||||
|
|
||||||
[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]
|
[module/public_ip]
|
||||||
type = custom/text
|
type = custom/text
|
||||||
content=
|
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]
|
[module/mic_status]
|
||||||
type = custom/script
|
type = custom/script
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ set vcs_backend_svn disabled
|
|||||||
# Truncate the long commit messages to this length when shown in the statusbar.
|
# Truncate the long commit messages to this length when shown in the statusbar.
|
||||||
set vcs_msg_length 50
|
set vcs_msg_length 50
|
||||||
|
|
||||||
# Use one of the supported image preview protocols
|
# Render image previews through Kitty's native graphics protocol.
|
||||||
set preview_images true
|
set preview_images true
|
||||||
|
|
||||||
# Set the preview image method. Supported methods:
|
# Set the preview image method. Supported methods:
|
||||||
@@ -114,7 +114,7 @@ set preview_images true
|
|||||||
# Preview images in full color with the external command "ueberzug".
|
# Preview images in full color with the external command "ueberzug".
|
||||||
# Images are shown by using a child window.
|
# Images are shown by using a child window.
|
||||||
# Only for users who run X11 in GNU/Linux.
|
# Only for users who run X11 in GNU/Linux.
|
||||||
set preview_images_method ueberzug
|
set preview_images_method kitty
|
||||||
|
|
||||||
# Delay in seconds before displaying an image with the w3m method.
|
# Delay in seconds before displaying an image with the w3m method.
|
||||||
# Increase it in case of experiencing display corruption.
|
# Increase it in case of experiencing display corruption.
|
||||||
|
|||||||
@@ -33,10 +33,10 @@
|
|||||||
"interval": 1,
|
"interval": 1,
|
||||||
"tooltip-format": "\n<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
|
"tooltip-format": "\n<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
|
||||||
"calendar-weeks-pos": "right",
|
"calendar-weeks-pos": "right",
|
||||||
"today-format": "<span color='#7645AD'><b><u>{}</u></b></span>",
|
"today-format": "<span color='#ff8800'><b><u>{}</u></b></span>",
|
||||||
"format-calendar": "<span color='#aeaeae'><b>{}</b></span>",
|
"format-calendar": "<span color='#f4c7a1'><b>{}</b></span>",
|
||||||
"format-calendar-weeks": "<span color='#aeaeae'><b>W{:%V}</b></span>",
|
"format-calendar-weeks": "<span color='#f4c7a1'><b>W{:%V}</b></span>",
|
||||||
"format-calendar-weekdays": "<span color='#aeaeae'><b>{}</b></span>"
|
"format-calendar-weekdays": "<span color='#f4c7a1'><b>{}</b></span>"
|
||||||
},
|
},
|
||||||
|
|
||||||
"disk": {
|
"disk": {
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env 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
|
|
||||||
|
|
||||||
|
# Toggle the default PulseAudio sink's mute state.
|
||||||
|
amixer -D pulse sset Master toggle >/dev/null
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ if [ "$updates" -gt 0 ]; then
|
|||||||
echo " ($(format $updates_arch)/$(format $updates_aur))"
|
echo " ($(format $updates_arch)/$(format $updates_aur))"
|
||||||
else
|
else
|
||||||
echo
|
echo
|
||||||
fia
|
fi
|
||||||
|
|||||||
+32
-31
@@ -1,22 +1,14 @@
|
|||||||
|
/* Noctalia Ember OLED: near-black surfaces, warm amber focus. */
|
||||||
* {
|
* {
|
||||||
font-family: "JetBrainsMono Nerd Font,JetBrainsMono NF" ;
|
font-family: "JetBrainsMono Nerd Font,JetBrainsMono NF";
|
||||||
color: white;
|
color: #fff1e6;
|
||||||
}
|
|
||||||
|
|
||||||
window#waybar {
|
|
||||||
background: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modules-right {
|
|
||||||
background: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modules-center {
|
|
||||||
background: #000000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window#waybar,
|
||||||
|
.modules-right,
|
||||||
|
.modules-center,
|
||||||
.modules-left {
|
.modules-left {
|
||||||
background: #000000;
|
background: #050403;
|
||||||
}
|
}
|
||||||
|
|
||||||
#battery,
|
#battery,
|
||||||
@@ -41,40 +33,49 @@ window#waybar {
|
|||||||
min-width: 1ex;
|
min-width: 1ex;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tray menu * {
|
#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,
|
#temperature.critical,
|
||||||
#pulseaudio {
|
#pulseaudio {
|
||||||
min-width: 5ex;
|
min-width: 5ex;
|
||||||
}
|
}
|
||||||
#pulseaudio.muted {
|
|
||||||
color: #FF0000;
|
#pulseaudio.muted,
|
||||||
}
|
|
||||||
#pulseaudio.mic.muted {
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
#pulseaudio.mic:not(.source-muted) {
|
#pulseaudio.mic:not(.source-muted) {
|
||||||
color: #fc0202;
|
color: #ff6b4a;
|
||||||
}
|
}
|
||||||
#clock{
|
|
||||||
color: #f9780e;
|
#pulseaudio.mic.muted {
|
||||||
|
color: #6e4a31;
|
||||||
|
}
|
||||||
|
|
||||||
|
#clock {
|
||||||
|
color: #ff8800;
|
||||||
}
|
}
|
||||||
|
|
||||||
#battery.charging {
|
#battery.charging {
|
||||||
color: #ffffff;
|
color: #1a0d00;
|
||||||
background-color: #26A65B;
|
background-color: #c98a45;
|
||||||
}
|
}
|
||||||
|
|
||||||
#battery.warning:not(.charging) {
|
#battery.warning:not(.charging) {
|
||||||
background-color: #ffbe61;
|
background-color: #ffb05c;
|
||||||
color: black;
|
color: #2b1600;
|
||||||
}
|
}
|
||||||
|
|
||||||
#battery.critical:not(.charging) {
|
#battery.critical:not(.charging) {
|
||||||
background-color: #f53c3c;
|
background-color: #ff6b4a;
|
||||||
color: #ffffff;
|
color: #2b0700;
|
||||||
animation-name: blink;
|
animation-name: blink;
|
||||||
animation-duration: 0.5s;
|
animation-duration: 0.5s;
|
||||||
animation-timing-function: linear;
|
animation-timing-function: linear;
|
||||||
|
|||||||
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-status-bridge/ui/src-tauri/target/release/pi-status-ui" "$@"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
__pycache__/
|
||||||
|
.ruff_cache/
|
||||||
|
index-cache.json
|
||||||
|
index-cache-*.json
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Safely create one direct child in the configured knowledge vault."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def fail(message: str) -> int:
|
||||||
|
print(message, file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def child_name(raw: str) -> str | None:
|
||||||
|
name = raw.strip()
|
||||||
|
if not name or name in {".", ".."} or "/" in name or "\\" in name or "\0" in name:
|
||||||
|
return None
|
||||||
|
if name.startswith("."):
|
||||||
|
return None
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if len(sys.argv) != 5:
|
||||||
|
return fail("usage: create-entry.py VAULT KIND CURRENT_DIRECTORY NAME")
|
||||||
|
raw_vault, kind, current_directory, raw_name = sys.argv[1:]
|
||||||
|
vault = Path(raw_vault).expanduser().resolve()
|
||||||
|
if not vault.is_dir():
|
||||||
|
return fail(f"vault does not exist: {vault}")
|
||||||
|
if kind not in {"note", "directory"}:
|
||||||
|
return fail("kind must be note or directory")
|
||||||
|
current = (vault / current_directory).resolve()
|
||||||
|
if current != vault and vault not in current.parents:
|
||||||
|
return fail("current directory escaped the vault")
|
||||||
|
if not current.is_dir():
|
||||||
|
return fail("current directory no longer exists")
|
||||||
|
|
||||||
|
name = child_name(raw_name)
|
||||||
|
if name is None:
|
||||||
|
return fail("use a non-hidden direct name without slashes")
|
||||||
|
if kind == "note" and not name.lower().endswith(".md"):
|
||||||
|
name += ".md"
|
||||||
|
target = (current / name).resolve()
|
||||||
|
if target.parent != current:
|
||||||
|
return fail("target escaped the current directory")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if kind == "directory":
|
||||||
|
target.mkdir()
|
||||||
|
else:
|
||||||
|
title = target.stem
|
||||||
|
with target.open("x", encoding="utf-8") as handle:
|
||||||
|
handle.write(f"# {title}\n")
|
||||||
|
except FileExistsError:
|
||||||
|
return fail(f"already exists: {name}")
|
||||||
|
except OSError as error:
|
||||||
|
return fail(f"cannot create {name}: {error}")
|
||||||
|
|
||||||
|
relative = target.relative_to(vault).as_posix()
|
||||||
|
json.dump(
|
||||||
|
{
|
||||||
|
"kind": kind,
|
||||||
|
"relative": relative,
|
||||||
|
"name": name,
|
||||||
|
"absolute": str(target),
|
||||||
|
},
|
||||||
|
sys.stdout,
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Focus the most recently focused Obsidian window under Hyprland."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from urllib.parse import quote, urlencode
|
||||||
|
|
||||||
|
OBSIDIAN_CLASS = "md.obsidian.Obsidian"
|
||||||
|
VAULT_ROOT: Path
|
||||||
|
OBSIDIAN_VAULT: str
|
||||||
|
|
||||||
|
|
||||||
|
def hyprctl(*arguments: str) -> subprocess.CompletedProcess[str]:
|
||||||
|
return subprocess.run(
|
||||||
|
["hyprctl", *arguments],
|
||||||
|
check=False,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def focus_expression(field: str, value: str) -> str:
|
||||||
|
escaped = value.replace("\\", "\\\\").replace('"', '\\"')
|
||||||
|
return f'hl.dispatch(hl.dsp.focus({{ {field} = "{escaped}" }}))'
|
||||||
|
|
||||||
|
|
||||||
|
def note_uri() -> str | None:
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print("usage: focus-obsidian.py VAULT VAULT_ID NOTE_PATH", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
note = Path(sys.argv[3]).resolve()
|
||||||
|
try:
|
||||||
|
relative = note.relative_to(VAULT_ROOT).as_posix()
|
||||||
|
except ValueError as error:
|
||||||
|
print(f"note escaped the knowledge vault: {error}", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
return "obsidian://open?" + urlencode(
|
||||||
|
{"vault": OBSIDIAN_VAULT, "file": relative}, quote_via=quote
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def dispatch_uri(uri: str) -> bool:
|
||||||
|
try:
|
||||||
|
subprocess.Popen(
|
||||||
|
["obsidian", uri],
|
||||||
|
stdin=subprocess.DEVNULL,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
start_new_session=True,
|
||||||
|
)
|
||||||
|
except OSError as error:
|
||||||
|
print(f"cannot open Obsidian: {error}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
global VAULT_ROOT, OBSIDIAN_VAULT
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print("usage: focus-obsidian.py VAULT VAULT_ID NOTE_PATH", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
VAULT_ROOT = Path(sys.argv[1]).expanduser().resolve()
|
||||||
|
OBSIDIAN_VAULT = sys.argv[2]
|
||||||
|
if not VAULT_ROOT.is_dir():
|
||||||
|
print(f"vault does not exist: {VAULT_ROOT}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
if not OBSIDIAN_VAULT:
|
||||||
|
print("vault is not registered in Obsidian", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
uri = note_uri()
|
||||||
|
if uri is None or not dispatch_uri(uri):
|
||||||
|
return 1
|
||||||
|
target: dict[str, object] | None = None
|
||||||
|
for _ in range(150):
|
||||||
|
result = hyprctl("clients", "-j")
|
||||||
|
if result.returncode == 0:
|
||||||
|
try:
|
||||||
|
clients = json.loads(result.stdout)
|
||||||
|
except json.JSONDecodeError as error:
|
||||||
|
print(f"cannot parse hyprctl clients: {error}", file=sys.stderr)
|
||||||
|
clients = []
|
||||||
|
matches = [
|
||||||
|
client for client in clients if client.get("class") == OBSIDIAN_CLASS
|
||||||
|
]
|
||||||
|
if matches:
|
||||||
|
target = min(
|
||||||
|
matches, key=lambda client: client.get("focusHistoryID", 1_000_000)
|
||||||
|
)
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
if target is None:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
workspace = target.get("workspace")
|
||||||
|
address = target.get("address")
|
||||||
|
if not isinstance(workspace, dict) or not isinstance(address, str):
|
||||||
|
return 1
|
||||||
|
workspace_id = workspace.get("id")
|
||||||
|
if not isinstance(workspace_id, int):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
workspace_expression = focus_expression("workspace", str(workspace_id))
|
||||||
|
selector = f"address:{address}"
|
||||||
|
window_expression = focus_expression("window", selector)
|
||||||
|
focused_samples = 0
|
||||||
|
for attempt in range(20):
|
||||||
|
if attempt == 0 or attempt % 5 == 0:
|
||||||
|
hyprctl("eval", workspace_expression)
|
||||||
|
hyprctl("eval", window_expression)
|
||||||
|
active = hyprctl("activewindow", "-j")
|
||||||
|
if active.returncode == 0:
|
||||||
|
try:
|
||||||
|
active_window = json.loads(active.stdout)
|
||||||
|
except json.JSONDecodeError as error:
|
||||||
|
print(f"cannot parse active Hyprland window: {error}", file=sys.stderr)
|
||||||
|
active_window = {}
|
||||||
|
focused_samples = (
|
||||||
|
focused_samples + 1 if active_window.get("address") == address else 0
|
||||||
|
)
|
||||||
|
if focused_samples >= 3:
|
||||||
|
# Re-send after focus: Electron occasionally consumes the URI
|
||||||
|
# before its renderer is ready, leaving the prior note visible.
|
||||||
|
if not dispatch_uri(uri):
|
||||||
|
return 1
|
||||||
|
time.sleep(0.35)
|
||||||
|
hyprctl("eval", window_expression)
|
||||||
|
return 0
|
||||||
|
time.sleep(0.1)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build bounded JSON cache chunks for a Markdown vault."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unicodedata
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
SKIP_DIRS = {
|
||||||
|
".git",
|
||||||
|
".obsidian",
|
||||||
|
".trash",
|
||||||
|
".stfolder",
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"build",
|
||||||
|
}
|
||||||
|
HEADING = re.compile(r"^#\s+(.+?)\s*$", re.MULTILINE)
|
||||||
|
WORDS = re.compile(r"[^\W_]+", re.UNICODE)
|
||||||
|
CHUNK_BYTES = 96 * 1024
|
||||||
|
RECORD_BYTES = 48 * 1024
|
||||||
|
|
||||||
|
|
||||||
|
def visible_directory(name: str) -> bool:
|
||||||
|
return name not in SKIP_DIRS and not name.startswith(".")
|
||||||
|
|
||||||
|
|
||||||
|
def note_title(path: Path, content: str) -> str:
|
||||||
|
match = HEADING.search(content)
|
||||||
|
return match.group(1).strip() if match else path.stem
|
||||||
|
|
||||||
|
|
||||||
|
def folded(value: str) -> str:
|
||||||
|
"""Case-fold and strip accents so ASCII queries match Unicode notes."""
|
||||||
|
normalized = unicodedata.normalize("NFKD", value.casefold())
|
||||||
|
return "".join(
|
||||||
|
character for character in normalized if not unicodedata.combining(character)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def token_buckets(content: str) -> dict[str, dict[str, list[str]]]:
|
||||||
|
buckets: dict[str, dict[str, list[str]]] = {}
|
||||||
|
for token in sorted(set(WORDS.findall(content))):
|
||||||
|
if not token:
|
||||||
|
continue
|
||||||
|
by_length = buckets.setdefault(token[0], {})
|
||||||
|
by_length.setdefault(str(len(token)), []).append(token)
|
||||||
|
return buckets
|
||||||
|
|
||||||
|
|
||||||
|
def encoded(record: dict[str, Any]) -> str:
|
||||||
|
return json.dumps(record, ensure_ascii=False, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
|
def fold_records(characters: set[str]) -> list[dict[str, Any]]:
|
||||||
|
mapping: dict[str, str] = {}
|
||||||
|
for character in characters:
|
||||||
|
variants = {character, character.lower(), character.upper(), character.title()}
|
||||||
|
for variant in variants:
|
||||||
|
for variant_character in variant:
|
||||||
|
mapping[variant_character] = folded(variant_character)
|
||||||
|
records: list[dict[str, Any]] = []
|
||||||
|
current: dict[str, str] = {}
|
||||||
|
for source, target in sorted(mapping.items()):
|
||||||
|
candidate = {**current, source: target}
|
||||||
|
record = {"kind": "fold", "map": candidate}
|
||||||
|
if current and len(encoded(record).encode("utf-8")) > RECORD_BYTES:
|
||||||
|
records.append({"kind": "fold", "map": current})
|
||||||
|
current = {source: target}
|
||||||
|
else:
|
||||||
|
current = candidate
|
||||||
|
if current:
|
||||||
|
records.append({"kind": "fold", "map": current})
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
|
def directory_record(relative: str) -> dict[str, Any]:
|
||||||
|
record = {"kind": "directory", "relative": relative}
|
||||||
|
if len(encoded(record).encode("utf-8")) > RECORD_BYTES:
|
||||||
|
raise ValueError(f"directory metadata exceeded bounded size: {relative}")
|
||||||
|
return record
|
||||||
|
|
||||||
|
|
||||||
|
def note_record(title: str, relative: str) -> dict[str, Any]:
|
||||||
|
display_title = title[:256] + ("…" if len(title) > 256 else "")
|
||||||
|
record = {
|
||||||
|
"kind": "note",
|
||||||
|
"id": relative,
|
||||||
|
"title": display_title,
|
||||||
|
"relative": relative,
|
||||||
|
"titleRaw": display_title.casefold(),
|
||||||
|
"pathRaw": relative.casefold(),
|
||||||
|
"titleSearch": folded(display_title),
|
||||||
|
"pathSearch": folded(relative),
|
||||||
|
}
|
||||||
|
if len(encoded(record).encode("utf-8")) > RECORD_BYTES:
|
||||||
|
raise ValueError(f"note metadata exceeded bounded size: {relative}")
|
||||||
|
return record
|
||||||
|
|
||||||
|
|
||||||
|
def content_record(relative: str, fragment: str) -> dict[str, Any]:
|
||||||
|
content_search = folded(fragment)
|
||||||
|
return {
|
||||||
|
"kind": "content",
|
||||||
|
"id": relative,
|
||||||
|
"fragment": fragment,
|
||||||
|
"lines": fragment.split("\n"),
|
||||||
|
"contentRaw": fragment.casefold(),
|
||||||
|
"contentSearch": content_search,
|
||||||
|
"contentTokens": token_buckets(content_search),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def content_records(relative: str, content: str) -> list[dict[str, Any]]:
|
||||||
|
"""Split one note into bounded records without changing its original text."""
|
||||||
|
pending = [content]
|
||||||
|
records: list[dict[str, Any]] = []
|
||||||
|
while pending:
|
||||||
|
fragment = pending.pop()
|
||||||
|
record = content_record(relative, fragment)
|
||||||
|
if len(encoded(record).encode("utf-8")) <= RECORD_BYTES:
|
||||||
|
records.append(record)
|
||||||
|
continue
|
||||||
|
midpoint = max(len(fragment) // 2, 1)
|
||||||
|
if midpoint >= len(fragment):
|
||||||
|
raise ValueError(f"cannot split oversized content in {relative}")
|
||||||
|
pending.extend((fragment[midpoint:], fragment[:midpoint]))
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
|
def index_records(root: Path) -> list[dict[str, Any]]:
|
||||||
|
notes: list[tuple[str, str, str]] = []
|
||||||
|
indexed_directories: set[str] = set()
|
||||||
|
characters: set[str] = set()
|
||||||
|
for current, directories, filenames in os.walk(root):
|
||||||
|
directories[:] = sorted(
|
||||||
|
name
|
||||||
|
for name in directories
|
||||||
|
if visible_directory(name) and not Path(current, name).is_symlink()
|
||||||
|
)
|
||||||
|
for directory in directories:
|
||||||
|
relative_directory = Path(current, directory).relative_to(root).as_posix()
|
||||||
|
indexed_directories.add(relative_directory)
|
||||||
|
characters.update(relative_directory)
|
||||||
|
for filename in sorted(filenames):
|
||||||
|
if not filename.lower().endswith(".md") or filename.startswith("."):
|
||||||
|
continue
|
||||||
|
path = Path(current, filename)
|
||||||
|
if path.is_symlink():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
content = path.read_text(encoding="utf-8", errors="replace")
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
relative = path.relative_to(root).as_posix()
|
||||||
|
title = note_title(path, content)
|
||||||
|
characters.update(title)
|
||||||
|
characters.update(relative)
|
||||||
|
characters.update(content)
|
||||||
|
notes.append((title, relative, content))
|
||||||
|
|
||||||
|
notes.sort(key=lambda note: (note[0].casefold(), note[1].casefold()))
|
||||||
|
records = fold_records(characters)
|
||||||
|
for relative in sorted(indexed_directories, key=str.casefold):
|
||||||
|
records.append(directory_record(relative))
|
||||||
|
for title, relative, content in notes:
|
||||||
|
records.append(note_record(title, relative))
|
||||||
|
records.extend(content_records(relative, content))
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
|
def write_chunks(cache: Path, records: list[dict[str, Any]]) -> list[str]:
|
||||||
|
encoded_records = [encoded(record) for record in records]
|
||||||
|
chunks: list[list[str]] = []
|
||||||
|
current: list[str] = []
|
||||||
|
current_bytes = 2
|
||||||
|
for record in encoded_records:
|
||||||
|
record_bytes = len(record.encode("utf-8"))
|
||||||
|
if record_bytes > RECORD_BYTES:
|
||||||
|
raise ValueError("index record exceeded its bounded size")
|
||||||
|
separator_bytes = 1 if current else 0
|
||||||
|
if current and current_bytes + separator_bytes + record_bytes > CHUNK_BYTES:
|
||||||
|
chunks.append(current)
|
||||||
|
current = []
|
||||||
|
current_bytes = 2
|
||||||
|
separator_bytes = 0
|
||||||
|
current.append(record)
|
||||||
|
current_bytes += separator_bytes + record_bytes
|
||||||
|
if current or not chunks:
|
||||||
|
chunks.append(current)
|
||||||
|
|
||||||
|
names: list[str] = []
|
||||||
|
for index, chunk in enumerate(chunks):
|
||||||
|
chunk_name = f"index-cache-{index:03d}.json"
|
||||||
|
path = (cache.parent / chunk_name).resolve()
|
||||||
|
if path.parent != cache.parent:
|
||||||
|
raise ValueError("cache chunk escaped the plugin directory")
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
mode="w", encoding="utf-8", dir=cache.parent, delete=False
|
||||||
|
) as handle:
|
||||||
|
handle.write("[" + ",".join(chunk) + "]")
|
||||||
|
temporary = Path(handle.name)
|
||||||
|
os.replace(temporary, path)
|
||||||
|
names.append(chunk_name)
|
||||||
|
|
||||||
|
active = set(names)
|
||||||
|
for stale in cache.parent.glob(f"{cache.stem}-*.json"):
|
||||||
|
if stale.name not in active:
|
||||||
|
stale.unlink(missing_ok=True)
|
||||||
|
cache.unlink(missing_ok=True)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("usage: index.py VAULT CACHE", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
root = Path(sys.argv[1]).expanduser().resolve()
|
||||||
|
requested_cache = Path(sys.argv[2]).expanduser().resolve()
|
||||||
|
plugin_dir = Path(__file__).resolve().parent
|
||||||
|
if (
|
||||||
|
requested_cache.parent != plugin_dir
|
||||||
|
or requested_cache.name != "index-cache.json"
|
||||||
|
):
|
||||||
|
print("cache must be index-cache.json in the plugin directory", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
if not root.is_dir():
|
||||||
|
print(f"vault does not exist: {root}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
records = index_records(root)
|
||||||
|
chunk_names = write_chunks(plugin_dir / "index-cache.json", records)
|
||||||
|
note_count = sum(record["kind"] == "note" for record in records)
|
||||||
|
json.dump(
|
||||||
|
{"chunks": chunk_names, "notes": note_count},
|
||||||
|
sys.stdout,
|
||||||
|
separators=(",", ":"),
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Safely move or delete entries inside the knowledge vault."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
VAULT: Path
|
||||||
|
|
||||||
|
|
||||||
|
def fail(message: str) -> int:
|
||||||
|
print(message, file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def vault_entry(relative: str) -> Path | None:
|
||||||
|
if not relative or relative.startswith("/") or "\0" in relative:
|
||||||
|
return None
|
||||||
|
candidate = VAULT / relative
|
||||||
|
parent = candidate.parent.resolve()
|
||||||
|
if parent != VAULT and VAULT not in parent.parents:
|
||||||
|
return None
|
||||||
|
return parent / candidate.name
|
||||||
|
|
||||||
|
|
||||||
|
def move_entry(source_relative: str, destination_relative: str) -> int:
|
||||||
|
source = vault_entry(source_relative)
|
||||||
|
destination_directory = (VAULT / destination_relative).resolve()
|
||||||
|
if source is None or not (source.exists() or source.is_symlink()):
|
||||||
|
return fail("selected entry no longer exists")
|
||||||
|
if destination_directory != VAULT and VAULT not in destination_directory.parents:
|
||||||
|
return fail("destination escaped the vault")
|
||||||
|
if not destination_directory.is_dir():
|
||||||
|
return fail("destination directory no longer exists")
|
||||||
|
if source.is_dir() and (
|
||||||
|
destination_directory == source or source in destination_directory.parents
|
||||||
|
):
|
||||||
|
return fail("cannot move a directory into itself")
|
||||||
|
|
||||||
|
destination = destination_directory / source.name
|
||||||
|
if destination.exists() or destination.is_symlink():
|
||||||
|
return fail(f"already exists: {destination.name}")
|
||||||
|
try:
|
||||||
|
source.rename(destination)
|
||||||
|
except OSError as error:
|
||||||
|
return fail(f"cannot move {source.name}: {error}")
|
||||||
|
|
||||||
|
json.dump(
|
||||||
|
{
|
||||||
|
"action": "move",
|
||||||
|
"relative": destination.relative_to(VAULT).as_posix(),
|
||||||
|
"kind": "directory" if destination.is_dir() else "note",
|
||||||
|
},
|
||||||
|
sys.stdout,
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def delete_entry(source_relative: str) -> int:
|
||||||
|
source = vault_entry(source_relative)
|
||||||
|
if source is None or not (source.exists() or source.is_symlink()):
|
||||||
|
return fail("selected entry no longer exists")
|
||||||
|
try:
|
||||||
|
if source.is_symlink():
|
||||||
|
source.unlink()
|
||||||
|
elif source.is_dir():
|
||||||
|
shutil.rmtree(source)
|
||||||
|
else:
|
||||||
|
source.unlink()
|
||||||
|
except OSError as error:
|
||||||
|
return fail(f"cannot delete {source.name}: {error}")
|
||||||
|
json.dump({"action": "delete", "relative": source_relative}, sys.stdout)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
global VAULT
|
||||||
|
if len(sys.argv) < 4:
|
||||||
|
return fail(
|
||||||
|
"usage: manage-entry.py VAULT ACTION SOURCE [DESTINATION_DIRECTORY]"
|
||||||
|
)
|
||||||
|
VAULT = Path(sys.argv[1]).expanduser().resolve()
|
||||||
|
if not VAULT.is_dir():
|
||||||
|
return fail(f"vault does not exist: {VAULT}")
|
||||||
|
action, source = sys.argv[2:4]
|
||||||
|
if action == "move" and len(sys.argv) == 5:
|
||||||
|
return move_entry(source, sys.argv[4])
|
||||||
|
if action == "delete" and len(sys.argv) == 4:
|
||||||
|
return delete_entry(source)
|
||||||
|
return fail("invalid file operation")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
|||||||
|
id = "alex/knowledge-lookup"
|
||||||
|
name = "Knowledge Lookup"
|
||||||
|
version = "1.0.0"
|
||||||
|
plugin_api = 24
|
||||||
|
author = "alex"
|
||||||
|
license = "MIT"
|
||||||
|
dependencies = []
|
||||||
|
tags = ["productivity", "knowledge"]
|
||||||
|
icon = "notes"
|
||||||
|
description = "Search and preview a local Obsidian knowledge vault from the bar."
|
||||||
|
|
||||||
|
[[setting]]
|
||||||
|
key = "vault_path"
|
||||||
|
type = "folder"
|
||||||
|
label_key = "Knowledge vault directory"
|
||||||
|
description_key = "Directory containing the Markdown vault to browse"
|
||||||
|
default = ""
|
||||||
|
|
||||||
|
[[widget]]
|
||||||
|
id = "bar"
|
||||||
|
entry = "widget.luau"
|
||||||
|
|
||||||
|
[[panel]]
|
||||||
|
id = "panel"
|
||||||
|
entry = "panel.luau"
|
||||||
|
width = 1100
|
||||||
|
height = 720
|
||||||
|
placement = "floating"
|
||||||
|
position = "center"
|
||||||
|
keyboard_focus = "exclusive"
|
||||||
|
dismiss_on_outside_click = true
|
||||||
|
capture_keys = [
|
||||||
|
"j",
|
||||||
|
"k",
|
||||||
|
"h",
|
||||||
|
"l",
|
||||||
|
"ctrl+U0063",
|
||||||
|
"ctrl+U0061",
|
||||||
|
"ctrl+U006e",
|
||||||
|
"g",
|
||||||
|
"shift+U0047",
|
||||||
|
"q",
|
||||||
|
"o",
|
||||||
|
"r",
|
||||||
|
"x",
|
||||||
|
"p",
|
||||||
|
"d",
|
||||||
|
"y",
|
||||||
|
"n",
|
||||||
|
"slash",
|
||||||
|
"enter",
|
||||||
|
]
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Validate a vault path and resolve its registered Obsidian vault ID."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
OBSIDIAN_CONFIG = Path.home() / ".config" / "obsidian" / "obsidian.json"
|
||||||
|
|
||||||
|
|
||||||
|
def fail(message: str) -> int:
|
||||||
|
json.dump({"ok": False, "error": message}, sys.stdout)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
return fail("No vault directory is configured")
|
||||||
|
raw_path = sys.argv[1].strip()
|
||||||
|
if not raw_path:
|
||||||
|
return fail("No vault directory is configured")
|
||||||
|
vault = Path(raw_path).expanduser().resolve()
|
||||||
|
if not vault.is_dir():
|
||||||
|
return fail(f"Vault directory was not found: {vault}")
|
||||||
|
|
||||||
|
vault_id: str | None = None
|
||||||
|
config_error: str | None = None
|
||||||
|
try:
|
||||||
|
config = json.loads(OBSIDIAN_CONFIG.read_text(encoding="utf-8"))
|
||||||
|
for registered_id, metadata in config.get("vaults", {}).items():
|
||||||
|
registered_path = Path(str(metadata.get("path", ""))).expanduser().resolve()
|
||||||
|
if registered_path == vault:
|
||||||
|
vault_id = str(registered_id)
|
||||||
|
break
|
||||||
|
except FileNotFoundError:
|
||||||
|
config_error = "Obsidian has not registered any vaults yet"
|
||||||
|
except (OSError, json.JSONDecodeError, TypeError) as error:
|
||||||
|
config_error = f"Cannot read Obsidian vault registration: {error}"
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"ok": True,
|
||||||
|
"path": str(vault),
|
||||||
|
"name": vault.name,
|
||||||
|
"vaultId": vault_id,
|
||||||
|
"obsidianError": config_error
|
||||||
|
or (
|
||||||
|
None
|
||||||
|
if vault_id
|
||||||
|
else "This directory is not registered as an Obsidian vault"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
json.dump(response, sys.stdout)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
--!strict
|
||||||
|
|
||||||
|
local PANEL_ID = "alex/knowledge-lookup:panel"
|
||||||
|
|
||||||
|
function update()
|
||||||
|
barWidget.setGlyph("book-2")
|
||||||
|
barWidget.setText("")
|
||||||
|
barWidget.setTooltip("Knowledge lookup · Super+N")
|
||||||
|
end
|
||||||
|
|
||||||
|
function onClick()
|
||||||
|
noctalia.togglePanel(PANEL_ID)
|
||||||
|
end
|
||||||
|
|
||||||
|
function onRightClick()
|
||||||
|
noctalia.runAsync({ "obsidian" })
|
||||||
|
end
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../projects/pi-status-bridge/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 previous = {}
|
||||||
local request_in_flight = false
|
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()
|
function update()
|
||||||
noctalia.setUpdateInterval(2000)
|
noctalia.setUpdateInterval(2000)
|
||||||
|
|
||||||
@@ -23,7 +43,8 @@ function update()
|
|||||||
request_in_flight = false
|
request_in_flight = false
|
||||||
|
|
||||||
if result.exitCode ~= 0 then
|
if result.exitCode ~= 0 then
|
||||||
barWidget.setText("CPU —")
|
renderStatus("CPU —", "#fff1e6")
|
||||||
|
barWidget.setTooltip("Unable to read CPU utilization")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -47,12 +68,19 @@ function update()
|
|||||||
previous[name] = { total = total, idle = idle }
|
previous[name] = { total = total, idle = idle }
|
||||||
end
|
end
|
||||||
|
|
||||||
barWidget.setGlyph("cpu")
|
|
||||||
if sampled > 0 then
|
if sampled > 0 then
|
||||||
barWidget.setText(string.format("%.0f%%", utilization))
|
-- Keep the aggregate display, but base its heat color on average
|
||||||
barWidget.setTooltip("Aggregate CPU utilization (100% per logical CPU)")
|
-- 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
|
else
|
||||||
barWidget.setText("—")
|
renderStatus("—", "#fff1e6")
|
||||||
barWidget.setTooltip("Sampling CPU utilization…")
|
barWidget.setTooltip("Sampling CPU utilization…")
|
||||||
end
|
end
|
||||||
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 {
|
END {
|
||||||
if (!total || !available) exit 1
|
if (!total || !available) exit 1
|
||||||
used = total - available
|
used = total - available
|
||||||
|
memory_used = used * 100 / total
|
||||||
if (swap_total > 0) {
|
if (swap_total > 0) {
|
||||||
swap_used = (swap_total - swap_free) * 100 / swap_total
|
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 {
|
} 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]]
|
}' /proc/meminfo]]
|
||||||
|
|
||||||
local request_in_flight = false
|
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()
|
function update()
|
||||||
noctalia.setUpdateInterval(5000)
|
noctalia.setUpdateInterval(5000)
|
||||||
|
|
||||||
@@ -30,14 +51,32 @@ function update()
|
|||||||
request_in_flight = false
|
request_in_flight = false
|
||||||
|
|
||||||
if result.exitCode ~= 0 then
|
if result.exitCode ~= 0 then
|
||||||
barWidget.setText("RAM —")
|
renderStatus("RAM —", "#fff1e6")
|
||||||
barWidget.setTooltip("Unable to read /proc/meminfo")
|
barWidget.setTooltip("Unable to read /proc/meminfo")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local text = string.gsub(result.stdout, "%s+$", "")
|
local text, memory_percent, swap_percent = string.match(
|
||||||
barWidget.setGlyph("memory")
|
result.stdout,
|
||||||
barWidget.setText(text)
|
"^([^\t]+)\t([%d.]+)\t([%d.]+)"
|
||||||
barWidget.setTooltip("RAM used / total · S = swap used")
|
)
|
||||||
|
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)
|
||||||
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"
|
version = "1.0.0"
|
||||||
plugin_api = 3
|
plugin_api = 3
|
||||||
author = "alex"
|
author = "alex"
|
||||||
description = "Low-overhead memory and swap indicator for the bar."
|
description = "Low-overhead system and network status indicators for the bar."
|
||||||
|
|
||||||
[[widget]]
|
[[widget]]
|
||||||
id = "cpu"
|
id = "cpu"
|
||||||
@@ -12,3 +12,23 @@ entry = "cpu.luau"
|
|||||||
[[widget]]
|
[[widget]]
|
||||||
id = "memory"
|
id = "memory"
|
||||||
entry = "memory.luau"
|
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
|
"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,
|
"quietStartup": true,
|
||||||
"lastChangelogVersion": "0.80.10",
|
"lastChangelogVersion": "0.80.10",
|
||||||
"defaultProvider": "openai-codex",
|
"defaultProvider": "openai-codex",
|
||||||
"defaultModel": "gpt-5.6-sol",
|
"defaultModel": "gpt-5.6-terra",
|
||||||
"defaultThinkingLevel": "high",
|
"defaultThinkingLevel": "high",
|
||||||
"packages": [
|
"packages": [
|
||||||
"npm:pi-subagents",
|
"npm:pi-subagents",
|
||||||
@@ -18,11 +18,11 @@
|
|||||||
"npm:bigpowers",
|
"npm:bigpowers",
|
||||||
"npm:@gotgenes/pi-permission-system",
|
"npm:@gotgenes/pi-permission-system",
|
||||||
"npm:pi-intercom",
|
"npm:pi-intercom",
|
||||||
"npm:gentle-engram",
|
"npm:gentle-engram@0.1.8",
|
||||||
"npm:pi-lens",
|
"npm:pi-lens",
|
||||||
"npm:@juicesharp/rpiv-todo",
|
"npm:@juicesharp/rpiv-todo",
|
||||||
"npm:@majorgilles/pi-grill-me",
|
"npm:@majorgilles/pi-grill-me",
|
||||||
"git:git.commumedia.org/alex/pi-map"
|
"npm:pi-mcp-adapter"
|
||||||
],
|
],
|
||||||
"powerline": "full",
|
"powerline": "full",
|
||||||
"hideThinkingBlock": false,
|
"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
|
# --- Terminal and responsiveness ---------------------------------------------
|
||||||
|
set -g default-terminal "tmux-256color"
|
||||||
set -g default-terminal "screen-256color" # colors!
|
set -as terminal-features ",xterm-256color:RGB,screen-256color:RGB,tmux-256color:RGB"
|
||||||
setw -g xterm-keys on
|
set -sg escape-time 10
|
||||||
set -s escape-time 10 # faster command sequences
|
set -sg repeat-time 600
|
||||||
set -sg repeat-time 600 # increase repeat timeout
|
|
||||||
set -s focus-events on
|
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
|
# --- Prefix and defaults ------------------------------------------------------
|
||||||
bind C-a send-prefix -2
|
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)
|
setw -g mode-keys vi
|
||||||
set -q -g utf8 on
|
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
|
# --- Vim-style panes ----------------------------------------------------------
|
||||||
bind e new-window -n "~/.tmux.conf.local" "sh -c '\${EDITOR:-vim} ~/.tmux.conf.local && tmux source ~/.tmux.conf && tmux display \"~/.tmux.conf sourced\"'"
|
# 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 h select-pane -L
|
||||||
bind r source-file ~/.tmux.conf \; display '~/.tmux.conf sourced'
|
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
|
# --- Windows, sessions, and buffers ------------------------------------------
|
||||||
run-shell "powerline-daemon -q"
|
bind -r f next-window
|
||||||
# source powerline tmux bindings
|
bind -r b previous-window
|
||||||
source "/usr/lib/python3.14/site-packages/powerline/bindings/tmux/powerline.conf"
|
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
|
# Keep tmux and the desktop clipboard in sync by default. `set-clipboard on`
|
||||||
set -s set-clipboard off
|
# 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
|
# --- Optional TPM plugins -----------------------------------------------------
|
||||||
setw -g pane-base-index 1 # make pane numbering consistent with windows
|
# 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
|
# Keep machine-specific bindings and experiments out of this tracked base file.
|
||||||
set -g renumber-windows on # renumber windows when a window is closed
|
if-shell '[ -f ~/.tmux.conf.local ]' 'source-file ~/.tmux.conf.local'
|
||||||
|
|
||||||
#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'
|
|
||||||
|
|||||||
+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
|
# Examples:
|
||||||
# - and tmux is 1.9 or 1.9a
|
# set -g status-position top
|
||||||
# - and iTerm2 is configured to let option key act as +Esc
|
# bind -n M-Left select-pane -L
|
||||||
# - 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
|
|
||||||
|
|||||||
@@ -156,437 +156,15 @@ alias sudo='sudo '
|
|||||||
export EDITOR=nvim
|
export EDITOR=nvim
|
||||||
export VISUAL=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
|
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
|
# add pyenv to the path
|
||||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
|
if (( $+commands[pyenv] )); then
|
||||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
|
export PYENV_ROOT="${PYENV_ROOT:-$HOME/.pyenv}"
|
||||||
echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc
|
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||||
export PYENV_ROOT="$HOME/.pyenv"
|
eval "$(pyenv init - zsh)"
|
||||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
fi
|
||||||
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)"
|
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
.ruff_cache/
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# system-config
|
||||||
|
|
||||||
|
A small, declarative Arch configuration managed by Decman.
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
- **Concerns live in `packages/`**: each concern has a native (`*-repo.txt`)
|
||||||
|
and AUR (`*-aur.txt`) list.
|
||||||
|
- **Hosts live in `hosts.py`**: a host composes concerns. `laptop()` contains
|
||||||
|
every explicit package. `desktop()` begins with shared concerns only.
|
||||||
|
- **System files live in `config/system/`**: shared files go in `common/`;
|
||||||
|
hardware, sleep/logind, and boot policy go in the relevant host directory.
|
||||||
|
- **State lives in `manifests/`**: units follow the same concern and host
|
||||||
|
scopes as packages.
|
||||||
|
- **Python glue lives in `modules/`**: package and system-state adapters only.
|
||||||
|
|
||||||
|
No yadm migration, user-home dotfiles, or application state is managed here.
|
||||||
|
Those can be added later as small, explicit modules.
|
||||||
|
|
||||||
|
## System policy
|
||||||
|
|
||||||
|
- `config/system/common/pacman/pacman.conf` enables only the official core,
|
||||||
|
extra, and multilib repositories. No debug repository is enabled.
|
||||||
|
- `config/system/common/makepkg/makepkg.conf` sets `OPTIONS` with `!debug`, so
|
||||||
|
newly built packages do not produce debug packages.
|
||||||
|
- `config/system/common/locale/` owns locale generation and system locale.
|
||||||
|
- `config/system/common/keyboard/` owns console and X11 keyboard policy.
|
||||||
|
- `config/system/laptop/sleep.conf.d/` owns sleep policy; the logind drop-in
|
||||||
|
remains in `config/system/laptop/systemd/`.
|
||||||
|
- `config/system/laptop/power/tlp.conf` owns laptop power policy. TLP reads
|
||||||
|
`/etc/tlp.conf` after drop-ins, so a whole-file policy is required here.
|
||||||
|
- `config/system/laptop/boot/mkinitcpio.conf` owns encrypted-root and resume
|
||||||
|
initramfs hooks; its module rebuilds the initramfs after a change.
|
||||||
|
- `config/system/laptop/refind/` owns the laptop ESP rEFInd configuration and
|
||||||
|
encrypted-root kernel options. It is intentionally laptop-only.
|
||||||
|
- `config/system/laptop/iwlwifi.conf` retains the Wi-Fi 6 stability workaround;
|
||||||
|
NetworkManager owns Wi-Fi power saving for battery use.
|
||||||
|
- `config/user/{common,laptop,desktop}/` owns selected active user dotfiles.
|
||||||
|
Host-specific Hyprland and Noctalia variants are selected by host composition.
|
||||||
|
- EnvyControl's generated NVIDIA blacklist and udev files are intentionally
|
||||||
|
unmanaged so GPU modes can be switched outside of Decman.
|
||||||
|
|
||||||
|
Changing the debug policy does not uninstall debug packages already installed;
|
||||||
|
remove those explicitly in a separate reviewed package change.
|
||||||
|
|
||||||
|
## Package concerns
|
||||||
|
|
||||||
|
| Scope | Concerns |
|
||||||
|
| --- | --- |
|
||||||
|
| Shared | core, wayland, fonts, development, productivity, media, research, network, services |
|
||||||
|
| Laptop | hardware, legacy; hardware units |
|
||||||
|
| Desktop | shared concerns now; add `packages/desktop/<concern>-{repo,aur}.txt` when hardware/software differs |
|
||||||
|
|
||||||
|
Every package must have a named purpose. Add a new concern when an existing one
|
||||||
|
does not explain a package. System and user units use the same naming:
|
||||||
|
`manifests/common/<concern>-{system,user}.txt` or
|
||||||
|
`manifests/laptop/<concern>-system.txt`.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/system-config
|
||||||
|
./scripts/verify.py
|
||||||
|
sudo decman --source source.py --dry-run --no-hooks
|
||||||
|
sudo decman --source source.py --no-hooks
|
||||||
|
```
|
||||||
|
|
||||||
|
`verify.py` proves that every currently explicit package appears exactly once
|
||||||
|
in the active laptop profile. The ignored dependency lists prevent Decman's
|
||||||
|
orphan cleanup from removing dependencies during adoption.
|
||||||
|
|
||||||
|
After intentional package changes, regenerate and review concern lists:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/split_packages.py
|
||||||
|
./scripts/refresh_orphan_guards.py
|
||||||
|
./scripts/verify.py
|
||||||
|
git diff
|
||||||
|
```
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Written by systemd-localed(8) or systemd-firstboot(1), read by systemd-localed
|
||||||
|
# and systemd-vconsole-setup(8). Use localectl(1) to update this file.
|
||||||
|
KEYMAP=us
|
||||||
|
XKBLAYOUT=us
|
||||||
|
XKBMODEL=variant
|
||||||
|
XKBVARIANT=altgr-intl
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Written by systemd-localed(8), read by systemd-localed and Xorg. It's
|
||||||
|
# probably wise not to edit this file manually. Use localectl(1) to
|
||||||
|
# update this file.
|
||||||
|
Section "InputClass"
|
||||||
|
Identifier "system-keyboard"
|
||||||
|
MatchIsKeyboard "on"
|
||||||
|
Option "XkbLayout" "us"
|
||||||
|
Option "XkbVariant" "intl"
|
||||||
|
EndSection
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[ids]
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
[main]
|
||||||
|
capslock = layer(capslayer)
|
||||||
|
' = G-'
|
||||||
|
|
||||||
|
|
||||||
|
[capslayer]
|
||||||
|
j = down
|
||||||
|
h = left
|
||||||
|
k = up
|
||||||
|
l = right
|
||||||
|
|
||||||
|
a = G-q
|
||||||
|
o = G-p
|
||||||
|
u = G-y
|
||||||
|
s = G-s
|
||||||
|
e = G-5
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# This is the fallback locale configuration provided by systemd.
|
||||||
|
|
||||||
|
LANG="en_US.UTF-8"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
en_US.UTF-8 UTF-8
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
#!/hint/bash
|
||||||
|
# shellcheck disable=2034
|
||||||
|
|
||||||
|
#
|
||||||
|
# /etc/makepkg.conf
|
||||||
|
#
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# SOURCE ACQUISITION
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
#-- The download utilities that makepkg should use to acquire sources
|
||||||
|
# Format: 'protocol::agent'
|
||||||
|
DLAGENTS=('file::/usr/bin/curl -qgC - -o %o %u'
|
||||||
|
'ftp::/usr/bin/curl -qgfC - --ftp-pasv --retry 3 --retry-delay 3 -o %o %u'
|
||||||
|
'http::/usr/bin/curl -qgb "" -fLC - --retry 3 --retry-delay 3 -o %o %u'
|
||||||
|
'https::/usr/bin/curl -qgb "" -fLC - --retry 3 --retry-delay 3 -o %o %u'
|
||||||
|
'rsync::/usr/bin/rsync --no-motd -z %u %o'
|
||||||
|
'scp::/usr/bin/scp -C %u %o')
|
||||||
|
|
||||||
|
# Other common tools:
|
||||||
|
# /usr/bin/snarf
|
||||||
|
# /usr/bin/lftpget -c
|
||||||
|
# /usr/bin/wget
|
||||||
|
|
||||||
|
#-- The package required by makepkg to download VCS sources
|
||||||
|
# Format: 'protocol::package'
|
||||||
|
VCSCLIENTS=('bzr::breezy'
|
||||||
|
'fossil::fossil'
|
||||||
|
'git::git'
|
||||||
|
'hg::mercurial'
|
||||||
|
'svn::subversion')
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# ARCHITECTURE, COMPILE FLAGS
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
CARCH="x86_64"
|
||||||
|
CHOST="x86_64-pc-linux-gnu"
|
||||||
|
|
||||||
|
#NPROC=2
|
||||||
|
|
||||||
|
#-- Compiler and Linker Flags
|
||||||
|
#CPPFLAGS=""
|
||||||
|
CFLAGS="-march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions \
|
||||||
|
-Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security \
|
||||||
|
-fstack-clash-protection -fcf-protection \
|
||||||
|
-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"
|
||||||
|
CXXFLAGS="$CFLAGS -Wp,-D_GLIBCXX_ASSERTIONS"
|
||||||
|
LDFLAGS="-Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now \
|
||||||
|
-Wl,-z,pack-relative-relocs"
|
||||||
|
LTOFLAGS="-flto=auto"
|
||||||
|
#-- Make Flags: change this for DistCC/SMP systems
|
||||||
|
#MAKEFLAGS="-j2"
|
||||||
|
#-- Debugging flags
|
||||||
|
DEBUG_CFLAGS="-g"
|
||||||
|
DEBUG_CXXFLAGS="$DEBUG_CFLAGS"
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# BUILD ENVIRONMENT
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
# Makepkg defaults: BUILDENV=(!distcc !color !ccache check !sign)
|
||||||
|
# A negated environment option will do the opposite of the comments below.
|
||||||
|
#
|
||||||
|
#-- distcc: Use the Distributed C/C++/ObjC compiler
|
||||||
|
#-- color: Colorize output messages
|
||||||
|
#-- ccache: Use ccache to cache compilation
|
||||||
|
#-- check: Run the check() function if present in the PKGBUILD
|
||||||
|
#-- sign: Generate PGP signature file
|
||||||
|
#
|
||||||
|
BUILDENV=(!distcc color !ccache check !sign)
|
||||||
|
#
|
||||||
|
#-- If using DistCC, your MAKEFLAGS will also need modification. In addition,
|
||||||
|
#-- specify a space-delimited list of hosts running in the DistCC cluster.
|
||||||
|
#DISTCC_HOSTS=""
|
||||||
|
#
|
||||||
|
#-- Specify a directory for package building.
|
||||||
|
#BUILDDIR=/tmp/makepkg
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# GLOBAL PACKAGE OPTIONS
|
||||||
|
# These are default values for the options=() settings
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
# Makepkg defaults:
|
||||||
|
# OPTIONS=(!strip docs libtool staticlibs emptydirs !zipman !purge !debug !lto !autodeps)
|
||||||
|
# A negated option will do the opposite of the comments below.
|
||||||
|
#
|
||||||
|
#-- strip: Strip symbols from binaries/libraries
|
||||||
|
#-- docs: Save doc directories specified by DOC_DIRS
|
||||||
|
#-- libtool: Leave libtool (.la) files in packages
|
||||||
|
#-- staticlibs: Leave static library (.a) files in packages
|
||||||
|
#-- emptydirs: Leave empty directories in packages
|
||||||
|
#-- zipman: Compress manual (man and info) pages in MAN_DIRS with gzip
|
||||||
|
#-- purge: Remove files specified by PURGE_TARGETS
|
||||||
|
#-- debug: Add debugging flags as specified in DEBUG_* variables
|
||||||
|
#-- lto: Add compile flags for building with link time optimization
|
||||||
|
#-- autodeps: Automatically add depends/provides
|
||||||
|
#
|
||||||
|
OPTIONS=(strip docs !libtool !staticlibs emptydirs zipman purge !debug lto)
|
||||||
|
|
||||||
|
#-- File integrity checks to use. Valid: md5, sha1, sha224, sha256, sha384, sha512, b2
|
||||||
|
INTEGRITY_CHECK=(sha256)
|
||||||
|
#-- Options to be used when stripping binaries. See `man strip' for details.
|
||||||
|
STRIP_BINARIES="--strip-all"
|
||||||
|
#-- Options to be used when stripping shared libraries. See `man strip' for details.
|
||||||
|
STRIP_SHARED="--strip-unneeded"
|
||||||
|
#-- Options to be used when stripping static libraries. See `man strip' for details.
|
||||||
|
STRIP_STATIC="--strip-debug"
|
||||||
|
#-- Manual (man and info) directories to compress (if zipman is specified)
|
||||||
|
MAN_DIRS=(usr{,/local}{,/share}/{man,info})
|
||||||
|
#-- Doc directories to remove (if !docs is specified)
|
||||||
|
DOC_DIRS=(usr/{,local/}{,share/}{doc,gtk-doc})
|
||||||
|
#-- Files to be removed from all packages (if purge is specified)
|
||||||
|
PURGE_TARGETS=(usr/{,share}/info/dir .packlist *.pod)
|
||||||
|
#-- Directory to store source code in for debug packages
|
||||||
|
DBGSRCDIR="/usr/src/debug"
|
||||||
|
#-- Prefix and directories for library autodeps
|
||||||
|
LIB_DIRS=('lib:usr/lib' 'lib32:usr/lib32')
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# PACKAGE OUTPUT
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
# Default: put built package and cached source in build directory
|
||||||
|
#
|
||||||
|
#-- Destination: specify a fixed directory where all packages will be placed
|
||||||
|
#PKGDEST=/home/packages
|
||||||
|
#-- Source cache: specify a fixed directory where source files will be cached
|
||||||
|
#SRCDEST=/home/sources
|
||||||
|
#-- Source packages: specify a fixed directory where all src packages will be placed
|
||||||
|
#SRCPKGDEST=/home/srcpackages
|
||||||
|
#-- Log files: specify a fixed directory where all log files will be placed
|
||||||
|
#LOGDEST=/home/makepkglogs
|
||||||
|
#-- Packager: name/email of the person or organization building packages
|
||||||
|
#PACKAGER="John Doe <john@doe.com>"
|
||||||
|
#-- Specify a key to use for package signing
|
||||||
|
#GPGKEY=""
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# COMPRESSION DEFAULTS
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
COMPRESSGZ=(gzip -c -f -n)
|
||||||
|
COMPRESSBZ2=(bzip2 -c -f)
|
||||||
|
COMPRESSXZ=(xz -c -z -)
|
||||||
|
COMPRESSZST=(zstd -c -T0 -)
|
||||||
|
COMPRESSLRZ=(lrzip -q)
|
||||||
|
COMPRESSLZO=(lzop -q)
|
||||||
|
COMPRESSZ=(compress -c -f)
|
||||||
|
COMPRESSLZ4=(lz4 -q)
|
||||||
|
COMPRESSLZ=(lzip -c -f)
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# EXTENSION DEFAULTS
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
PKGEXT='.pkg.tar.zst'
|
||||||
|
SRCEXT='.src.tar.gz'
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
# OTHER
|
||||||
|
#########################################################################
|
||||||
|
#
|
||||||
|
#-- Command used to run pacman as root, instead of trying sudo and su
|
||||||
|
#PACMAN_AUTH=()
|
||||||
|
# vim: set ft=sh ts=2 sw=2 et:
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#
|
||||||
|
# /etc/pacman.conf
|
||||||
|
#
|
||||||
|
# See the pacman.conf(5) manpage for option and repository directives
|
||||||
|
|
||||||
|
#
|
||||||
|
# GENERAL OPTIONS
|
||||||
|
#
|
||||||
|
[options]
|
||||||
|
# The following paths are commented out with their default values listed.
|
||||||
|
# If you wish to use different paths, uncomment and update the paths.
|
||||||
|
#RootDir = /
|
||||||
|
#DBPath = /var/lib/pacman/
|
||||||
|
#CacheDir = /var/cache/pacman/pkg/
|
||||||
|
#LogFile = /var/log/pacman.log
|
||||||
|
#GPGDir = /etc/pacman.d/gnupg/
|
||||||
|
#HookDir = /etc/pacman.d/hooks/
|
||||||
|
HoldPkg = pacman glibc
|
||||||
|
#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
|
||||||
|
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
|
||||||
|
#CleanMethod = KeepInstalled
|
||||||
|
Architecture = auto
|
||||||
|
|
||||||
|
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
|
||||||
|
#IgnorePkg =
|
||||||
|
#IgnoreGroup =
|
||||||
|
|
||||||
|
#NoUpgrade =
|
||||||
|
#NoExtract =
|
||||||
|
|
||||||
|
# Misc options
|
||||||
|
#UseSyslog
|
||||||
|
#Color
|
||||||
|
#NoProgressBar
|
||||||
|
CheckSpace
|
||||||
|
#VerbosePkgLists
|
||||||
|
#ParallelDownloads = 5
|
||||||
|
DownloadUser = alpm
|
||||||
|
#DisableSandbox
|
||||||
|
|
||||||
|
# By default, pacman accepts packages signed by keys that its local keyring
|
||||||
|
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||||
|
SigLevel = Required DatabaseOptional
|
||||||
|
LocalFileSigLevel = Optional
|
||||||
|
#RemoteFileSigLevel = Required
|
||||||
|
|
||||||
|
# NOTE: You must run `pacman-key --init` before first using pacman; the local
|
||||||
|
# keyring can then be populated with the keys of all official Arch Linux
|
||||||
|
# packagers with `pacman-key --populate archlinux`.
|
||||||
|
|
||||||
|
#
|
||||||
|
# REPOSITORIES
|
||||||
|
# - can be defined here or included from another file
|
||||||
|
# - pacman will search repositories in the order defined here
|
||||||
|
# - local/custom mirrors can be added here or in separate files
|
||||||
|
# - repositories listed first will take precedence when packages
|
||||||
|
# have identical names, regardless of version number
|
||||||
|
# - URLs will have $repo replaced by the name of the current repo
|
||||||
|
# - URLs will have $arch replaced by the name of the architecture
|
||||||
|
#
|
||||||
|
# Repository entries are of the format:
|
||||||
|
# [repo-name]
|
||||||
|
# Server = ServerName
|
||||||
|
# Include = IncludePath
|
||||||
|
#
|
||||||
|
# The header [repo-name] is crucial - it must be present and
|
||||||
|
# uncommented to enable the repo.
|
||||||
|
#
|
||||||
|
|
||||||
|
# The testing repositories are disabled by default. To enable, uncomment the
|
||||||
|
# repo name header and Include lines. You can add preferred servers immediately
|
||||||
|
# after the header, and they will be used before the default mirrors.
|
||||||
|
|
||||||
|
#[core-testing]
|
||||||
|
#Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[core]
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
#[extra-testing]
|
||||||
|
#Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
# If you want to run 32 bit applications on your x86_64 system,
|
||||||
|
# enable the multilib repositories as required here.
|
||||||
|
|
||||||
|
#[multilib-testing]
|
||||||
|
#Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[multilib]
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
# An example of a custom package repository. See the pacman manpage for
|
||||||
|
# tips on creating your own repositories.
|
||||||
|
#[custom]
|
||||||
|
#SigLevel = Optional TrustAll
|
||||||
|
#Server = file:///home/custompkgs
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# vim:set ft=sh
|
||||||
|
# MODULES
|
||||||
|
# The following modules are loaded before any boot hooks are
|
||||||
|
# run. Advanced users may wish to specify all system modules
|
||||||
|
# in this array. For instance:
|
||||||
|
# MODULES=(usbhid xhci_hcd)
|
||||||
|
MODULES=()
|
||||||
|
|
||||||
|
# BINARIES
|
||||||
|
# This setting includes any additional binaries a given user may
|
||||||
|
# wish into the CPIO image. This is run last, so it may be used to
|
||||||
|
# override the actual binaries included by a given hook
|
||||||
|
# BINARIES are dependency parsed, so you may safely ignore libraries
|
||||||
|
BINARIES=()
|
||||||
|
|
||||||
|
# FILES
|
||||||
|
# This setting is similar to BINARIES above, however, files are added
|
||||||
|
# as-is and are not parsed in any way. This is useful for config files.
|
||||||
|
FILES=()
|
||||||
|
|
||||||
|
# HOOKS
|
||||||
|
# This is the most important setting in this file. The HOOKS control the
|
||||||
|
# modules and scripts added to the image, and what happens at boot time.
|
||||||
|
# Order is important, and it is recommended that you do not change the
|
||||||
|
# order in which HOOKS are added. Run 'mkinitcpio -H <hook name>' for
|
||||||
|
# help on a given hook.
|
||||||
|
# 'base' is _required_ unless you know precisely what you are doing.
|
||||||
|
# 'udev' is _required_ in order to automatically load modules
|
||||||
|
# 'filesystems' is _required_ unless you specify your fs modules in MODULES
|
||||||
|
# Examples:
|
||||||
|
## This setup specifies all modules in the MODULES setting above.
|
||||||
|
## No RAID, lvm2, or encrypted root is needed.
|
||||||
|
# HOOKS=(base)
|
||||||
|
#
|
||||||
|
## This setup will autodetect all modules for your system and should
|
||||||
|
## work as a sane default
|
||||||
|
# HOOKS=(base udev autodetect modconf block filesystems fsck)
|
||||||
|
#
|
||||||
|
## This setup will generate a 'full' image which supports most systems.
|
||||||
|
## No autodetection is done.
|
||||||
|
# HOOKS=(base udev modconf block filesystems fsck)
|
||||||
|
#
|
||||||
|
## This setup assembles a mdadm array with an encrypted root file system.
|
||||||
|
## Note: See 'mkinitcpio -H mdadm_udev' for more information on RAID devices.
|
||||||
|
# HOOKS=(base udev modconf keyboard keymap consolefont block mdadm_udev encrypt filesystems fsck)
|
||||||
|
#
|
||||||
|
## This setup loads an lvm2 volume group.
|
||||||
|
# HOOKS=(base udev modconf block lvm2 filesystems fsck)
|
||||||
|
#
|
||||||
|
## This will create a systemd based initramfs which loads an encrypted root filesystem.
|
||||||
|
# HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole sd-encrypt block filesystems fsck)
|
||||||
|
#
|
||||||
|
## NOTE: If you have /usr on a separate partition, you MUST include the
|
||||||
|
# usr and fsck hooks.
|
||||||
|
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems resume fsck)
|
||||||
|
|
||||||
|
# COMPRESSION
|
||||||
|
# Use this to compress the initramfs image. By default, zstd compression
|
||||||
|
# is used for Linux ≥ 5.9 and gzip compression is used for Linux < 5.9.
|
||||||
|
# Use 'cat' to create an uncompressed image.
|
||||||
|
#COMPRESSION="zstd"
|
||||||
|
#COMPRESSION="gzip"
|
||||||
|
#COMPRESSION="bzip2"
|
||||||
|
#COMPRESSION="lzma"
|
||||||
|
#COMPRESSION="xz"
|
||||||
|
#COMPRESSION="lzop"
|
||||||
|
#COMPRESSION="lz4"
|
||||||
|
|
||||||
|
# COMPRESSION_OPTIONS
|
||||||
|
# Additional options for the compressor
|
||||||
|
#COMPRESSION_OPTIONS=()
|
||||||
|
|
||||||
|
# MODULES_DECOMPRESS
|
||||||
|
# Decompress loadable kernel modules and their firmware during initramfs
|
||||||
|
# creation. Switch (yes/no).
|
||||||
|
# Enable to allow further decreasing image size when using high compression
|
||||||
|
# (e.g. xz -9e or zstd --long --ultra -22) at the expense of increased RAM usage
|
||||||
|
# at early boot.
|
||||||
|
# Note that any compressed files will be placed in the uncompressed early CPIO
|
||||||
|
# to avoid double compression.
|
||||||
|
#MODULES_DECOMPRESS="no"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Keep Wi-Fi 6 disabled for this laptop's known stability workaround.
|
||||||
|
# NetworkManager owns association-level Wi-Fi power saving.
|
||||||
|
options iwlwifi disable_11ax=1
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
DEVICES_TO_DISABLE_ON_STARTUP="bluetooth"
|
||||||
|
DEVICES_TO_DISABLE_ON_BAT_NOT_IN_USE="bluetooth"
|
||||||
|
|
||||||
|
CPU_ENERGY_PERF_POLICY_ON_AC=balance
|
||||||
|
CPU_ENERGY_PERF_POLICY_ON_BAT=power
|
||||||
|
|
||||||
|
CPU_BOOST_ON_AC=1
|
||||||
|
CPU_BOOST_ON_BAT=0
|
||||||
|
|
||||||
|
CPU_MAX_PERF_ON_AC=100
|
||||||
|
CPU_MAX_PERF_ON_BAT=70
|
||||||
@@ -0,0 +1,732 @@
|
|||||||
|
#
|
||||||
|
# refind.conf
|
||||||
|
# Configuration file for the rEFInd boot menu
|
||||||
|
#
|
||||||
|
|
||||||
|
# Timeout in seconds for the main menu screen. Setting the timeout to 0
|
||||||
|
# disables automatic booting (i.e., no timeout). Setting it to -1 causes
|
||||||
|
# an immediate boot to the default OS *UNLESS* a keypress is in the buffer
|
||||||
|
# when rEFInd launches, in which case that keypress is interpreted as a
|
||||||
|
# shortcut key. If no matching shortcut is found, rEFInd displays its
|
||||||
|
# menu with no timeout.
|
||||||
|
#
|
||||||
|
timeout 20
|
||||||
|
|
||||||
|
# Set the logging level. When set to 0, rEFInd does not log its actions.
|
||||||
|
# When set to 1 or above, rEFInd creates a file called refind.log in
|
||||||
|
# its home directory on the ESP and records information about what it's
|
||||||
|
# doing. Higher values record more information, up to a maximum of 4.
|
||||||
|
# This token should be left at the default of 0 except when debugging
|
||||||
|
# problems.
|
||||||
|
# Default value is 0
|
||||||
|
#
|
||||||
|
#log_level 1
|
||||||
|
|
||||||
|
# Normally, when the timeout period has passed, rEFInd boots the
|
||||||
|
# default_selection. If the following option is uncommented, though,
|
||||||
|
# rEFInd will instead attempt to shut down the computer.
|
||||||
|
# CAUTION: MANY COMPUTERS WILL INSTEAD HANG OR REBOOT! Macs and more
|
||||||
|
# recent UEFI-based PCs are most likely to work with this feature.
|
||||||
|
# Default value is true
|
||||||
|
#
|
||||||
|
#shutdown_after_timeout
|
||||||
|
|
||||||
|
# Whether to store rEFInd's rEFInd-specific variables in NVRAM (1, true,
|
||||||
|
# or on) or in files in the "vars" subdirectory of rEFInd's directory on
|
||||||
|
# disk (0, false, or off). Using NVRAM works well with most computers;
|
||||||
|
# however, it increases wear on the motherboard's NVRAM, and if the EFI
|
||||||
|
# is buggy or the NVRAM is old and worn out, it may not work at all.
|
||||||
|
# Storing variables on disk is a viable alternative in such cases, or
|
||||||
|
# if you want to minimize wear and tear on the NVRAM; however, it won't
|
||||||
|
# work if rEFInd is stored on a filesystem that's read-only to the EFI
|
||||||
|
# (such as an HFS+ volume), and it increases the risk of filesystem
|
||||||
|
# damage. Note that this option affects ONLY rEFInd's own variables,
|
||||||
|
# such as the PreviousBoot, HiddenTags, HiddenTools, and HiddenLegacy
|
||||||
|
# variables. It does NOT affect Secure Boot or other non-rEFInd
|
||||||
|
# variables.
|
||||||
|
# Default is true
|
||||||
|
#
|
||||||
|
use_nvram false
|
||||||
|
|
||||||
|
# Screen saver timeout; the screen blanks after the specified number of
|
||||||
|
# seconds with no keyboard input. The screen returns after most keypresses
|
||||||
|
# (unfortunately, not including modifier keys such as Shift, Control, Alt,
|
||||||
|
# or Option). Setting a value of "-1" causes rEFInd to start up with its
|
||||||
|
# screen saver active. The default is 0, which disables the screen saver.
|
||||||
|
#
|
||||||
|
#screensaver 300
|
||||||
|
|
||||||
|
# Hide user interface elements for personal preference or to increase
|
||||||
|
# security:
|
||||||
|
# banner - the rEFInd title banner (built-in or loaded via "banner")
|
||||||
|
# label - boot option text label in the menu
|
||||||
|
# singleuser - remove the submenu options to boot macOS in single-user
|
||||||
|
# or verbose modes; affects ONLY macOS
|
||||||
|
# safemode - remove the submenu option to boot macOS in "safe mode"
|
||||||
|
# hwtest - the submenu option to run Apple's hardware test
|
||||||
|
# arrows - scroll arrows on the OS selection tag line
|
||||||
|
# hints - brief command summary in the menu
|
||||||
|
# editor - the options editor (+, F2, or Insert on boot options menu)
|
||||||
|
# badges - device-type badges for boot options
|
||||||
|
# all - all of the above
|
||||||
|
# Default is none of these (all elements active)
|
||||||
|
#
|
||||||
|
#hideui singleuser
|
||||||
|
#hideui all
|
||||||
|
|
||||||
|
# Set the name of a subdirectory in which icons are stored. Icons must
|
||||||
|
# have the same names they have in the standard directory. The directory
|
||||||
|
# name is specified relative to the main rEFInd binary's directory. If
|
||||||
|
# an icon can't be found in the specified directory, an attempt is made
|
||||||
|
# to load it from the default directory; thus, you can replace just some
|
||||||
|
# icons in your own directory and rely on the default for others.
|
||||||
|
# Icon files may be in any supported format -- ICNS (*.icns), BMP (*.bmp),
|
||||||
|
# PNG (*.png), or JPEG (*.jpg or *.jpeg); however, rEFInd's BMP and JPEG
|
||||||
|
# implementations do not support transparency, which is highly desirable
|
||||||
|
# in icons.
|
||||||
|
# Default is "icons".
|
||||||
|
#
|
||||||
|
#icons_dir myicons
|
||||||
|
#icons_dir icons/snowy
|
||||||
|
|
||||||
|
# Use a custom title banner instead of the rEFInd icon and name. The file
|
||||||
|
# path is relative to the directory where refind.efi is located. The color
|
||||||
|
# in the top left corner of the image is used as the background color
|
||||||
|
# for the menu screens. Currently uncompressed BMP images with color
|
||||||
|
# depths of 24, 8, 4 or 1 bits are supported, as well as PNG and JPEG
|
||||||
|
# images. (ICNS images can also be used, but ICNS has limitations that
|
||||||
|
# make it a poor choice for this purpose.) PNG and JPEG support is
|
||||||
|
# limited by the underlying libraries; some files, like progressive JPEGs,
|
||||||
|
# will not work.
|
||||||
|
#
|
||||||
|
#banner hostname.bmp
|
||||||
|
#banner mybanner.jpg
|
||||||
|
#banner icons/snowy/banner-snowy.png
|
||||||
|
|
||||||
|
# Specify how to handle banners that aren't exactly the same as the screen
|
||||||
|
# size:
|
||||||
|
# noscale - Crop if too big, show with border if too small
|
||||||
|
# fillscreen - Fill the screen
|
||||||
|
# Default is noscale
|
||||||
|
#
|
||||||
|
#banner_scale fillscreen
|
||||||
|
|
||||||
|
# Icon sizes. All icons are square, so just one value is specified. The
|
||||||
|
# big icons are used for OS selectors in the first row and the small
|
||||||
|
# icons are used for tools on the second row. Drive-type badges are 1/4
|
||||||
|
# the size of the big icons. Legal values are 32 and above. If the icon
|
||||||
|
# files do not hold icons of the proper size, the icons are scaled to
|
||||||
|
# the specified size. The default values are 48 and 128 for small and
|
||||||
|
# big icons, respectively.
|
||||||
|
#
|
||||||
|
#small_icon_size 96
|
||||||
|
#big_icon_size 256
|
||||||
|
|
||||||
|
# Custom images for the selection background. There is a big one (144 x 144)
|
||||||
|
# for the OS icons, and a small one (64 x 64) for the function icons in the
|
||||||
|
# second row. If only a small image is given, that one is also used for
|
||||||
|
# the big icons by stretching it in the middle. If only a big one is given,
|
||||||
|
# the built-in default will be used for the small icons. If an image other
|
||||||
|
# than the optimal size is specified, it will be scaled in a way that may
|
||||||
|
# be ugly.
|
||||||
|
#
|
||||||
|
# Like the banner option above, these options take a filename of an
|
||||||
|
# uncompressed BMP, PNG, JPEG, or ICNS image file with a color depth of
|
||||||
|
# 24, 8, 4, or 1 bits. The PNG or ICNS format is required if you need
|
||||||
|
# transparency support (to let you "see through" to a full-screen banner).
|
||||||
|
#
|
||||||
|
#selection_big selection-big.bmp
|
||||||
|
#selection_small selection-small.bmp
|
||||||
|
|
||||||
|
# Set the font to be used for all textual displays in graphics mode.
|
||||||
|
# For best results, the font must be a PNG file with alpha channel
|
||||||
|
# transparency. It must contain ASCII characters 32-126 (space through
|
||||||
|
# tilde), inclusive, plus a glyph to be displayed in place of characters
|
||||||
|
# outside of this range, for a total of 96 glyphs. Only monospaced fonts
|
||||||
|
# are supported. Fonts may be of any size, although large fonts can
|
||||||
|
# produce display irregularities.
|
||||||
|
# The default is rEFInd's built-in font, Luxi Mono Regular 12 point.
|
||||||
|
#
|
||||||
|
#font myfont.png
|
||||||
|
|
||||||
|
# Use text mode only. When enabled, this option forces rEFInd into text mode.
|
||||||
|
# Passing this option a "0" value causes graphics mode to be used. Pasing
|
||||||
|
# it no value or any non-0 value causes text mode to be used.
|
||||||
|
# Default is to use graphics mode.
|
||||||
|
#
|
||||||
|
#textonly
|
||||||
|
|
||||||
|
# Set the EFI text mode to be used for textual displays. This option
|
||||||
|
# takes a single digit that refers to a mode number. Mode 0 is normally
|
||||||
|
# 80x25, 1 is sometimes 80x50, and higher numbers are system-specific
|
||||||
|
# modes. Mode 1024 is a special code that tells rEFInd to not set the
|
||||||
|
# text mode; it uses whatever was in use when the program was launched.
|
||||||
|
# If you specify an invalid mode, rEFInd pauses during boot to inform
|
||||||
|
# you of valid modes.
|
||||||
|
# CAUTION: On VirtualBox, and perhaps on some real computers, specifying
|
||||||
|
# a text mode and uncommenting the "textonly" option while NOT specifying
|
||||||
|
# a resolution can result in an unusable display in the booted OS.
|
||||||
|
# Default is 1024 (no change)
|
||||||
|
#
|
||||||
|
#textmode 2
|
||||||
|
|
||||||
|
# Set the screen's video resolution. Pass this option one of the following:
|
||||||
|
# * two integer values, corresponding to the X and Y resolutions
|
||||||
|
# * one integer value, corresponding to a GOP (UEFI) video mode
|
||||||
|
# * the string "max", which sets the maximum available resolution
|
||||||
|
# Note that not all resolutions are supported. On UEFI systems, passing
|
||||||
|
# an incorrect value results in a message being shown on the screen to
|
||||||
|
# that effect, along with a list of supported modes. On EFI 1.x systems
|
||||||
|
# (e.g., Macintoshes), setting an incorrect mode silently fails. On both
|
||||||
|
# types of systems, setting an incorrect resolution results in the default
|
||||||
|
# resolution being used. A resolution of 1024x768 usually works, but higher
|
||||||
|
# values often don't.
|
||||||
|
# Default is "0 0" (use the system default resolution, usually 800x600).
|
||||||
|
#
|
||||||
|
#resolution 1024 768
|
||||||
|
#resolution 1440 900
|
||||||
|
#resolution 3
|
||||||
|
#resolution max
|
||||||
|
|
||||||
|
# Enable touch screen support. If active, this feature enables use of
|
||||||
|
# touch screen controls (as on tablets). Note, however, that not all
|
||||||
|
# tablets' EFIs provide the necessary underlying support, so this
|
||||||
|
# feature may not work for you. If it does work, you should be able
|
||||||
|
# to launch an OS or tool by touching it. In a submenu, touching
|
||||||
|
# anywhere launches the currently-selection item; there is, at present,
|
||||||
|
# no way to select a specific submenu item. This feature is mutually
|
||||||
|
# exclusive with the enable_mouse feature. If both are uncommented,
|
||||||
|
# the one read most recently takes precedence.
|
||||||
|
#
|
||||||
|
#enable_touch
|
||||||
|
|
||||||
|
# Enable mouse support. If active, this feature enables use of the
|
||||||
|
# computer's mouse. Note, however, that not all computers' EFIs
|
||||||
|
# provide the necessary underlying support, so this feature may not
|
||||||
|
# work for you. If it does work, you should be able to launch an
|
||||||
|
# OS or tool by clicking it with the mouse pointer. This feature
|
||||||
|
# is mutually exclusive with the enable_touch feature. If both
|
||||||
|
# are uncommented, the one read most recently takes precedence.
|
||||||
|
#
|
||||||
|
#enable_mouse
|
||||||
|
|
||||||
|
# Size of the mouse pointer, in pixels, per side.
|
||||||
|
# Default is 16
|
||||||
|
#
|
||||||
|
#mouse_size 16
|
||||||
|
|
||||||
|
# Speed of mouse tracking. Higher numbers equate to faster
|
||||||
|
# mouse movement. This option requires that enable_mouse be
|
||||||
|
# uncommented.
|
||||||
|
# Legal values are between 1 and 32. Default is 4.
|
||||||
|
#
|
||||||
|
#mouse_speed 4
|
||||||
|
|
||||||
|
# Launch specified OSes in graphics mode. By default, rEFInd switches
|
||||||
|
# to text mode and displays basic pre-launch information when launching
|
||||||
|
# all OSes except macOS. Using graphics mode can produce a more seamless
|
||||||
|
# transition, but displays no information, which can make matters
|
||||||
|
# difficult if you must debug a problem. Also, on at least one known
|
||||||
|
# computer, using graphics mode prevents a crash when using the Linux
|
||||||
|
# kernel's EFI stub loader. You can specify an empty list to boot all
|
||||||
|
# OSes in text mode.
|
||||||
|
# Valid options:
|
||||||
|
# osx - macOS
|
||||||
|
# linux - A Linux kernel with EFI stub loader
|
||||||
|
# elilo - The ELILO boot loader
|
||||||
|
# grub - The GRUB (Legacy or 2) boot loader
|
||||||
|
# windows - Microsoft Windows
|
||||||
|
# Default value: osx
|
||||||
|
#
|
||||||
|
#use_graphics_for osx,linux
|
||||||
|
|
||||||
|
# Which non-bootloader tools to show on the tools line, and in what
|
||||||
|
# order to display them:
|
||||||
|
# shell - the EFI shell (requires external program; see rEFInd
|
||||||
|
# documentation for details)
|
||||||
|
# memtest - the memtest86 program, in EFI/tools, EFI/memtest86,
|
||||||
|
# EFI/memtest, EFI/tools/memtest86, or EFI/tools/memtest
|
||||||
|
# gptsync - the (dangerous) gptsync.efi utility (requires external
|
||||||
|
# program; see rEFInd documentation for details)
|
||||||
|
# gdisk - the gdisk partitioning program
|
||||||
|
# apple_recovery - boots the Apple Recovery HD partition, if present
|
||||||
|
# windows_recovery - boots an OEM Windows recovery tool, if present
|
||||||
|
# (see also the windows_recovery_files option)
|
||||||
|
# mok_tool - makes available the Machine Owner Key (MOK) maintenance
|
||||||
|
# tool, MokManager.efi, used on Secure Boot systems
|
||||||
|
# csr_rotate - adjusts Apple System Integrity Protection (SIP)
|
||||||
|
# policy. Requires "csr_values" to be set.
|
||||||
|
# install - an option to install rEFInd from the current location
|
||||||
|
# to another ESP
|
||||||
|
# bootorder - adjust the EFI's (NOT rEFInd's) boot order
|
||||||
|
# about - an "about this program" option
|
||||||
|
# hidden_tags - manage hidden tags
|
||||||
|
# exit - a tag to exit from rEFInd
|
||||||
|
# shutdown - shuts down the computer (a bug causes this to reboot
|
||||||
|
# many UEFI systems)
|
||||||
|
# reboot - a tag to reboot the computer
|
||||||
|
# firmware - a tag to reboot the computer into the firmware's
|
||||||
|
# user interface (ignored on older computers)
|
||||||
|
# fwupdate - a tag to update the firmware; launches the fwupx64.efi
|
||||||
|
# (or similar) program
|
||||||
|
# netboot - launch the ipxe.efi tool for network (PXE) booting
|
||||||
|
# Default is shell,memtest,gdisk,apple_recovery,windows_recovery,mok_tool,about,hidden_tags,shutdown,reboot,firmware,fwupdate
|
||||||
|
# To completely disable scanning for all tools, provide a showtools line
|
||||||
|
# with no options.
|
||||||
|
#
|
||||||
|
#showtools shell, bootorder, gdisk, memtest, mok_tool, apple_recovery, windows_recovery, about, hidden_tags, reboot, exit, firmware, fwupdate
|
||||||
|
|
||||||
|
# Tool binaries to be excluded from the tools line, even if the
|
||||||
|
# general class is specified in showtools. This enables trimming an
|
||||||
|
# overabundance of tools, as when you see multiple mok_tool entries
|
||||||
|
# after installing multiple Linux distributions.
|
||||||
|
# Just as with dont_scan_files, you can specify a filename alone, a
|
||||||
|
# full pathname, or a volume identifier (filesystem label, partition
|
||||||
|
# name, or partition GUID) and a full pathname.
|
||||||
|
# Default is an empty list (nothing is excluded)
|
||||||
|
#
|
||||||
|
#dont_scan_tools ESP2:/EFI/ubuntu/mmx64.efi,gptsync_x64.efi
|
||||||
|
|
||||||
|
# Boot loaders that can launch a Windows restore or emergency system.
|
||||||
|
# These tend to be OEM-specific.
|
||||||
|
# Default is LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi
|
||||||
|
#
|
||||||
|
#windows_recovery_files LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi
|
||||||
|
|
||||||
|
# Directories in which to search for EFI drivers. These drivers can
|
||||||
|
# provide filesystem support, give access to hard disks on plug-in
|
||||||
|
# controllers, etc. In most cases none are needed, but if you add
|
||||||
|
# EFI drivers and you want rEFInd to automatically load them, you
|
||||||
|
# should specify one or more paths here. rEFInd always scans the
|
||||||
|
# "drivers" and "drivers_{arch}" subdirectories of its own installation
|
||||||
|
# directory (where "{arch}" is your architecture code); this option
|
||||||
|
# specifies ADDITIONAL directories to scan.
|
||||||
|
# Default is to scan no additional directories for EFI drivers
|
||||||
|
#
|
||||||
|
#scan_driver_dirs EFI/tools/drivers,drivers
|
||||||
|
|
||||||
|
# Which types of boot loaders to search, and in what order to display them:
|
||||||
|
# internal - internal EFI disk-based boot loaders
|
||||||
|
# external - external EFI disk-based boot loaders
|
||||||
|
# optical - EFI optical discs (CD, DVD, etc.)
|
||||||
|
# netboot - EFI network (PXE) boot options
|
||||||
|
# hdbios - BIOS disk-based boot loaders
|
||||||
|
# biosexternal - BIOS external boot loaders (USB, eSATA, etc.)
|
||||||
|
# cd - BIOS optical-disc boot loaders
|
||||||
|
# manual - use stanzas later in this configuration file
|
||||||
|
# firmware - boot EFI programs set in the firmware's NVRAM
|
||||||
|
# Note that the legacy BIOS options require firmware support, which is
|
||||||
|
# not present on all computers.
|
||||||
|
# The netboot option is experimental and relies on the ipxe.efi and
|
||||||
|
# ipxe_discover.efi program files.
|
||||||
|
# On UEFI PCs, default is internal,external,optical,manual
|
||||||
|
# On Macs, default is internal,hdbios,external,biosexternal,optical,cd,manual
|
||||||
|
#
|
||||||
|
#scanfor internal,external,optical,manual,firmware
|
||||||
|
|
||||||
|
# By default, rEFInd relies on the UEFI firmware to detect BIOS-mode boot
|
||||||
|
# devices. This sometimes doesn't detect all the available devices, though.
|
||||||
|
# For these cases, uefi_deep_legacy_scan results in a forced scan and
|
||||||
|
# modification of NVRAM variables on each boot. Adding "0", "off", or
|
||||||
|
# "false" resets to the default value. This token has no effect on Macs or
|
||||||
|
# when no BIOS-mode options are set via scanfor.
|
||||||
|
# Default is unset (or "uefi_deep_legacy_scan false")
|
||||||
|
#
|
||||||
|
#uefi_deep_legacy_scan
|
||||||
|
|
||||||
|
# Delay for the specified number of seconds before scanning disks.
|
||||||
|
# This can help some users who find that some of their disks
|
||||||
|
# (usually external or optical discs) aren't detected initially,
|
||||||
|
# but are detected after pressing Esc.
|
||||||
|
# The default is 0.
|
||||||
|
#
|
||||||
|
#scan_delay 5
|
||||||
|
|
||||||
|
# When scanning volumes for EFI boot loaders, rEFInd always looks for
|
||||||
|
# macOS's and Microsoft Windows' boot loaders in their normal locations,
|
||||||
|
# and scans the root directory and every subdirectory of the /EFI directory
|
||||||
|
# for additional boot loaders, but it doesn't recurse into these directories.
|
||||||
|
# The also_scan_dirs token adds more directories to the scan list.
|
||||||
|
# Directories are specified relative to the volume's root directory. This
|
||||||
|
# option applies to ALL the volumes that rEFInd scans UNLESS you include
|
||||||
|
# a volume name and colon before the directory name, as in "myvol:/somedir"
|
||||||
|
# to scan the somedir directory only on the filesystem named myvol. If a
|
||||||
|
# specified directory doesn't exist, it's ignored (no error condition
|
||||||
|
# results). The "+" symbol denotes appending to the list of scanned
|
||||||
|
# directories rather than overwriting that list.
|
||||||
|
# The default is to scan the "boot" and "@/boot" directories in addition
|
||||||
|
# to various hard-coded directories.
|
||||||
|
#
|
||||||
|
#also_scan_dirs boot,ESP2:EFI/linux/kernels
|
||||||
|
#also_scan_dirs boot,@/boot
|
||||||
|
#also_scan_dirs +,@/kernels
|
||||||
|
|
||||||
|
# Partitions (or whole disks, for legacy-mode boots) to omit from scans.
|
||||||
|
# For EFI-mode scans, you normally specify a volume by its label, which you
|
||||||
|
# can obtain in an EFI shell by typing "vol", from Linux by typing
|
||||||
|
# "blkid /dev/{devicename}", or by examining the disk's label in various
|
||||||
|
# OSes' file browsers. It's also possible to identify a partition by its
|
||||||
|
# unique GUID (aka its "PARTUUID" in Linux parlance). (Note that this is
|
||||||
|
# NOT the partition TYPE CODE GUID.) This identifier can be obtained via
|
||||||
|
# "blkid" in Linux or "diskutil info {partition-id}" in macOS.
|
||||||
|
# For legacy-mode scans, you can specify any subset of the boot loader
|
||||||
|
# description shown when you highlight the option in rEFInd.
|
||||||
|
# The default is "LRS_ESP".
|
||||||
|
#
|
||||||
|
#dont_scan_volumes "Recovery HD"
|
||||||
|
|
||||||
|
# Directories that should NOT be scanned for boot loaders. By default,
|
||||||
|
# rEFInd doesn't scan its own directory, the EFI/tools directory, the
|
||||||
|
# EFI/memtest directory, the EFI/memtest86 directory, or the
|
||||||
|
# com.apple.recovery.boot directory. Using the dont_scan_dirs option
|
||||||
|
# enables you to "blacklist" other directories; but be sure to use "+"
|
||||||
|
# as the first element if you want to continue blacklisting existing
|
||||||
|
# directories. You might use this token to keep EFI/boot/bootx64.efi out
|
||||||
|
# of the menu if that's a duplicate of another boot loader or to exclude
|
||||||
|
# a directory that holds drivers or non-bootloader utilities provided by
|
||||||
|
# a hardware manufacturer. If a directory is listed both here and in
|
||||||
|
# also_scan_dirs, dont_scan_dirs takes precedence. Note that this
|
||||||
|
# blacklist applies to ALL the filesystems that rEFInd scans, not just
|
||||||
|
# the ESP, unless you precede the directory name by a filesystem name or
|
||||||
|
# partition unique GUID, as in "myvol:EFI/somedir" to exclude EFI/somedir
|
||||||
|
# from the scan on the myvol volume but not on other volumes.
|
||||||
|
#
|
||||||
|
#dont_scan_dirs ESP:/EFI/boot,EFI/Dell,EFI/memtest86
|
||||||
|
|
||||||
|
# Files that should NOT be included as EFI boot loaders (on the
|
||||||
|
# first line of the display). If you're using a boot loader that
|
||||||
|
# relies on support programs or drivers that are installed alongside
|
||||||
|
# the main binary or if you want to "blacklist" certain loaders by
|
||||||
|
# name rather than location, use this option. Note that this will
|
||||||
|
# NOT prevent certain binaries from showing up in the second-row
|
||||||
|
# set of tools. Most notably, various Secure Boot and recovery
|
||||||
|
# tools are present in this list, but may appear as second-row
|
||||||
|
# items.
|
||||||
|
# The file may be specified as a bare name (e.g., "notme.efi"), as
|
||||||
|
# a complete pathname (e.g., "/EFI/somedir/notme.efi"), or as a
|
||||||
|
# complete pathname with volume (e.g., "SOMEDISK:/EFI/somedir/notme.efi"
|
||||||
|
# or 2C17D5ED-850D-4F76-BA31-47A561740082:/EFI/somedir/notme.efi").
|
||||||
|
# OS tags hidden via the Delete or '-' key in the rEFInd menu are
|
||||||
|
# added to this list, but stored in NVRAM.
|
||||||
|
# The default is shim.efi,shim-fedora.efi,shimx64.efi,PreLoader.efi,
|
||||||
|
# TextMode.efi,ebounce.efi,GraphicsConsole.efi,MokManager.efi,HashTool.efi,
|
||||||
|
# HashTool-signed.efi,bootmgr.efi,fb{arch}.efi
|
||||||
|
# (where "{arch}" is the architecture code, like "x64").
|
||||||
|
# If you want to keep these defaults but add to them, be sure to
|
||||||
|
# specify "+" as the first item in the new list; if you don't, then
|
||||||
|
# items from the default list are likely to appear.
|
||||||
|
#
|
||||||
|
#dont_scan_files shim.efi,MokManager.efi
|
||||||
|
|
||||||
|
# EFI NVRAM Boot#### variables that should NOT be presented as loaders
|
||||||
|
# when "firmware" is an option to "scanfor". The comma-separated list
|
||||||
|
# presented here contains strings that are matched against the
|
||||||
|
# description field -- if a value here is a case-insensitive substring
|
||||||
|
# of the boot option description, then it will be excluded from the
|
||||||
|
# boot list. To specify a string that includes a space, enclose it
|
||||||
|
# in quotes. Specifying "shell" will counteract the automatic
|
||||||
|
# inclusion of built-in EFI shells.
|
||||||
|
#
|
||||||
|
#dont_scan_firmware HARDDISK,shell,"Removable Device"
|
||||||
|
|
||||||
|
# Scan for Linux kernels that lack a ".efi" filename extension. This is
|
||||||
|
# useful for better integration with Linux distributions that provide
|
||||||
|
# kernels with EFI stub loaders but that don't give those kernels filenames
|
||||||
|
# that end in ".efi", particularly if the kernels are stored on a
|
||||||
|
# filesystem that the EFI can read. When set to "1", "true", or "on", this
|
||||||
|
# option causes all files in scanned directories with names that begin with
|
||||||
|
# "vmlinuz", "bzImage", or "kernel" to be included as loaders, even if they
|
||||||
|
# lack ".efi" extensions. Passing this option a "0", "false", or "off" value
|
||||||
|
# causes kernels without ".efi" extensions to NOT be scanned.
|
||||||
|
# Default is "true" -- to scan for kernels without ".efi" extensions.
|
||||||
|
#
|
||||||
|
#scan_all_linux_kernels false
|
||||||
|
|
||||||
|
# Support loaders that have been compressed with gzip.
|
||||||
|
# On x86 and x86-64 platforms, Linux kernels are self-decompressing.
|
||||||
|
# On ARM64, Linux kernel files are typically compressed with gzip,
|
||||||
|
# including the EFI stub loader. This makes them unloadable in rEFInd
|
||||||
|
# unless rEFInd itself uncompresses them. This option enables rEFInd
|
||||||
|
# to do this. This feature is unnecessary on x86 and x86-64 systems.
|
||||||
|
# Default is "false" on x86 and x86-64; "true" on ARM64.
|
||||||
|
#
|
||||||
|
#support_gzipped_loaders true
|
||||||
|
|
||||||
|
# Combine all Linux kernels in a given directory into a single entry.
|
||||||
|
# When so set, the kernel with the most recent time stamp will be launched
|
||||||
|
# by default, and its filename will appear in the entry's description.
|
||||||
|
# To launch other kernels, the user must press F2 or Insert; alternate
|
||||||
|
# kernels then appear as options on the sub-menu.
|
||||||
|
# Default is "true" -- kernels are "folded" into a single menu entry.
|
||||||
|
#
|
||||||
|
#fold_linux_kernels false
|
||||||
|
|
||||||
|
# Comma-delimited list of strings to treat as if they were numbers for the
|
||||||
|
# purpose of kernel version number detection. These strings are matched on a
|
||||||
|
# first-found basis; that is, if you want to treat both "linux-lts" and
|
||||||
|
# "linux" as version strings, they MUST be specified as "linux-lts,linux",
|
||||||
|
# since if you specify it the other way, both vmlinuz-linux and
|
||||||
|
# vmlinuz-linux-lts will return with "linux" as the "version string," which
|
||||||
|
# is not what you'd want. Also, if the kernel or initrd file includes both a
|
||||||
|
# specified string and digits, the "version string" includes both. For
|
||||||
|
# instance, "vmlinuz-linux-4.8" would yield a version string of "linux-4.8".
|
||||||
|
# This option is intended for Arch and other distributions that don't include
|
||||||
|
# version numbers in their kernel filenames, but may provide other uniquely
|
||||||
|
# identifying strings for multiple kernels. If this feature causes problems
|
||||||
|
# (say, if your kernel filename includes "linux" but the initrd filename
|
||||||
|
# doesn't), be sure this is set to an empty string
|
||||||
|
# (extra_kernel_version_strings "") or comment out the option to disable it.
|
||||||
|
# Default is no extra version strings
|
||||||
|
#
|
||||||
|
#extra_kernel_version_strings linux-lts,linux
|
||||||
|
|
||||||
|
# Write to systemd EFI variables (currently only LoaderDevicePartUUID) when
|
||||||
|
# launching Linux via an EFI stub loader, ELILO, or GRUB. This variable,
|
||||||
|
# when present, causes systemd to mount the ESP at /boot or /efi *IF* either
|
||||||
|
# directory is empty and nothing else is mounted there.
|
||||||
|
# Default is "false"
|
||||||
|
#
|
||||||
|
#write_systemd_vars true
|
||||||
|
|
||||||
|
# Symlinked loaders will be processed when this setting is set to true.
|
||||||
|
# These are ignored by default as they may result in undesirable outcomes.
|
||||||
|
# This token may, however, be useful on Linux setups that provide symbolic
|
||||||
|
# links in scanned locations that point to kernels in unscanned locations,
|
||||||
|
# such as some openSUSE installations.
|
||||||
|
#
|
||||||
|
#follow_symlinks true
|
||||||
|
|
||||||
|
# Set the maximum number of tags that can be displayed on the screen at
|
||||||
|
# any time. If more loaders are discovered than this value, rEFInd shows
|
||||||
|
# a subset in a scrolling list. If this value is set too high for the
|
||||||
|
# screen to handle, it's reduced to the value that the screen can manage.
|
||||||
|
# If this value is set to 0 (the default), it's adjusted to the number
|
||||||
|
# that the screen can handle.
|
||||||
|
#
|
||||||
|
#max_tags 0
|
||||||
|
|
||||||
|
# Set the default menu selection. The available arguments match the
|
||||||
|
# keyboard accelerators available within rEFInd. You may select the
|
||||||
|
# default loader using:
|
||||||
|
# - A digit between 1 and 9, in which case the Nth loader in the menu
|
||||||
|
# will be the default.
|
||||||
|
# - A "+" symbol at the start of the string, which refers to the most
|
||||||
|
# recently booted loader.
|
||||||
|
# - Any substring that corresponds to a portion of the loader's title
|
||||||
|
# (usually the OS's name, boot loader's path, or a volume or
|
||||||
|
# filesystem title).
|
||||||
|
# You may also specify multiple selectors by separating them with commas
|
||||||
|
# and enclosing the list in quotes. (The "+" option is only meaningful in
|
||||||
|
# this context.)
|
||||||
|
# If you follow the selector(s) with two times, in 24-hour format, the
|
||||||
|
# default will apply only between those times. The times are in the
|
||||||
|
# motherboard's time standard, whether that's UTC or local time, so if
|
||||||
|
# you use UTC, you'll need to adjust this from local time manually.
|
||||||
|
# Times may span midnight as in "23:30 00:30", which applies to 11:30 PM
|
||||||
|
# to 12:30 AM. You may specify multiple default_selection lines, in which
|
||||||
|
# case the last one to match takes precedence. Thus, you can set a main
|
||||||
|
# option without a time followed by one or more that include times to
|
||||||
|
# set different defaults for different times of day.
|
||||||
|
# The default behavior is to boot the previously-booted OS.
|
||||||
|
#
|
||||||
|
#default_selection 1
|
||||||
|
#default_selection Microsoft
|
||||||
|
#default_selection "+,bzImage,vmlinuz"
|
||||||
|
#default_selection Maintenance 23:30 2:00
|
||||||
|
#default_selection "Maintenance,macOS" 1:00 2:30
|
||||||
|
|
||||||
|
# Enable VMX bit and lock the CPU MSR if unlocked.
|
||||||
|
# On some Intel Apple computers, the firmware does not lock the MSR 0x3A.
|
||||||
|
# The symptom on Windows is Hyper-V not working even if the CPU
|
||||||
|
# meets the minimum requirements (HW assisted virtualization and SLAT)
|
||||||
|
# DO NOT SET THIS EXCEPT ON INTEL CPUs THAT SUPPORT VMX! See
|
||||||
|
# http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature
|
||||||
|
# for more on this subject.
|
||||||
|
# The default is false: Don't try to enable and lock the MSR.
|
||||||
|
#
|
||||||
|
#enable_and_lock_vmx false
|
||||||
|
|
||||||
|
# Tell a Mac's EFI that macOS is about to be launched, even when it's not.
|
||||||
|
# This option causes some Macs to initialize their hardware differently than
|
||||||
|
# when a third-party OS is launched normally. In some cases (particularly on
|
||||||
|
# Macs with multiple video cards), using this option can cause hardware to
|
||||||
|
# work that would not otherwise work. On the other hand, using this option
|
||||||
|
# when it is not necessary can cause hardware (such as keyboards and mice) to
|
||||||
|
# become inaccessible. Therefore, you should not enable this option if your
|
||||||
|
# non-Apple OSes work correctly; enable it only if you have problems with
|
||||||
|
# some hardware devices. When needed, a value of "10.9" usually works, but
|
||||||
|
# you can experiment with other values. This feature has no effect on
|
||||||
|
# non-Apple computers.
|
||||||
|
# The default is inactive (no macOS spoofing is done).
|
||||||
|
#
|
||||||
|
#spoof_osx_version 10.9
|
||||||
|
|
||||||
|
# Set the CSR values for Apple's System Integrity Protection (SIP) feature.
|
||||||
|
# Values are two-byte (four-character) hexadecimal numbers. These values
|
||||||
|
# define which specific security features are enabled. Below are the codes
|
||||||
|
# for what the values mean. Add them up (in hexadecimal!) to set new values.
|
||||||
|
# Apple's "csrutil enable" and "csrutil disable" commands set values of 10
|
||||||
|
# and 877, respectively. (Prior to OS 11, 77 was used rather than 877; 877
|
||||||
|
# is required for OS 11, and should work for OS X 10.x, too.)
|
||||||
|
# CSR_ALLOW_UNTRUSTED_KEXTS 0x0001
|
||||||
|
# CSR_ALLOW_UNRESTRICTED_FS 0x0002
|
||||||
|
# CSR_ALLOW_TASK_FOR_PID 0x0004
|
||||||
|
# CSR_ALLOW_KERNEL_DEBUGGER 0x0008
|
||||||
|
# CSR_ALLOW_APPLE_INTERNAL 0x0010
|
||||||
|
# CSR_ALLOW_UNRESTRICTED_DTRACE 0x0020
|
||||||
|
# CSR_ALLOW_UNRESTRICTED_NVRAM 0x0040
|
||||||
|
# CSR_ALLOW_DEVICE_CONFIGURATION 0x0080
|
||||||
|
# CSR_ALLOW_ANY_RECOVERY_OS 0x0100
|
||||||
|
# CSR_ALLOW_UNAPPROVED_KEXTS 0x0200
|
||||||
|
# CSR_ALLOW_EXECUTABLE_POLICY_OVERRIDE 0x0400
|
||||||
|
# CSR_ALLOW_UNAUTHENTICATED_ROOT 0x0800
|
||||||
|
#csr_values 10,877
|
||||||
|
|
||||||
|
# Include a secondary configuration file within this one. This secondary
|
||||||
|
# file is loaded as if its options appeared at the point of the "include"
|
||||||
|
# token itself, so if you want to override a setting in the main file,
|
||||||
|
# the secondary file must be referenced AFTER the setting you want to
|
||||||
|
# override. Note that the secondary file may NOT load a tertiary file.
|
||||||
|
#
|
||||||
|
#include manual.conf
|
||||||
|
|
||||||
|
# Sample manual configuration stanzas. Each begins with the "menuentry"
|
||||||
|
# keyword followed by a name that's to appear in the menu (use quotes
|
||||||
|
# if you want the name to contain a space) and an open curly brace
|
||||||
|
# ("{"). Each entry ends with a close curly brace ("}"). Common
|
||||||
|
# keywords within each stanza include:
|
||||||
|
#
|
||||||
|
# volume - identifies the filesystem from which subsequent files
|
||||||
|
# are loaded. You can specify the volume by filesystem
|
||||||
|
# label, by partition label, or by partition GUID number
|
||||||
|
# (but NOT yet by filesystem UUID number).
|
||||||
|
# loader - identifies the boot loader file
|
||||||
|
# initrd - Specifies an initial RAM disk file
|
||||||
|
# icon - specifies a custom boot loader icon
|
||||||
|
# ostype - OS type code to determine boot options available by
|
||||||
|
# pressing Insert. Valid values are "MacOS", "Linux",
|
||||||
|
# "Windows", and "XOM". Case-sensitive.
|
||||||
|
# graphics - set to "on" to enable graphics-mode boot (useful
|
||||||
|
# mainly for MacOS) or "off" for text-mode boot.
|
||||||
|
# Default is auto-detected from loader filename.
|
||||||
|
# options - sets options to be passed to the boot loader; use
|
||||||
|
# quotes if more than one option should be passed or
|
||||||
|
# if any options use characters that might be changed
|
||||||
|
# by rEFInd parsing procedures (=, /, #, or tab).
|
||||||
|
# disabled - use alone or set to "yes" to disable this entry.
|
||||||
|
#
|
||||||
|
# Note that you can use either DOS/Windows/EFI-style backslashes (\)
|
||||||
|
# or Unix-style forward slashes (/) as directory separators. Either
|
||||||
|
# way, all file references are on the ESP from which rEFInd was
|
||||||
|
# launched.
|
||||||
|
# Use of quotes around parameters causes them to be interpreted as
|
||||||
|
# one keyword, and for parsing of special characters (spaces, =, /,
|
||||||
|
# and #) to be disabled. This is useful mainly with the "options"
|
||||||
|
# keyword. Use of quotes around parameters that specify filenames is
|
||||||
|
# permissible, but you must then use backslashes instead of slashes,
|
||||||
|
# except when you must pass a forward slash to the loader, as when
|
||||||
|
# passing a root= option to a Linux kernel.
|
||||||
|
|
||||||
|
# Below are several sample boot stanzas. All are disabled by default.
|
||||||
|
# Find one similar to what you need, copy it, remove the "disabled" line,
|
||||||
|
# and adjust the entries to suit your needs.
|
||||||
|
|
||||||
|
# A sample entry for a Linux 3.13 kernel with EFI boot stub support
|
||||||
|
# on a partition with a GUID of 904404F8-B481-440C-A1E3-11A5A954E601.
|
||||||
|
# This entry includes Linux-specific boot options and specification
|
||||||
|
# of an initial RAM disk. Note uses of Linux-style forward slashes.
|
||||||
|
# Also note that a leading slash is optional in file specifications.
|
||||||
|
menuentry Linux {
|
||||||
|
icon EFI/refind/icons/os_linux.png
|
||||||
|
volume 904404F8-B481-440C-A1E3-11A5A954E601
|
||||||
|
loader bzImage-3.3.0-rc7
|
||||||
|
initrd initrd-3.3.0.img
|
||||||
|
options "ro root=UUID=5f96cafa-e0a7-4057-b18f-fa709db5b837"
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# Below is a more complex Linux example, specifically for Arch Linux.
|
||||||
|
# This example MUST be modified for your specific installation; if nothing
|
||||||
|
# else, the PARTUUID code must be changed for your disk. Because Arch Linux
|
||||||
|
# does not include version numbers in its kernel and initrd filenames, you
|
||||||
|
# may need to use manual boot stanzas when using fallback initrds or
|
||||||
|
# multiple kernels with Arch. This example is modified from one in the Arch
|
||||||
|
# wiki page on rEFInd (https://wiki.archlinux.org/index.php/rEFInd).
|
||||||
|
menuentry "Arch Linux" {
|
||||||
|
icon /EFI/refind/icons/os_arch.png
|
||||||
|
volume "Arch Linux"
|
||||||
|
loader /boot/vmlinuz-linux
|
||||||
|
initrd /boot/initramfs-linux.img
|
||||||
|
options "root=PARTUUID=5028fa50-0079-4c40-b240-abfaf28693ea rw add_efi_memmap"
|
||||||
|
submenuentry "Boot using fallback initramfs" {
|
||||||
|
initrd /boot/initramfs-linux-fallback.img
|
||||||
|
}
|
||||||
|
submenuentry "Boot to terminal" {
|
||||||
|
add_options "systemd.unit=multi-user.target"
|
||||||
|
}
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# A sample entry for loading Ubuntu using its standard name for
|
||||||
|
# its GRUB 2 boot loader. Note uses of Linux-style forward slashes
|
||||||
|
menuentry Ubuntu {
|
||||||
|
loader /EFI/ubuntu/grubx64.efi
|
||||||
|
icon /EFI/refind/icons/os_linux.png
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# A minimal ELILO entry, which probably offers nothing that
|
||||||
|
# auto-detection can't accomplish.
|
||||||
|
menuentry "ELILO" {
|
||||||
|
loader \EFI\elilo\elilo.efi
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# Like the ELILO entry, this one offers nothing that auto-detection
|
||||||
|
# can't do; but you might use it if you want to disable auto-detection
|
||||||
|
# but still boot Windows....
|
||||||
|
menuentry "Windows 7" {
|
||||||
|
loader \EFI\Microsoft\Boot\bootmgfw.efi
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# EFI shells are programs just like boot loaders, and can be
|
||||||
|
# launched in the same way. You can pass a shell the name of a
|
||||||
|
# script that it's to run on the "options" line. The script
|
||||||
|
# could initialize hardware and then launch an OS, or it could
|
||||||
|
# do something entirely different.
|
||||||
|
menuentry "Windows via shell script" {
|
||||||
|
icon \EFI\refind\icons\os_win.png
|
||||||
|
loader \EFI\tools\shell.efi
|
||||||
|
options "fs0:\EFI\tools\launch_windows.nsh"
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# MacOS is normally detected and run automatically; however,
|
||||||
|
# if you want to do something unusual, a manual boot stanza may
|
||||||
|
# be the way to do it. This one does nothing very unusual, but
|
||||||
|
# it may serve as a starting point. Note that you'll almost
|
||||||
|
# certainly need to change the "volume" line for this example
|
||||||
|
# to work.
|
||||||
|
menuentry "My macOS" {
|
||||||
|
icon \EFI\refind\icons\os_mac.png
|
||||||
|
volume "macOS boot"
|
||||||
|
loader \System\Library\CoreServices\boot.efi
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
# The firmware_bootnum token takes a HEXADECIMAL value as an option
|
||||||
|
# and sets that value using the EFI's BootNext variable and then
|
||||||
|
# reboots the computer. This then causes a one-time boot of the
|
||||||
|
# computer using this EFI boot option. It can be used for various
|
||||||
|
# purposes, but one that's likely to interest some rEFInd users is
|
||||||
|
# that some Macs with HiDPI displays produce lower-resolution
|
||||||
|
# desktops when booted through rEFInd than when booted via Apple's
|
||||||
|
# own boot manager. Booting using the firmware_bootnum option
|
||||||
|
# produces the better resolution. Note that no loader option is
|
||||||
|
# used in this type of configuration.
|
||||||
|
menuentry "macOS via BootNext" {
|
||||||
|
icon /EFI/refind/icons/os_mac.png
|
||||||
|
firmware_bootnum 80
|
||||||
|
disabled
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"Boot with standard options" "rw root=/dev/mapper/cryptroot cryptdevice=UUID=c452045f-1bad-48c0-9816-f53c67a416dc:cryptroot resume=UUID=11c0ac93-cd2a-451d-9a6e-cf7f855fb26a quiet"
|
||||||
|
"Boot to single-user mode" "rw root=/dev/mapper/cryptroot cryptdevice=UUID=c452045f-1bad-48c0-9816-f53c67a416dc:cryptroot resume=UUID=11c0ac93-cd2a-451d-9a6e-cf7f855fb26a quiet single"
|
||||||
|
"Boot with minimal options" "rw root=/dev/mapper/cryptroot cryptdevice=UUID=c452045f-1bad-48c0-9816-f53c67a416dc:cryptroot resume=UUID=11c0ac93-cd2a-451d-9a6e-cf7f855fb26a quiet"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Laptop suspend and hibernation policy.
|
||||||
|
[Sleep]
|
||||||
|
AllowSuspend=yes
|
||||||
|
AllowHibernation=yes
|
||||||
|
AllowSuspendThenHibernate=yes
|
||||||
|
HibernateDelaySec=15min
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[Login]
|
||||||
|
IdleAction=ignore
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Section "InputClass"
|
||||||
|
Identifier "touchpad"
|
||||||
|
Driver "libinput"
|
||||||
|
MatchIsTouchpad "on"
|
||||||
|
Option "Tapping" "on"
|
||||||
|
Option "TappingButtonMap" "lrm"
|
||||||
|
Option "NaturalScrolling" "true"
|
||||||
|
Option "ClickMethod" "clickfinger"
|
||||||
|
EndSection
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# File to be place under /etc/NetworkManager/conf.d
|
||||||
|
[connection]
|
||||||
|
# Values are 0 (use default), 1 (ignore/don't touch), 2 (disable) or 3 (enable).
|
||||||
|
wifi.powersave = 3
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Used by the Noctalia Pi Status Bridge adapter and the Hyprland launcher.
|
||||||
|
PI_STATUS_BRIDGE_CLIENT=/home/alex/.npm-global/bin/pi-status-bridge-client
|
||||||
|
PI_STATUS_UI_BINARY=/home/alex/.local/bin/pi-status-ui
|
||||||
@@ -29,3 +29,16 @@ end
|
|||||||
# bun
|
# bun
|
||||||
set --export BUN_INSTALL "$HOME/.bun"
|
set --export BUN_INSTALL "$HOME/.bun"
|
||||||
set --export PATH $BUN_INSTALL/bin $PATH
|
set --export PATH $BUN_INSTALL/bin $PATH
|
||||||
|
|
||||||
|
# opencode
|
||||||
|
fish_add_path /home/alex/.opencode/bin
|
||||||
|
|
||||||
|
# Yazi wrapper that keeps the shell in its selected directory.
|
||||||
|
function y
|
||||||
|
set tmp (mktemp -t "yazi-cwd.XXXXXX")
|
||||||
|
command yazi $argv --cwd-file="$tmp"
|
||||||
|
if read -z cwd <"$tmp"; and [ "$cwd" != "$PWD" ]; and test -d "$cwd"
|
||||||
|
builtin cd -- "$cwd"
|
||||||
|
end
|
||||||
|
command rm -f -- "$tmp"
|
||||||
|
end
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -10,16 +10,21 @@ for _, monitor in ipairs(machine.monitors or {}) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local main_mod = "SUPER"
|
local main_mod = "SUPER"
|
||||||
local terminal = "alacritty"
|
local terminal = "kitty"
|
||||||
|
|
||||||
hl.config({
|
local input = {
|
||||||
input = {
|
|
||||||
kb_layout = "us",
|
kb_layout = "us",
|
||||||
kb_variant = "intl",
|
kb_variant = "intl",
|
||||||
numlock_by_default = true,
|
numlock_by_default = true,
|
||||||
},
|
}
|
||||||
|
for key, value in pairs(machine.input or {}) do
|
||||||
|
input[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
input = input,
|
||||||
general = {
|
general = {
|
||||||
gaps_in = 8,
|
gaps_in = 4,
|
||||||
-- Keep a thin black perimeter so the bottom border remains on-screen.
|
-- Keep a thin black perimeter so the bottom border remains on-screen.
|
||||||
gaps_out = 2,
|
gaps_out = 2,
|
||||||
border_size = 2,
|
border_size = 2,
|
||||||
@@ -35,24 +40,45 @@ hl.config({
|
|||||||
animations = {
|
animations = {
|
||||||
enabled = false,
|
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.
|
-- Application and session bindings.
|
||||||
local noctalia_ipc = "noctalia msg "
|
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.
|
-- 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 .. " + 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 .. " + RETURN", hl.dsp.exec_cmd(terminal))
|
||||||
hl.bind(main_mod .. " + CTRL + RETURN", hl.dsp.exec_cmd(terminal .. " -e zellij"))
|
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 .. " + 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 .. " + N", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle alex/knowledge-lookup:panel"))
|
||||||
hl.bind(main_mod .. " + S", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"))
|
hl.bind(main_mod .. " + S", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"))
|
||||||
|
hl.bind(main_mod .. " + 0", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle session"))
|
||||||
hl.bind(main_mod .. " + SHIFT + F", hl.dsp.exec_cmd(noctalia_ipc .. "bar-toggle main"))
|
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"))
|
hl.bind(main_mod .. " + SHIFT + R", hl.dsp.exec_cmd("hyprctl reload"))
|
||||||
hl.bind(main_mod .. " + CTRL + L", hl.dsp.exec_cmd("command -v hyprlock >/dev/null && hyprlock || loginctl lock-session"))
|
hl.bind(main_mod .. " + CTRL + L", hl.dsp.exec_cmd("command -v hyprlock >/dev/null && hyprlock || loginctl lock-session"))
|
||||||
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + S", hl.dsp.exec_cmd("systemctl suspend"))
|
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 .. " + CTRL + SHIFT + ALT + H", hl.dsp.exec_cmd("systemctl hibernate"))
|
||||||
hl.bind(main_mod .. " + SHIFT + C", hl.dsp.window.close())
|
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.
|
-- Audio, media, brightness, and calculator keys.
|
||||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true })
|
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true })
|
||||||
@@ -64,10 +90,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("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 .. " + XF86AudioRaiseVolume", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||||
hl.bind(main_mod .. " + XF86AudioLowerVolume", hl.dsp.exec_cmd("playerctl previous"), { 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("XF86MonBrightnessUp", hl.dsp.exec_cmd('light -A 5'), { locked = true })
|
||||||
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd('light -U 5 && notify-send "Brightness set to $(light)"'), { 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.2 && notify-send "Brightness set to min"'), { 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 && notify-send "Brightness set to max"'), { 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 })
|
hl.bind("XF86Calculator", hl.dsp.exec_cmd("qalculate-qt"), { locked = true })
|
||||||
|
|
||||||
-- Retain i3's hjkl and arrow-key directional workflow.
|
-- Retain i3's hjkl and arrow-key directional workflow.
|
||||||
@@ -88,7 +114,9 @@ for workspace = 1, 9 do
|
|||||||
hl.bind(main_mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = workspace }))
|
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 }))
|
hl.bind(main_mod .. " + CTRL + " .. key, hl.dsp.window.move({ workspace = workspace, follow = true }))
|
||||||
end
|
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 + RIGHT", hl.dsp.focus({ workspace = "+1" }))
|
||||||
hl.bind(main_mod .. " + CTRL + LEFT", hl.dsp.focus({ workspace = "-1" }))
|
hl.bind(main_mod .. " + CTRL + LEFT", hl.dsp.focus({ workspace = "-1" }))
|
||||||
|
|
||||||
@@ -112,7 +140,9 @@ local function float_rule(name, match, border_size)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
hl.window_rule({ name = "obsidian-workspace", match = { class = "^obsidian$" }, workspace = "8" })
|
||||||
hl.window_rule({ name = "thunderbird-workspace", match = { class = "^Thunderbird$" }, workspace = "9" })
|
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("alsamixer", { title = "^alsamixer$" }, 1)
|
||||||
float_rule("qalculate", { title = "^Qalculate!$" })
|
float_rule("qalculate", { title = "^Qalculate!$" })
|
||||||
float_rule("psensor", { class = "^Psensor$" })
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Match the active Alacritty look while retaining Kitty's native graphics protocol.
|
||||||
|
font_family MesloLGS NF
|
||||||
|
font_size 15.0
|
||||||
|
|
||||||
|
# Palette: active ~/.config/alacritty/alacritty.toml plus Noctalia cursor/selection.
|
||||||
|
foreground #FCFCFA
|
||||||
|
background #2D2A2E
|
||||||
|
cursor #fff1e6
|
||||||
|
cursor_text_color #000000
|
||||||
|
selection_foreground #fff1e6
|
||||||
|
selection_background #3b220f
|
||||||
|
|
||||||
|
color0 #403E41
|
||||||
|
color1 #FF6188
|
||||||
|
color2 #A9DC76
|
||||||
|
color3 #FFD866
|
||||||
|
color4 #FC9867
|
||||||
|
color5 #AB9DF2
|
||||||
|
color6 #78DCE8
|
||||||
|
color7 #FCFCFA
|
||||||
|
color8 #727072
|
||||||
|
color9 #FF6188
|
||||||
|
color10 #A9DC76
|
||||||
|
color11 #FFD866
|
||||||
|
color12 #FC9867
|
||||||
|
color13 #AB9DF2
|
||||||
|
color14 #78DCE8
|
||||||
|
color15 #FCFCFA
|
||||||
|
|
||||||
|
# Preserve Alacritty-like minimal window behavior.
|
||||||
|
window_padding_width 0
|
||||||
|
copy_on_select no
|
||||||
|
|
||||||
|
# Keep the shell integration and graphics protocol available to Ranger.
|
||||||
|
shell_integration enabled
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# Shared Noctalia defaults. Keep GUI experiments in state; promote durable choices here.
|
||||||
|
[shell]
|
||||||
|
setup_wizard_enabled = false
|
||||||
|
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", "alex/knowledge-lookup"]
|
||||||
|
|
||||||
|
[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.knowledge-lookup]
|
||||||
|
type = "alex/knowledge-lookup:bar"
|
||||||
|
|
||||||
|
[widget.temp]
|
||||||
|
type = "sysmon"
|
||||||
|
stat = "cpu_temp"
|
||||||
|
visualization = "none"
|
||||||
|
show_value = true
|
||||||
|
|
||||||
|
[widget.disk]
|
||||||
|
type = "sysmon"
|
||||||
|
stat = "disk_used_pct"
|
||||||
|
visualization = "none"
|
||||||
|
show_value = true
|
||||||
|
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
|
||||||
@@ -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/.npm-global/bin:/usr/local/bin:/usr/bin:/bin
|
||||||
|
ExecStart=/usr/bin/env pi-status-bridge --session-root %h/.local/state/pi-status-bridge/sessions
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=OpenSSH key agent
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
|
||||||
|
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 yazi-rs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Catppuccin
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<div align="center">
|
||||||
|
<img src="https://github.com/sxyazi/yazi/blob/main/assets/logo.png?raw=true" alt="Yazi logo" width="20%">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 align="center">
|
||||||
|
Catppuccin Macchiato Flavor for <a href="https://github.com/sxyazi/yazi">Yazi</a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
## 👀 Preview
|
||||||
|
|
||||||
|
<img src="preview.png" width="600" />
|
||||||
|
|
||||||
|
## 🎨 Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pkg add yazi-rs/flavors:catppuccin-macchiato
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚙️ Usage
|
||||||
|
|
||||||
|
Set the content of your `theme.toml` to enable it as your _dark_ flavor:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[flavor]
|
||||||
|
dark = "catppuccin-macchiato"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure your `theme.toml` doesn't contain anything other than `[flavor]`, unless you want to override certain styles of this flavor.
|
||||||
|
|
||||||
|
See the [Yazi flavor documentation](https://yazi-rs.github.io/docs/flavors/overview) for more details.
|
||||||
|
|
||||||
|
## 📜 License
|
||||||
|
|
||||||
|
The flavor is MIT-licensed, and the included tmTheme is also MIT-licensed.
|
||||||
|
|
||||||
|
Check the [LICENSE](LICENSE) and [LICENSE-tmtheme](LICENSE-tmtheme) file for more details.
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
# vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
|
||||||
|
# : Manager {{{
|
||||||
|
|
||||||
|
[mgr]
|
||||||
|
cwd = { fg = "#8bd5ca" }
|
||||||
|
|
||||||
|
# Find
|
||||||
|
find_keyword = { fg = "#eed49f", bold = true, italic = true, underline = true }
|
||||||
|
find_position = { fg = "#f5bde6", bg = "reset", bold = true, italic = true }
|
||||||
|
|
||||||
|
# Marker
|
||||||
|
marker_copied = { fg = "#a6da95", bg = "#a6da95" }
|
||||||
|
marker_cut = { fg = "#ed8796", bg = "#ed8796" }
|
||||||
|
marker_marked = { fg = "#8bd5ca", bg = "#8bd5ca" }
|
||||||
|
marker_selected = { fg = "#eed49f", bg = "#eed49f" }
|
||||||
|
|
||||||
|
# Count
|
||||||
|
count_copied = { fg = "#24273a", bg = "#a6da95" }
|
||||||
|
count_cut = { fg = "#24273a", bg = "#ed8796" }
|
||||||
|
count_selected = { fg = "#24273a", bg = "#eed49f" }
|
||||||
|
|
||||||
|
# Border
|
||||||
|
border_symbol = "│"
|
||||||
|
border_style = { fg = "#8087a2" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Tabs {{{
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
active = { fg = "#24273a", bg = "#8aadf4", bold = true }
|
||||||
|
inactive = { fg = "#8aadf4", bg = "#363a4f" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Mode {{{
|
||||||
|
|
||||||
|
[mode]
|
||||||
|
|
||||||
|
normal_main = { fg = "#24273a", bg = "#8aadf4", bold = true }
|
||||||
|
normal_alt = { fg = "#8aadf4", bg = "#363a4f" }
|
||||||
|
|
||||||
|
# Select mode
|
||||||
|
select_main = { fg = "#24273a", bg = "#8bd5ca", bold = true }
|
||||||
|
select_alt = { fg = "#8bd5ca", bg = "#363a4f" }
|
||||||
|
|
||||||
|
# Unset mode
|
||||||
|
unset_main = { fg = "#24273a", bg = "#f0c6c6", bold = true }
|
||||||
|
unset_alt = { fg = "#f0c6c6", bg = "#363a4f" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Status bar {{{
|
||||||
|
|
||||||
|
[status]
|
||||||
|
# Permissions
|
||||||
|
perm_sep = { fg = "#8087a2" }
|
||||||
|
perm_type = { fg = "#8aadf4" }
|
||||||
|
perm_read = { fg = "#eed49f" }
|
||||||
|
perm_write = { fg = "#ed8796" }
|
||||||
|
perm_exec = { fg = "#a6da95" }
|
||||||
|
|
||||||
|
# Progress
|
||||||
|
progress_label = { fg = "#ffffff", bold = true }
|
||||||
|
progress_normal = { fg = "#a6da95", bg = "#494d64" }
|
||||||
|
progress_error = { fg = "#eed49f", bg = "#ed8796" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Pick {{{
|
||||||
|
|
||||||
|
[pick]
|
||||||
|
border = { fg = "#8aadf4" }
|
||||||
|
active = { fg = "#f5bde6", bold = true }
|
||||||
|
inactive = {}
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Input {{{
|
||||||
|
|
||||||
|
[input]
|
||||||
|
border = { fg = "#8aadf4" }
|
||||||
|
title = {}
|
||||||
|
value = {}
|
||||||
|
selected = { reversed = true }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Completion {{{
|
||||||
|
|
||||||
|
[cmp]
|
||||||
|
border = { fg = "#8aadf4" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Tasks {{{
|
||||||
|
|
||||||
|
[tasks]
|
||||||
|
border = { fg = "#8aadf4" }
|
||||||
|
title = {}
|
||||||
|
hovered = { fg = "#f5bde6", bold = true }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Which {{{
|
||||||
|
|
||||||
|
[which]
|
||||||
|
border = { fg = "#8aadf4" }
|
||||||
|
cand = { fg = "#8bd5ca" }
|
||||||
|
rest = { fg = "#939ab7" }
|
||||||
|
desc = { fg = "#f5bde6" }
|
||||||
|
separator = " "
|
||||||
|
separator_style = { fg = "#5b6078" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Help {{{
|
||||||
|
|
||||||
|
[help]
|
||||||
|
on = { fg = "#8bd5ca" }
|
||||||
|
run = { fg = "#f5bde6" }
|
||||||
|
hovered = { reversed = true, bold = true }
|
||||||
|
footer = { fg = "#363a4f", bg = "#cad3f5" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Spotter {{{
|
||||||
|
|
||||||
|
[spot]
|
||||||
|
border = { fg = "#8aadf4" }
|
||||||
|
title = { fg = "#8aadf4" }
|
||||||
|
tbl_col = { fg = "#8bd5ca" }
|
||||||
|
tbl_cell = { fg = "#f5bde6", bg = "#494d64" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : Notification {{{
|
||||||
|
|
||||||
|
[notify]
|
||||||
|
title_info = { fg = "#a6da95" }
|
||||||
|
title_warn = { fg = "#eed49f" }
|
||||||
|
title_error = { fg = "#ed8796" }
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
|
||||||
|
# : File-specific styles {{{
|
||||||
|
|
||||||
|
[filetype]
|
||||||
|
|
||||||
|
rules = [
|
||||||
|
# Image
|
||||||
|
{ mime = "**/image/*", fg = "#8bd5ca" },
|
||||||
|
# Media
|
||||||
|
{ mime = "**/{audio,video}/*", fg = "#eed49f" },
|
||||||
|
# Archive
|
||||||
|
{ mime = "**/application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}", fg = "#f5bde6" },
|
||||||
|
# Document
|
||||||
|
{ mime = "**/application/{pdf,doc,rtf}", fg = "#a6da95" },
|
||||||
|
# Virtual file system
|
||||||
|
{ mime = "vfs/{absent,stale}", fg = "#939ab7" },
|
||||||
|
# Fallback
|
||||||
|
{ url = "*", fg = "#cad3f5" },
|
||||||
|
{ url = "*/", fg = "#8aadf4" },
|
||||||
|
]
|
||||||
|
|
||||||
|
# : }}}
|
||||||
|
|
||||||
|
[icon]
|
||||||
|
|
||||||
|
dirs = [
|
||||||
|
{ name = ".config", text = "", fg = "#f5bde6" },
|
||||||
|
{ name = ".git", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = ".github", text = "", fg = "#8aadf4" },
|
||||||
|
{ name = ".npm", text = "", fg = "#8aadf4" },
|
||||||
|
{ name = "Desktop", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Development", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Documents", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Downloads", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Library", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Movies", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Music", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Pictures", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Public", text = "", fg = "#8bd5ca" },
|
||||||
|
{ name = "Videos", text = "", fg = "#8bd5ca" },
|
||||||
|
]
|
||||||
|
conds = [
|
||||||
|
# Special files
|
||||||
|
{ if = "orphan", text = "", fg = "#cad3f5" },
|
||||||
|
{ if = "link", text = "", fg = "#8087a2" },
|
||||||
|
{ if = "block", text = "", fg = "#f0c6c6" },
|
||||||
|
{ if = "char", text = "", fg = "#f0c6c6" },
|
||||||
|
{ if = "fifo", text = "", fg = "#f0c6c6" },
|
||||||
|
{ if = "sock", text = "", fg = "#f0c6c6" },
|
||||||
|
{ if = "sticky", text = "", fg = "#f0c6c6" },
|
||||||
|
{ if = "dummy", text = "", fg = "#ed8796" },
|
||||||
|
|
||||||
|
# Fallback
|
||||||
|
{ if = "dir & hovered", text = "", fg = "#8aadf4" },
|
||||||
|
{ if = "dir", text = "", fg = "#8aadf4" },
|
||||||
|
{ if = "exec", text = "", fg = "#a6da95" },
|
||||||
|
{ if = "!dir", text = "", fg = "#cad3f5" },
|
||||||
|
]
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 674 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
require("git"):setup {
|
||||||
|
order = 1500,
|
||||||
|
}
|
||||||
|
|
||||||
|
require("githead"):setup {
|
||||||
|
branch_prefix = "on ",
|
||||||
|
branch_symbol = " ",
|
||||||
|
branch_borders = "()",
|
||||||
|
branch_color = "#ffb05c",
|
||||||
|
remote_branch_color = "#f4c7a1",
|
||||||
|
tag_color = "#ffcc99",
|
||||||
|
commit_color = "#f4c7a1",
|
||||||
|
behind_remote_color = "#ff6b4a",
|
||||||
|
ahead_remote_color = "#ff8800",
|
||||||
|
stashes_color = "#c98a45",
|
||||||
|
state_color = "#ff6b4a",
|
||||||
|
staged_color = "#ff8800",
|
||||||
|
unstaged_color = "#ffb05c",
|
||||||
|
untracked_color = "#f4c7a1",
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#:schema https://yazi-rs.github.io/schemas/keymap.json
|
||||||
|
|
||||||
|
[[mgr.prepend_keymap]]
|
||||||
|
on = "l"
|
||||||
|
run = "plugin smart-enter"
|
||||||
|
desc = "Enter the child directory, or open the file"
|
||||||
|
|
||||||
|
[[mgr.prepend_keymap]]
|
||||||
|
on = ["g", "d"]
|
||||||
|
run = "cd ~/downloads"
|
||||||
|
desc = "Cd to Downloads"
|
||||||
|
|
||||||
|
[[mgr.prepend_keymap]]
|
||||||
|
on = ["g", "D"]
|
||||||
|
run = "cd ~/cloud/documents"
|
||||||
|
desc = "Cd to Documents"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:smart-enter"
|
||||||
|
rev = "0be29a9"
|
||||||
|
hash = "187cc58ba7ac3befd49c342129e6f1b6"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:git"
|
||||||
|
rev = "3f2b882"
|
||||||
|
hash = "336548d9f67926e12d5584f60b790f1"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "llanosrocas/githead"
|
||||||
|
rev = "317d09f"
|
||||||
|
hash = "41dc37a724b2afd21da4f1ea6c1182d8"
|
||||||
|
|
||||||
|
[[flavor.deps]]
|
||||||
|
use = "yazi-rs/flavors:catppuccin-macchiato"
|
||||||
|
rev = "be0b21d"
|
||||||
|
hash = "5b1bf96d1cba26376087c37de993c517"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 yazi-rs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# git.yazi
|
||||||
|
|
||||||
|
Show the status of Git file changes as linemode in the file list.
|
||||||
|
|
||||||
|
https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pkg add yazi-rs/plugins:git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Add the following to your `~/.config/yazi/init.lua`:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("git"):setup {
|
||||||
|
-- Order of status signs showing in the linemode
|
||||||
|
order = 1500,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And register it as fetchers in your `~/.config/yazi/yazi.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[plugin.prepend_fetchers]]
|
||||||
|
url = "*"
|
||||||
|
run = "git"
|
||||||
|
group = "git"
|
||||||
|
|
||||||
|
[[plugin.prepend_fetchers]]
|
||||||
|
url = "*/"
|
||||||
|
run = "git"
|
||||||
|
group = "git"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced
|
||||||
|
|
||||||
|
You can customize the [Style](https://yazi-rs.github.io/docs/configuration/theme#types.style) of the status sign with:
|
||||||
|
|
||||||
|
- `[git].unknown` - status cannot/not yet determined
|
||||||
|
- `[git].modified` - modified file
|
||||||
|
- `[git].added` - added file
|
||||||
|
- `[git].untracked` - untracked file
|
||||||
|
- `[git].ignored` - ignored file
|
||||||
|
- `[git].deleted` - deleted file
|
||||||
|
- `[git].updated` - updated file
|
||||||
|
- `[git].clean` - clean file
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# theme.toml / flavor.toml
|
||||||
|
[git]
|
||||||
|
modified = { fg = "blue" }
|
||||||
|
deleted = { fg = "red", bold = true }
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also customize the text of the status sign with:
|
||||||
|
|
||||||
|
- `[git].unknown_sign` - status cannot/not yet determined
|
||||||
|
- `[git].modified_sign` - modified file
|
||||||
|
- `[git].added_sign` - added file
|
||||||
|
- `[git].untracked_sign` - untracked file
|
||||||
|
- `[git].ignored_sign` - ignored file
|
||||||
|
- `[git].deleted_sign` - deleted file
|
||||||
|
- `[git].updated_sign` - updated file
|
||||||
|
- `[git].clean_sign` - clean file
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# theme.toml / flavor.toml
|
||||||
|
[git]
|
||||||
|
unknown_sign = " "
|
||||||
|
modified_sign = "M"
|
||||||
|
deleted_sign = "D"
|
||||||
|
clean_sign = "✔"
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
--- @since 26.5.6
|
||||||
|
|
||||||
|
local WINDOWS = ya.target_family() == "windows"
|
||||||
|
|
||||||
|
-- The code of supported git status,
|
||||||
|
-- also used to determine which status to show for directories when they contain different statuses
|
||||||
|
-- see `bubble_up`
|
||||||
|
---@enum CODES
|
||||||
|
local CODES = {
|
||||||
|
unknown = 100, -- status cannot/not yet determined
|
||||||
|
excluded = 99, -- ignored directory
|
||||||
|
ignored = 6, -- ignored file
|
||||||
|
untracked = 5,
|
||||||
|
modified = 4,
|
||||||
|
added = 3,
|
||||||
|
deleted = 2,
|
||||||
|
updated = 1,
|
||||||
|
clean = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
local PATTERNS = {
|
||||||
|
{ "!$", CODES.ignored },
|
||||||
|
{ "?$", CODES.untracked },
|
||||||
|
{ "[MT]", CODES.modified },
|
||||||
|
{ "[AC]", CODES.added },
|
||||||
|
{ "D", CODES.deleted },
|
||||||
|
{ "U", CODES.updated },
|
||||||
|
{ "[AD][AD]", CODES.updated },
|
||||||
|
}
|
||||||
|
|
||||||
|
local function theme()
|
||||||
|
local t = th.git or {}
|
||||||
|
return {
|
||||||
|
[CODES.unknown] = t.unknown or ui.Style(),
|
||||||
|
[CODES.ignored] = t.ignored or ui.Style():fg("darkgray"),
|
||||||
|
[CODES.untracked] = t.untracked or ui.Style():fg("magenta"),
|
||||||
|
[CODES.modified] = t.modified or ui.Style():fg("yellow"),
|
||||||
|
[CODES.added] = t.added or ui.Style():fg("green"),
|
||||||
|
[CODES.deleted] = t.deleted or ui.Style():fg("red"),
|
||||||
|
[CODES.updated] = t.updated or ui.Style():fg("yellow"),
|
||||||
|
[CODES.clean] = t.clean or ui.Style(),
|
||||||
|
}, {
|
||||||
|
[CODES.unknown] = t.unknown_sign or "",
|
||||||
|
[CODES.ignored] = t.ignored_sign or " ",
|
||||||
|
[CODES.untracked] = t.untracked_sign or "? ",
|
||||||
|
[CODES.modified] = t.modified_sign or " ",
|
||||||
|
[CODES.added] = t.added_sign or " ",
|
||||||
|
[CODES.deleted] = t.deleted_sign or " ",
|
||||||
|
[CODES.updated] = t.updated_sign or " ",
|
||||||
|
[CODES.clean] = t.clean_sign or "",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param line string
|
||||||
|
---@return CODES, string
|
||||||
|
local function match(line)
|
||||||
|
local signs = line:sub(1, 2)
|
||||||
|
for _, p in ipairs(PATTERNS) do
|
||||||
|
local path, pattern, code = nil, p[1], p[2]
|
||||||
|
if signs:find(pattern) then
|
||||||
|
path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4)
|
||||||
|
path = WINDOWS and path:gsub("/", "\\") or path
|
||||||
|
end
|
||||||
|
if not path then
|
||||||
|
elseif path:find("[/\\]$") then
|
||||||
|
-- Mark the ignored directory as `excluded`, so we can process it further within `propagate_down`
|
||||||
|
return code == CODES.ignored and CODES.excluded or code, path:sub(1, -2)
|
||||||
|
else
|
||||||
|
return code, path
|
||||||
|
end
|
||||||
|
---@diagnostic disable-next-line: missing-return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param cwd Url
|
||||||
|
---@return string?
|
||||||
|
local function root(cwd)
|
||||||
|
local is_worktree = function(url)
|
||||||
|
local file, head = io.open(tostring(url)), nil
|
||||||
|
if file then
|
||||||
|
head = file:read(8)
|
||||||
|
file:close()
|
||||||
|
end
|
||||||
|
return head == "gitdir: "
|
||||||
|
end
|
||||||
|
|
||||||
|
repeat
|
||||||
|
local next = cwd:join(".git")
|
||||||
|
local cha = fs.cha(next)
|
||||||
|
if cha and (cha.is_dir or is_worktree(next)) then
|
||||||
|
return tostring(cwd)
|
||||||
|
end
|
||||||
|
cwd = cwd.parent
|
||||||
|
until not cwd
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param changed Changes
|
||||||
|
---@return Changes
|
||||||
|
local function bubble_up(changed)
|
||||||
|
local new, empty = {}, Url("")
|
||||||
|
for path, code in pairs(changed) do
|
||||||
|
if code ~= CODES.ignored then
|
||||||
|
local url = Url(path).parent
|
||||||
|
while url and url ~= empty do
|
||||||
|
local s = tostring(url)
|
||||||
|
new[s] = (new[s] or CODES.clean) > code and new[s] or code
|
||||||
|
url = url.parent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param excluded string[]
|
||||||
|
---@param cwd Url
|
||||||
|
---@param repo Url
|
||||||
|
---@return Changes
|
||||||
|
local function propagate_down(excluded, cwd, repo)
|
||||||
|
local new, rel = {}, cwd:strip_prefix(repo)
|
||||||
|
for _, path in ipairs(excluded) do
|
||||||
|
if rel:starts_with(path) then
|
||||||
|
-- If `cwd` is a subdirectory of an excluded directory, also mark it as `excluded`
|
||||||
|
new[tostring(cwd)] = CODES.excluded
|
||||||
|
elseif cwd == repo:join(path).parent then
|
||||||
|
-- If `path` is a direct subdirectory of `cwd`, mark it as `ignored`
|
||||||
|
new[path] = CODES.ignored
|
||||||
|
else
|
||||||
|
-- Skipping, we only care about `cwd` itself and its direct subdirectories for maximum performance
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param cwd string
|
||||||
|
---@param repo string
|
||||||
|
---@param changed Changes
|
||||||
|
local add = ya.sync(function(st, cwd, repo, changed)
|
||||||
|
---@cast st State
|
||||||
|
|
||||||
|
st.dirs[cwd] = repo
|
||||||
|
st.repos[repo] = st.repos[repo] or {}
|
||||||
|
for path, code in pairs(changed) do
|
||||||
|
if code == CODES.clean then
|
||||||
|
st.repos[repo][path] = nil
|
||||||
|
elseif code == CODES.excluded then
|
||||||
|
-- Mark the directory with a special value `excluded` so that it can be distinguished during UI rendering
|
||||||
|
st.dirs[path] = CODES.excluded
|
||||||
|
else
|
||||||
|
st.repos[repo][path] = code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ui.render()
|
||||||
|
end)
|
||||||
|
|
||||||
|
---@param cwd string
|
||||||
|
local remove = ya.sync(function(st, cwd)
|
||||||
|
---@cast st State
|
||||||
|
|
||||||
|
local repo = st.dirs[cwd]
|
||||||
|
if not repo then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
ui.render()
|
||||||
|
st.dirs[cwd] = nil
|
||||||
|
if not st.repos[repo] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, r in pairs(st.dirs) do
|
||||||
|
if r == repo then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
st.repos[repo] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
---@param st State
|
||||||
|
---@param opts Options
|
||||||
|
local function setup(st, opts)
|
||||||
|
st.dirs = {}
|
||||||
|
st.repos = {}
|
||||||
|
|
||||||
|
opts = opts or {}
|
||||||
|
opts.order = opts.order or 1500
|
||||||
|
|
||||||
|
local styles, signs = theme()
|
||||||
|
ps.sub("theme", function()
|
||||||
|
styles, signs = theme()
|
||||||
|
end)
|
||||||
|
|
||||||
|
Linemode:children_add(function(self)
|
||||||
|
if not self._file.in_current then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local url = self._file.url
|
||||||
|
local repo = st.dirs[tostring(url.base or url.parent)]
|
||||||
|
local code = CODES.unknown
|
||||||
|
if repo then
|
||||||
|
code = repo == CODES.excluded and CODES.ignored or st.repos[repo][tostring(url):sub(#repo + 2)] or CODES.clean
|
||||||
|
end
|
||||||
|
|
||||||
|
if signs[code] == "" then
|
||||||
|
return ""
|
||||||
|
elseif self._file.is_hovered then
|
||||||
|
return ui.Line { " ", signs[code] }
|
||||||
|
else
|
||||||
|
return ui.Line { " ", ui.Span(signs[code]):style(styles[code]) }
|
||||||
|
end
|
||||||
|
end, opts.order)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type UnstableFetcher
|
||||||
|
local function fetch(_, job)
|
||||||
|
local cwd = job.files[1].url.base or job.files[1].url.parent
|
||||||
|
local repo = root(cwd)
|
||||||
|
if not repo then
|
||||||
|
remove(tostring(cwd))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local paths = {}
|
||||||
|
for _, file in ipairs(job.files) do
|
||||||
|
paths[#paths + 1] = tostring(file.url)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- stylua: ignore
|
||||||
|
local output, err = Command("git")
|
||||||
|
:cwd(tostring(cwd))
|
||||||
|
:arg({ "--no-optional-locks", "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" })
|
||||||
|
:arg(paths)
|
||||||
|
:output()
|
||||||
|
if not output then
|
||||||
|
return true, Err("Cannot spawn `git` command, error: %s", err)
|
||||||
|
end
|
||||||
|
|
||||||
|
local changed, excluded = {}, {}
|
||||||
|
for line in output.stdout:gmatch("[^\r\n]+") do
|
||||||
|
local code, path = match(line)
|
||||||
|
if code == CODES.excluded then
|
||||||
|
excluded[#excluded + 1] = path
|
||||||
|
else
|
||||||
|
changed[path] = code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if job.files[1].cha.is_dir then
|
||||||
|
ya.dict_merge(changed, bubble_up(changed))
|
||||||
|
end
|
||||||
|
ya.dict_merge(changed, propagate_down(excluded, cwd, Url(repo)))
|
||||||
|
|
||||||
|
-- Reset the status of any files that don't appear in the output of `git status` to `clean`,
|
||||||
|
-- so that cleaning up outdated statuses from `st.repos`
|
||||||
|
for _, path in ipairs(paths) do
|
||||||
|
local s = path:sub(#repo + 2)
|
||||||
|
changed[s] = changed[s] or CODES.clean
|
||||||
|
end
|
||||||
|
|
||||||
|
add(tostring(cwd), repo, changed)
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: remove
|
||||||
|
local function fetch_compact(self, job)
|
||||||
|
if ya.throttle then
|
||||||
|
fetch(self, job)
|
||||||
|
return ya.co(function()
|
||||||
|
for _, file in ipairs(job.files) do
|
||||||
|
coroutine.yield(file, { retry = true })
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
return fetch(self, job)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { setup = setup, fetch = fetch_compact }
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
---@class State
|
||||||
|
---@field dirs table<string, string|CODES> Mapping between a directory and its corresponding repository
|
||||||
|
---@field repos table<string, Changes> Mapping between a repository and the status of each of its files
|
||||||
|
|
||||||
|
---@class Options
|
||||||
|
---@field order number The order in which the status is displayed
|
||||||
|
---@field renamed boolean Whether to include renamed files in the status (or treat them as modified)
|
||||||
|
|
||||||
|
-- TODO: move this to `types.yazi` once it's get stable
|
||||||
|
---@alias UnstableFetcher fun(self: unknown, job: { files: File[] }): boolean, Error?
|
||||||
|
|
||||||
|
---@alias Changes table<string, CODES>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 llanosrocas
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
# githead.yazi
|
||||||
|
|
||||||
|
Git status header for yazi inspired by [powerlevel10k](https://github.com/romkatv/powerlevel10k?tab=readme-ov-file#what-do-different-symbols-in-git-status-mean).
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
All supported features are listed [here](#features). More presets are available [here](#presets).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- yazi version >= [26.1.22](https://github.com/sxyazi/yazi/releases/tag/v26.1.22).
|
||||||
|
- Font with symbol support. For example [Nerd Fonts](https://www.nerdfonts.com/).
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
To keep the plugin up to date, there are two branches: `main` and `nightly`.
|
||||||
|
The `main` branch follows major yazi releases, while `nightly` is linked to specific yazi commits or changes.
|
||||||
|
|
||||||
|
This setup allows shipping stable versions on time, while giving early access to "cutting-edge" changes. See matrix below.
|
||||||
|
|
||||||
|
<details close>
|
||||||
|
<summary>Compatibility matrix</summary>
|
||||||
|
|
||||||
|
| githead | yazi |
|
||||||
|
| :-------------------------------------------------------------------------------------------------------: | ----------------------------------------------------------------------------------------- |
|
||||||
|
| [v2.0.2](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.2) | [v26.1.22](https://github.com/sxyazi/yazi/releases/tag/v26.1.22) |
|
||||||
|
| [v2.0.2](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.2) | [v25.12.29](https://github.com/sxyazi/yazi/releases/tag/v25.12.29) |
|
||||||
|
| [v2.0.2-nightly.292d37c](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.2-nightly.292d37c) | [2f66561](https://github.com/sxyazi/yazi/commit/2f66561a8251f8788b2b0fd366af90555ecafc86) |
|
||||||
|
| [v2.0.2-nightly.292d37c](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.2-nightly.292d37c) | [6cfa92f](https://github.com/sxyazi/yazi/commit/6cfa92f11205d212155579b5b76d4cbabe723829) |
|
||||||
|
| [v2.0.2-nightly.292d37c](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.2-nightly.292d37c) | [292d37c](https://github.com/sxyazi/yazi/commit/292d37ccde5fb09dc7318247caf552213d16ec36) |
|
||||||
|
| [v2.0.1](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.1) | [917e1f5](https://github.com/sxyazi/yazi/commit/917e1f54a10445f2e25147c4b81a3c77d8233632) |
|
||||||
|
| [v2.0.0](https://github.com/llanosrocas/githead.yazi/releases/tag/v2.0.0) | [693dff2](https://github.com/sxyazi/yazi/commit/693dff25e3165e357cc9d0b94ca3f2b176741a36) |
|
||||||
|
| [v1.7.0](https://github.com/llanosrocas/githead.yazi/releases/tag/v1.7.0) | [693dff2](https://github.com/sxyazi/yazi/tree/693dff25e3165e357cc9d0b94ca3f2b176741a36) |
|
||||||
|
| [v1.6.0](https://github.com/llanosrocas/githead.yazi/releases/tag/v1.6.0) | [v25.5.31](https://github.com/sxyazi/yazi/releases/tag/v25.5.31) |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Using yazi package manager
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pkg add llanosrocas/githead
|
||||||
|
```
|
||||||
|
|
||||||
|
_Or manually copy `main.lua` to the `~/.config/yazi/plugins/githead.yazi/main.lua`_
|
||||||
|
|
||||||
|
2. Add this line to your `~/.config/yazi/init.lua`:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
This is default config, if you want to see copy-paste presets go to [this section](#presets).
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup({
|
||||||
|
order = {
|
||||||
|
"__spacer__",
|
||||||
|
"branch",
|
||||||
|
"remote",
|
||||||
|
"__spacer__",
|
||||||
|
"tag",
|
||||||
|
"__spacer__",
|
||||||
|
"commit",
|
||||||
|
"__spacer__",
|
||||||
|
"behind_ahead_remote",
|
||||||
|
"__spacer__",
|
||||||
|
"stashes",
|
||||||
|
"__spacer__",
|
||||||
|
"state",
|
||||||
|
"__spacer__",
|
||||||
|
"staged",
|
||||||
|
"__spacer__",
|
||||||
|
"unstaged",
|
||||||
|
"__spacer__",
|
||||||
|
"untracked",
|
||||||
|
},
|
||||||
|
|
||||||
|
show_numbers = true, -- shows staged, unstaged, untracked, stashes count
|
||||||
|
|
||||||
|
show_branch = true,
|
||||||
|
branch_prefix = "",
|
||||||
|
branch_color = "blue",
|
||||||
|
branch_symbol = "",
|
||||||
|
branch_borders = "",
|
||||||
|
|
||||||
|
show_remote_branch = true, -- only shown if different from local branch
|
||||||
|
always_show_remote_branch = false, -- always show remote branch even if it the same as local branch
|
||||||
|
always_show_remote_repo = false, -- Adds `origin/` if `always_show_remote_branch` is enabled
|
||||||
|
remote_branch_prefix = ":",
|
||||||
|
remote_branch_color = "bright magenta",
|
||||||
|
|
||||||
|
show_tag = true, -- only shown if branch is not available
|
||||||
|
always_show_tag = false,
|
||||||
|
tag_color = "magenta",
|
||||||
|
tag_symbol = "#",
|
||||||
|
|
||||||
|
show_commit = true, -- only shown if branch AND tag are not available
|
||||||
|
always_show_commit = false,
|
||||||
|
commit_color = "bright magenta",
|
||||||
|
commit_symbol = "@",
|
||||||
|
|
||||||
|
show_behind_ahead_remote = true,
|
||||||
|
behind_remote_color = "bright magenta",
|
||||||
|
behind_remote_symbol = "⇣",
|
||||||
|
ahead_remote_color = "bright magenta",
|
||||||
|
ahead_remote_symbol = "⇡",
|
||||||
|
|
||||||
|
show_stashes = true,
|
||||||
|
stashes_color = "bright magenta",
|
||||||
|
stashes_symbol = "$",
|
||||||
|
|
||||||
|
show_state = true,
|
||||||
|
show_state_prefix = true,
|
||||||
|
state_color = "red",
|
||||||
|
state_symbol = "~",
|
||||||
|
|
||||||
|
show_staged = true,
|
||||||
|
staged_color = "bright yellow",
|
||||||
|
staged_symbol = "+",
|
||||||
|
|
||||||
|
show_unstaged = true,
|
||||||
|
unstaged_color = "bright yellow",
|
||||||
|
unstaged_symbol = "!",
|
||||||
|
|
||||||
|
show_untracked = true,
|
||||||
|
untracked_color = "blue",
|
||||||
|
untracked_symbol = "?",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
/cwd on ( feature):origin/main #v1.0.0 #1234567 ⇣2⇡3 $1 rebase 1/2 ~2 +4 !1 ?5
|
||||||
|
| | | | ││ | | | | | | | | | | | |
|
||||||
|
| | | | ││ | | | | | | | | | | | └─── untracked_symbol
|
||||||
|
| | | | ││ | | | | | | | | | | └────── unstaged_symbol
|
||||||
|
| | | | ││ | | | | | | | | | └───────── staged_symbol
|
||||||
|
| | | | ││ | | | | | | | | └──────────── state_symbol
|
||||||
|
| | | | ││ | | | | | | | └─────────────────────── state_prefix
|
||||||
|
| | | | ││ | | | | | | └────────────────────────── stashes_symbol
|
||||||
|
| | | | ││ | | | | | └───────────────────────────── ahead_symbol
|
||||||
|
| | | | ││ | | | | └─────────────────────────────── behind_symbol
|
||||||
|
| | | | ││ | | | └──────────────────────────────────────── commit_symbol
|
||||||
|
| | | | ││ | | └──────────────────────────────────────────────── tag_symbol
|
||||||
|
| | | | ││ | └───────────────────────────────────────────────────── remote_branch
|
||||||
|
| | | | ││ └─────────────────────────────────────────────────────────── remote_repo
|
||||||
|
| | | | |└───────────────────────────────────────────────────────────── remote_branch_prefix
|
||||||
|
| | | | └────────────────────────────────────────────────────────────── branch_borders
|
||||||
|
| | | └──────────────────────────────────────────────────────────────────── branch
|
||||||
|
| | └─────────────────────────────────────────────────────────────────────── branch_symbol
|
||||||
|
| └─────────────────────────────────────────────────────────────────────────── branch_prefix
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────── cwd
|
||||||
|
```
|
||||||
|
|
||||||
|
## Presets
|
||||||
|
|
||||||
|
- v1 default (My config)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Config</summary>
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup({
|
||||||
|
branch_prefix = "on",
|
||||||
|
branch_symbol = " ",
|
||||||
|
branch_borders = "()",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- [spaceship-prompt](https://github.com/spaceship-prompt/spaceship-prompt)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Config</summary>
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup({
|
||||||
|
order = {
|
||||||
|
"__spacer__",
|
||||||
|
"branch",
|
||||||
|
"remote",
|
||||||
|
"__spacer__",
|
||||||
|
"tag",
|
||||||
|
"__spacer__",
|
||||||
|
"commit",
|
||||||
|
"__spacer__",
|
||||||
|
"behind_ahead_remote",
|
||||||
|
"stashes",
|
||||||
|
"state",
|
||||||
|
"staged",
|
||||||
|
"unstaged",
|
||||||
|
"untracked",
|
||||||
|
},
|
||||||
|
|
||||||
|
show_numbers = false,
|
||||||
|
|
||||||
|
branch_symbol = " ",
|
||||||
|
branch_prefix = "on",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- [robertgzr/porcelain](https://github.com/robertgzr/porcelain)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Config</summary>
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup({
|
||||||
|
order = {
|
||||||
|
"__spacer__",
|
||||||
|
"branch",
|
||||||
|
"commit",
|
||||||
|
"__spacer__",
|
||||||
|
"behind_ahead_remote",
|
||||||
|
"__spacer__",
|
||||||
|
"untracked",
|
||||||
|
"state",
|
||||||
|
"unstaged",
|
||||||
|
"__spacer__",
|
||||||
|
"staged",
|
||||||
|
},
|
||||||
|
|
||||||
|
show_numbers = false,
|
||||||
|
|
||||||
|
show_branch = true,
|
||||||
|
branch_prefix = "",
|
||||||
|
branch_color = "#288BD2",
|
||||||
|
|
||||||
|
always_show_commit = true,
|
||||||
|
commit_color = "#859A00",
|
||||||
|
|
||||||
|
show_behind_ahead_remote = true,
|
||||||
|
behind_remote_symbol = "↓",
|
||||||
|
ahead_remote_symbol = "↑",
|
||||||
|
behind_remote_color = "#DC322E",
|
||||||
|
ahead_remote_color = "#4DB6AC",
|
||||||
|
|
||||||
|
show_state = true,
|
||||||
|
show_state_prefix = false,
|
||||||
|
state_symbol = "!!",
|
||||||
|
state_color = "#B58901",
|
||||||
|
|
||||||
|
staged_symbol = "✔",
|
||||||
|
staged_color = "green",
|
||||||
|
|
||||||
|
unstaged_symbol = "Δ",
|
||||||
|
unstaged_color = "#288BD2",
|
||||||
|
|
||||||
|
untracked_symbol = "?",
|
||||||
|
untracked_color = "#415F65",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- Minimal (No color)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Config</summary>
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup({
|
||||||
|
branch_color = "",
|
||||||
|
|
||||||
|
remote_branch_prefix = "@",
|
||||||
|
remote_branch_color = "",
|
||||||
|
|
||||||
|
tag_color = "",
|
||||||
|
|
||||||
|
commit_color = "",
|
||||||
|
|
||||||
|
ahead_remote_symbol = "+",
|
||||||
|
ahead_remote_color = "",
|
||||||
|
behind_remote_symbol = "-",
|
||||||
|
behind_remote_color = "",
|
||||||
|
|
||||||
|
stashes_symbol = "*",
|
||||||
|
stashes_color = "",
|
||||||
|
|
||||||
|
show_state_prefix = false,
|
||||||
|
state_symbol = "~",
|
||||||
|
state_color = "",
|
||||||
|
|
||||||
|
staged_symbol = "S",
|
||||||
|
staged_color = "",
|
||||||
|
|
||||||
|
unstaged_symbol = "U",
|
||||||
|
unstaged_color = "",
|
||||||
|
|
||||||
|
untracked_symbol = "N",
|
||||||
|
untracked_color = "",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- Vibrant (Full)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Config</summary>
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("githead"):setup({
|
||||||
|
order = {
|
||||||
|
"__spacer__",
|
||||||
|
"stashes",
|
||||||
|
"__spacer__",
|
||||||
|
"state",
|
||||||
|
"__spacer__",
|
||||||
|
"staged",
|
||||||
|
"__spacer__",
|
||||||
|
"unstaged",
|
||||||
|
"__spacer__",
|
||||||
|
"untracked",
|
||||||
|
"__spacer__",
|
||||||
|
"branch",
|
||||||
|
"remote_branch",
|
||||||
|
"__spacer__",
|
||||||
|
"tag",
|
||||||
|
"__spacer__",
|
||||||
|
"commit",
|
||||||
|
"__spacer__",
|
||||||
|
"behind_ahead_remote",
|
||||||
|
"__spacer__",
|
||||||
|
},
|
||||||
|
|
||||||
|
branch_borders = "{}",
|
||||||
|
branch_prefix = "|",
|
||||||
|
branch_color = "#7aa2f7",
|
||||||
|
remote_branch_color = "#9ece6a",
|
||||||
|
always_show_remote_branch = true,
|
||||||
|
always_show_remote_repo = true,
|
||||||
|
|
||||||
|
tag_symbol = "",
|
||||||
|
always_show_tag = true,
|
||||||
|
tag_color = "#bb9af7",
|
||||||
|
|
||||||
|
commit_symbol = "",
|
||||||
|
always_show_commit = true,
|
||||||
|
commit_color = "#e0af68",
|
||||||
|
|
||||||
|
staged_color = "#73daca",
|
||||||
|
staged_symbol = "●",
|
||||||
|
|
||||||
|
unstaged_color = "#e0af68",
|
||||||
|
unstaged_symbol = "✗",
|
||||||
|
|
||||||
|
untracked_color = "#f7768e",
|
||||||
|
untracked_symbol = "?",
|
||||||
|
|
||||||
|
state_color = "#f5c359",
|
||||||
|
state_symbol = "",
|
||||||
|
|
||||||
|
stashes_color = "#565f89",
|
||||||
|
stashes_symbol = "⚑",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [x] Current branch
|
||||||
|
- [x] Remote and remote branch
|
||||||
|
- [x] Latest tag
|
||||||
|
- [x] Latest commit
|
||||||
|
- [x] Behind/Ahead of the remote
|
||||||
|
- [x] Stashes
|
||||||
|
- [x] States
|
||||||
|
- [x] merge
|
||||||
|
- [x] cherry
|
||||||
|
- [x] rebase (+ done counter)
|
||||||
|
- [x] revert
|
||||||
|
- [x] bisect
|
||||||
|
- [x] Staged
|
||||||
|
- [x] Unstaged
|
||||||
|
- [x] Untracked
|
||||||
|
|
||||||
|
### Under the hood
|
||||||
|
|
||||||
|
The goal is to use minimum amount of shell commands.
|
||||||
|
|
||||||
|
- Branch, stashes, staged files, unstaged files, untracked files.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git status --ignore-submodules=dirty --branch --show-stash --ahead-behind
|
||||||
|
```
|
||||||
|
|
||||||
|
- Remote branch and repo:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git rev-parse --abbrev-ref --symbolic-full-name @{upstream}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Latest tag and commit:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git log --format="commit %h%d" -n 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- [yazi source code](https://github.com/sxyazi/yazi)
|
||||||
|
- [powerlevel10k](https://github.com/romkatv/powerlevel10k)
|
||||||
|
- [twio142](https://github.com/twio142/githead.yazi)
|
||||||
@@ -0,0 +1,598 @@
|
|||||||
|
---@diagnostic disable: undefined-global
|
||||||
|
|
||||||
|
local save = ya.sync(function(this, cwd, output)
|
||||||
|
if cwd:match("%.git[/\\]") or cwd:match("%.git$") then
|
||||||
|
this.output = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if cx.active.current.cwd == Url(cwd) then
|
||||||
|
this.output = output
|
||||||
|
ui.render()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return {
|
||||||
|
setup = function(this, options)
|
||||||
|
options = options or {}
|
||||||
|
|
||||||
|
local config = {
|
||||||
|
order = options.order or {
|
||||||
|
"__spacer__",
|
||||||
|
"branch",
|
||||||
|
"remote_branch",
|
||||||
|
"__spacer__",
|
||||||
|
"tag",
|
||||||
|
"__spacer__",
|
||||||
|
"commit",
|
||||||
|
"__spacer__",
|
||||||
|
"behind_ahead_remote",
|
||||||
|
"__spacer__",
|
||||||
|
"stashes",
|
||||||
|
"__spacer__",
|
||||||
|
"state",
|
||||||
|
"__spacer__",
|
||||||
|
"staged",
|
||||||
|
"__spacer__",
|
||||||
|
"unstaged",
|
||||||
|
"__spacer__",
|
||||||
|
"untracked",
|
||||||
|
},
|
||||||
|
|
||||||
|
show_numbers = options.show_numbers == nil and true
|
||||||
|
or options.show_numbers,
|
||||||
|
|
||||||
|
show_branch = options.show_branch == nil and true or options.show_branch,
|
||||||
|
branch_prefix = options.branch_prefix or "",
|
||||||
|
branch_color = options.branch_color or "blue",
|
||||||
|
branch_symbol = options.branch_symbol or "",
|
||||||
|
branch_borders = options.branch_borders or "",
|
||||||
|
|
||||||
|
show_remote_branch = options.show_remote_branch == nil and true
|
||||||
|
or options.show_remote_branch,
|
||||||
|
always_show_remote_branch = options.always_show_remote_branch == nil
|
||||||
|
and false
|
||||||
|
or options.always_show_remote_branch,
|
||||||
|
always_show_remote_repo = options.always_show_remote_repo == nil
|
||||||
|
and false
|
||||||
|
or options.always_show_remote_repo,
|
||||||
|
remote_branch_prefix = options.remote_branch_prefix or ":",
|
||||||
|
remote_branch_color = options.remote_branch_color or "bright magenta",
|
||||||
|
|
||||||
|
show_tag = options.show_tag == nil and true or options.show_tag,
|
||||||
|
always_show_tag = options.always_show_tag == nil and false
|
||||||
|
or options.always_show_tag,
|
||||||
|
tag_color = options.tag_color or "magenta",
|
||||||
|
tag_symbol = options.tag_symbol == nil and "#" or options.tag_symbol,
|
||||||
|
|
||||||
|
show_commit = options.show_commit == nil and true or options.show_commit,
|
||||||
|
always_show_commit = options.always_show_commit == nil and false
|
||||||
|
or options.always_show_commit,
|
||||||
|
commit_color = options.commit_color or "bright magenta",
|
||||||
|
commit_symbol = options.commit_symbol == nil and "@"
|
||||||
|
or options.commit_symbol,
|
||||||
|
|
||||||
|
show_behind_ahead_remote = options.show_behind_ahead_remote == nil
|
||||||
|
and true
|
||||||
|
or options.show_behind_ahead_remote,
|
||||||
|
behind_remote_color = options.behind_remote_color or "bright magenta",
|
||||||
|
behind_remote_symbol = options.behind_remote_symbol or "⇣",
|
||||||
|
ahead_remote_color = options.ahead_remote_color or "bright magenta",
|
||||||
|
ahead_remote_symbol = options.ahead_remote_symbol or "⇡",
|
||||||
|
|
||||||
|
show_stashes = options.show_stashes == nil and true
|
||||||
|
or options.show_stashes,
|
||||||
|
stashes_color = options.stashes_color or "bright magenta",
|
||||||
|
stashes_symbol = options.stashes_symbol or "$",
|
||||||
|
|
||||||
|
show_state = options.show_state == nil and true or options.show_state,
|
||||||
|
show_state_prefix = options.show_state_prefix == nil and true
|
||||||
|
or options.show_state_prefix,
|
||||||
|
state_color = options.state_color or "red",
|
||||||
|
state_symbol = options.state_symbol or "~",
|
||||||
|
|
||||||
|
show_staged = options.show_staged == nil and true or options.show_staged,
|
||||||
|
staged_color = options.staged_color or "bright yellow",
|
||||||
|
staged_symbol = options.staged_symbol or "+",
|
||||||
|
|
||||||
|
show_unstaged = options.show_unstaged == nil and true
|
||||||
|
or options.show_unstaged,
|
||||||
|
unstaged_color = options.unstaged_color or "bright yellow",
|
||||||
|
unstaged_symbol = options.unstaged_symbol or "!",
|
||||||
|
|
||||||
|
show_untracked = options.show_untracked == nil and true
|
||||||
|
or options.show_untracked,
|
||||||
|
untracked_color = options.untracked_color or "bright blue",
|
||||||
|
untracked_symbol = options.untracked_symbol or "?",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_branch(data)
|
||||||
|
local branch = data.branch
|
||||||
|
|
||||||
|
if not branch then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local left_border = config.branch_borders:sub(1, 1)
|
||||||
|
local right_border = config.branch_borders:sub(2, 2)
|
||||||
|
|
||||||
|
local branch_string = ""
|
||||||
|
|
||||||
|
if config.branch_symbol == "" then
|
||||||
|
branch_string = left_border .. branch .. right_border
|
||||||
|
else
|
||||||
|
branch_string = left_border
|
||||||
|
.. config.branch_symbol
|
||||||
|
.. branch
|
||||||
|
.. right_border
|
||||||
|
end
|
||||||
|
|
||||||
|
local branch_prefix = config.branch_prefix == "" and ""
|
||||||
|
or config.branch_prefix .. " "
|
||||||
|
|
||||||
|
return ui.Line({
|
||||||
|
ui.Span(branch_prefix),
|
||||||
|
ui.Span(branch_string):fg(config.branch_color),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_remote_branch(data)
|
||||||
|
local branch = data.branch
|
||||||
|
local remote_branch = data.remote_branch
|
||||||
|
local remote_repo = data.remote_repo
|
||||||
|
|
||||||
|
if not remote_branch then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local show_remote = config.always_show_remote_branch
|
||||||
|
or branch ~= remote_branch
|
||||||
|
if not show_remote then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local remote_branch_label = config.always_show_remote_repo
|
||||||
|
and (remote_repo .. "/" .. remote_branch)
|
||||||
|
or remote_branch
|
||||||
|
|
||||||
|
return ui.Line({
|
||||||
|
ui.Span(config.remote_branch_prefix),
|
||||||
|
ui.Span(remote_branch_label):fg(config.remote_branch_color),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_tag(data)
|
||||||
|
local branch = data.branch
|
||||||
|
local tag = data.tag
|
||||||
|
|
||||||
|
if not tag then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if not branch or config.always_show_tag then
|
||||||
|
return ui.Line({
|
||||||
|
ui.Span(config.tag_symbol),
|
||||||
|
ui.Span(tag):fg(config.tag_color),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_commit(data)
|
||||||
|
local branch = data.branch
|
||||||
|
local tag = data.tag
|
||||||
|
local commit = data.commit
|
||||||
|
|
||||||
|
if not commit then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if (not branch and not tag) or config.always_show_commit then
|
||||||
|
return ui.Line({
|
||||||
|
ui.Span(config.commit_symbol),
|
||||||
|
ui.Span(commit):fg(config.commit_color),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_behind_ahead_remote(data)
|
||||||
|
local behind = data.behind_remote
|
||||||
|
local ahead = data.ahead_remote
|
||||||
|
|
||||||
|
local behind_label = behind
|
||||||
|
and behind > 0
|
||||||
|
and ui.Span(
|
||||||
|
config.behind_remote_symbol .. (config.show_numbers and behind or "")
|
||||||
|
):fg(config.behind_remote_color)
|
||||||
|
|
||||||
|
local ahead_label = ahead
|
||||||
|
and ahead > 0
|
||||||
|
and ui.Span(
|
||||||
|
config.ahead_remote_symbol .. (config.show_numbers and ahead or "")
|
||||||
|
):fg(config.ahead_remote_color)
|
||||||
|
|
||||||
|
if ahead_label and behind_label then
|
||||||
|
return ui.Line({
|
||||||
|
behind_label,
|
||||||
|
ahead_label,
|
||||||
|
})
|
||||||
|
elseif ahead_label then
|
||||||
|
return ahead_label
|
||||||
|
elseif behind_label then
|
||||||
|
return behind_label
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_stashes(data)
|
||||||
|
local stashes_count = data.stashes
|
||||||
|
|
||||||
|
if not stashes_count then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local stashes_label = config.stashes_symbol
|
||||||
|
|
||||||
|
if config.show_numbers then
|
||||||
|
stashes_label = stashes_label .. stashes_count
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui.Span(stashes_label):fg(config.stashes_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_state(data)
|
||||||
|
local state_prefix = data.state_prefix
|
||||||
|
local unmerged_count = data.unmerged_count
|
||||||
|
local rebase_done = data.rebase_done
|
||||||
|
local rebase_total = data.rebase_total
|
||||||
|
|
||||||
|
if state_prefix then
|
||||||
|
local state_label = ""
|
||||||
|
if config.show_state_prefix then
|
||||||
|
state_label = state_prefix
|
||||||
|
if
|
||||||
|
state_prefix == "rebase-i"
|
||||||
|
and config.show_numbers
|
||||||
|
and rebase_done
|
||||||
|
and rebase_total
|
||||||
|
then
|
||||||
|
state_label = state_label
|
||||||
|
.. " "
|
||||||
|
.. rebase_done
|
||||||
|
.. "/"
|
||||||
|
.. rebase_total
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local unmerged_label = ""
|
||||||
|
local symbol = ""
|
||||||
|
|
||||||
|
if unmerged_count and unmerged_count > 0 then
|
||||||
|
symbol = " " .. config.state_symbol
|
||||||
|
if config.show_numbers then
|
||||||
|
unmerged_label = tostring(unmerged_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui.Span(state_label .. symbol .. unmerged_label)
|
||||||
|
:fg(config.state_color)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_staged(data)
|
||||||
|
local staged = data.staged
|
||||||
|
|
||||||
|
if staged then
|
||||||
|
local staged_label = config.staged_symbol
|
||||||
|
|
||||||
|
if config.show_numbers then
|
||||||
|
local filtered_staged = staged:gsub("^[%s]*%b()[%s]*", "")
|
||||||
|
|
||||||
|
local staged_count = 0
|
||||||
|
for line in filtered_staged:gmatch("[^\r\n]+") do
|
||||||
|
if line:match("%S") then
|
||||||
|
staged_count = staged_count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
staged_label = staged_label .. staged_count
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui.Span(staged_label):fg(config.staged_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_unstaged(data)
|
||||||
|
local unstaged = data.unstaged
|
||||||
|
|
||||||
|
if unstaged then
|
||||||
|
local unstaged_label = config.unstaged_symbol
|
||||||
|
|
||||||
|
if config.show_numbers then
|
||||||
|
local filtered_unstaged =
|
||||||
|
unstaged:gsub("^[%s]*%b()[\r\n]*", ""):gsub("^[%s]*%b()[\r\n]*", "")
|
||||||
|
|
||||||
|
local unstaged_count = 0
|
||||||
|
for line in filtered_unstaged:gmatch("[^\r\n]+") do
|
||||||
|
if line:match("%S") then
|
||||||
|
unstaged_count = unstaged_count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unstaged_label = unstaged_label .. unstaged_count
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui.Span(unstaged_label):fg(config.unstaged_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param data GitStatusData
|
||||||
|
function Header:render_untracked(data)
|
||||||
|
local untracked = data.untracked
|
||||||
|
|
||||||
|
if untracked then
|
||||||
|
local untracked_label = config.untracked_symbol
|
||||||
|
|
||||||
|
if config.show_numbers then
|
||||||
|
local filtered_untracked = untracked:gsub("^[%s]*%b()[\r\n]*", "")
|
||||||
|
local untracked_count = 0
|
||||||
|
|
||||||
|
for line in filtered_untracked:gmatch("[^\r\n]+") do
|
||||||
|
if line:match("%S") then
|
||||||
|
untracked_count = untracked_count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
untracked_label = untracked_label .. untracked_count
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui.Span(untracked_label):fg(config.untracked_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Header:githead()
|
||||||
|
--- @type GitStatusData
|
||||||
|
local data = this.output
|
||||||
|
|
||||||
|
if not data then
|
||||||
|
return ui.Line({})
|
||||||
|
end
|
||||||
|
|
||||||
|
local head = {}
|
||||||
|
|
||||||
|
for _, key in ipairs(config.order) do
|
||||||
|
if key == "__spacer__" then
|
||||||
|
if head[#head] ~= " " then
|
||||||
|
table.insert(head, " ")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local fn = self["render_" .. key]
|
||||||
|
local is_shown = config["show_" .. key]
|
||||||
|
|
||||||
|
if fn and is_shown then
|
||||||
|
local value = fn(self, data)
|
||||||
|
if value then
|
||||||
|
table.insert(head, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui.Line(head)
|
||||||
|
end
|
||||||
|
|
||||||
|
Header:children_add(Header.githead, 2000, Header.LEFT)
|
||||||
|
|
||||||
|
local callback = function()
|
||||||
|
local cwd = cx.active.current.cwd
|
||||||
|
ya.emit("plugin", {
|
||||||
|
this._id,
|
||||||
|
ya.quote(tostring(cwd), true),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
ps.sub("cd", callback)
|
||||||
|
ps.sub("rename", callback)
|
||||||
|
ps.sub("bulk", callback)
|
||||||
|
ps.sub("move", callback)
|
||||||
|
ps.sub("trash", callback)
|
||||||
|
ps.sub("delete", callback)
|
||||||
|
ps.sub("tab", callback)
|
||||||
|
end,
|
||||||
|
|
||||||
|
entry = function(_, job)
|
||||||
|
local args = job.args or job
|
||||||
|
|
||||||
|
---@class GitStatusData
|
||||||
|
---@field ahead_remote? integer
|
||||||
|
---@field behind_remote? integer
|
||||||
|
---@field branch? string
|
||||||
|
---@field commit? string
|
||||||
|
---@field rebase_done? integer
|
||||||
|
---@field remote_branch? string
|
||||||
|
---@field remote_repo? string
|
||||||
|
---@field staged? string
|
||||||
|
---@field stashes? integer
|
||||||
|
---@field state_prefix? "bisect"|"cherry"|"merge"|"rebase-i"|"revert"
|
||||||
|
---@field tag? string
|
||||||
|
---@field unmerged_count? integer
|
||||||
|
---@field unstaged? string
|
||||||
|
---@field untracked? string
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_behind_ahead_remote = function(status)
|
||||||
|
local diverged_ahead, diverged_behind =
|
||||||
|
status:match("have (%d+) and (%d+) different")
|
||||||
|
if diverged_ahead and diverged_behind then
|
||||||
|
data.behind_remote = tonumber(diverged_behind)
|
||||||
|
data.ahead_remote = tonumber(diverged_ahead)
|
||||||
|
else
|
||||||
|
local behind_remote = status:match("behind %S+ by (%d+) commits?")
|
||||||
|
local ahead_remote = status:match("ahead of %S+ by (%d+) commits?")
|
||||||
|
|
||||||
|
data.behind_remote = tonumber(behind_remote)
|
||||||
|
data.ahead_remote = tonumber(ahead_remote)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_branch = function(status)
|
||||||
|
data.branch = status:match("On branch (%S+)")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_stashes = function(status)
|
||||||
|
data.stashes = tonumber(status:match("Your stash currently has (%d+)"))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_state = function(status)
|
||||||
|
local unmerged = status:match("Unmerged paths:%s*(.-)%s*\n\n")
|
||||||
|
if unmerged then
|
||||||
|
local filtered_unmerged =
|
||||||
|
unmerged:gsub("^[%s]*%b()[%s]*", ""):gsub("^[%s]*%b()[%s]*", "")
|
||||||
|
local count = 0
|
||||||
|
for line in filtered_unmerged:gmatch("[^\r\n]+") do
|
||||||
|
if line:match("%S") then
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
data.unmerged_count = count
|
||||||
|
end
|
||||||
|
|
||||||
|
if status:find("git merge") then
|
||||||
|
data.state_prefix = "merge"
|
||||||
|
elseif status:find("git cherry%-pick") then
|
||||||
|
data.state_prefix = "cherry"
|
||||||
|
elseif status:find("git rebase") then
|
||||||
|
data.state_prefix = "rebase-i"
|
||||||
|
local commands_done = status:match("%((%d+) commands? done%)")
|
||||||
|
if commands_done then
|
||||||
|
data.rebase_done = commands_done
|
||||||
|
if not data.unmerged_count then
|
||||||
|
data.rebase_total = commands_done
|
||||||
|
else
|
||||||
|
data.rebase_total = data.unmerged_count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif status:find("git revert") then
|
||||||
|
data.state_prefix = "revert"
|
||||||
|
elseif status:find("git bisect") then
|
||||||
|
data.state_prefix = "bisect"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_staged = function(status)
|
||||||
|
data.staged = status:match("Changes to be committed:%s*(.-)%s*\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_unstaged = function(status)
|
||||||
|
data.unstaged =
|
||||||
|
status:match("Changes not staged for commit:%s*(.-)%s*\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param status string
|
||||||
|
local get_untracked = function(status)
|
||||||
|
data.untracked = status:match("Untracked files:%s*(.-)%s*\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local get_status = function()
|
||||||
|
local cmd = Command("git")
|
||||||
|
:arg({
|
||||||
|
"status",
|
||||||
|
"--ignore-submodules=dirty",
|
||||||
|
"--branch",
|
||||||
|
"--show-stash",
|
||||||
|
"--ahead-behind",
|
||||||
|
})
|
||||||
|
:cwd(args[1])
|
||||||
|
:env("LANGUAGE", "en_US.UTF-8")
|
||||||
|
:stdout(Command.PIPED)
|
||||||
|
local cmd_output = cmd:output()
|
||||||
|
|
||||||
|
if cmd_output then
|
||||||
|
local status = cmd_output.stdout
|
||||||
|
|
||||||
|
get_branch(status)
|
||||||
|
get_behind_ahead_remote(status)
|
||||||
|
get_stashes(status)
|
||||||
|
get_state(status)
|
||||||
|
get_staged(status)
|
||||||
|
get_unstaged(status)
|
||||||
|
get_untracked(status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local get_remote_branch = function()
|
||||||
|
local cmd = Command("git")
|
||||||
|
:arg({
|
||||||
|
"rev-parse",
|
||||||
|
"--abbrev-ref",
|
||||||
|
"--symbolic-full-name",
|
||||||
|
"@{upstream}",
|
||||||
|
})
|
||||||
|
:cwd(args[1])
|
||||||
|
:env("LANGUAGE", "en_US.UTF-8")
|
||||||
|
:stdout(Command.PIPED)
|
||||||
|
local cmd_output = cmd:output()
|
||||||
|
|
||||||
|
if cmd_output then
|
||||||
|
local remote_branch = cmd_output.stdout
|
||||||
|
|
||||||
|
data.remote_branch =
|
||||||
|
remote_branch:gsub("[\r\n]", ""):match("^[^/]+/(.+)")
|
||||||
|
data.remote_repo = remote_branch:gsub("[\r\n]", ""):match("^([^/]+)/")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param log string
|
||||||
|
local get_tag = function(log)
|
||||||
|
data.tag = log:match("tag: ([^, )]+)")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param log string
|
||||||
|
local get_commit = function(log)
|
||||||
|
data.commit = log:match("^commit%s+([a-f0-9]+)")
|
||||||
|
end
|
||||||
|
|
||||||
|
local get_git_log = function()
|
||||||
|
local cmd = Command("git")
|
||||||
|
:arg({ "log", "--format=commit %h%d", "-n", "1" })
|
||||||
|
:cwd(args[1])
|
||||||
|
:env("LANGUAGE", "en_US.UTF-8")
|
||||||
|
:stdout(Command.PIPED)
|
||||||
|
local cmd_output = cmd:output()
|
||||||
|
|
||||||
|
if cmd_output then
|
||||||
|
local log = cmd_output.stdout
|
||||||
|
|
||||||
|
get_tag(log)
|
||||||
|
get_commit(log)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get_status()
|
||||||
|
get_remote_branch()
|
||||||
|
get_git_log()
|
||||||
|
|
||||||
|
save(args[1], data)
|
||||||
|
end,
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 yazi-rs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# smart-enter.yazi
|
||||||
|
|
||||||
|
[`Open`][open] files or [`enter`][enter] directories all in one key!
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ya pkg add yazi-rs/plugins:smart-enter
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Bind your <kbd>l</kbd> key to the plugin, in your `~/.config/yazi/keymap.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[mgr.prepend_keymap]]
|
||||||
|
on = "l"
|
||||||
|
run = "plugin smart-enter"
|
||||||
|
desc = "Enter the child directory, or open the file"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced
|
||||||
|
|
||||||
|
By default, `--hovered` is passed to the [`open`][open] action, make the behavior consistent with [`enter`][enter] avoiding accidental triggers,
|
||||||
|
which means both will only target the currently hovered file.
|
||||||
|
|
||||||
|
If you still want `open` to target multiple selected files, add this to your `~/.config/yazi/init.lua`:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("smart-enter"):setup {
|
||||||
|
open_multi = true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
|
||||||
|
|
||||||
|
[open]: https://yazi-rs.github.io/docs/configuration/keymap/#mgr.open
|
||||||
|
[enter]: https://yazi-rs.github.io/docs/configuration/keymap/#mgr.enter
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
--- @since 25.5.31
|
||||||
|
--- @sync entry
|
||||||
|
|
||||||
|
local function setup(self, opts) self.open_multi = opts.open_multi end
|
||||||
|
|
||||||
|
local function entry(self)
|
||||||
|
local h = cx.active.current.hovered
|
||||||
|
ya.emit(h and h.cha.is_dir and "enter" or "open", { hovered = not self.open_multi })
|
||||||
|
end
|
||||||
|
|
||||||
|
return { entry = entry, setup = setup }
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# Ember OLED: aligned with Noctalia's "Ember OLED" palette and tmux status line.
|
||||||
|
[flavor]
|
||||||
|
dark = "catppuccin-macchiato"
|
||||||
|
|
||||||
|
[mgr]
|
||||||
|
cwd = { fg = "#ffb05c", bold = true }
|
||||||
|
find_keyword = { fg = "#ffcc99", bold = true, underline = true }
|
||||||
|
find_position = { fg = "#ff8800", bold = true }
|
||||||
|
marker_copied = { fg = "#c98a45", bg = "#c98a45" }
|
||||||
|
marker_cut = { fg = "#ff6b4a", bg = "#ff6b4a" }
|
||||||
|
marker_marked = { fg = "#ff8800", bg = "#ff8800" }
|
||||||
|
marker_selected = { fg = "#ffcc99", bg = "#ffcc99" }
|
||||||
|
count_copied = { fg = "#050403", bg = "#c98a45" }
|
||||||
|
count_cut = { fg = "#050403", bg = "#ff6b4a" }
|
||||||
|
count_selected = { fg = "#050403", bg = "#ffcc99" }
|
||||||
|
border_symbol = "│"
|
||||||
|
border_style = { fg = "#6e4a31" }
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
active = { fg = "#fff1e6", bg = "#1a110c", bold = true }
|
||||||
|
inactive = { fg = "#f4c7a1", bg = "#050403" }
|
||||||
|
|
||||||
|
[mode]
|
||||||
|
normal_main = { fg = "#050403", bg = "#ff8800", bold = true }
|
||||||
|
normal_alt = { fg = "#ffb05c", bg = "#1a110c" }
|
||||||
|
select_main = { fg = "#050403", bg = "#ffb05c", bold = true }
|
||||||
|
select_alt = { fg = "#ffb05c", bg = "#1a110c" }
|
||||||
|
unset_main = { fg = "#050403", bg = "#ff6b4a", bold = true }
|
||||||
|
unset_alt = { fg = "#ff6b4a", bg = "#1a110c" }
|
||||||
|
|
||||||
|
[status]
|
||||||
|
perm_sep = { fg = "#6e4a31" }
|
||||||
|
perm_type = { fg = "#ffb05c" }
|
||||||
|
perm_read = { fg = "#fff1e6" }
|
||||||
|
perm_write = { fg = "#ff6b4a" }
|
||||||
|
perm_exec = { fg = "#c98a45" }
|
||||||
|
progress_label = { fg = "#fff1e6", bold = true }
|
||||||
|
progress_normal = { fg = "#ff8800", bg = "#1a110c" }
|
||||||
|
progress_error = { fg = "#fff1e6", bg = "#ff6b4a" }
|
||||||
|
|
||||||
|
[pick]
|
||||||
|
border = { fg = "#ff8800" }
|
||||||
|
active = { fg = "#ffb05c", bold = true }
|
||||||
|
|
||||||
|
[input]
|
||||||
|
border = { fg = "#ff8800" }
|
||||||
|
selected = { fg = "#050403", bg = "#ffb05c" }
|
||||||
|
|
||||||
|
[cmp]
|
||||||
|
border = { fg = "#ff8800" }
|
||||||
|
|
||||||
|
[tasks]
|
||||||
|
border = { fg = "#ff8800" }
|
||||||
|
title = { fg = "#fff1e6" }
|
||||||
|
hovered = { fg = "#ffb05c", bold = true }
|
||||||
|
|
||||||
|
[which]
|
||||||
|
border = { fg = "#ff8800" }
|
||||||
|
cand = { fg = "#ffb05c" }
|
||||||
|
rest = { fg = "#f4c7a1" }
|
||||||
|
desc = { fg = "#fff1e6" }
|
||||||
|
separator = " "
|
||||||
|
separator_style = { fg = "#6e4a31" }
|
||||||
|
|
||||||
|
[help]
|
||||||
|
on = { fg = "#ffb05c" }
|
||||||
|
run = { fg = "#fff1e6" }
|
||||||
|
hovered = { fg = "#050403", bg = "#ffb05c", bold = true }
|
||||||
|
footer = { fg = "#fff1e6", bg = "#1a110c" }
|
||||||
|
|
||||||
|
[spot]
|
||||||
|
border = { fg = "#ff8800" }
|
||||||
|
title = { fg = "#ffb05c" }
|
||||||
|
tbl_col = { fg = "#ffb05c" }
|
||||||
|
tbl_cell = { fg = "#fff1e6", bg = "#1a110c" }
|
||||||
|
|
||||||
|
[notify]
|
||||||
|
title_info = { fg = "#c98a45" }
|
||||||
|
title_warn = { fg = "#ffb05c" }
|
||||||
|
title_error = { fg = "#ff6b4a" }
|
||||||
|
|
||||||
|
[filetype]
|
||||||
|
rules = [
|
||||||
|
{ mime = "**/image/*", fg = "#ffcc99" },
|
||||||
|
{ mime = "**/{audio,video}/*", fg = "#c98a45" },
|
||||||
|
{ mime = "**/application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}", fg = "#ffb05c" },
|
||||||
|
{ mime = "**/application/{pdf,doc,rtf}", fg = "#f4c7a1" },
|
||||||
|
{ mime = "vfs/{absent,stale}", fg = "#6e4a31" },
|
||||||
|
{ url = "*", fg = "#fff1e6" },
|
||||||
|
{ url = "*/", fg = "#ffb05c" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[icon]
|
||||||
|
dirs = [
|
||||||
|
{ name = ".config", text = "", fg = "#ffb05c" },
|
||||||
|
{ name = ".git", text = "", fg = "#ff8800" },
|
||||||
|
{ name = ".github", text = "", fg = "#ffb05c" },
|
||||||
|
{ name = "Desktop", text = "", fg = "#ffb05c" },
|
||||||
|
{ name = "Documents", text = "", fg = "#ffb05c" },
|
||||||
|
{ name = "Downloads", text = "", fg = "#ffb05c" },
|
||||||
|
{ name = "Pictures", text = "", fg = "#ffcc99" },
|
||||||
|
{ name = "Videos", text = "", fg = "#c98a45" },
|
||||||
|
]
|
||||||
|
conds = [
|
||||||
|
{ if = "orphan", text = "", fg = "#ff6b4a" },
|
||||||
|
{ if = "link", text = "", fg = "#6e4a31" },
|
||||||
|
{ if = "dir & hovered", text = "", fg = "#ffcc99" },
|
||||||
|
{ if = "dir", text = "", fg = "#ffb05c" },
|
||||||
|
{ if = "exec", text = "", fg = "#c98a45" },
|
||||||
|
{ if = "!dir", text = "", fg = "#fff1e6" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[git]
|
||||||
|
modified = { fg = "#ffb05c" }
|
||||||
|
added = { fg = "#c98a45" }
|
||||||
|
untracked = { fg = "#f4c7a1" }
|
||||||
|
deleted = { fg = "#ff6b4a", bold = true }
|
||||||
|
updated = { fg = "#ff8800" }
|
||||||
|
ignored = { fg = "#6e4a31" }
|
||||||
|
modified_sign = "M "
|
||||||
|
added_sign = "A "
|
||||||
|
untracked_sign = "? "
|
||||||
|
deleted_sign = "D "
|
||||||
|
updated_sign = "U "
|
||||||
|
ignored_sign = "I "
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[[plugin.prepend_fetchers]]
|
||||||
|
url = "*"
|
||||||
|
run = "git"
|
||||||
|
group = "git"
|
||||||
|
|
||||||
|
[[plugin.prepend_fetchers]]
|
||||||
|
url = "*/"
|
||||||
|
run = "git"
|
||||||
|
group = "git"
|
||||||
+2
@@ -10,8 +10,10 @@ return {
|
|||||||
},
|
},
|
||||||
startup = {
|
startup = {
|
||||||
"noctalia",
|
"noctalia",
|
||||||
|
"hypridle",
|
||||||
-- Electron's tray icon registers only when the SNI watcher already exists.
|
-- Electron's tray icon registers only when the SNI watcher already exists.
|
||||||
"sh -c 'sleep 2; exec mullvad-vpn'",
|
"sh -c 'sleep 2; exec mullvad-vpn'",
|
||||||
|
"obsidian",
|
||||||
"thunderbird",
|
"thunderbird",
|
||||||
"nextcloud",
|
"nextcloud",
|
||||||
"spotify",
|
"spotify",
|
||||||
+30
-49
@@ -1,20 +1,29 @@
|
|||||||
# Desktop-specific shell layout and hardware telemetry.
|
# Desktop-specific shell layout and hardware telemetry.
|
||||||
|
# Pi Status Bridge is installed locally from ~/projects/pi-status-bridge.
|
||||||
|
[plugins]
|
||||||
|
enabled = ["alex/system-status", "alex/pi-status-bridge", "alex/knowledge-lookup"]
|
||||||
|
|
||||||
|
[widget.pi-status]
|
||||||
|
type = "alex/pi-status-bridge:bridge"
|
||||||
|
|
||||||
[bar.main]
|
[bar.main]
|
||||||
position = "bottom"
|
position = "bottom"
|
||||||
layer = "overlay"
|
layer = "top"
|
||||||
|
scale = 0.95
|
||||||
capsule_radius = 5
|
capsule_radius = 5
|
||||||
center = ["group:g3", "notifications"]
|
center = ["group:g3", "notifications"]
|
||||||
end = ["bluetooth", "volume", "control-center", "group:g1", "session"]
|
end = ["group:g2", "group:g6", "group:g1", "session"]
|
||||||
font_weight = 400
|
font_weight = 400
|
||||||
margin_ends = 0
|
margin_ends = 0
|
||||||
padding = 0
|
padding = 0
|
||||||
panel_overlap = 3
|
panel_overlap = 3
|
||||||
radius = 0
|
radius = 0
|
||||||
shadow = false
|
shadow = false
|
||||||
smart_auto_hide = true
|
# Keep the desktop status bar visible and reserve its screen edge.
|
||||||
# The bar may overlay the thin perimeter while visible; hidden bars release the space.
|
auto_hide = false
|
||||||
reserve_space = false
|
smart_auto_hide = false
|
||||||
start = ["tray", "group:g4", "group:g2", "privacy"]
|
reserve_space = true
|
||||||
|
start = ["tray", "group:g4", "privacy"]
|
||||||
thickness = 39
|
thickness = 39
|
||||||
widget_spacing = 10
|
widget_spacing = 10
|
||||||
|
|
||||||
@@ -22,7 +31,7 @@ widget_spacing = 10
|
|||||||
enabled = true
|
enabled = true
|
||||||
fill = "surface_variant"
|
fill = "surface_variant"
|
||||||
id = "g1"
|
id = "g1"
|
||||||
members = ["caffeine", "date", "clock"]
|
members = ["idle-inhibitors", "caffeine", "date", "clock"]
|
||||||
opacity = 1.0
|
opacity = 1.0
|
||||||
padding = 6.0
|
padding = 6.0
|
||||||
|
|
||||||
@@ -30,7 +39,7 @@ padding = 6.0
|
|||||||
enabled = true
|
enabled = true
|
||||||
fill = "surface_variant"
|
fill = "surface_variant"
|
||||||
id = "g2"
|
id = "g2"
|
||||||
members = ["network_rx", "network_tx", "network"]
|
members = ["network", "bluetooth"]
|
||||||
opacity = 1.0
|
opacity = 1.0
|
||||||
padding = 6.0
|
padding = 6.0
|
||||||
|
|
||||||
@@ -47,64 +56,36 @@ radius = 5.0
|
|||||||
enabled = true
|
enabled = true
|
||||||
fill = "surface_variant"
|
fill = "surface_variant"
|
||||||
id = "g4"
|
id = "g4"
|
||||||
members = ["cpu", "temp", "ram", "gpu", "gpu_temp", "disk", "battery"]
|
members = ["pi-status", "cpu", "temp", "ram", "gpu", "gpu_temp", "disk"]
|
||||||
opacity = 1.0
|
opacity = 1.0
|
||||||
padding = 6.0
|
padding = 6.0
|
||||||
|
|
||||||
[widget.cpu]
|
[[bar.main.capsule_group]]
|
||||||
type = "alex/system-status:cpu"
|
enabled = true
|
||||||
|
fill = "surface_variant"
|
||||||
[widget.ram]
|
id = "g6"
|
||||||
type = "alex/system-status:memory"
|
members = ["input_volume", "volume"]
|
||||||
|
opacity = 1.0
|
||||||
[widget.temp]
|
padding = 6.0
|
||||||
type = "sysmon"
|
radius = 5.0
|
||||||
stat = "cpu_temp"
|
|
||||||
display = "text"
|
|
||||||
|
|
||||||
[widget.gpu]
|
[widget.gpu]
|
||||||
type = "sysmon"
|
type = "sysmon"
|
||||||
stat = "gpu_usage"
|
stat = "gpu_usage"
|
||||||
display = "graph"
|
visualization = "graph"
|
||||||
|
show_value = true
|
||||||
|
|
||||||
[widget.gpu_temp]
|
[widget.gpu_temp]
|
||||||
type = "sysmon"
|
type = "sysmon"
|
||||||
stat = "gpu_temp"
|
stat = "gpu_temp"
|
||||||
display = "text"
|
visualization = "none"
|
||||||
|
show_value = true
|
||||||
[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]
|
[control_center]
|
||||||
sidebar = "full"
|
sidebar = "full"
|
||||||
sidebar_section = "full"
|
sidebar_section = "full"
|
||||||
width = 880
|
width = 880
|
||||||
|
|
||||||
[desktop_widgets]
|
|
||||||
enabled = false
|
|
||||||
|
|
||||||
[wallpaper]
|
|
||||||
enabled = true
|
|
||||||
fill_color = "#000000"
|
|
||||||
|
|
||||||
[wallpaper.default]
|
|
||||||
path = "color:#000000"
|
|
||||||
|
|
||||||
[system.monitor]
|
[system.monitor]
|
||||||
# GPU polling is disabled by Noctalia by default; enable it for the RTX 3090 widgets.
|
# GPU polling is disabled by Noctalia by default; enable it for the RTX 3090 widgets.
|
||||||
gpu_poll_seconds = 2.0
|
gpu_poll_seconds = 2.0
|
||||||
|
|
||||||
[plugins]
|
|
||||||
enabled = ["alex/system-status"]
|
|
||||||
|
|
||||||
[nightlight]
|
|
||||||
enabled = true
|
|
||||||
force = false
|
|
||||||
temperature_day = 6500
|
|
||||||
temperature_night = 2500
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- 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",
|
||||||
|
-- Start after Noctalia has claimed the StatusNotifier watcher.
|
||||||
|
"sh -c 'sleep 2; exec mullvad-vpn'",
|
||||||
|
"obsidian",
|
||||||
|
"thunderbird",
|
||||||
|
"nextcloud",
|
||||||
|
"spotify",
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# Laptop-specific Noctalia layout. Shared privacy/theme defaults live in 10-base.toml.
|
||||||
|
[bar.main]
|
||||||
|
position = "top"
|
||||||
|
layer = "top"
|
||||||
|
scale = 0.95
|
||||||
|
capsule_radius = 5
|
||||||
|
center = ["group:g3", "notifications"]
|
||||||
|
end = ["group:g2", "group:g6", "group:g5", "group:g1", "session"]
|
||||||
|
font_weight = 400
|
||||||
|
margin_ends = 0
|
||||||
|
padding = 0
|
||||||
|
panel_overlap = 3
|
||||||
|
radius = 0
|
||||||
|
shadow = false
|
||||||
|
auto_hide = false
|
||||||
|
smart_auto_hide = false
|
||||||
|
reserve_space = true
|
||||||
|
start = ["tray", "group:g4"]
|
||||||
|
# Accommodate the battery-rate widget's wattage + ETA lines without clipping.
|
||||||
|
thickness = 39
|
||||||
|
widget_spacing = 10
|
||||||
|
|
||||||
|
[[bar.main.capsule_group]]
|
||||||
|
enabled = true
|
||||||
|
fill = "surface_variant"
|
||||||
|
id = "g1"
|
||||||
|
members = ["idle-inhibitors", "caffeine", "date", "clock"]
|
||||||
|
opacity = 1.0
|
||||||
|
padding = 6.0
|
||||||
|
|
||||||
|
[[bar.main.capsule_group]]
|
||||||
|
enabled = true
|
||||||
|
fill = "surface_variant"
|
||||||
|
id = "g2"
|
||||||
|
members = ["network", "bluetooth"]
|
||||||
|
opacity = 1.0
|
||||||
|
padding = 6.0
|
||||||
|
|
||||||
|
[[bar.main.capsule_group]]
|
||||||
|
enabled = true
|
||||||
|
fill = "surface_variant"
|
||||||
|
id = "g3"
|
||||||
|
members = ["launcher", "media", "control-center", "clipboard"]
|
||||||
|
opacity = 1.0
|
||||||
|
padding = 6.0
|
||||||
|
radius = 5.0
|
||||||
|
|
||||||
|
[[bar.main.capsule_group]]
|
||||||
|
enabled = true
|
||||||
|
fill = "surface_variant"
|
||||||
|
id = "g4"
|
||||||
|
members = ["cpu", "temp", "ram", "gpu-mode", "disk"]
|
||||||
|
opacity = 1.0
|
||||||
|
padding = 6.0
|
||||||
|
|
||||||
|
[[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
|
||||||
|
|
||||||
|
[[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.battery-rate]
|
||||||
|
type = "alex/system-status:battery-rate"
|
||||||
|
|
||||||
|
[widget.gpu-mode]
|
||||||
|
type = "alex/system-status:gpu-mode"
|
||||||
|
|
||||||
|
# Only suspend-then-hibernate after 30 minutes when UPower confirms battery power.
|
||||||
|
# The command fails closed on AC or when UPower is unavailable.
|
||||||
|
[idle.behavior.suspend-then-hibernate]
|
||||||
|
command = "busctl get-property org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower OnBattery 2>/dev/null | grep -qx 'b true' && loginctl lock-session && systemctl suspend-then-hibernate"
|
||||||
|
|
||||||
|
[control_center]
|
||||||
|
sidebar = "full"
|
||||||
|
sidebar_section = "full"
|
||||||
|
width = 720
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Local, untracked Noctalia overrides.
|
||||||
|
# This file is loaded after the shared base (10-base.toml) and machine profile
|
||||||
|
# (90-machine.toml). Keep host-only experiments and machine-local adjustments here.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# [bar.main]
|
||||||
|
# thickness = 32
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
enabled = [
|
||||||
|
"alex/system-status",
|
||||||
|
"alex/pi-status-bridge",
|
||||||
|
"alex/knowledge-lookup",
|
||||||
|
]
|
||||||
|
|
||||||
|
[widget.pi-status]
|
||||||
|
type = "alex/pi-status-bridge:bridge"
|
||||||
|
|
||||||
|
[widget.knowledge-lookup]
|
||||||
|
type = "alex/knowledge-lookup:bar"
|
||||||
|
|
||||||
|
[bar.main]
|
||||||
|
center = ["pi-status", "knowledge-lookup", "group:g3", "notifications"]
|
||||||
|
end = ["group:g2", "group:g6", "group:g5", "group:g1", "session"]
|
||||||
|
|
||||||
|
# Migrated from Noctalia's GUI-managed state so these host preferences survive
|
||||||
|
# resetting the state override file.
|
||||||
|
[location]
|
||||||
|
address = "Leipzig, Germany"
|
||||||
|
|
||||||
|
[lockscreen_widgets]
|
||||||
|
enabled = false
|
||||||
|
schema_version = 2
|
||||||
|
widget_order = ["lockscreen-login-box@eDP-1"]
|
||||||
|
|
||||||
|
[lockscreen_widgets.grid]
|
||||||
|
cell_size = 16
|
||||||
|
major_interval = 4
|
||||||
|
visible = true
|
||||||
|
|
||||||
|
[lockscreen_widgets.widget."lockscreen-login-box@eDP-1"]
|
||||||
|
box_height = 70.0
|
||||||
|
box_width = 400.0
|
||||||
|
cx = 960.0
|
||||||
|
cy = 1081.0
|
||||||
|
output = "eDP-1"
|
||||||
|
rotation = 0.0
|
||||||
|
type = "login_box"
|
||||||
|
|
||||||
|
[lockscreen_widgets.widget."lockscreen-login-box@eDP-1".settings]
|
||||||
|
background_color = "surface_variant"
|
||||||
|
background_opacity = 0.88
|
||||||
|
background_radius = 12.0
|
||||||
|
center_password_text = false
|
||||||
|
input_opacity = 1.0
|
||||||
|
input_radius = 6.0
|
||||||
|
show_caps_lock = true
|
||||||
|
show_keyboard_layout = true
|
||||||
|
show_login_button = true
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
"""Machine profiles compose concerns; concerns never depend on a host."""
|
||||||
|
|
||||||
|
from modules.host_system import desktop_system, laptop_system
|
||||||
|
from modules.packages import PackageConcern
|
||||||
|
|
||||||
|
COMMON = (
|
||||||
|
"common/core",
|
||||||
|
"common/wayland",
|
||||||
|
"common/fonts",
|
||||||
|
"common/development",
|
||||||
|
"common/productivity",
|
||||||
|
"common/media",
|
||||||
|
"common/research",
|
||||||
|
"common/network",
|
||||||
|
"common/services",
|
||||||
|
)
|
||||||
|
LAPTOP = ("laptop/hardware",)
|
||||||
|
DESKTOP = ()
|
||||||
|
|
||||||
|
|
||||||
|
def _concerns(names: tuple[str, ...]) -> list[PackageConcern]:
|
||||||
|
return [PackageConcern(name) for name in names]
|
||||||
|
|
||||||
|
|
||||||
|
def laptop() -> list:
|
||||||
|
"""Laptop: shared concerns, laptop hardware, and laptop system configuration."""
|
||||||
|
return [*_concerns((*COMMON, *LAPTOP)), *laptop_system()]
|
||||||
|
|
||||||
|
|
||||||
|
def desktop() -> list:
|
||||||
|
"""Future desktop: shared concerns plus desktop-only concerns when declared."""
|
||||||
|
return [*_concerns((*COMMON, *DESKTOP)), *desktop_system()]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
getty@.service
|
||||||
|
remote-fs.target
|
||||||
|
systemd-resolved-monitor.socket
|
||||||
|
systemd-resolved-varlink.socket
|
||||||
|
systemd-resolved.service
|
||||||
|
systemd-timesyncd.service
|
||||||
|
systemd-userdbd.socket
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
gnome-keyring-daemon.socket
|
||||||
|
p11-kit-server.socket
|
||||||
|
pipewire-pulse.socket
|
||||||
|
pipewire.socket
|
||||||
|
wireplumber.service
|
||||||
|
xdg-user-dirs.service
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
docker.service
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
idle-inhibitor-monitor.service
|
||||||
|
pi-status-bridge.service
|
||||||
|
ssh-agent.service
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
avahi-daemon.service
|
||||||
|
avahi-daemon.socket
|
||||||
|
avahi-dnsconfd.service
|
||||||
|
cups.path
|
||||||
|
cups.service
|
||||||
|
cups.socket
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
NetworkManager-dispatcher.service
|
||||||
|
NetworkManager-wait-online.service
|
||||||
|
NetworkManager.service
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mullvad-daemon.service
|
||||||
|
mullvad-early-boot-blocking.service
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
bluetooth.service
|
||||||
|
keyd.service
|
||||||
|
lm_sensors.service
|
||||||
|
thermald.service
|
||||||
|
tlp-pd.service
|
||||||
|
tlp.service
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Modules
|
||||||
|
|
||||||
|
Only two adapters belong here:
|
||||||
|
|
||||||
|
- `packages.py` turns package concern lists into Decman package declarations.
|
||||||
|
- `host_system.py` deploys reviewed system policy, user configuration, and enabled units for a host.
|
||||||
|
|
||||||
|
Keep policy in `packages/`, `config/`, and `manifests/`; keep this directory
|
||||||
|
thin and reusable. User configuration belongs under `config/user/{common,laptop,desktop}/`
|
||||||
|
and is installed with owner `alex`.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user