Add 16 files (16+ files changed)

This commit is contained in:
2026-08-01 07:19:37 -04:00
parent 112a003e51
commit 899a1aa1ab
17 changed files with 1073 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
# GitHub Dark Default theme (matching Alacritty)
background = #0d1117
foreground = #b3b1ad
palette = 0=#484f58
palette = 1=#ff7b72
palette = 2=#3fb950
palette = 3=#d29922
palette = 4=#58a6ff
palette = 5=#bc8cff
palette = 6=#39c5cf
palette = 7=#b1bac4
palette = 8=#6e7681
palette = 9=#ffa198
palette = 10=#56d364
palette = 11=#e3b341
palette = 12=#79c0ff
palette = 13=#d2a8ff
palette = 14=#56d4dd
palette = 15=#f0f6fc
palette = 16=#d18616
palette = 17=#ffa198
# Font
font-family = SFMono Nerd Font
font-family-bold = SFMono Nerd Font SemiBold
font-family-italic = SFMono Nerd Font Italic
font-family-bold-italic = SFMono Nerd Font Bold Italic
font-size = 11.25
# Window
background-opacity = 0.95
window-padding-x = 5
window-padding-y = 5
# Cursor
cursor-style = block
cursor-style-blink = false
# Mouse
mouse-hide-while-typing = true
confirm-close-surface = false
window-save-state = always
bold-is-bright = true
resize-overlay-duration = 0
selection-foreground = #0d1117
selection-background = #b3b1ad
# Selection - auto-copy to clipboard on select
copy-on-select = clipboard
# Scrolling
scrollback-limit = 10000
# Shell
command = /bin/zsh --login
# Terminal env
term = xterm-256color
# Cursor shaders — warp trail + ripple pulse
custom-shader-animation = always
custom-shader = cursor_warp.glsl
custom-shader = ripple_rectangle_cursor.glsl
# Keybindings (matching Alacritty)
keybind = ctrl+shift+c=copy_to_clipboard
keybind = ctrl+shift+v=paste_from_clipboard
keybind = ctrl+shift+n=new_window
+308
View File
@@ -0,0 +1,308 @@
// sRGB -> Linear conversion (needed because Ghostty passes sRGB values but the shader pipeline operates in linear color space)
vec3 sRGBToLinear(vec3 c) {
return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(vec3(0.04045), c));
}
// --- CONFIGURATION ---
vec4 TRAIL_COLOR = vec4(sRGBToLinear(iCurrentCursorColor.rgb), iCurrentCursorColor.a); // for custom color: vec4(0.2, 0.6, 1.0, 0.5); (wrap in sRGBToLinear for correct brightness)
const float DURATION = 0.2; // total animation time
const float TRAIL_SIZE = 0.8; // 0.0 = all corners move together. 1.0 = max smear (leading corners jump instantly)
const float THRESHOLD_MIN_DISTANCE = 1.5; // min distance to show trail (units of cursor height)
const float BLUR = 1.0; // blur size in pixels (for antialiasing)
const float TRAIL_THICKNESS = 1.0; // 1.0 = full cursor height, 0.0 = zero height, >1.0 = funky aah
const float TRAIL_THICKNESS_X = 0.9;
const float FADE_ENABLED = 0.0; // 1.0 to enable fade gradient along the trail, 0.0 to disable
const float FADE_EXPONENT = 5.0; // exponent for fade gradient along the trail
// --- CONSTANTS for easing functions ---
const float PI = 3.14159265359;
const float C1_BACK = 1.70158;
const float C2_BACK = C1_BACK * 1.525;
const float C3_BACK = C1_BACK + 1.0;
const float C4_ELASTIC = (2.0 * PI) / 3.0;
const float C5_ELASTIC = (2.0 * PI) / 4.5;
const float SPRING_STIFFNESS = 9.0;
const float SPRING_DAMPING = 0.9;
// --- EASING FUNCTIONS ---
// // Linear
// float ease(float x) {
// return x;
// }
// // EaseOutQuad
// float ease(float x) {
// return 1.0 - (1.0 - x) * (1.0 - x);
// }
// // EaseOutCubic
// float ease(float x) {
// return 1.0 - pow(1.0 - x, 3.0);
// }
// // EaseOutQuart
// float ease(float x) {
// return 1.0 - pow(1.0 - x, 4.0);
// }
// // EaseOutQuint
// float ease(float x) {
// return 1.0 - pow(1.0 - x, 5.0);
// }
// // EaseOutSine
// float ease(float x) {
// return sin((x * PI) / 2.0);
// }
// // EaseOutExpo
// float ease(float x) {
// return x == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * x);
// }
// EaseOutCirc
float ease(float x) {
return sqrt(1.0 - pow(x - 1.0, 2.0));
}
// // EaseOutBack
// float ease(float x) {
// return 1.0 + C3_BACK * pow(x - 1.0, 3.0) + C1_BACK * pow(x - 1.0, 2.0);
// }
// // EaseOutElastic
// float ease(float x) {
// return x == 0.0 ? 0.0
// : x == 1.0 ? 1.0
// : pow(2.0, -10.0 * x) * sin((x * 10.0 - 0.75) * C4_ELASTIC) + 1.0;
// }
// // Parametric Spring
// float ease(float x) {
// x = clamp(x, 0.0, 1.0);
// float decay = exp(-SPRING_DAMPING * SPRING_STIFFNESS * x);
// float freq = sqrt(SPRING_STIFFNESS * (1.0 - SPRING_DAMPING * SPRING_DAMPING));
// float osc = cos(freq * 6.283185 * x) + (SPRING_DAMPING * sqrt(SPRING_STIFFNESS) / freq) * sin(freq * 6.283185 * x);
// return 1.0 - decay * osc;
// }
float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b)
{
vec2 d = abs(p - xy) - b;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/
// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching
float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) {
vec2 e = b - a;
vec2 w = p - a;
vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0);
float segd = dot(p - proj, p - proj);
d = min(d, segd);
float c0 = step(0.0, p.y - a.y);
float c1 = 1.0 - step(0.0, p.y - b.y);
float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x);
float allCond = c0 * c1 * c2;
float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2);
float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond));
s *= flip;
return d;
}
float getSdfConvexQuad(in vec2 p, in vec2 v1, in vec2 v2, in vec2 v3, in vec2 v4) {
float s = 1.0;
float d = dot(p - v1, p - v1);
d = seg(p, v1, v2, s, d);
d = seg(p, v2, v3, s, d);
d = seg(p, v3, v4, s, d);
d = seg(p, v4, v1, s, d);
return s * sqrt(d);
}
vec2 normalize(vec2 value, float isPosition) {
return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y;
}
float antialising(float distance, float blurAmount) {
return 1. - smoothstep(0., normalize(vec2(blurAmount, blurAmount), 0.).x, distance);
}
// Determines animation duration based on a corner's alignment with the move direction(dot product)
// dot_val will be in [-2, 2]
// > 0.5 (1 or 2) = Leading
// > -0.5 (0) = Side
// <= -0.5 (-1 or -2) = Trailing
float getDurationFromDot(float dot_val, float DURATION_LEAD, float DURATION_SIDE, float DURATION_TRAIL) {
float isLead = step(0.5, dot_val);
float isSide = step(-0.5, dot_val) * (1.0 - isLead);
// Start with trailing duration
float duration = mix(DURATION_TRAIL, DURATION_SIDE, isSide);
// Mix in leading duration
duration = mix(duration, DURATION_LEAD, isLead);
return duration;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord){
#if !defined(WEB)
fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy);
#endif
// normalization & setup(-1, 1 coords)
vec2 vu = normalize(fragCoord, 1.);
vec2 offsetFactor = vec2(-.5, 0.5);
vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.));
vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.));
vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor);
vec2 halfSizeCC = currentCursor.zw * 0.5;
vec2 centerCP = previousCursor.xy - (previousCursor.zw * offsetFactor);
vec2 halfSizeCP = previousCursor.zw * 0.5;
float sdfCurrentCursor = getSdfRectangle(vu, centerCC, halfSizeCC);
float lineLength = distance(centerCC, centerCP);
float minDist = currentCursor.w * THRESHOLD_MIN_DISTANCE;
vec4 newColor = vec4(fragColor);
float baseProgress = iTime - iTimeCursorChange;
if (lineLength > minDist && baseProgress < DURATION - 0.001) {
// defining corners of cursors
// Y (Height) with TRAIL_THICKNESS
float cc_half_height = currentCursor.w * 0.5;
float cc_center_y = currentCursor.y - cc_half_height;
float cc_new_half_height = cc_half_height * TRAIL_THICKNESS;
float cc_new_top_y = cc_center_y + cc_new_half_height;
float cc_new_bottom_y = cc_center_y - cc_new_half_height;
// X (Width) with TRAIL_THICKNESS
float cc_half_width = currentCursor.z * 0.5;
float cc_center_x = currentCursor.x + cc_half_width;
float cc_new_half_width = cc_half_width * TRAIL_THICKNESS_X;
float cc_new_left_x = cc_center_x - cc_new_half_width;
float cc_new_right_x = cc_center_x + cc_new_half_width;
vec2 cc_tl = vec2(cc_new_left_x, cc_new_top_y);
vec2 cc_tr = vec2(cc_new_right_x, cc_new_top_y);
vec2 cc_bl = vec2(cc_new_left_x, cc_new_bottom_y);
vec2 cc_br = vec2(cc_new_right_x, cc_new_bottom_y);
// same thing for previous cursor
float cp_half_height = previousCursor.w * 0.5;
float cp_center_y = previousCursor.y - cp_half_height;
float cp_new_half_height = cp_half_height * TRAIL_THICKNESS;
float cp_new_top_y = cp_center_y + cp_new_half_height;
float cp_new_bottom_y = cp_center_y - cp_new_half_height;
float cp_half_width = previousCursor.z * 0.5;
float cp_center_x = previousCursor.x + cp_half_width;
float cp_new_half_width = cp_half_width * TRAIL_THICKNESS_X;
float cp_new_left_x = cp_center_x - cp_new_half_width;
float cp_new_right_x = cp_center_x + cp_new_half_width;
vec2 cp_tl = vec2(cp_new_left_x, cp_new_top_y);
vec2 cp_tr = vec2(cp_new_right_x, cp_new_top_y);
vec2 cp_bl = vec2(cp_new_left_x, cp_new_bottom_y);
vec2 cp_br = vec2(cp_new_right_x, cp_new_bottom_y);
// calculating durations for every corner
const float DURATION_TRAIL = DURATION;
const float DURATION_LEAD = DURATION * (1.0 - TRAIL_SIZE);
const float DURATION_SIDE = (DURATION_LEAD + DURATION_TRAIL) / 2.0;
vec2 moveVec = centerCC - centerCP;
vec2 s = sign(moveVec);
// dot products for each corner, determining alignment with movement direction
float dot_tl = dot(vec2(-1., 1.), s);
float dot_tr = dot(vec2( 1., 1.), s);
float dot_bl = dot(vec2(-1.,-1.), s);
float dot_br = dot(vec2( 1.,-1.), s);
// assign durations based on dot products
float dur_tl = getDurationFromDot(dot_tl, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL);
float dur_tr = getDurationFromDot(dot_tr, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL);
float dur_bl = getDurationFromDot(dot_bl, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL);
float dur_br = getDurationFromDot(dot_br, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL);
// check direction of horizontal movement
float isMovingRight = step(0.5, s.x);
float isMovingLeft = step(0.5, -s.x);
// calculate vertical-rail durations
float dot_right_edge = (dot_tr + dot_br) * 0.5;
float dur_right_rail = getDurationFromDot(dot_right_edge, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL);
float dot_left_edge = (dot_tl + dot_bl) * 0.5;
float dur_left_rail = getDurationFromDot(dot_left_edge, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL);
float final_dur_tl = mix(dur_tl, dur_left_rail, isMovingLeft);
float final_dur_bl = mix(dur_bl, dur_left_rail, isMovingLeft);
float final_dur_tr = mix(dur_tr, dur_right_rail, isMovingRight);
float final_dur_br = mix(dur_br, dur_right_rail, isMovingRight);
// calculate progress for each corner based on the duration and time since cursor change
float prog_tl = ease(clamp(baseProgress / final_dur_tl, 0.0, 1.0));
float prog_tr = ease(clamp(baseProgress / final_dur_tr, 0.0, 1.0));
float prog_bl = ease(clamp(baseProgress / final_dur_bl, 0.0, 1.0));
float prog_br = ease(clamp(baseProgress / final_dur_br, 0.0, 1.0));
// get the trial corner positions based on progress
vec2 v_tl = mix(cp_tl, cc_tl, prog_tl);
vec2 v_tr = mix(cp_tr, cc_tr, prog_tr);
vec2 v_br = mix(cp_br, cc_br, prog_br);
vec2 v_bl = mix(cp_bl, cc_bl, prog_bl);
// DRAWING THE TRAIL
float sdfTrail = getSdfConvexQuad(vu, v_tl, v_tr, v_br, v_bl);
// --- FADE GRADIENT CALCULATION ---
vec2 fragVec = vu - centerCP;
// project fragment onto movement vector, normalize to [0, 1]
// 0.0 at tail, 1.0 at head
// tiny epsilon to avoid division by zero if moveVec is (0,0)
float fadeProgress = clamp(dot(fragVec, moveVec) / (dot(moveVec, moveVec) + 1e-6), 0.0, 1.0);
vec4 trail = TRAIL_COLOR;
float effectiveBlur = BLUR;
if (BLUR < 2.5) {
// no antialising on horizontal/vertical movement, fixes 'pulse' like thing on end cursor
float isDiagonal = abs(s.x) * abs(s.y); // 1.0 if diagonal, 0.0 if H/V
float effectiveBlur = mix(0.0, BLUR, isDiagonal);
}
float shapeAlpha = antialising(sdfTrail, effectiveBlur); // shape mask
if (FADE_ENABLED > 0.5) {
// apply fade gradient along the trail
// float fadeStart = 0.2;
// float easedProgress = smoothstep(fadeStart, 1.0, fadeProgress);
// easedProgress = pow(2.0, 10.0 * (fadeProgress - 1.0));
float easedProgress = pow(fadeProgress, FADE_EXPONENT);
trail.a *= easedProgress;
}
float finalAlpha = trail.a * shapeAlpha;
// newColor.a to preserve the background alpha.
newColor = mix(newColor, vec4(trail.rgb, newColor.a), finalAlpha);
// punch hole on the trail, so current cursor is drawn on top
newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.));
}
fragColor = newColor;
}
@@ -0,0 +1,138 @@
// CONFIGURATION
const float DURATION = 0.15; // How long the ripple animates (seconds)
const float MAX_SIZE = 0.05; // Max radius in normalized coords (0.5 = 1/4 screen height)
const float RING_THICKNESS = 0.02; // Ring width in normalized coords
const float CURSOR_WIDTH_CHANGE_THRESHOLD = 0.5; // Triggers ripple if cursor width changes by this fraction
vec4 COLOR = vec4(0.35, 0.36, 0.44, 1.0); // change to iCurrentCursorColor for your cursor's color
const float BLUR = 1.0; // Blur level in pixels
const float ANIMATION_START_OFFSET = 0.0; // Start the ripple slightly progressed (0.0 - 1.0)
// Easing functions
float easeOutQuad(float t) {
return 1.0 - (1.0 - t) * (1.0 - t);
}
float easeInOutQuad(float t) {
return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0;
}
float easeOutCubic(float t) {
return 1.0 - pow(1.0 - t, 3.0);
}
float easeOutQuart(float t) {
return 1.0 - pow(1.0 - t, 4.0);
}
float easeOutQuint(float t) {
return 1.0 - pow(1.0 - t, 5.0);
}
float easeOutExpo(float t) {
return t == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * t);
}
float easeOutCirc(float t) {
return sqrt(1.0 - pow(t - 1.0, 2.0));
}
float easeOutSine(float t) {
return sin((t * 3.1415916) / 2.0);
}
float easeOutElastic(float t) {
const float c4 = (2.0 * 3.1415916) / 3.0;
return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0;
}
float easeOutBounce(float t) {
const float n1 = 7.5625;
const float d1 = 2.75;
if (t < 1.0 / d1) {
return n1 * t * t;
} else if (t < 2.0 / d1) {
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else {
return n1 * (t -= 2.625 / d1) * t + 0.984375;
}
}
float easeOutBack(float t) {
const float c1 = 1.70158;
const float c3 = c1 + 1.0;
return 1.0 + c3 * pow(t - 1.0, 3.0) + c1 * pow(t - 1.0, 2.0);
}
// Pulse fade functions
float easeOutPulse(float t) {
return t * (2.0 - t);
}
float exponentialDecayPulse(float t) {
return exp(-3.0 * t) * sin(t * 3.1415916);
}
vec2 normalize(vec2 value, float isPosition) {
return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y;
}
float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b){
vec2 d = abs(p - xy) - b;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord){
#if !defined(WEB)
fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy);
#endif
// Normalization & setup (-1 to 1 coords)
vec2 vu = normalize(fragCoord, 1.);
vec2 offsetFactor = vec2(-.5, 0.5);
vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.));
vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.));
vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor);
float cellWidth = max(currentCursor.z, previousCursor.z); // width of the 'block' cursor
// check for significant width change
float widthChange = abs(currentCursor.z - previousCursor.z);
float widthThresholdNorm = cellWidth * CURSOR_WIDTH_CHANGE_THRESHOLD;
float isModeChange = step(widthThresholdNorm, widthChange);
// ANIMATION
float rippleProgress = (iTime - iTimeCursorChange) / DURATION + ANIMATION_START_OFFSET;
// don't clamp yet; we need to know if it's > 1.0 (finished)
float isAnimating = 1.0 - step(1.0, rippleProgress); // progress < 1.0 ? 1.0: 0.0
if (isModeChange > 0.0 && isAnimating > 0.0) {
// Apply easing to progress
// float easedProgress = rippleProgress;
// float easedProgress = easeOutQuad(rippleProgress);
// float easedProgress = easeInOutQuad(rippleProgress);
// float easedProgress = easeOutCubic(rippleProgress);
// float easedProgress = easeOutQuart(rippleProgress);
// float easedProgress = easeOutQuint(rippleProgress);
// float easedProgress = easeOutExpo(rippleProgress);
float easedProgress = easeOutCirc(rippleProgress);
// float easedProgress = easeOutSine(rippleProgress);
// float easedProgress = easeOutBack(rippleProgress);
// RIPPLE CALCULATION
float rippleExpansion = easedProgress * MAX_SIZE;
// float fade = 1.0; // no fade
// float fade = 1.0 - easedProgress; // linear fade
float fade = 1.0 - easeOutPulse(rippleProgress);
// float fade = 1.0 - exponentialDecayPulse(rippleProgress);
// Calculate distance from frag to cursor center
// float dist = distance(vu, centerCC);
// float sdfRing = abs(dist - rippleExpansion) - RING_THICKNESS * 0.5;
vec2 halfSizeCC = vec2(currentCursor.z, currentCursor.w) * 0.5 + vec2(rippleExpansion);
float sdfRectRing = abs(getSdfRectangle(vu, centerCC, halfSizeCC)) - RING_THICKNESS * 0.5;
// Antialias (1-pixel width in normalized coords)
float antiAliasSize = normalize(vec2(BLUR, BLUR), 0.0).x;
float ripple = (1.0 - smoothstep(-antiAliasSize, antiAliasSize, sdfRectRing)) * fade;
// Apply ripple effect
fragColor = mix(fragColor, COLOR, ripple * COLOR.a);
}
// else: do nothing, keep original fragColor
}
+101
View File
@@ -0,0 +1,101 @@
# Starship prompt configuration - managed by the zshrc repo.
# Local edits to ~/.config/starship.toml are overwritten on the next interactive
# shell start (reproducible/self-configuring design). Uses Nerd Font symbols
# (JetBrainsMono Nerd Font is installed by the tmux config).
command_timeout = 1000
add_newline = true
# Two-line prompt:
# line 1: directory + git status + command duration
# line 2: the input arrow (red on error)
format = """
$directory\
$git_branch\
$git_status\
$cmd_duration\
$line_break\
$character\
"""
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✗](bold red)"
vimcmd_symbol = "[V](bold green)"
[directory]
truncation_length = 3
truncate_to_repo = true
style = "bold blue"
read_only = " 󰌾"
read_only_style = "red"
repo_root_style = "bold cyan"
[git_branch]
symbol = " "
style = "bold purple"
format = "[$symbol$branch]($style) "
[git_status]
style = "bold red"
conflicted = "=${count}"
ahead = "⇡${count}"
behind = "⇣${count}"
diverged = "⇕↑${ahead_count}↓${behind_count}"
untracked = "?${count}"
stashed = " *${count}"
modified = " !${count}"
staged = " +${count}"
renamed = " »${count}"
deleted = " ✘${count}"
format = '([$all_status$ahead_behind]($style) )'
[cmd_duration]
min_time = 2000
format = "took [$duration](bold yellow) "
[status]
disabled = false
format = '[$symbol]($style)'
symbol = "✗ "
success_symbol = ""
style = "bold red"
[username]
show_always = false
style_user = "bold yellow"
style_root = "bold red"
format = "[$user]($style)@"
[hostname]
ssh_only = true
style = "bold green"
format = "[$hostname]($style) "
[python]
symbol = " "
format = '[${symbol}${pyenv_prefix}(${version})(\($virtualenv\))]($style) '
[nodejs]
symbol = " "
format = "[$symbol($version)]($style) "
[rust]
symbol = " "
format = "[$symbol($version)]($style) "
[golang]
symbol = " "
format = "[$symbol($version)]($style) "
[java]
symbol = " "
format = "[$symbol($version)]($style) "
[docker_context]
symbol = " "
format = "[$symbol$context]($style) "
[shell]
disabled = true
style = "bold cyan"
+139
View File
@@ -0,0 +1,139 @@
# set prefix key to Ctrl-a
set -g prefix C-a
# enable mouse mode
set -g mouse on
# set default terminal to xterm-256color
set -g default-terminal "tmux-256color"
# bind keys for pane navigation
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# bind key for closing panes
bind x kill-pane
bind q confirm-before kill-session
# bind key for switching between windows
bind n next-window
bind p previous-window
# cheatsheet & reload
bind ? display-popup -h 27 -w 46 -E "echo -e '╔══════════════════════════════════════════╗\n║  Tmux Cheatsheet ║\n╠══════════════════════════════════════════╣\n║ Press Ctrl+A (prefix) then: ║\n╠══════════════════════════════════════════╣\n║ PANES ║\n║ h/j/k/l Navigate pane ║\n║ | Split horizontally ║\n║ - Split vertically ║\n║ x Kill pane ║\n║ Ctrl+S Swap pane layout ║\n╠══════════════════════════════════════════╣\n║ WINDOWS ║\n║ n Next window ║\n║ p Previous window ║\n║ q Kill session ║\n║ c New window ║\n║ , Rename window ║\n╠══════════════════════════════════════════╣\n║ GENERAL ║\n║ r Reload config ║\n║ ? This cheatsheet ║\n╚══════════════════════════════════════════╝\nPress any key to close.' && read -n 1 -s"
bind r source-file ~/.config/tmux/tmux.conf
# disable terminal flow control (so C-s doesn't freeze)
# set -g flow-control off # option not available in this tmux build
# bind key for toggling between horizontal and vertical split
bind C-s swap-pane -s .-1
# split panes using | and -
bind | split-window -h
bind - split-window -v
unbind '"'
unbind %
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-online-status'
set -g @plugin 'tmux-plugins/tmux-battery'
set -g @plugin 'tmux-plugins/tmux-cpu'
# GitHub Dark color palette
set -g @thm_bg "#0d1117"
set -g @thm_surface_0 "#161b22"
set -g @thm_overlay_0 "#30363d"
set -g @thm_red "#f85149"
set -g @thm_green "#3fb950"
set -g @thm_yellow "#d29922"
set -g @thm_blue "#58a6ff"
set -g @thm_mauve "#bc8cff"
set -g @thm_pink "#f778ba"
set -g @thm_peach "#f0883e"
set -g @thm_maroon "#ff7b72"
set -g @thm_rosewater "#c9d1d9"
# Configure Online
set -g @online_icon "ok"
set -g @offline_icon "nok"
# status left look and feel
set -g status-left-length 100
set -g status-left ""
set -ga status-left "#{?client_prefix,#{#[bg=#{@thm_red},fg=#{@thm_bg},bold]  #S },#{#[bg=#{@thm_bg},fg=#{@thm_green}]  #S }}"
set -ga status-left "#[bg=#{@thm_bg},fg=#{@thm_overlay_0},none]│"
set -ga status-left "#[bg=#{@thm_bg},fg=#{@thm_maroon}]  #{pane_current_command} "
set -ga status-left "#[bg=#{@thm_bg},fg=#{@thm_overlay_0},none]│"
set -ga status-left "#[bg=#{@thm_bg},fg=#{@thm_blue}]  #{=/-32/...:#{s|$USER|~|:#{b:pane_current_path}}} "
set -ga status-left "#[bg=#{@thm_bg},fg=#{@thm_overlay_0},none]#{?window_zoomed_flag,│,}"
set -ga status-left "#[bg=#{@thm_bg},fg=#{@thm_yellow}]#{?window_zoomed_flag,  zoom ,}"
# status right look and feel
set -g status-right-length 100
set -g status-right ""
set -ga status-right "#{?#{e|>=:10,#{battery_percentage}},#{#[bg=#{@thm_red},fg=#{@thm_bg}]},#{#[bg=#{@thm_bg},fg=#{@thm_pink}]}} #{battery_icon} #{battery_percentage} "
set -ga status-right "#[bg=#{@thm_bg},fg=#{@thm_overlay_0}, none]│"
set -ga status-right "#[bg=#{@thm_bg}]#{?#{==:#{online_status},ok},#[fg=#{@thm_mauve}] 󰖩 on ,#[fg=#{@thm_red},bold]#[reverse] 󰖪 off }"
set -ga status-right "#[bg=#{@thm_bg},fg=#{@thm_overlay_0}, none]│"
set -ga status-right "#[bg=#{@thm_bg},fg=#{@thm_blue}] 󰭦 %a, %m-%d-%Y 󰅐 %I:%M %p "
# start indexing at 1 (not 0)
set -g base-index 1
setw -g pane-base-index 1
# misc quality-of-life
set -sg escape-time 0
set -g status-interval 5
set -g renumber-windows on
set -g focus-events on
setw -g aggressive-resize on
set -g set-clipboard on
# bootstrap tpm
if "test ! -d ~/.config/tmux/plugins/tpm" \
"run 'git clone https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpm && ~/.config/tmux/plugins/tpm/bin/install_plugins'"
# auto-install a Nerd Font if missing (for icons)
run 'if ! fc-list :lang=en 2>/dev/null | grep -qi "nerd\\|jetbrainsmono\\|firacode\\|hack\\|iosevka\\|meslo"; then
mkdir -p ~/.local/share/fonts
if command -v curl >/dev/null 2>&1; then
curl -sL "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/JetBrainsMono.zip" -o /tmp/jetbrains-nerd.zip
elif command -v wget >/dev/null 2>&1; then
wget -q "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/JetBrainsMono.zip" -O /tmp/jetbrains-nerd.zip
fi
if [ -f /tmp/jetbrains-nerd.zip ]; then
unzip -qo /tmp/jetbrains-nerd.zip -d ~/.local/share/fonts/ 2>/dev/null
rm -f /tmp/jetbrains-nerd.zip
fc-cache -f ~/.local/share/fonts/ 2>/dev/null
fi
fi'
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.config/tmux/plugins/tpm/tpm'
# Configure Tmux
set -g status-position bottom
set -g status-style "bg=#{@thm_bg}"
set -g status-justify "absolute-centre"
# pane border look and feel
setw -g pane-border-status bottom
setw -g pane-border-format ""
setw -g pane-active-border-style "bg=#{@thm_bg},fg=#{@thm_overlay_0}"
setw -g pane-border-style "bg=#{@thm_bg},fg=#{@thm_surface_0}"
setw -g pane-border-lines single
# window look and feel
set -wg automatic-rename on
set -g automatic-rename-format "#{pane_current_command}"
set -g window-status-format " #I#{?#{!=:#{window_name},Window},: #W,} "
set -g window-status-style "bg=#{@thm_bg},fg=#{@thm_rosewater}"
set -g window-status-last-style "bg=#{@thm_bg},fg=#{@thm_peach}"
set -g window-status-activity-style "bg=#{@thm_red},fg=#{@thm_bg}"
set -g window-status-bell-style "bg=#{@thm_red},fg=#{@thm_bg},bold"
set -gF window-status-separator "#[bg=#{@thm_bg},fg=#{@thm_overlay_0}]│"
set -g window-status-current-format " #I#{?#{!=:#{window_name},Window},: #W,} "
set -g window-status-current-style "bg=#{@thm_peach},fg=#{@thm_bg},bold"
+10
View File
@@ -0,0 +1,10 @@
# ~/.zlogin: Executed for LOGIN shells, AFTER .zshrc has loaded.
# Use for final tasks that require the full environment to be ready (e.g., welcome messages, mail checks).
# Rarely needed for standard configuration.
[[ -f $HOME/.zshrc.local ]] || touch $HOME/.zshrc.local
source $HOME/.zshrc.local
if [[ $FFENABLED != "false" ]] && command -v fastfetch >/dev/null; then
fastfetch --config examples/13
fi
+2
View File
@@ -0,0 +1,2 @@
# ~/.zlogout: Executed when a LOGIN shell exits.
# Use for cleanup tasks: resetting terminal titles, stopping agents, or clearing temp files.
+8
View File
@@ -0,0 +1,8 @@
# ~/.zprofile: Executed once for LOGIN shells (initial terminal/SSH).
# Use for one-time setup: PATH modifications, starting agents, or environment exports.
# Runs BEFORE .zshrc. Ideal for variables that shouldn't be re-evaluated in every sub-shell.
[[ -d "$HOME/Scripts" ]] && path+=("$HOME/Scripts")
[[ -d "$HOME/.local/bin" ]] && path+=("$HOME/.local/bin")
[[ -d "$HOME/AppImages" ]] && path+=("$HOME/AppImages")
[[ -d "$HOME/.opencode/bin" ]] && path+=("$HOME/.opencode/bin")
+27
View File
@@ -0,0 +1,27 @@
# frameworks like oh-my-zsh are supported
getantidote/use-omz # handle OMZ dependencies
ohmyzsh/ohmyzsh path:lib # load OMZ's library
using:ohmyzsh/ohmyzsh path:plugins
git
sudo
extract
eza
history
kitty
docker
docker-compose
archlinux
encode64
universalarchive
fzf
systemd
vscode
rsync
# popular fish-like plugins
zsh-users/zsh-autosuggestions
zdharma-continuum/fast-syntax-highlighting kind:defer
zsh-users/zsh-history-substring-search
Aloxaf/fzf-tab
View File
+9
View File
@@ -0,0 +1,9 @@
# ~/.zshrc: Executed for EVERY INTERACTIVE shell (terminal tabs/windows).
# Use for aliases, functions, prompt themes, key bindings, and shell options (setopt).
# This is where 90% of your customization belongs.
source ${ZDOTDIR}/init.zsh
source ${ZDOTDIR}/aliases.zsh
source ${ZDOTDIR}/functions.zsh
eval "$(starship init zsh)"
+27
View File
@@ -0,0 +1,27 @@
_hl_flag="--hyperlink"
if command -v eza >/dev/null && eza --help 2>&1 | grep -q -- '--hyperlink.*<WHEN>'; then
_hl_flag="--hyperlink=always"
fi
for _ea in la ldot lD lDD ll ls lsd lsdl lS lT; do
(( $+aliases[$_ea] )) && alias "$_ea"="${aliases[$_ea]} $_hl_flag"
done
unset _ea _hl_flag
# bat: colored `cat` and colored man pages. bat/batcat handled by bootstrap.
if command -v bat >/dev/null; then
alias cat='bat'
export BAT_THEME="${BAT_THEME:-Monokai Extended}"
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
export MANROFFOPT='-c'
fi
# delta: prettier git diffs as git's pager (git respects GIT_PAGER). Auto-installed
# by the bootstrap. Not aliased to `diff` since delta reads diff input on stdin,
# not two file arguments — GIT_PAGER is the correct integration.
command -v delta >/dev/null && export GIT_PAGER='delta'
alias c='clear'
alias q="exit"
alias nbstat=$'netbird status --json | jq -r \'.peers.details[]? | [(.hostname // .fqdn), .netbirdIp, .status] | @tsv\' | column -t -s $\'\\t\''
alias open-ports="ss -tulpn | grep LISTEN"
alias yeet='yay -Rcs'
+138
View File
@@ -0,0 +1,138 @@
#!/bin/bash
set -e
# --- Helpers ---
info() { printf "\033[1;34m%s\033[0m\n" "$*"; }
warn() { printf "\033[1;33m%s\033[0m\n" "$*"; }
error() { printf "\033[1;31m%s\033[0m\n" "$*"; }
arch() {
case "$(uname -m)" in
x86_64) echo "x86_64" ;;
aarch64) echo "aarch64" ;;
armv7l) echo "armhf" ;;
*) echo "unknown" ;;
esac
}
# --- Check existing ---
check_all() {
local missing=()
for cmd in git curl jq fzf starship eza bat delta fastfetch dotstate; do
command -v "$cmd" &>/dev/null || missing+=("$cmd")
done
if [[ ${#missing[@]} -eq 0 ]]; then
info "all tools present" >&2
exit 0
fi
echo "${missing[@]}"
}
MISSING=($(check_all))
[[ ${#MISSING[@]} -eq 0 ]] && exit 0
# --- Detect package manager ---
install_pkgs() {
if command -v pacman &>/dev/null; then
sudo pacman -S --noconfirm "$@"
elif command -v dnf &>/dev/null; then
sudo dnf install -y "$@"
elif command -v apt &>/dev/null; then
sudo apt update -qq && sudo apt install -y "$@"
elif command -v zypper &>/dev/null; then
sudo zypper install -y "$@"
elif command -v apk &>/dev/null; then
sudo apk add "$@"
else
return 1
fi
}
# --- Install from system repos ---
SYS_pkgs=()
BIN_pkgs=()
# Map tool names to distro package names where they differ
declare -A PKG_NAMES=(
[git]="git"
[curl]="curl"
[jq]="jq"
[fzf]="fzf"
[eza]="eza"
[bat]="bat"
[delta]="git-delta"
[fastfetch]="fastfetch"
)
# starship and dotstate have no distro package, always binary
for tool in "${MISSING[@]}"; do
if [[ "$tool" == "starship" || "$tool" == "dotstate" ]]; then
BIN_pkgs+=("$tool")
continue
fi
pkg="${PKG_NAMES[$tool]:-$tool}"
SYS_pkgs+=("$pkg")
done
if [[ ${#SYS_pkgs[@]} -gt 0 ]]; then
info "installing from system repos: ${SYS_pkgs[*]}"
install_pkgs "${SYS_pkgs[@]}" || {
warn "system install failed, falling back to binaries"
BIN_pkgs+=("${SYS_pkgs[@]}")
}
fi
# --- Install pre-built binaries ---
install_binary() {
local name="$1"
local arch
arch=$(arch)
case "$name" in
starship)
info "installing starship"
curl -sS https://starship.rs/install.sh | sh -s -- -y
;;
eza)
info "installing eza"
local url="https://github.com/eza-community/eza/releases/latest/download/eza-${arch}-unknown-linux-musl.tar.gz"
curl -sSfL "$url" | sudo tar xz -C /usr/local/bin
;;
bat)
info "installing bat"
local url="https://github.com/sharkdp/bat/releases/latest/download/bat-${arch}-unknown-linux-musl.tar.gz"
curl -sSfL "$url" | sudo tar xz --strip-components=1 -C /usr/local/bin "bat-${arch}-unknown-linux-musl/bat"
;;
delta)
info "installing delta"
local url="https://github.com/dandavison/delta/releases/latest/download/delta-${arch}-unknown-linux-musl.tar.gz"
curl -sSfL "$url" | sudo tar xz --strip-components=1 -C /usr/local/bin "delta-${arch}-unknown-linux-musl/delta"
;;
fastfetch)
info "installing fastfetch"
local url="https://github.com/fastfetch-cli/fastfetch/releases/latest/download/fastfetch-linux-${arch}.tar.gz"
curl -sSfL "$url" | sudo tar xz --strip-components=2 -C /usr/local/bin
;;
jq)
info "installing jq"
local url="https://github.com/jqlang/jq/releases/latest/download/jq-linux-${arch}"
curl -sSfL "$url" -o /usr/local/bin/jq
sudo chmod +x /usr/local/bin/jq
;;
dotstate)
info "installing dotstate"
curl -fsSL https://dotstate.serkan.dev/install.sh | bash
;;
esac
}
for tool in "${BIN_pkgs[@]}"; do
install_binary "$tool"
done
info "done"
+7
View File
@@ -0,0 +1,7 @@
fix_btopbg(){
sed -i 's/theme_background = true/theme_background = false/' ~/.config/btop/btop.conf
}
install_opencode(){
curl -fsSL https://opencode.ai/install | bash
}
+54
View File
@@ -0,0 +1,54 @@
# first, run this from an interactive zsh terminal session:
if [[ -e "${ZDOTDIR}/.antidote" && ! -d "${ZDOTDIR}/.antidote" ]]; then
mkdir -p "${ZDOTDIR}/.antidote" && chmod 700 "${ZDOTDIR}/.antidote"
git clone --depth=1 https://github.com/mattmc3/antidote.git ${ZDOTDIR}/.antidote
fi
zsh_plugins=${ZDOTDIR}/.zsh_plugins
[[ -f ${zsh_plugins}.txt ]] || touch ${zsh_plugins}.txt
# source antidote
source ${ZDOTDIR}/.antidote/antidote.zsh
# Eza plugin options
zstyle ':omz:plugins:eza' dirs-first yes
zstyle ':omz:plugins:eza' git-status yes
zstyle ':omz:plugins:eza' header yes
zstyle ':omz:plugins:eza' show-group yes
zstyle ':omz:plugins:eza' icons yes
zstyle ':omz:plugins:eza' color-scale all
zstyle ':omz:plugins:eza' color-scale-mode fixed
zstyle ':omz:plugins:eza' size-prefix si
# Note: 'hyperlink' is omitted as per your comment
# Completion settings
zstyle ':completion:*' menu select
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'
zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
zstyle ':completion:*' special-dirs true
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
# Ensure directories exist
mkdir -p "$XDG_CACHE_HOME/zsh"
export HISTFILE="$XDG_CACHE_HOME/zsh/history"
export ZSH_COMPDUMP="$XDG_CACHE_HOME/zsh/zcompdump-${HOST}-${ZSH_VERSION}"
export HISTSIZE=10000
export SAVEHIST=10000
setopt SHARE_HISTORY
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_REDUCE_BLANKS
setopt HIST_FCNTL_LOCK
setopt AUTO_CD
setopt AUTO_LIST
setopt INTERACTIVE_COMMENTS
setopt HIST_VERIFY
setopt EXTENDED_HISTORY
setopt AUTO_PUSHD
setopt PUSHD_IGNORE_DUPS
setopt PUSHD_SILENT
# initialize plugins statically with ${ZDOTDIR:-$HOME}/.zsh_plugins.txt
antidote load