lacy 1.8.11 → 1.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +26 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +49 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- package/.github/SECURITY.md +32 -0
- package/.github/assets/logo-horizontal-dark.png +0 -0
- package/.github/assets/logo-horizontal-dark.svg +17 -0
- package/.github/assets/logo-horizontal.png +0 -0
- package/.github/assets/logo-horizontal.svg +17 -0
- package/.github/assets/logo.png +0 -0
- package/.github/assets/logo.svg +12 -0
- package/.github/assets/social-preview.png +0 -0
- package/.github/assets/social-preview.svg +50 -0
- package/.github/dependabot.yml +21 -0
- package/.github/workflows/ci.yml +80 -0
- package/.github/workflows/dependabot-auto-merge.yml +32 -0
- package/CHANGELOG.md +366 -0
- package/CLAUDE.md +340 -0
- package/CONTRIBUTING.md +141 -0
- package/LICENSE +110 -0
- package/README.md +201 -31
- package/RELEASING.md +148 -0
- package/STYLE.md +202 -0
- package/assets/hero.jpeg +0 -0
- package/assets/mode-indicators.jpeg +0 -0
- package/assets/real-time-indicator.jpeg +0 -0
- package/assets/supported-tools.jpeg +0 -0
- package/bin/lacy +1028 -0
- package/docs/ADDING-BACKENDS.md +124 -0
- package/docs/DEVTO-ARTICLE.md +94 -0
- package/docs/DOCS.md +68 -0
- package/docs/GROWTH-STRATEGY.md +119 -0
- package/docs/HN-RESPONSES.md +122 -0
- package/docs/LAUNCH-COPY-FINAL.md +105 -0
- package/docs/MARKETING.md +411 -0
- package/docs/NATURAL_LANGUAGE_DETECTION.md +204 -0
- package/docs/UGC_VIDEO_SCRIPT.md +114 -0
- package/docs/articles/devto-how-i-made-my-terminal-understand-english.md +117 -0
- package/docs/demo-color-transition.gif +0 -0
- package/docs/demo-full.gif +0 -0
- package/docs/demo-indicator.gif +0 -0
- package/docs/launch-thread-may6.sh +158 -0
- package/docs/videos/README.md +189 -0
- package/docs/videos/generate_frames.py +510 -0
- package/docs/videos/generate_frames_v2.py +729 -0
- package/docs/videos/generate_short.py +328 -0
- package/docs/videos/generate_short_v2.py +526 -0
- package/docs/videos/lacy-shell-demo-v2.mp4 +0 -0
- package/docs/videos/lacy-shell-demo.mp4 +0 -0
- package/docs/videos/lacy-shell-short-v2.mp4 +0 -0
- package/docs/videos/lacy-shell-short.mp4 +0 -0
- package/install.sh +1009 -0
- package/lacy.plugin.bash +75 -0
- package/lacy.plugin.fish +43 -0
- package/lacy.plugin.zsh +65 -0
- package/lib/animations.zsh +3 -0
- package/lib/bash/completions.bash +40 -0
- package/lib/bash/execute.bash +233 -0
- package/lib/bash/init.bash +40 -0
- package/lib/bash/keybindings.bash +134 -0
- package/lib/bash/prompt.bash +85 -0
- package/lib/commands/info.sh +25 -0
- package/lib/config.zsh +3 -0
- package/lib/constants.zsh +3 -0
- package/lib/core/animations.sh +271 -0
- package/lib/core/commands.sh +297 -0
- package/lib/core/config.sh +340 -0
- package/lib/core/constants.sh +366 -0
- package/lib/core/context.sh +260 -0
- package/lib/core/detection.sh +417 -0
- package/lib/core/mcp.sh +741 -0
- package/lib/core/modes.sh +123 -0
- package/lib/core/preheat.sh +496 -0
- package/lib/core/spinner.sh +174 -0
- package/lib/core/telemetry.sh +99 -0
- package/lib/detection.zsh +3 -0
- package/lib/execute.zsh +3 -0
- package/lib/fish/config.fish +66 -0
- package/lib/fish/detection.fish +90 -0
- package/lib/fish/execute.fish +105 -0
- package/lib/fish/keybindings.fish +42 -0
- package/lib/fish/prompt.fish +30 -0
- package/lib/keybindings.zsh +3 -0
- package/lib/mcp.zsh +3 -0
- package/lib/modes.zsh +3 -0
- package/lib/preheat.zsh +3 -0
- package/lib/prompt.zsh +3 -0
- package/lib/spinner.zsh +3 -0
- package/lib/zsh/completions.zsh +60 -0
- package/lib/zsh/execute.zsh +294 -0
- package/lib/zsh/init.zsh +26 -0
- package/lib/zsh/keybindings.zsh +551 -0
- package/lib/zsh/prompt.zsh +90 -0
- package/package.json +42 -27
- package/packages/lacy/README.md +61 -0
- package/packages/lacy/commands/info.sh +25 -0
- package/{index.mjs → packages/lacy/index.mjs} +247 -20
- package/packages/lacy/package-lock.json +71 -0
- package/packages/lacy/package.json +42 -0
- package/script/release.ts +487 -0
- package/squirrel.toml +36 -0
- package/tests/test_bash.bash +163 -0
- package/tests/test_core.sh +607 -0
- package/tests/test_gemini.sh +119 -0
- package/tests/test_gemini_mcp.sh +126 -0
- package/tests/test_preheat_server.zsh +446 -0
- package/uninstall.sh +52 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Prompt handling for Lacy Shell — Bash adapter
|
|
4
|
+
# - Mode badge in left prompt (no right prompt in Bash)
|
|
5
|
+
# - No real-time indicator (Bash lacks per-keystroke hooks)
|
|
6
|
+
|
|
7
|
+
# Store original prompt (captured later, after user's profile loads)
|
|
8
|
+
LACY_SHELL_ORIGINAL_PS1=""
|
|
9
|
+
LACY_SHELL_BASE_PS1=""
|
|
10
|
+
LACY_SHELL_PROMPT_INITIALIZED=false
|
|
11
|
+
|
|
12
|
+
# Setup prompt integration (called during init, defers to first PROMPT_COMMAND)
|
|
13
|
+
lacy_shell_setup_prompt() {
|
|
14
|
+
LACY_SHELL_PROMPT_INITIALIZED=false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Actually initialize the prompt (called on first PROMPT_COMMAND)
|
|
18
|
+
lacy_shell_init_prompt_once() {
|
|
19
|
+
[[ "$LACY_SHELL_PROMPT_INITIALIZED" == true ]] && return
|
|
20
|
+
|
|
21
|
+
# Capture the user's fully-loaded prompt
|
|
22
|
+
LACY_SHELL_ORIGINAL_PS1="$PS1"
|
|
23
|
+
LACY_SHELL_BASE_PS1="$PS1"
|
|
24
|
+
|
|
25
|
+
# Mark initialized BEFORE calling update_prompt to prevent infinite recursion
|
|
26
|
+
# (update_prompt calls init_prompt_once, which would call update_prompt again)
|
|
27
|
+
LACY_SHELL_PROMPT_INITIALIZED=true
|
|
28
|
+
|
|
29
|
+
# Set initial prompt with mode badge
|
|
30
|
+
lacy_shell_update_prompt
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Get ANSI color escape for a 256-color code
|
|
34
|
+
_lacy_bash_color() {
|
|
35
|
+
printf '\[\e[38;5;%dm\]' "$1"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_lacy_bash_reset() {
|
|
39
|
+
printf '\[\e[0m\]'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Update prompt with mode badge
|
|
43
|
+
lacy_shell_update_prompt() {
|
|
44
|
+
# Initialize on first call
|
|
45
|
+
lacy_shell_init_prompt_once
|
|
46
|
+
|
|
47
|
+
local mode_text mode_color
|
|
48
|
+
case "$LACY_SHELL_CURRENT_MODE" in
|
|
49
|
+
"shell")
|
|
50
|
+
mode_text="SHELL"
|
|
51
|
+
mode_color="$LACY_COLOR_SHELL"
|
|
52
|
+
;;
|
|
53
|
+
"agent")
|
|
54
|
+
mode_text="AGENT"
|
|
55
|
+
mode_color="$LACY_COLOR_AGENT"
|
|
56
|
+
;;
|
|
57
|
+
"auto")
|
|
58
|
+
mode_text="AUTO"
|
|
59
|
+
mode_color="$LACY_COLOR_AUTO"
|
|
60
|
+
;;
|
|
61
|
+
*)
|
|
62
|
+
mode_text="?"
|
|
63
|
+
mode_color="$LACY_COLOR_NEUTRAL"
|
|
64
|
+
;;
|
|
65
|
+
esac
|
|
66
|
+
|
|
67
|
+
# Build prompt: [MODE] indicator original_ps1
|
|
68
|
+
local badge
|
|
69
|
+
badge="$(_lacy_bash_color "$mode_color")${mode_text}$(_lacy_bash_reset)"
|
|
70
|
+
local indicator
|
|
71
|
+
indicator="$(_lacy_bash_color "$LACY_COLOR_NEUTRAL")${LACY_INDICATOR_CHAR}$(_lacy_bash_reset)"
|
|
72
|
+
|
|
73
|
+
PS1="${badge} ${indicator} ${LACY_SHELL_BASE_PS1}"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Restore original prompt
|
|
77
|
+
lacy_shell_restore_prompt() {
|
|
78
|
+
if [[ -n "$LACY_SHELL_ORIGINAL_PS1" ]]; then
|
|
79
|
+
PS1="$LACY_SHELL_ORIGINAL_PS1"
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Stubs for removed features (from ZSH adapter)
|
|
84
|
+
lacy_shell_remove_top_bar() { :; }
|
|
85
|
+
lacy_shell_show_top_bar_message() { :; }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Lacy Shell - Info command
|
|
4
|
+
# Shows basic information and guides users to setup
|
|
5
|
+
|
|
6
|
+
_lacy_info_version() {
|
|
7
|
+
local pkg="${HOME}/.lacy/package.json"
|
|
8
|
+
if [[ -f "$pkg" ]]; then
|
|
9
|
+
grep '"version"' "$pkg" 2>/dev/null | head -1 | sed 's/.*"version"[[:space:]]*:[[:space:]]*"//' | sed 's/".*//'
|
|
10
|
+
else
|
|
11
|
+
echo "unknown"
|
|
12
|
+
fi
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
printf '\033[38;5;75m%s\033[0m\n' "🔧 Lacy Shell v$(_lacy_info_version)"
|
|
16
|
+
echo
|
|
17
|
+
printf '%s\n' "Lacy Shell detects natural language and routes it to AI coding agents."
|
|
18
|
+
echo
|
|
19
|
+
printf '%s\n' "Quick tips:"
|
|
20
|
+
printf ' • %s\n' "Type normally for shell commands"
|
|
21
|
+
printf ' • %s\n' "Type natural language for AI assistance"
|
|
22
|
+
printf ' • %s\n' "Press Ctrl+Space to toggle modes"
|
|
23
|
+
echo
|
|
24
|
+
printf '%b\n' "Run '\033[38;5;200mlacy setup\033[0m' to configure your AI tool and settings."
|
|
25
|
+
printf '%b\n' "Run '\033[38;5;200mlacy mode\033[0m' to see current mode and legend."
|
package/lib/config.zsh
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Braille Loading Animations for Lacy Shell
|
|
4
|
+
# 18 Unicode Braille animations for the agent spinner
|
|
5
|
+
# Sourced from https://github.com/gunnargray-dev/unicode-animations
|
|
6
|
+
# ALL frames are exactly 4 braille characters wide (pad with ⠀ U+2800)
|
|
7
|
+
# to prevent horizontal shifting when switching animations
|
|
8
|
+
#
|
|
9
|
+
# Braille dot layout (2×4 grid per char):
|
|
10
|
+
# dot1 (0x01) dot4 (0x08)
|
|
11
|
+
# dot2 (0x02) dot5 (0x10)
|
|
12
|
+
# dot3 (0x04) dot6 (0x20)
|
|
13
|
+
# dot7 (0x40) dot8 (0x80)
|
|
14
|
+
|
|
15
|
+
# Available animation names
|
|
16
|
+
LACY_SPINNER_ANIMATIONS=(
|
|
17
|
+
"braille" "dots" "ascii" "braillewave" "dna" "scan" "rain" "scanline"
|
|
18
|
+
"pulse" "snake" "sparkle" "cascade" "columns" "orbit"
|
|
19
|
+
"breathe" "waverows" "checkerboard" "helix" "fillsweep" "diagswipe"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Set the active spinner animation frames
|
|
23
|
+
# Usage: lacy_set_spinner_animation "name"
|
|
24
|
+
# Sets LACY_SPINNER_ANIM array
|
|
25
|
+
lacy_set_spinner_animation() {
|
|
26
|
+
local name="${1:-braille}"
|
|
27
|
+
|
|
28
|
+
# "random" picks a random animation each time
|
|
29
|
+
if [[ "$name" == "random" ]]; then
|
|
30
|
+
local count=${#LACY_SPINNER_ANIMATIONS[@]}
|
|
31
|
+
local arr_off=${_LACY_ARR_OFFSET:-0}
|
|
32
|
+
if [[ "$LACY_SHELL_TYPE" == "zsh" ]]; then
|
|
33
|
+
name="${LACY_SPINNER_ANIMATIONS[$(( (RANDOM % count) + 1 ))]}"
|
|
34
|
+
else
|
|
35
|
+
name="${LACY_SPINNER_ANIMATIONS[$(( RANDOM % count ))]}"
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
case "$name" in
|
|
40
|
+
braille)
|
|
41
|
+
# Classic rotating dots
|
|
42
|
+
LACY_SPINNER_ANIM=("⠋⠀⠀⠀" "⠙⠀⠀⠀" "⠹⠀⠀⠀" "⠸⠀⠀⠀" "⠼⠀⠀⠀" "⠴⠀⠀⠀"
|
|
43
|
+
"⠦⠀⠀⠀" "⠧⠀⠀⠀" "⠇⠀⠀⠀" "⠏⠀⠀⠀")
|
|
44
|
+
;;
|
|
45
|
+
dots)
|
|
46
|
+
# Single dot traveling all 8 braille positions
|
|
47
|
+
LACY_SPINNER_ANIM=("⠁⠀⠀⠀" "⠂⠀⠀⠀" "⠄⠀⠀⠀" "⡀⠀⠀⠀" "⢀⠀⠀⠀" "⠠⠀⠀⠀"
|
|
48
|
+
"⠐⠀⠀⠀" "⠈⠀⠀⠀")
|
|
49
|
+
;;
|
|
50
|
+
ascii)
|
|
51
|
+
# ASCII-only fallback for terminals without Unicode
|
|
52
|
+
LACY_SPINNER_ANIM=("| " "/ " "- " "\\ ")
|
|
53
|
+
;;
|
|
54
|
+
braillewave)
|
|
55
|
+
# Traveling dot wave
|
|
56
|
+
LACY_SPINNER_ANIM=("⠁⠂⠄⡀" "⠂⠄⡀⢀" "⠄⡀⢀⠠" "⡀⢀⠠⠐" "⢀⠠⠐⠈" "⠠⠐⠈⠁"
|
|
57
|
+
"⠐⠈⠁⠂" "⠈⠁⠂⠄")
|
|
58
|
+
;;
|
|
59
|
+
dna)
|
|
60
|
+
# DNA helix strand
|
|
61
|
+
LACY_SPINNER_ANIM=("⠋⠉⠙⠚" "⠉⠙⠚⠒" "⠙⠚⠒⠂" "⠚⠒⠂⠂" "⠒⠂⠂⠒" "⠂⠂⠒⠲"
|
|
62
|
+
"⠂⠒⠲⠴" "⠒⠲⠴⠤" "⠲⠴⠤⠄" "⠴⠤⠄⠋" "⠤⠄⠋⠉" "⠄⠋⠉⠙")
|
|
63
|
+
;;
|
|
64
|
+
scan)
|
|
65
|
+
# Lit column scanning across (8×4 grid)
|
|
66
|
+
LACY_SPINNER_ANIM=("⠀⠀⠀⠀" "⡇⠀⠀⠀" "⣿⠀⠀⠀" "⢸⡇⠀⠀" "⠀⣿⠀⠀" "⠀⢸⡇⠀"
|
|
67
|
+
"⠀⠀⣿⠀" "⠀⠀⢸⡇" "⠀⠀⠀⣿" "⠀⠀⠀⢸")
|
|
68
|
+
;;
|
|
69
|
+
rain)
|
|
70
|
+
# Dots falling at staggered heights (8×4 grid)
|
|
71
|
+
LACY_SPINNER_ANIM=("⢁⠂⠔⠈" "⠂⠌⡠⠐" "⠄⡐⢀⠡" "⡈⠠⠀⢂" "⠐⢀⠁⠄" "⠠⠁⠊⡀"
|
|
72
|
+
"⢁⠂⠔⠈" "⠂⠌⡠⠐" "⠄⡐⢀⠡" "⡈⠠⠀⢂" "⠐⢀⠁⠄" "⠠⠁⠊⡀")
|
|
73
|
+
;;
|
|
74
|
+
scanline)
|
|
75
|
+
# Horizontal line bouncing up and down (6×4 grid)
|
|
76
|
+
LACY_SPINNER_ANIM=("⠉⠉⠉⠀" "⠓⠓⠓⠀" "⠦⠦⠦⠀" "⣄⣄⣄⠀" "⠦⠦⠦⠀" "⠓⠓⠓⠀")
|
|
77
|
+
;;
|
|
78
|
+
pulse)
|
|
79
|
+
# Expanding/contracting ring (6×4 grid)
|
|
80
|
+
LACY_SPINNER_ANIM=("⠀⠶⠀⠀" "⠰⣿⠆⠀" "⢾⣉⡷⠀" "⣏⠀⣹⠀" "⡁⠀⢈⠀")
|
|
81
|
+
;;
|
|
82
|
+
snake)
|
|
83
|
+
# Snake traversing a 4×4 grid
|
|
84
|
+
LACY_SPINNER_ANIM=("⣁⡀⠀⠀" "⣉⠀⠀⠀" "⡉⠁⠀⠀" "⠉⠉⠀⠀" "⠈⠙⠀⠀" "⠀⠛⠀⠀"
|
|
85
|
+
"⠐⠚⠀⠀" "⠒⠒⠀⠀" "⠖⠂⠀⠀" "⠶⠀⠀⠀" "⠦⠄⠀⠀" "⠤⠤⠀⠀"
|
|
86
|
+
"⠠⢤⠀⠀" "⠀⣤⠀⠀" "⢀⣠⠀⠀" "⣀⣀⠀⠀")
|
|
87
|
+
;;
|
|
88
|
+
sparkle)
|
|
89
|
+
# Pseudo-random twinkling dots (8×4 grid)
|
|
90
|
+
LACY_SPINNER_ANIM=("⡡⠊⢔⠡" "⠊⡰⡡⡘" "⢔⢅⠈⢢" "⡁⢂⠆⡍" "⢔⠨⢑⢐" "⠨⡑⡠⠊")
|
|
91
|
+
;;
|
|
92
|
+
cascade)
|
|
93
|
+
# Diagonal wave sweeping across (8×4 grid)
|
|
94
|
+
LACY_SPINNER_ANIM=("⠀⠀⠀⠀" "⠀⠀⠀⠀" "⠁⠀⠀⠀" "⠋⠀⠀⠀" "⠞⠁⠀⠀" "⡴⠋⠀⠀"
|
|
95
|
+
"⣠⠞⠁⠀" "⢀⡴⠋⠀" "⠀⣠⠞⠁" "⠀⢀⡴⠋" "⠀⠀⣠⠞" "⠀⠀⢀⡴"
|
|
96
|
+
"⠀⠀⠀⣠" "⠀⠀⠀⢀")
|
|
97
|
+
;;
|
|
98
|
+
columns)
|
|
99
|
+
# Columns filling left to right (6×4 grid)
|
|
100
|
+
LACY_SPINNER_ANIM=("⡀⠀⠀⠀" "⡄⠀⠀⠀" "⡆⠀⠀⠀" "⡇⠀⠀⠀" "⣇⠀⠀⠀" "⣧⠀⠀⠀"
|
|
101
|
+
"⣷⠀⠀⠀" "⣿⠀⠀⠀" "⣿⡀⠀⠀" "⣿⡄⠀⠀" "⣿⡆⠀⠀" "⣿⡇⠀⠀"
|
|
102
|
+
"⣿⣇⠀⠀" "⣿⣧⠀⠀" "⣿⣷⠀⠀" "⣿⣿⠀⠀" "⣿⣿⡀⠀" "⣿⣿⡄⠀"
|
|
103
|
+
"⣿⣿⡆⠀" "⣿⣿⡇⠀" "⣿⣿⣇⠀" "⣿⣿⣧⠀" "⣿⣿⣷⠀" "⣿⣿⣿⠀"
|
|
104
|
+
"⣿⣿⣿⠀" "⠀⠀⠀⠀")
|
|
105
|
+
;;
|
|
106
|
+
orbit)
|
|
107
|
+
# Two dots circling a 2×4 cell
|
|
108
|
+
LACY_SPINNER_ANIM=("⠃⠀⠀⠀" "⠉⠀⠀⠀" "⠘⠀⠀⠀" "⠰⠀⠀⠀" "⢠⠀⠀⠀" "⣀⠀⠀⠀"
|
|
109
|
+
"⡄⠀⠀⠀" "⠆⠀⠀⠀")
|
|
110
|
+
;;
|
|
111
|
+
breathe)
|
|
112
|
+
# Dots filling and draining diagonally
|
|
113
|
+
LACY_SPINNER_ANIM=("⠀⠀⠀⠀" "⠂⠀⠀⠀" "⠌⠀⠀⠀" "⡑⠀⠀⠀" "⢕⠀⠀⠀" "⢝⠀⠀⠀"
|
|
114
|
+
"⣫⠀⠀⠀" "⣟⠀⠀⠀" "⣿⠀⠀⠀" "⣟⠀⠀⠀" "⣫⠀⠀⠀" "⢝⠀⠀⠀"
|
|
115
|
+
"⢕⠀⠀⠀" "⡑⠀⠀⠀" "⠌⠀⠀⠀" "⠂⠀⠀⠀" "⠀⠀⠀⠀")
|
|
116
|
+
;;
|
|
117
|
+
waverows)
|
|
118
|
+
# Sine wave traveling across (8×4 grid)
|
|
119
|
+
LACY_SPINNER_ANIM=("⠖⠉⠉⠑" "⡠⠖⠉⠉" "⣠⡠⠖⠉" "⣄⣠⡠⠖" "⠢⣄⣠⡠" "⠙⠢⣄⣠"
|
|
120
|
+
"⠉⠙⠢⣄" "⠊⠉⠙⠢" "⠜⠊⠉⠙" "⡤⠜⠊⠉" "⣀⡤⠜⠊" "⢤⣀⡤⠜"
|
|
121
|
+
"⠣⢤⣀⡤" "⠑⠣⢤⣀" "⠉⠑⠣⢤" "⠋⠉⠑⠣")
|
|
122
|
+
;;
|
|
123
|
+
checkerboard)
|
|
124
|
+
# Alternating patterns (6×4 grid)
|
|
125
|
+
LACY_SPINNER_ANIM=("⢕⢕⢕⠀" "⡪⡪⡪⠀" "⢊⠔⡡⠀" "⡡⢊⠔⠀")
|
|
126
|
+
;;
|
|
127
|
+
helix)
|
|
128
|
+
# Double helix — two sine strands crossing (8×4 grid)
|
|
129
|
+
LACY_SPINNER_ANIM=("⢌⣉⢎⣉" "⣉⡱⣉⡱" "⣉⢎⣉⢎" "⡱⣉⡱⣉" "⢎⣉⢎⣉" "⣉⡱⣉⡱"
|
|
130
|
+
"⣉⢎⣉⢎" "⡱⣉⡱⣉" "⢎⣉⢎⣉" "⣉⡱⣉⡱" "⣉⢎⣉⢎" "⡱⣉⡱⣉"
|
|
131
|
+
"⢎⣉⢎⣉" "⣉⡱⣉⡱" "⣉⢎⣉⢎" "⡱⣉⡱⣉")
|
|
132
|
+
;;
|
|
133
|
+
fillsweep)
|
|
134
|
+
# Rows filling then draining (4×4 grid)
|
|
135
|
+
LACY_SPINNER_ANIM=("⣀⣀⠀⠀" "⣤⣤⠀⠀" "⣶⣶⠀⠀" "⣿⣿⠀⠀" "⣿⣿⠀⠀" "⣿⣿⠀⠀"
|
|
136
|
+
"⣶⣶⠀⠀" "⣤⣤⠀⠀" "⣀⣀⠀⠀" "⠀⠀⠀⠀" "⠀⠀⠀⠀")
|
|
137
|
+
;;
|
|
138
|
+
diagswipe)
|
|
139
|
+
# Diagonal fill and clear (4×4 grid)
|
|
140
|
+
LACY_SPINNER_ANIM=("⠁⠀⠀⠀" "⠋⠀⠀⠀" "⠟⠁⠀⠀" "⡿⠋⠀⠀" "⣿⠟⠀⠀" "⣿⡿⠀⠀"
|
|
141
|
+
"⣿⣿⠀⠀" "⣿⣿⠀⠀" "⣾⣿⠀⠀" "⣴⣿⠀⠀" "⣠⣾⠀⠀" "⢀⣴⠀⠀"
|
|
142
|
+
"⠀⣠⠀⠀" "⠀⢀⠀⠀" "⠀⠀⠀⠀" "⠀⠀⠀⠀")
|
|
143
|
+
;;
|
|
144
|
+
*)
|
|
145
|
+
# Unknown — fall back to braille
|
|
146
|
+
LACY_SPINNER_ANIM=("⠋⠀⠀⠀" "⠙⠀⠀⠀" "⠹⠀⠀⠀" "⠸⠀⠀⠀" "⠼⠀⠀⠀" "⠴⠀⠀⠀"
|
|
147
|
+
"⠦⠀⠀⠀" "⠧⠀⠀⠀" "⠇⠀⠀⠀" "⠏⠀⠀⠀")
|
|
148
|
+
;;
|
|
149
|
+
esac
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# Preview all animations simultaneously
|
|
153
|
+
# Each animation shown on its own line with its name as the shimmer label
|
|
154
|
+
lacy_preview_all_spinners() {
|
|
155
|
+
local duration="${1:-4}"
|
|
156
|
+
local delay="${LACY_SPINNER_FRAME_DELAY:-0.05}"
|
|
157
|
+
local num_anims=${#LACY_SPINNER_ANIMATIONS[@]}
|
|
158
|
+
local arr_off=${_LACY_ARR_OFFSET:-0}
|
|
159
|
+
|
|
160
|
+
# Shimmer colors — ZSH doesn't word-split $var, use ${=var}
|
|
161
|
+
local -a shimmer_colors
|
|
162
|
+
if [[ "$LACY_SHELL_TYPE" == "zsh" ]]; then
|
|
163
|
+
shimmer_colors=("${LACY_COLOR_SHIMMER[@]}")
|
|
164
|
+
else
|
|
165
|
+
shimmer_colors=("${LACY_COLOR_SHIMMER[@]}")
|
|
166
|
+
fi
|
|
167
|
+
local num_colors=${#shimmer_colors[@]}
|
|
168
|
+
|
|
169
|
+
# Declare ALL loop variables here — ZSH's local/typeset prints values
|
|
170
|
+
# when re-declared inside a loop, causing garbage output
|
|
171
|
+
local _n _a _name _nf _fidx _spinner _text_len _shimmer _center
|
|
172
|
+
local _i _char _dist _cidx _color _dots_phase _dots
|
|
173
|
+
local _loop_start _loop_end
|
|
174
|
+
local frame_num=0
|
|
175
|
+
local start=$SECONDS
|
|
176
|
+
|
|
177
|
+
# Hide cursor
|
|
178
|
+
printf '\e[?25l'
|
|
179
|
+
|
|
180
|
+
# Print initial blank lines
|
|
181
|
+
for ((_n = 0; _n < num_anims; _n++)); do
|
|
182
|
+
printf '\n'
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
if [[ "$LACY_SHELL_TYPE" == "zsh" ]]; then
|
|
186
|
+
_loop_start=1; _loop_end=$num_anims
|
|
187
|
+
else
|
|
188
|
+
_loop_start=0; _loop_end=$((num_anims - 1))
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
while (( SECONDS - start < duration )); do
|
|
192
|
+
# Move cursor up to first line
|
|
193
|
+
printf '\e[%dA' "$num_anims"
|
|
194
|
+
|
|
195
|
+
for ((_a = _loop_start; _a <= _loop_end; _a++)); do
|
|
196
|
+
_name="${LACY_SPINNER_ANIMATIONS[$_a]}"
|
|
197
|
+
|
|
198
|
+
# Load this animation's frames
|
|
199
|
+
lacy_set_spinner_animation "$_name"
|
|
200
|
+
_nf=${#LACY_SPINNER_ANIM[@]}
|
|
201
|
+
|
|
202
|
+
if [[ "$LACY_SHELL_TYPE" == "zsh" ]]; then
|
|
203
|
+
_fidx=$(( (frame_num % _nf) + 1 ))
|
|
204
|
+
else
|
|
205
|
+
_fidx=$(( frame_num % _nf ))
|
|
206
|
+
fi
|
|
207
|
+
_spinner="${LACY_SPINNER_ANIM[$_fidx]}"
|
|
208
|
+
|
|
209
|
+
# Build shimmer text for the animation name
|
|
210
|
+
_text_len=${#_name}
|
|
211
|
+
_shimmer=""
|
|
212
|
+
_center=$(( frame_num % (_text_len + 4) ))
|
|
213
|
+
|
|
214
|
+
for ((_i = 0; _i < _text_len; _i++)); do
|
|
215
|
+
if [[ "$LACY_SHELL_TYPE" == "zsh" ]]; then
|
|
216
|
+
_char="${_name[$((_i + 1))]}"
|
|
217
|
+
else
|
|
218
|
+
_char="${_name:$_i:1}"
|
|
219
|
+
fi
|
|
220
|
+
_dist=$(( _center - _i ))
|
|
221
|
+
(( _dist < 0 )) && _dist=$(( -_dist ))
|
|
222
|
+
|
|
223
|
+
if (( _dist < num_colors )); then
|
|
224
|
+
_cidx=$(( _dist + arr_off ))
|
|
225
|
+
else
|
|
226
|
+
_cidx=$(( num_colors - 1 + arr_off ))
|
|
227
|
+
fi
|
|
228
|
+
_color=${shimmer_colors[$_cidx]}
|
|
229
|
+
_shimmer+="\e[38;5;${_color}m${_char}"
|
|
230
|
+
done
|
|
231
|
+
_shimmer+="\e[0m"
|
|
232
|
+
|
|
233
|
+
# Cycling dots
|
|
234
|
+
_dots_phase=$(( (frame_num / 3) % 4 ))
|
|
235
|
+
_dots=""
|
|
236
|
+
case $_dots_phase in
|
|
237
|
+
1) _dots="." ;; 2) _dots=".." ;; 3) _dots="..." ;;
|
|
238
|
+
esac
|
|
239
|
+
|
|
240
|
+
printf "\e[2K\r \e[38;5;${LACY_COLOR_AGENT}m%s\e[0m %b\e[38;5;${LACY_COLOR_NEUTRAL}m%s\e[0m\n" \
|
|
241
|
+
"$_spinner" "$_shimmer" "$_dots"
|
|
242
|
+
done
|
|
243
|
+
|
|
244
|
+
frame_num=$((frame_num + 1))
|
|
245
|
+
sleep "$delay"
|
|
246
|
+
done
|
|
247
|
+
|
|
248
|
+
# Show cursor
|
|
249
|
+
printf '\e[?25h'
|
|
250
|
+
|
|
251
|
+
# Restore active spinner
|
|
252
|
+
lacy_set_spinner_animation "${LACY_SPINNER_STYLE:-braille}"
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
# List available animations
|
|
256
|
+
lacy_list_spinner_animations() {
|
|
257
|
+
local current="${LACY_SPINNER_STYLE:-braille}"
|
|
258
|
+
local name
|
|
259
|
+
for name in "${LACY_SPINNER_ANIMATIONS[@]}"; do
|
|
260
|
+
if [[ "$name" == "$current" ]]; then
|
|
261
|
+
lacy_print_color "$LACY_COLOR_AGENT" " ● $name (active)"
|
|
262
|
+
else
|
|
263
|
+
lacy_print_color "$LACY_COLOR_NEUTRAL" " ○ $name"
|
|
264
|
+
fi
|
|
265
|
+
done
|
|
266
|
+
if [[ "$current" == "random" ]]; then
|
|
267
|
+
lacy_print_color "$LACY_COLOR_AGENT" " ● random (active)"
|
|
268
|
+
else
|
|
269
|
+
lacy_print_color "$LACY_COLOR_NEUTRAL" " ○ random"
|
|
270
|
+
fi
|
|
271
|
+
}
|