simplified my pipewire conf

This commit is contained in:
2026-02-15 00:54:45 +01:00
parent 885fbc1551
commit 4e2e75a044
26 changed files with 823 additions and 314 deletions

129
dot_config/gtk-4.0/gtk.css Normal file
View File

@@ -0,0 +1,129 @@
/* Apex Theme System — GTK4 / Libadwaita */
/* Auto-generated from Apex DNA */
/* Scheme: Apex Neon (dark) */
@media (prefers-color-scheme: dark) {
:root {
/* Core Surfaces */
@define-color window_bg_color #050505;
@define-color window_fg_color #ededed;
@define-color view_bg_color #050505;
@define-color view_fg_color #ededed;
@define-color headerbar_bg_color #141414;
@define-color headerbar_fg_color #ededed;
@define-color headerbar_border_color #262626;
@define-color headerbar_backdrop_color @window_bg_color;
@define-color headerbar_shade_color rgba(0, 0, 0, 0.07);
@define-color popover_bg_color #141414;
@define-color popover_fg_color #ededed;
@define-color card_bg_color #141414;
@define-color card_fg_color #ededed;
@define-color card_shade_color rgba(0, 0, 0, 0.07);
@define-color dialog_bg_color #141414;
@define-color dialog_fg_color #ededed;
/* Accents */
@define-color accent_color #00eaff;
@define-color accent_bg_color #00eaff;
@define-color accent_fg_color #050505;
@define-color destructive_color #ff0044;
@define-color destructive_bg_color #ff0044;
@define-color destructive_fg_color #050505;
@define-color success_color #00ff99;
@define-color success_bg_color #00ff99;
@define-color success_fg_color #050505;
@define-color warning_color #ffb700;
@define-color warning_bg_color #ffb700;
@define-color warning_fg_color #050505;
@define-color error_color #ff8899;
@define-color error_bg_color #ff8899;
@define-color error_fg_color #050505;
/* UI Elements */
@define-color borders #262626;
@define-color sidebar_bg_color #141414;
@define-color sidebar_fg_color #ededed;
@define-color sidebar_backdrop_color @window_bg_color;
@define-color sidebar_shade_color rgba(0, 0, 0, 0.07);
/* Custom Apex Palette */
@define-color apex_razor #ff0044;
@define-color apex_void #050505;
@define-color apex_stealth #404040;
}
}
/* Scheme: Apex Aeon (light) */
@media (prefers-color-scheme: light) {
:root {
/* Core Surfaces */
@define-color window_bg_color #f5f5f5;
@define-color window_fg_color #0a0a0a;
@define-color view_bg_color #f5f5f5;
@define-color view_fg_color #0a0a0a;
@define-color headerbar_bg_color #e8e8e8;
@define-color headerbar_fg_color #0a0a0a;
@define-color headerbar_border_color #737373;
@define-color headerbar_backdrop_color @window_bg_color;
@define-color headerbar_shade_color rgba(0, 0, 0, 0.07);
@define-color popover_bg_color #e8e8e8;
@define-color popover_fg_color #0a0a0a;
@define-color card_bg_color #e8e8e8;
@define-color card_fg_color #0a0a0a;
@define-color card_shade_color rgba(0, 0, 0, 0.07);
@define-color dialog_bg_color #e8e8e8;
@define-color dialog_fg_color #0a0a0a;
/* Accents */
@define-color accent_color #007a88;
@define-color accent_bg_color #007a88;
@define-color accent_fg_color #f5f5f5;
@define-color destructive_color #ff0044;
@define-color destructive_bg_color #ff0044;
@define-color destructive_fg_color #f5f5f5;
@define-color success_color #00b377;
@define-color success_bg_color #00b377;
@define-color success_fg_color #f5f5f5;
@define-color warning_color #d18f00;
@define-color warning_bg_color #d18f00;
@define-color warning_fg_color #f5f5f5;
@define-color error_color #ff4d6d;
@define-color error_bg_color #ff4d6d;
@define-color error_fg_color #f5f5f5;
/* UI Elements */
@define-color borders #737373;
@define-color sidebar_bg_color #e8e8e8;
@define-color sidebar_fg_color #0a0a0a;
@define-color sidebar_backdrop_color @window_bg_color;
@define-color sidebar_shade_color rgba(0, 0, 0, 0.07);
/* Custom Apex Palette */
@define-color apex_razor #ff0044;
@define-color apex_void #f5f5f5;
@define-color apex_stealth #a0a0a0;
}
}

View File

@@ -3,10 +3,10 @@
##############################################
# Set programs that you use
$terminal = uwsm app -- ghostty
$term_tmux = uwsm app -- ghostty -e tmux
$term_tmux_append = uwsm app -- ghostty -e tmux a
$editor = uwsm app -- ghostty -e nvim
$terminal = uwsm app -- kitty
$term_tmux = uwsm app -- kitty -e tmux
$term_tmux_append = uwsm app -- kitty -e tmux a
$editor = uwsm app -- kitty -e nvim
$alteditor = uwsm app -- zeditor
$filemanager = uwsm app -- nautilus
@@ -56,6 +56,7 @@ bind = $mainMod, X, exec, $taskman
bind = $mainMod, C, exec, $clipman
bind = $mainMod, R, exec, $pwdmgr
bind = $mainMod, F4, exec, $soundctl
bind = $mainMod, backslash, exec, mic-toggle-usb
# Communication
bind = $mainMod, A, exec, hypr-element-toggle
@@ -123,6 +124,10 @@ bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# MOVE CURRENT WORKSPACE TO A MONITOR with mainMod + SHIFT + [,/.]
bind = $mainMod SHIFT, comma, movecurrentworkspacetomonitor, l
bind = $mainMod SHIFT, period, movecurrentworkspacetomonitor, r
# MOVE ACTIVE WINDOW TO A WORKSPACE with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2

View File

@@ -13,8 +13,8 @@ application/x-extension-xht=firefox.desktop
application/pdf=org.pwmt.zathura-pdf-mupdf.desktop
x-scheme-handler/jetbrains=jetbrains-toolbox.desktop
application/gml+xml=dev.zed.Zed.desktop
image/png=satty.desktop
image/jpeg=satty.desktop
image/png=gimp.desktop
image/jpeg=gimp.desktop
[Added Associations]
x-scheme-handler/http=firefox.desktop;
@@ -29,5 +29,5 @@ application/x-extension-xhtml=firefox.desktop;
application/x-extension-xht=firefox.desktop;
application/pdf=org.pwmt.zathura-pdf-mupdf.desktop;
application/gml+xml=dev.zed.Zed.desktop;
image/png=satty.desktop;
image/jpeg=satty.desktop;
image/png=satty.desktop;gimp.desktop;
image/jpeg=satty.desktop;gimp.desktop;

View File

@@ -0,0 +1,72 @@
context.modules = [
{ name = libpipewire-module-echo-cancel
args = {
# Standard mode: Acts as a virtual sink/source pair
monitor.mode = false
library.name = aec/libspa-aec-webrtc
node.description = "Voice Engine (AEC)"
# 1. The Virtual Sink (Reference)
# Route your Game/Desktop audio here so it gets cancelled from the mic.
# It will automatically pass through to your default speakers.
sink.props = {
node.name = "voice_engine_reference"
node.description = "Voice Engine Reference (Sink)"
}
# 2. The Processed Source (Mic)
# This is the output of the echo canceller. We feed this into RNNoise below.
source.props = {
node.name = "voice_engine_aec_source"
node.description = "Voice Engine AEC Output"
}
aec.args = {
# CRITICAL: Fixes robotic audio by handling clock drift between USB devices
webrtc.drift_compensation_enabled = true
# We use RNNoise separately for better quality, so disable this
webrtc.noise_suppression = false
webrtc.voice_detection = true
webrtc.extended_filter = true
}
}
},
{ name = libpipewire-module-filter-chain
args = {
node.description = "Voice Engine (Final)"
media.name = "Voice Engine (Final)"
filter.graph = {
nodes = [
{
type = ladspa
name = rnnoise
plugin = "/usr/lib/ladspa/librnnoise_ladspa.so"
label = noise_suppressor_mono
control = {
"VAD Threshold (%)" = 50.0
"VAD Grace Period (ms)" = 200
"Retroactive VAD Grace (ms)" = 20
}
}
]
}
# Automatically grabs the output from the AEC module above
capture.props = {
node.name = "voice_engine_rnnoise_in"
node.passive = true
"target.object" = "voice_engine_aec_source"
}
# This is the FINAL device you select in Discord/Zoom/etc.
playback.props = {
node.name = "voice_engine_final"
node.description = "Voice Engine (Final)"
media.class = "Audio/Source"
}
}
}
]

View File

@@ -1,39 +0,0 @@
context.modules = [
{
name = libpipewire-module-echo-cancel
args = {
library.name = aec/libspa-aec-webrtc
monitor.mode = true
capture.props = {
node.name = "EC Capture"
node.passive = true
"target.object" = "{{ .chezmoi.config.data.microphone }}"
}
source.props = {
node.name = "source_ec"
node.description = "Echo-cancelled microphone"
node.autoconnect = false
audio.channels = 1
audio.position = [ MONO ]
}
sink.props = {
node.name = "sink_ec"
node.description = "Echo cancellation reference"
}
playback.props = {
node.name = "EC Playback"
node.passive = true
}
aec.args = {
webrtc.extended_filter = false
webrtc.gain_control = false
webrtc.voice_detection = true
}
}
}
]

View File

@@ -1,45 +0,0 @@
context.modules = [
{
name = libpipewire-module-filter-chain
args = {
node.description = "Noise Canceling source"
media.name = "Noise Canceling source"
audio.channels = 1
audio.position = [ MONO ]
filter.graph = {
nodes = [
{
type = ladspa
name = rnnoise
plugin = /usr/lib/ladspa/librnnoise_ladspa.so
label = noise_suppressor_mono
control = {
"VAD Threshold (%)" = 80.0
"VAD Grace Period (ms)" = 200
"Retroactive VAD Grace (ms)" = 0
}
}
]
}
capture.props = {
node.name = "capture.rnnoise_source"
node.passive = true
audio.channels = 1
audio.position = [ MONO ]
audio.rate = 48000
"target.object" = "source_ec"
}
playback.props = {
node.name = "rnnoise_source"
media.class = "Audio/Source"
audio.channels = 1
audio.position = [ MONO ]
audio.rate = 48000
}
}
}
]

View File

@@ -0,0 +1,66 @@
# Beware! This file is rewritten by htop when settings are changed in the interface.
# The parser is also very primitive, and not human-friendly.
htop_version=3.4.1-3.4.1
config_reader_min_version=3
fields=0 4 5 48 17 18 38 39 40 47 2 46 47 49 1
hide_kernel_threads=1
hide_userland_threads=0
hide_running_in_container=0
shadow_other_users=0
show_thread_names=0
show_program_path=1
highlight_base_name=1
highlight_deleted_exe=1
shadow_distribution_path_prefix=0
highlight_megabytes=1
highlight_threads=1
highlight_changes=0
highlight_changes_delay_secs=5
find_comm_in_cmdline=1
strip_exe_from_cmdline=1
show_merged_command=0
header_margin=1
screen_tabs=1
detailed_cpu_time=0
cpu_count_from_one=0
show_cpu_usage=1
show_cpu_frequency=1
show_cpu_temperature=1
degree_fahrenheit=0
show_cached_memory=1
update_process_names=0
account_guest_in_cpu_meter=0
color_scheme=5
enable_mouse=1
delay=15
hide_function_bar=0
header_layout=three_30_40_30
column_meters_0=System DateTime Uptime DiskIO NetworkIO
column_meter_modes_0=2 2 2 2 2
column_meters_1=AllCPUs4 MemorySwap GPU
column_meter_modes_1=1 1 1
column_meters_2=Tasks LoadAverage FileDescriptors SystemdUser Systemd
column_meter_modes_2=2 2 2 2 2
tree_view=1
sort_key=40
tree_sort_key=39
sort_direction=-1
tree_sort_direction=-1
tree_view_always_by_pid=0
all_branches_collapsed=0
screen:Main=PID PGRP SESSION USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE PERCENT_MEM STATE PERCENT_CPU PERCENT_MEM TIME Command
.sort_key=M_SHARE
.tree_sort_key=M_RESIDENT
.tree_view_always_by_pid=0
.tree_view=1
.sort_direction=-1
.tree_sort_direction=-1
.all_branches_collapsed=0
screen:I/O=PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command
.sort_key=IO_RATE
.tree_sort_key=PID
.tree_view_always_by_pid=0
.tree_view=0
.sort_direction=-1
.tree_sort_direction=1
.all_branches_collapsed=0

View File

@@ -127,6 +127,15 @@
"icon-size": 16
},
"custom/mic-usb": {
"exec": "mic-usb-status",
"return-type": "json",
"interval": 2,
"format": " {text}",
"tooltip": true,
"on-click": "mic-toggle-usb"
},
"wireplumber#source": {
"node-type": "Audio/Source",
"format": " {volume}%",
@@ -327,6 +336,7 @@
"group/volume": {
"orientation": "vertical",
"modules": [
"custom/mic-usb",
"wireplumber#source",
"wireplumber#sink"
]

View File

@@ -81,7 +81,8 @@ window#waybar {
#custom-swaync,
#custom-temps-cycle,
#custom-hyprsunset,
#custom-alhp {
#custom-alhp,
#custom-mic-usb {
background: @pill_bg;
color: @foreground;
border: 1px solid @border;
@@ -107,7 +108,8 @@ window#waybar {
#custom-swaync:hover,
#custom-temps-cycle:hover,
#custom-hyprsunset:hover,
#custom-alhp:hover {
#custom-alhp:hover,
#custom-mic-usb:hover {
background: @pill_hover;
border-color: @accent;
}
@@ -123,7 +125,8 @@ window#waybar {
}
#custom-alhp.stale,
#wireplumber.muted {
#wireplumber.muted,
#custom-mic-usb.mic-usb-muted {
border-color: @warning;
}
@@ -154,8 +157,11 @@ window#waybar {
border-color: @error;
}
#wireplumber.muted { color: @dim; }
#wireplumber.muted,
#custom-mic-usb.mic-usb-muted { color: @dim; }
#idle_inhibitor.deactivated { color: @dim; }
#custom-mic-usb.mic-usb-unknown,
#custom-mic-usb.mic-unavailable { border-color: @error; color: @error; }
/* Group wrappers */
#group-temps,
@@ -194,6 +200,11 @@ window#waybar {
padding: 2px 3px;
}
#group-volume #wireplumber:hover { background: @pill_hover; border-color: @accent; }
#group-volume #custom-mic-usb {
margin: 1px 0;
padding: 2px 3px;
}
#group-volume #custom-mic-usb:hover { background: @pill_hover; border-color: @accent; }
/* Tooltips */
tooltip,

View File

@@ -82,10 +82,15 @@ typeset -g apex_in_git=0
typeset -g apex_git_branch=""
typeset -g apex_git_dirty_wt=0
typeset -g apex_git_dirty_ix=0
typeset -g apex_git_untracked=0
typeset -g apex_git_conflict=0
typeset -g apex_git_op=""
typeset -g apex_git_up_ok=0
typeset -g apex_git_ahead=0
typeset -g apex_git_behind=0
typeset -g apex_git_stash=0
typeset -g apex_git_root=""
typeset -g apex_git_dir=""
# Radar previous snapshots (transition detection)
typeset -g apex_prev_in_git=-1
@@ -123,6 +128,50 @@ apex__project_sig() {
[[ -n "$s" ]] && print -r -- "$s"
}
apex__escape_prompt() {
local s="$1"
s="${s//\\%/%%}"
print -r -- "$s"
}
apex__now_float() {
if [[ -n "${EPOCHREALTIME:-}" ]]; then
print -r -- "$EPOCHREALTIME"
elif [[ -n "${EPOCHSECONDS:-}" ]]; then
print -r -- "${EPOCHSECONDS}.0"
else
print -r -- "0.0"
fi
}
apex__find_git_root() {
local dir="$PWD"
local git_root=""
local git_dir=""
while [[ -n "$dir" ]]; do
if [[ -d "$dir/.git" ]]; then
git_root="$dir"
git_dir="$dir/.git"
break
elif [[ -f "$dir/.git" ]]; then
local line
line="$(<"$dir/.git")"
if [[ "$line" == gitdir:* ]]; then
git_root="$dir"
git_dir="${line#gitdir: }"
[[ "$git_dir" != /* ]] && git_dir="$dir/$git_dir"
break
fi
fi
[[ "$dir" == "/" ]] && break
dir="${dir:h}"
done
[[ -n "$git_root" ]] && print -r -- "${git_root}|${git_dir}"
}
# -----------------------------------------------------------------------------
# 6) INTEL (sticky; updated each prompt)
# -----------------------------------------------------------------------------
@@ -143,6 +192,8 @@ apex_update_intel() {
apex_mode_sig="nix"
elif [[ -n "$DIRENV_DIR" ]]; then
apex_mode_sig="direnv"
elif [[ -f /run/.containerenv || -f /.dockerenv ]]; then
apex_mode_sig="ctr"
else
apex_mode_sig=""
fi
@@ -164,39 +215,101 @@ apex_git_update() {
apex_git_branch=""
apex_git_dirty_wt=0
apex_git_dirty_ix=0
apex_git_untracked=0
apex_git_conflict=0
apex_git_op=""
apex_git_up_ok=0
apex_git_ahead=0
apex_git_behind=0
apex_git_stash=0
command git rev-parse --is-inside-work-tree &>/dev/null || return
local status_out
status_out="$(command git status --porcelain=2 --branch 2>/dev/null)" || {
apex_git_root=""
apex_git_dir=""
return
}
apex_in_git=1
apex_git_branch="$(
command git symbolic-ref --quiet --short HEAD 2>/dev/null \
|| command git rev-parse --short HEAD 2>/dev/null
)"
if (( apex_pwd_changed )) || [[ -z "$apex_git_root" ]]; then
local root_info
root_info="$(apex__find_git_root)"
if [[ -n "$root_info" ]]; then
apex_git_root="${root_info%%|*}"
apex_git_dir="${root_info#*|}"
else
apex_git_root=""
apex_git_dir=""
fi
fi
local gd; gd="$(command git rev-parse --git-dir 2>/dev/null)" || return
[[ -d "$gd/rebase-apply" || -d "$gd/rebase-merge" ]] && apex_git_op="rebase"
[[ -f "$gd/MERGE_HEAD" ]] && apex_git_op="merge"
[[ -f "$gd/CHERRY_PICK_HEAD" ]] && apex_git_op="cherry-pick"
[[ -f "$gd/BISECT_LOG" ]] && apex_git_op="bisect"
local branch_head="" branch_oid="" upstream=""
local xy="" ix="" wt=""
local line
while IFS= read -r line; do
case "$line" in
\#\ branch.head\ *)
branch_head="${line#\# branch.head }"
;;
\#\ branch.oid\ *)
branch_oid="${line#\# branch.oid }"
;;
\#\ branch.upstream\ *)
upstream="${line#\# branch.upstream }"
;;
\#\ branch.ab\ *)
local ab a b
ab="${line#\# branch.ab }"
IFS=' ' read -r a b <<<"$ab"
a="${a#+}"
b="${b#-}"
apex_git_ahead="${a:-0}"
apex_git_behind="${b:-0}"
;;
1\ *|2\ *)
xy="${line[3,4]}"
ix="${xy[1]}"
wt="${xy[2]}"
[[ "$ix" != "." ]] && apex_git_dirty_ix=1
[[ "$wt" != "." ]] && apex_git_dirty_wt=1
;;
u\ *)
apex_git_conflict=1
apex_git_dirty_ix=1
apex_git_dirty_wt=1
;;
\?\ *)
apex_git_untracked=1
;;
esac
done <<<"$status_out"
# Dirty markers
command git diff --quiet --ignore-submodules -- 2>/dev/null || apex_git_dirty_wt=1
command git diff --cached --quiet --ignore-submodules -- 2>/dev/null || apex_git_dirty_ix=1
if [[ -n "$branch_head" && "$branch_head" != "(detached)" && "$branch_head" != "HEAD" ]]; then
apex_git_branch="$branch_head"
elif [[ -n "$branch_oid" ]]; then
apex_git_branch="${branch_oid[1,7]}"
fi
# Upstream (earned ✓)
if command git rev-parse --abbrev-ref --symbolic-full-name @{u} &>/dev/null; then
local counts behind ahead
counts="$(command git rev-list --left-right --count @{u}...HEAD 2>/dev/null)" || return
local IFS=$' \t'
read -r behind ahead <<<"$counts"
apex_git_behind="${behind:-0}"
apex_git_ahead="${ahead:-0}"
if [[ -n "$apex_git_dir" ]]; then
[[ -d "$apex_git_dir/rebase-apply" || -d "$apex_git_dir/rebase-merge" ]] && apex_git_op="rebase"
[[ -f "$apex_git_dir/MERGE_HEAD" ]] && apex_git_op="merge"
[[ -f "$apex_git_dir/CHERRY_PICK_HEAD" ]] && apex_git_op="cherry-pick"
[[ -f "$apex_git_dir/BISECT_LOG" ]] && apex_git_op="bisect"
if (( apex_git_dirty_wt == 0 && apex_git_dirty_ix == 0 )) && [[ -z "$apex_git_op" ]]; then
if [[ -f "$apex_git_dir/logs/refs/stash" ]]; then
local -a stash_lines
stash_lines=(${(f)"$(<"$apex_git_dir/logs/refs/stash")"})
apex_git_stash=$#stash_lines
elif [[ -f "$apex_git_dir/refs/stash" ]]; then
apex_git_stash=1
fi
fi
(( apex_git_conflict )) && apex_git_op="conflict"
if [[ -n "$upstream" && "$upstream" != "(gone)" ]]; then
if (( apex_git_dirty_wt == 0 && apex_git_dirty_ix == 0 && apex_git_untracked == 0 && apex_git_conflict == 0 && apex_git_stash == 0 )) \
&& [[ -z "$apex_git_op" ]]; then
[[ "$apex_git_behind" == "0" && "$apex_git_ahead" == "0" ]] && apex_git_up_ok=1
fi
fi
@@ -248,19 +361,23 @@ apex_intel_r() {
apex_vcs_r() {
(( APEX[SHOW_VCS] )) || return 0
(( apex_in_git )) || return 0
local branch; branch="$(apex__escape_prompt "$apex_git_branch")"
if [[ -n "$apex_git_op" ]]; then
print -n "%F{${C[ALERT]}}${I[GIT]} ${apex_git_branch} ${apex_git_op}%f"
print -n "%F{${C[ALERT]}}${I[GIT]} ${branch} ${apex_git_op}%f"
return 0
fi
print -n "%F{${C[CYAN]}}${I[GIT]} ${apex_git_branch}%f"
print -n "%F{${C[CYAN]}}${I[GIT]} ${branch}%f"
local mark=""
(( apex_git_dirty_ix )) && mark+="+"
(( apex_git_dirty_wt )) && mark+="!"
(( apex_git_untracked )) && mark+="?"
[[ -n "$mark" ]] && print -n "%F{${C[GOLD]}} ${mark}%f"
(( apex_git_stash > 0 )) && print -n "%F{${C[MUTED]}} s${apex_git_stash}%f"
(( apex_git_up_ok )) && print -n "%F{${C[OK]}} ✓%f"
if (( APEX[GIT_AHEAD_BEHIND] )); then
@@ -270,15 +387,23 @@ apex_vcs_r() {
}
apex_friction_r() {
if (( APEX[SHOW_RO] )) && [[ ! -w . ]]; then
print -n "%F{${C[GOLD]}}${I[ROOT]} ro%f"
return 0
if (( APEX[SHOW_RO] )); then
local ro=0
[[ ! -w . ]] && ro=1
if (( apex_in_git )) && [[ -n "$apex_git_root" && ! -w "$apex_git_root" ]]; then
ro=1
fi
if (( ro )); then
print -n "%F{${C[GOLD]}}${I[ROOT]} ro%f"
return 0
fi
fi
if (( APEX[SHOW_JOBS] )); then
local jc
jc=$(jobs -p 2>/dev/null | wc -l | tr -d ' ')
if [[ -n "$jc" && "$jc" != "0" ]]; then
local -a job_pids
job_pids=(${(f)"$(jobs -p 2>/dev/null)"})
local jc=$#job_pids
if (( jc > 0 )); then
print -n "%F{${C[MUTED]}}${I[JOBS]} ${jc}%f"
return 0
fi
@@ -313,6 +438,7 @@ apex_radar_aar() {
(( show )) || return 0
local short; short="$(apex__short_cmd "$cmd")"
short="$(apex__escape_prompt "$short")"
local dur_color="${C[MUTED]}"
(( ms >= ${APEX[SLOW_HARD_MS]} )) && dur_color="${C[GOLD]}"
@@ -388,10 +514,11 @@ apex_radar_context_burst() {
# Git first
if (( apex_in_git )); then
local branch; branch="$(apex__escape_prompt "$apex_git_branch")"
if [[ -n "$apex_git_op" ]]; then
out+="%F{${C[ALERT]}}${I[GIT]} ${apex_git_branch} ${apex_git_op}%f"
out+="%F{${C[ALERT]}}${I[GIT]} ${branch} ${apex_git_op}%f"
else
out+="%F{${C[CYAN]}}${I[GIT]} ${apex_git_branch}%f"
out+="%F{${C[CYAN]}}${I[GIT]} ${branch}%f"
fi
fi
@@ -417,7 +544,7 @@ apex_radar_context_burst() {
# -----------------------------------------------------------------------------
apex_preexec_hook() {
apex_has_run_cmd=1
apex_cmd_start=${EPOCHREALTIME:-$EPOCHSECONDS}
apex_cmd_start="$(apex__now_float)"
apex_last_cmd="$1"
}
@@ -436,9 +563,14 @@ apex_precmd_hook() {
(( apex_has_run_cmd )) && ran=1
if (( ran )); then
local now=${EPOCHREALTIME:-$EPOCHSECONDS}
local -i ms
ms=$(( (now - apex_cmd_start) * 1000 ))
local now; now="$(apex__now_float)"
local -i ms=0
local -F delta=0.0
if [[ -n "$now" ]]; then
delta=$(( now - apex_cmd_start ))
(( delta < 0 )) && delta=0
ms=$(( delta * 1000 ))
fi
# Show time if: slow OR ops OR failed.
local dur=""

View File

@@ -82,10 +82,15 @@ typeset -g apex_in_git=0
typeset -g apex_git_branch=""
typeset -g apex_git_dirty_wt=0
typeset -g apex_git_dirty_ix=0
typeset -g apex_git_untracked=0
typeset -g apex_git_conflict=0
typeset -g apex_git_op=""
typeset -g apex_git_up_ok=0
typeset -g apex_git_ahead=0
typeset -g apex_git_behind=0
typeset -g apex_git_stash=0
typeset -g apex_git_root=""
typeset -g apex_git_dir=""
# Radar previous snapshots (transition detection)
typeset -g apex_prev_in_git=-1
@@ -123,6 +128,50 @@ apex__project_sig() {
[[ -n "$s" ]] && print -r -- "$s"
}
apex__escape_prompt() {
local s="$1"
s="${s//\\%/%%}"
print -r -- "$s"
}
apex__now_float() {
if [[ -n "${EPOCHREALTIME:-}" ]]; then
print -r -- "$EPOCHREALTIME"
elif [[ -n "${EPOCHSECONDS:-}" ]]; then
print -r -- "${EPOCHSECONDS}.0"
else
print -r -- "0.0"
fi
}
apex__find_git_root() {
local dir="$PWD"
local git_root=""
local git_dir=""
while [[ -n "$dir" ]]; do
if [[ -d "$dir/.git" ]]; then
git_root="$dir"
git_dir="$dir/.git"
break
elif [[ -f "$dir/.git" ]]; then
local line
line="$(<"$dir/.git")"
if [[ "$line" == gitdir:* ]]; then
git_root="$dir"
git_dir="${line#gitdir: }"
[[ "$git_dir" != /* ]] && git_dir="$dir/$git_dir"
break
fi
fi
[[ "$dir" == "/" ]] && break
dir="${dir:h}"
done
[[ -n "$git_root" ]] && print -r -- "${git_root}|${git_dir}"
}
# -----------------------------------------------------------------------------
# 6) INTEL (sticky; updated each prompt)
# -----------------------------------------------------------------------------
@@ -143,6 +192,8 @@ apex_update_intel() {
apex_mode_sig="nix"
elif [[ -n "$DIRENV_DIR" ]]; then
apex_mode_sig="direnv"
elif [[ -f /run/.containerenv || -f /.dockerenv ]]; then
apex_mode_sig="ctr"
else
apex_mode_sig=""
fi
@@ -164,39 +215,101 @@ apex_git_update() {
apex_git_branch=""
apex_git_dirty_wt=0
apex_git_dirty_ix=0
apex_git_untracked=0
apex_git_conflict=0
apex_git_op=""
apex_git_up_ok=0
apex_git_ahead=0
apex_git_behind=0
apex_git_stash=0
command git rev-parse --is-inside-work-tree &>/dev/null || return
local status_out
status_out="$(command git status --porcelain=2 --branch 2>/dev/null)" || {
apex_git_root=""
apex_git_dir=""
return
}
apex_in_git=1
apex_git_branch="$(
command git symbolic-ref --quiet --short HEAD 2>/dev/null \
|| command git rev-parse --short HEAD 2>/dev/null
)"
if (( apex_pwd_changed )) || [[ -z "$apex_git_root" ]]; then
local root_info
root_info="$(apex__find_git_root)"
if [[ -n "$root_info" ]]; then
apex_git_root="${root_info%%|*}"
apex_git_dir="${root_info#*|}"
else
apex_git_root=""
apex_git_dir=""
fi
fi
local gd; gd="$(command git rev-parse --git-dir 2>/dev/null)" || return
[[ -d "$gd/rebase-apply" || -d "$gd/rebase-merge" ]] && apex_git_op="rebase"
[[ -f "$gd/MERGE_HEAD" ]] && apex_git_op="merge"
[[ -f "$gd/CHERRY_PICK_HEAD" ]] && apex_git_op="cherry-pick"
[[ -f "$gd/BISECT_LOG" ]] && apex_git_op="bisect"
local branch_head="" branch_oid="" upstream=""
local xy="" ix="" wt=""
local line
while IFS= read -r line; do
case "$line" in
\#\ branch.head\ *)
branch_head="${line#\# branch.head }"
;;
\#\ branch.oid\ *)
branch_oid="${line#\# branch.oid }"
;;
\#\ branch.upstream\ *)
upstream="${line#\# branch.upstream }"
;;
\#\ branch.ab\ *)
local ab a b
ab="${line#\# branch.ab }"
IFS=' ' read -r a b <<<"$ab"
a="${a#+}"
b="${b#-}"
apex_git_ahead="${a:-0}"
apex_git_behind="${b:-0}"
;;
1\ *|2\ *)
xy="${line[3,4]}"
ix="${xy[1]}"
wt="${xy[2]}"
[[ "$ix" != "." ]] && apex_git_dirty_ix=1
[[ "$wt" != "." ]] && apex_git_dirty_wt=1
;;
u\ *)
apex_git_conflict=1
apex_git_dirty_ix=1
apex_git_dirty_wt=1
;;
\?\ *)
apex_git_untracked=1
;;
esac
done <<<"$status_out"
# Dirty markers
command git diff --quiet --ignore-submodules -- 2>/dev/null || apex_git_dirty_wt=1
command git diff --cached --quiet --ignore-submodules -- 2>/dev/null || apex_git_dirty_ix=1
if [[ -n "$branch_head" && "$branch_head" != "(detached)" && "$branch_head" != "HEAD" ]]; then
apex_git_branch="$branch_head"
elif [[ -n "$branch_oid" ]]; then
apex_git_branch="${branch_oid[1,7]}"
fi
# Upstream (earned ✓)
if command git rev-parse --abbrev-ref --symbolic-full-name @{u} &>/dev/null; then
local counts behind ahead
counts="$(command git rev-list --left-right --count @{u}...HEAD 2>/dev/null)" || return
local IFS=$' \t'
read -r behind ahead <<<"$counts"
apex_git_behind="${behind:-0}"
apex_git_ahead="${ahead:-0}"
if [[ -n "$apex_git_dir" ]]; then
[[ -d "$apex_git_dir/rebase-apply" || -d "$apex_git_dir/rebase-merge" ]] && apex_git_op="rebase"
[[ -f "$apex_git_dir/MERGE_HEAD" ]] && apex_git_op="merge"
[[ -f "$apex_git_dir/CHERRY_PICK_HEAD" ]] && apex_git_op="cherry-pick"
[[ -f "$apex_git_dir/BISECT_LOG" ]] && apex_git_op="bisect"
if (( apex_git_dirty_wt == 0 && apex_git_dirty_ix == 0 )) && [[ -z "$apex_git_op" ]]; then
if [[ -f "$apex_git_dir/logs/refs/stash" ]]; then
local -a stash_lines
stash_lines=(${(f)"$(<"$apex_git_dir/logs/refs/stash")"})
apex_git_stash=$#stash_lines
elif [[ -f "$apex_git_dir/refs/stash" ]]; then
apex_git_stash=1
fi
fi
(( apex_git_conflict )) && apex_git_op="conflict"
if [[ -n "$upstream" && "$upstream" != "(gone)" ]]; then
if (( apex_git_dirty_wt == 0 && apex_git_dirty_ix == 0 && apex_git_untracked == 0 && apex_git_conflict == 0 && apex_git_stash == 0 )) \
&& [[ -z "$apex_git_op" ]]; then
[[ "$apex_git_behind" == "0" && "$apex_git_ahead" == "0" ]] && apex_git_up_ok=1
fi
fi
@@ -248,19 +361,23 @@ apex_intel_r() {
apex_vcs_r() {
(( APEX[SHOW_VCS] )) || return 0
(( apex_in_git )) || return 0
local branch; branch="$(apex__escape_prompt "$apex_git_branch")"
if [[ -n "$apex_git_op" ]]; then
print -n "%F{${C[ALERT]}}${I[GIT]} ${apex_git_branch} ${apex_git_op}%f"
print -n "%F{${C[ALERT]}}${I[GIT]} ${branch} ${apex_git_op}%f"
return 0
fi
print -n "%F{${C[CYAN]}}${I[GIT]} ${apex_git_branch}%f"
print -n "%F{${C[CYAN]}}${I[GIT]} ${branch}%f"
local mark=""
(( apex_git_dirty_ix )) && mark+="+"
(( apex_git_dirty_wt )) && mark+="!"
(( apex_git_untracked )) && mark+="?"
[[ -n "$mark" ]] && print -n "%F{${C[GOLD]}} ${mark}%f"
(( apex_git_stash > 0 )) && print -n "%F{${C[MUTED]}} s${apex_git_stash}%f"
(( apex_git_up_ok )) && print -n "%F{${C[OK]}} ✓%f"
if (( APEX[GIT_AHEAD_BEHIND] )); then
@@ -270,15 +387,23 @@ apex_vcs_r() {
}
apex_friction_r() {
if (( APEX[SHOW_RO] )) && [[ ! -w . ]]; then
print -n "%F{${C[GOLD]}}${I[ROOT]} ro%f"
return 0
if (( APEX[SHOW_RO] )); then
local ro=0
[[ ! -w . ]] && ro=1
if (( apex_in_git )) && [[ -n "$apex_git_root" && ! -w "$apex_git_root" ]]; then
ro=1
fi
if (( ro )); then
print -n "%F{${C[GOLD]}}${I[ROOT]} ro%f"
return 0
fi
fi
if (( APEX[SHOW_JOBS] )); then
local jc
jc=$(jobs -p 2>/dev/null | wc -l | tr -d ' ')
if [[ -n "$jc" && "$jc" != "0" ]]; then
local -a job_pids
job_pids=(${(f)"$(jobs -p 2>/dev/null)"})
local jc=$#job_pids
if (( jc > 0 )); then
print -n "%F{${C[MUTED]}}${I[JOBS]} ${jc}%f"
return 0
fi
@@ -313,6 +438,7 @@ apex_radar_aar() {
(( show )) || return 0
local short; short="$(apex__short_cmd "$cmd")"
short="$(apex__escape_prompt "$short")"
local dur_color="${C[MUTED]}"
(( ms >= ${APEX[SLOW_HARD_MS]} )) && dur_color="${C[GOLD]}"
@@ -388,10 +514,11 @@ apex_radar_context_burst() {
# Git first
if (( apex_in_git )); then
local branch; branch="$(apex__escape_prompt "$apex_git_branch")"
if [[ -n "$apex_git_op" ]]; then
out+="%F{${C[ALERT]}}${I[GIT]} ${apex_git_branch} ${apex_git_op}%f"
out+="%F{${C[ALERT]}}${I[GIT]} ${branch} ${apex_git_op}%f"
else
out+="%F{${C[CYAN]}}${I[GIT]} ${apex_git_branch}%f"
out+="%F{${C[CYAN]}}${I[GIT]} ${branch}%f"
fi
fi
@@ -417,7 +544,7 @@ apex_radar_context_burst() {
# -----------------------------------------------------------------------------
apex_preexec_hook() {
apex_has_run_cmd=1
apex_cmd_start=${EPOCHREALTIME:-$EPOCHSECONDS}
apex_cmd_start="$(apex__now_float)"
apex_last_cmd="$1"
}
@@ -436,9 +563,14 @@ apex_precmd_hook() {
(( apex_has_run_cmd )) && ran=1
if (( ran )); then
local now=${EPOCHREALTIME:-$EPOCHSECONDS}
local -i ms
ms=$(( (now - apex_cmd_start) * 1000 ))
local now; now="$(apex__now_float)"
local -i ms=0
local -F delta=0.0
if [[ -n "$now" ]]; then
delta=$(( now - apex_cmd_start ))
(( delta < 0 )) && delta=0
ms=$(( delta * 1000 ))
fi
# Show time if: slow OR ops OR failed.
local dur=""