@kecan0406/ttheme 1.2.2 → 1.2.4

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.2",
2
+ "version": "1.2.4",
3
3
  "gate": [
4
4
  {
5
5
  "rule": "foreground",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kecan0406/ttheme",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "ttheme": "bin/ttheme.js"
@@ -37,6 +37,7 @@
37
37
  "@material/material-color-utilities": "^0.4.0",
38
38
  "@types/bun": "^1.3.0",
39
39
  "@types/pngjs": "6.0.5",
40
+ "@xterm/headless": "6.0.0",
40
41
  "fast-string-width": "^3.0.2",
41
42
  "jpeg-js": "^0.4.4",
42
43
  "pngjs": "7.0.0",
@@ -55,6 +55,8 @@ __tt_reloaded() { : }
55
55
 
56
56
  __tt_worn() { : }
57
57
 
58
+ __tt_blurred() { : }
59
+
58
60
  __tt_keepable() { return 1 }
59
61
 
60
62
  __tt_paints() { return 0 }
@@ -63,6 +65,8 @@ __tt_unpainted() { : }
63
65
 
64
66
  __tt_follows_focus() { return 1 }
65
67
 
68
+ __tt_takes_default() { return 0 }
69
+
66
70
  __tt_follows_prompt() { return 1 }
67
71
 
68
72
  __tt_prompted() { : }
@@ -16,20 +16,28 @@ __tt_pictured() {
16
16
  return 0
17
17
  }
18
18
 
19
+ __tt_ghostty_owner() {
20
+ local pid=$1 ppid comm
21
+ REPLY=0
22
+ while (( pid > 1 )); do
23
+ read -r ppid comm <<< "$(ps -o ppid=,comm= -p $pid)"
24
+ if [[ ${comm:t} == ghostty ]]; then
25
+ REPLY=$pid
26
+ return 0
27
+ fi
28
+ pid=$ppid
29
+ done
30
+ return 1
31
+ }
32
+
19
33
  __tt_reload_ghostty() {
20
- local pid=$PPID ppid comm owner=$TTHEME_GHOSTTY_PID
21
- (( TTHEME_TMUX )) && { pid=$(tmux display -p '#{client_pid}' 2>/dev/null) owner="" }
22
- if [[ -z $owner ]]; then
23
- owner=0
24
- while (( pid > 1 )); do
25
- read -r ppid comm <<< "$(ps -o ppid=,comm= -p $pid)"
26
- if [[ ${comm:t} == ghostty ]]; then
27
- owner=$pid
28
- break
29
- fi
30
- pid=$ppid
31
- done
32
- (( TTHEME_TMUX )) || TTHEME_GHOSTTY_PID=$owner
34
+ local REPLY owner=$TTHEME_GHOSTTY_PID
35
+ if (( TTHEME_TMUX )); then
36
+ __tt_ghostty_owner "$(tmux display -p '#{client_pid}' 2>/dev/null)"
37
+ owner=$REPLY
38
+ elif [[ -z $owner ]]; then
39
+ __tt_ghostty_owner $PPID
40
+ owner=$REPLY TTHEME_GHOSTTY_PID=$REPLY
33
41
  fi
34
42
  (( owner )) && kill -USR2 $owner 2>/dev/null && return
35
43
  pkill -USR2 -x ghostty 2>/dev/null
@@ -1 +1,3 @@
1
1
  __tt_keepable() { (( ${TTHEME_TERMINALS[(Ie)alacritty]} )) }
2
+
3
+ __tt_follows_focus() { return 0 }
@@ -1,11 +1,204 @@
1
1
  source $TTHEME_HOME/adapters/_bg.zsh
2
2
 
3
+ typeset -g TTHEME_GHOSTTY_TABS=$TTHEME_STATE_DIR/ghostty TTHEME_GHOSTTY_FRONT="" TTHEME_GHOSTTY_BLUR=""
4
+ typeset -gF TTHEME_GHOSTTY_ASKED=0 TTHEME_GHOSTTY_WANT=0 TTHEME_GHOSTTY_HUSH=0
5
+ typeset -gi TTHEME_GHOSTTY_IDLE=1 TTHEME_GHOSTTY_TICK=0 TTHEME_GHOSTTY_NONE=0 TTHEME_GHOSTTY_FOLLOWS=-1
6
+ typeset -gA TTHEME_GHOSTTY_SEEN=() TTHEME_GHOSTTY_RUN=()
7
+ typeset -g TTHEME_GHOSTTY_JS='ObjC.import("AppKit");function run(v){var p=+v[0],E=$.NSAppleEventDescriptor,G="com.mitchellh.ghostty",f=function(s){return(s.charCodeAt(0)<<24)|(s.charCodeAt(1)<<16)|(s.charCodeAt(2)<<8)|s.charCodeAt(3)},a=p?$.NSRunningApplication.runningApplicationWithProcessIdentifier(p):$.NSRunningApplication.runningApplicationsWithBundleIdentifier(G).firstObject;if(!a||a.isNil())return"none";var s=$.NSString.stringWithContentsOfFileEncodingError(a.bundleURL.path.js+"/Contents/Resources/Ghostty.sdef",4,null);if(s.isNil()||s.js.indexOf("code=\"Gtty\"")<0)return"blind";var t=E.descriptorWithProcessIdentifier(a.processIdentifier);function q(c,o){var d=E.recordDescriptor;d.setDescriptorForKeyword(E.descriptorWithTypeCode(f("prop")),f("want"));d.setDescriptorForKeyword(o,f("from"));d.setDescriptorForKeyword(E.descriptorWithEnumCode(f("prop")),f("form"));d.setDescriptorForKeyword(E.descriptorWithTypeCode(f(c)),f("seld"));return d.coerceToDescriptorType(f("obj "))}function g(o){var e=E.appleEventWithEventClassEventIDTargetDescriptorReturnIDTransactionID(f("core"),f("getd"),t,-1,0);e.setParamDescriptorForKeyword(o,f("----"));var r=e.sendEventWithOptionsTimeoutError(3,5,null);return!r||r.isNil()||!r.paramDescriptorForKeyword(f("errn")).isNil()?null:r.paramDescriptorForKeyword(f("----"))}var n=E.nullDescriptor,m=q("GTfT",q("GWsT",q("GFWn",n))),w=g(q("pisf",n)),y=g(q("Gtty",m)),i=g(q("Gpid",m));if(!w||!y||!i||w.isNil()||y.isNil()||i.isNil())return"none";return(w.booleanValue?1:0)+" "+y.stringValue.js+" "+i.int32Value}'
8
+
3
9
  __tt_follows_focus() { return 0 }
4
10
 
11
+ __tt_follows_prompt() { return 0 }
12
+
5
13
  __tt_keepable() { return 0 }
6
14
 
7
15
  __tt_bg_shown() { __tt_ghostty_shown }
8
16
 
17
+ __tt_ghostty_key() { REPLY=${${1#/dev/}//\//-} }
18
+
19
+ __tt_ghostty_wears() {
20
+ REPLY=""
21
+ [[ -n $1 ]] && __tt_name_of "$1"
22
+ [[ -n ${TTHEME_PALETTE[$REPLY]} ]] || REPLY=""
23
+ }
24
+
25
+ __tt_ghostty_modules() {
26
+ zmodload -F zsh/files b:zf_rm b:zf_mkdir
27
+ zmodload -F zsh/zselect b:zselect
28
+ zmodload -F zsh/datetime p:EPOCHREALTIME p:EPOCHSECONDS
29
+ } 2>/dev/null
30
+
31
+ __tt_ghostty_follows() {
32
+ local -a at
33
+ (( TTHEME_GHOSTTY_FOLLOWS < 0 )) || return $(( ! TTHEME_GHOSTTY_FOLLOWS ))
34
+ TTHEME_GHOSTTY_FOLLOWS=0
35
+ [[ $TERM_PROGRAM == ghostty && -o interactive && -n $TTY ]] && (( $+commands[osascript] && ! TTHEME_TMUX )) || return 1
36
+ if zstat -A at +mtime -- $TTHEME_GHOSTTY_TABS/.blind 2>/dev/null && [[ "$(<$TTHEME_GHOSTTY_TABS/.blind)" == "${TERM_PROGRAM_VERSION:--}" ]]; then
37
+ zmodload -F zsh/datetime p:EPOCHSECONDS 2>/dev/null
38
+ (( EPOCHSECONDS - at[1] < 86400 )) && return 1
39
+ fi
40
+ TTHEME_GHOSTTY_FOLLOWS=1
41
+ }
42
+
43
+ __tt_ghostty_publish() {
44
+ local f line REPLY
45
+ __tt_ghostty_follows || return 0
46
+ line="$$ ${TTHEME_STARTUP:--} ${1:--} $TTY"
47
+ __tt_ghostty_key $TTY
48
+ f=$TTHEME_GHOSTTY_TABS/$REPLY
49
+ [[ -r $f && "$(<$f)" == "$line" ]] && return 0
50
+ if [[ ! -d $TTHEME_GHOSTTY_TABS ]]; then
51
+ zmodload -F zsh/files b:zf_mkdir 2>/dev/null
52
+ zf_mkdir -p $TTHEME_GHOSTTY_TABS 2>/dev/null || return 0
53
+ fi
54
+ __tt_put $f "$line" 2>/dev/null
55
+ return 0
56
+ }
57
+
58
+ __tt_worn() {
59
+ local REPLY
60
+ (( TTHEME_RAW )) && return 0
61
+ __tt_ghostty_wears "$1"
62
+ __tt_ghostty_publish "$REPLY"
63
+ }
64
+
65
+ __tt_prompted() {
66
+ emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
67
+ local REPLY
68
+ __tt_ghostty_wears "$TTHEME_SPEC"
69
+ __tt_ghostty_publish "$REPLY"
70
+ __tt_ghostty_follow
71
+ }
72
+
73
+ __tt_blurred() {
74
+ __tt_ghostty_follows && [[ -d $TTHEME_GHOSTTY_TABS ]] && : >| $TTHEME_GHOSTTY_TABS/.blur 2>/dev/null
75
+ return 0
76
+ }
77
+
78
+ __tt_ghostty_follow() {
79
+ local fd lock=$TTHEME_GHOSTTY_TABS/.follow
80
+ __tt_ghostty_follows && [[ -d $TTHEME_GHOSTTY_TABS ]] || return 0
81
+ if [[ -e $TTHEME_GHOSTTY_TABS/.blind ]]; then
82
+ TTHEME_GHOSTTY_FOLLOWS=-1
83
+ __tt_ghostty_follows || return 0
84
+ fi
85
+ [[ -e $lock ]] || : >>| $lock 2>/dev/null || return 0
86
+ zsystem flock -t 0 -f fd $lock 2>/dev/null || return 0
87
+ zsystem flock -u $fd
88
+ zsh -fc 'source $1; __tt_ghostty_follower' zsh $TTHEME_HOME/ttheme.zsh </dev/null >/dev/null 2>&1 &!
89
+ }
90
+
91
+ __tt_ghostty_ask() {
92
+ REPLY=$(osascript -l JavaScript -e $TTHEME_GHOSTTY_JS ${TTHEME_GHOSTTY_PID:-0} 2>/dev/null)
93
+ TTHEME_GHOSTTY_ASKED=$EPOCHREALTIME
94
+ [[ -n $REPLY ]]
95
+ }
96
+
97
+ __tt_ghostty_check() {
98
+ local REPLY shown key pal conf=${TTHEME_CONFIG:h}/backgrounds/shown.conf
99
+ local -a at ans rec
100
+ integer n
101
+ __tt_ghostty_modules
102
+ for (( n = 0; n < 3; n++ )); do
103
+ at=("")
104
+ zstat -F %s.%N -A at +mtime -- $conf 2>/dev/null
105
+ shown=$at[1]
106
+ __tt_ghostty_ask || return 0
107
+ at=("")
108
+ zstat -F %s.%N -A at +mtime -- $conf 2>/dev/null
109
+ [[ $at[1] == "$shown" ]] && break
110
+ done
111
+ if [[ $REPLY == blind ]] || { [[ $REPLY == none ]] && (( ++TTHEME_GHOSTTY_NONE >= 5 )) }; then
112
+ __tt_put $TTHEME_GHOSTTY_TABS/.blind "${TERM_PROGRAM_VERSION:--}" 2>/dev/null
113
+ return 1
114
+ fi
115
+ [[ $REPLY == none ]] && return 0
116
+ TTHEME_GHOSTTY_NONE=0
117
+ ans=(${=REPLY})
118
+ if [[ $ans[1] != 1 || -z $ans[2] ]]; then
119
+ TTHEME_GHOSTTY_FRONT=""
120
+ return 0
121
+ fi
122
+ __tt_ghostty_key $ans[2]
123
+ key=$REPLY
124
+ TTHEME_GHOSTTY_FRONT=$key TTHEME_GHOSTTY_IDLE=1
125
+ [[ -r $TTHEME_GHOSTTY_TABS/$key ]] || return 0
126
+ rec=(${=${"$(<$TTHEME_GHOSTTY_TABS/$key)"}})
127
+ [[ $rec[1] == "$ans[3]" ]] || TTHEME_GHOSTTY_IDLE=0
128
+ pal=${rec[3]#-}
129
+ [[ $rec[2] != - && -z $TTHEME_STARTUP ]] && pal=""
130
+ [[ -n $pal && -n ${TTHEME_PALETTE[$pal]} ]] || return 0
131
+ __tt_shown "$pal" force && __tt_reload_ghostty
132
+ return 0
133
+ }
134
+
135
+ __tt_ghostty_tick() {
136
+ local f key
137
+ local -a at rec
138
+ local -F now=$EPOCHREALTIME
139
+ integer seen
140
+ zstat -F %s.%N -A at +mtime -- $TTHEME_HOME/palettes.zsh 2>/dev/null && [[ $at[1] != "$TTHEME_PALETTES_AT" ]] && __tt_palettes_load
141
+ if zstat -F %s.%N -A at +mtime -- $TTHEME_GHOSTTY_TABS/.blur 2>/dev/null && [[ $at[1] != "$TTHEME_GHOSTTY_BLUR" ]]; then
142
+ [[ -n $TTHEME_GHOSTTY_BLUR ]] && TTHEME_GHOSTTY_WANT=$now
143
+ TTHEME_GHOSTTY_BLUR=$at[1]
144
+ fi
145
+ for f in $TTHEME_GHOSTTY_TABS/[^.]*(N); do
146
+ key=${f:t}
147
+ rec=(${=${"$(<$f)"}})
148
+ zstat -F %s.%N -A at +atime -- ${rec[4]:-/nonexistent} 2>/dev/null || continue
149
+ if [[ $at[1] == "${TTHEME_GHOSTTY_SEEN[$key]}" ]]; then
150
+ TTHEME_GHOSTTY_RUN[$key]=0
151
+ continue
152
+ fi
153
+ seen=${+TTHEME_GHOSTTY_SEEN[$key]}
154
+ TTHEME_GHOSTTY_SEEN[$key]=$at[1]
155
+ (( seen )) || continue
156
+ if [[ $key == "$TTHEME_GHOSTTY_FRONT" ]]; then
157
+ TTHEME_GHOSTTY_HUSH=$now
158
+ elif (( ++TTHEME_GHOSTTY_RUN[$key] < 5 )); then
159
+ TTHEME_GHOSTTY_WANT=$now
160
+ fi
161
+ done
162
+ if (( TTHEME_GHOSTTY_HUSH && now - TTHEME_GHOSTTY_HUSH >= 0.3 && now - TTHEME_GHOSTTY_ASKED >= (TTHEME_GHOSTTY_IDLE ? 10 : 2) )); then
163
+ TTHEME_GHOSTTY_HUSH=0 TTHEME_GHOSTTY_WANT=$now
164
+ fi
165
+ (( TTHEME_GHOSTTY_WANT && now - TTHEME_GHOSTTY_ASKED >= 0.2 )) || return 0
166
+ TTHEME_GHOSTTY_WANT=0
167
+ __tt_ghostty_check
168
+ }
169
+
170
+ __tt_ghostty_live() {
171
+ local f pid
172
+ integer live=0
173
+ (( TTHEME_GHOSTTY_PID )) && ! kill -0 $TTHEME_GHOSTTY_PID 2>/dev/null && return 1
174
+ for f in $TTHEME_GHOSTTY_TABS/[^.]*(N); do
175
+ pid=${"$(<$f)"%% *}
176
+ if [[ $pid == <-> ]] && kill -0 $pid 2>/dev/null; then
177
+ live=1
178
+ else
179
+ zf_rm -f -- $f 2>/dev/null
180
+ unset "TTHEME_GHOSTTY_SEEN[${f:t}]" "TTHEME_GHOSTTY_RUN[${f:t}]"
181
+ fi
182
+ done
183
+ (( live ))
184
+ }
185
+
186
+ __tt_ghostty_follower() {
187
+ emulate -L zsh
188
+ local fd REPLY
189
+ __tt_ghostty_modules
190
+ zsystem flock -t 0 -f fd $TTHEME_GHOSTTY_TABS/.follow 2>/dev/null || return 0
191
+ trap '' HUP
192
+ __tt_ghostty_owner $PPID
193
+ TTHEME_GHOSTTY_PID=$REPLY
194
+ __tt_ghostty_check || return 0
195
+ while [[ -e $TTHEME_HOME/palettes.zsh ]]; do
196
+ __tt_ghostty_tick || break
197
+ (( ++TTHEME_GHOSTTY_TICK % 50 )) || __tt_ghostty_live || break
198
+ zselect -t 10
199
+ done
200
+ }
201
+
9
202
  __tt_reset_reloaded() {
10
203
  local REPLY
11
204
  integer i
@@ -21,6 +214,8 @@ __tt_reset_reloaded() {
21
214
 
22
215
  __tt_shown() {
23
216
  local dir=${TTHEME_CONFIG:h}/backgrounds was REPLY
217
+ __tt_ghostty_publish "$1"
218
+ [[ $2 == force ]] || (( TTHEME_FRONT || TTHEME_TMUX )) || return 1
24
219
  __tt_bg_shown
25
220
  was=$REPLY
26
221
  [[ $was == $1 ]] && return 1
@@ -1,17 +1,35 @@
1
1
  source $TTHEME_HOME/adapters/_bg.zsh
2
2
 
3
3
  if (( ! ${+TTHEME_ITERM_SHOWN} )); then
4
- typeset -gx TTHEME_ITERM_SHOWN=""
4
+ typeset -gx TTHEME_ITERM_SHOWN="" TTHEME_ITERM_DYED=0
5
5
  [[ $ITERM_PROFILE == 'ttheme · '* ]] && TTHEME_ITERM_SHOWN=${ITERM_PROFILE#ttheme · }
6
6
  fi
7
7
 
8
8
  __tt_keepable() { return 0 }
9
9
 
10
+ __tt_follows_focus() { return 0 }
11
+
12
+ __tt_takes_default() {
13
+ local REPLY was=$TTHEME_ITERM_SHOWN
14
+ (( ! TTHEME_ITERM_DYED )) || return 1
15
+ (( TTHEME_TMUX )) && was=$(tmux show -qv @ttheme_shown 2>/dev/null)
16
+ [[ $was == default ]] && return 0
17
+ [[ -z $was ]] && __tt_hear && [[ $REPLY == ${TTHEME_PALETTE[$TTHEME_STARTUP]%% *} ]] || return 1
18
+ TTHEME_ITERM_SHOWN=default
19
+ (( TTHEME_TMUX )) && tmux set -q @ttheme_shown default 2>/dev/null
20
+ return 0
21
+ }
22
+
23
+ __tt_worn() { [[ -z $1 ]] || TTHEME_ITERM_DYED=1 }
24
+
10
25
  __tt_pv_paint() {
11
26
  local -a p=(${=1})
12
27
  if (( ${#p} < 20 )); then
13
28
  __tt_out $'\e]110\e\\\e]111\e\\'
14
- elif [[ $p[1] == - ]]; then
29
+ return 0
30
+ fi
31
+ TTHEME_ITERM_DYED=1
32
+ if [[ $p[1] == - ]]; then
15
33
  __tt_out $'\e]111\e\\\e]10;'$p[2]$'\e\\'
16
34
  else
17
35
  __tt_out $'\e]11;'$p[1]$'\e\\\e]10;'$p[2]$'\e\\'
@@ -34,7 +52,7 @@ __tt_shown() {
34
52
  [[ -r $dir/${${1/@/--}/\//--}.conf || ( -n $was && -r $dir/${${was/@/--}/\//--}.conf ) ]] || (( TTHEME_MUXED )) || return 1
35
53
  (( ${TTHEME_ORDER[(Ie)$1]} )) || return 1
36
54
  __tt_out $'\e]1337;SetProfile=ttheme · '$1$'\a'
37
- TTHEME_ITERM_SHOWN=$1
55
+ TTHEME_ITERM_SHOWN=$1 TTHEME_ITERM_DYED=0
38
56
  (( TTHEME_TMUX )) && tmux set -q @ttheme_shown $1 2>/dev/null
39
57
  return 1
40
58
  }
@@ -44,7 +62,7 @@ __tt_unshown() {
44
62
  (( TTHEME_TMUX )) && was=$(tmux show -qv @ttheme_shown 2>/dev/null)
45
63
  [[ $1 != force && $was == "$want" ]] && return 0
46
64
  __tt_out $'\e]1337;SetProfile=\a'
47
- TTHEME_ITERM_SHOWN=$want
65
+ TTHEME_ITERM_SHOWN=$want TTHEME_ITERM_DYED=0
48
66
  (( TTHEME_TMUX )) && tmux set -q @ttheme_shown "$want" 2>/dev/null
49
67
  return 0
50
68
  }
@@ -6,6 +6,10 @@ __tt_unpainted() {
6
6
 
7
7
  __tt_keepable() { __tt_paints }
8
8
 
9
+ __tt_takes_default() { __tt_osc_reset }
10
+
11
+ __tt_follows_focus() { return 0 }
12
+
9
13
  __tt_scheme() {
10
14
  local -a p=(${=TTHEME_PALETTE[$1]})
11
15
  REPLY="ColorScheme=ttheme-${${1/@/--}/\//--};UseCustomCursorColor=true;customCursorColor=$p[3]"
@@ -21,6 +21,8 @@ __tt_hear() {
21
21
 
22
22
  __tt_heard() { TTHEME_TERMINAL_BASE=$1 }
23
23
 
24
+ __tt_takes_default() { return 1 }
25
+
24
26
  __tt_osc_reset() {
25
27
  [[ -n $TTHEME_TERMINAL_BASE ]] && __tt_osc_apply "$TTHEME_TERMINAL_BASE"
26
28
  unset TTHEME_PAINTED
@@ -4,6 +4,8 @@ typeset -g TTHEME_WEZTERM_SHOWN="" TTHEME_WEZTERM_VIEW=""
4
4
 
5
5
  __tt_keepable() { (( ${TTHEME_TERMINALS[(Ie)wezterm]} )) }
6
6
 
7
+ __tt_follows_focus() { return 0 }
8
+
7
9
  __tt_wezterm_var() {
8
10
  local REPLY
9
11
  __tt_b64s "$2"
@@ -1,5 +1,14 @@
1
1
  __tt_keepable() { (( ${TTHEME_TERMINALS[(Ie)windows-terminal]} )) }
2
2
 
3
- __tt_reloaded() { __tt_repaint }
3
+ __tt_reloaded() {
4
+ local REPLY
5
+ integer i
6
+ [[ -n $TTHEME_PAINTED ]] || return 0
7
+ for (( i = 0; i < 20; i++ )); do
8
+ __tt_query_bg && [[ ${(L)REPLY} == ${(L)${TTHEME_SPEC%% *}} ]] || break
9
+ sleep 0.05
10
+ done
11
+ __tt_repaint
12
+ }
4
13
 
5
14
  __tt_follows_focus() { return 0 }
package/shell/ttheme.zsh CHANGED
@@ -14,14 +14,32 @@ __tt_palettes_load() {
14
14
  __tt_fresh() {
15
15
  emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
16
16
  local -a at
17
- local was=$TTHEME_STARTUP
17
+ local was=$TTHEME_STARTUP start="$TTHEME_STARTUP ${TTHEME_PALETTE[$TTHEME_STARTUP]}"
18
18
  if ! zstat -F %s.%N -A at +mtime -- $TTHEME_HOME/palettes.zsh 2>/dev/null; then
19
19
  [[ -e $TTHEME_HOME ]] || __tt_gone
20
20
  return 0
21
21
  fi
22
- [[ $at[1] == "$TTHEME_PALETTES_AT" ]] && return 0
23
- __tt_palettes_load && __tt_reloaded
24
- [[ -n $was && -z $TTHEME_STARTUP && -n $TTHEME_SPEC ]] && __tt_active && __tt_off_here
22
+ if [[ $at[1] != "$TTHEME_PALETTES_AT" ]]; then
23
+ __tt_palettes_load && { __tt_follow "$start" && __tt_sync; __tt_reloaded }
24
+ [[ -n $was && -z $TTHEME_STARTUP && -n $TTHEME_SPEC ]] && __tt_active && __tt_off_here
25
+ fi
26
+ at=("")
27
+ zstat -F %s.%N -A at +mtime -- $TTHEME_PINS_FILE 2>/dev/null
28
+ [[ $at[1] == "$TTHEME_PINS_AT" ]] && return 0
29
+ __tt_pins_load
30
+ __tt_active && __tt_dir_sync
31
+ }
32
+
33
+ __tt_prompt() {
34
+ emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
35
+ (( TTHEME_FRONT < 0 )) || TTHEME_FRONT=0
36
+ __tt_fresh
37
+ }
38
+
39
+ __tt_follow() {
40
+ [[ -n $TTHEME_STARTUP && "$TTHEME_STARTUP ${TTHEME_PALETTE[$TTHEME_STARTUP]}" != "$1" && -z $TTHEME_PAINTED ]] || return 1
41
+ __tt_active && __tt_takes_default || return 1
42
+ TTHEME_SPEC=${TTHEME_PALETTE[$TTHEME_STARTUP]}
25
43
  }
26
44
 
27
45
  __tt_gone() {
@@ -30,7 +48,7 @@ __tt_gone() {
30
48
  __tt_reload
31
49
  __tt_reset_reloaded $bg
32
50
  print -n $'\e[?1004l'
33
- for hook in precmd:__tt_fresh precmd:__tt_precmd precmd:__tt_prompted precmd:__tt_unmux preexec:__tt_preexec preexec:__tt_mux chpwd:__tt_chpwd; do
51
+ for hook in precmd:__tt_prompt precmd:__tt_precmd precmd:__tt_prompted precmd:__tt_unmux preexec:__tt_preexec preexec:__tt_mux chpwd:__tt_chpwd; do
34
52
  add-zsh-hook -d ${hook%%:*} ${hook#*:}
35
53
  done
36
54
  (( $+functions[add-zle-hook-widget] )) && add-zle-hook-widget -d line-init __tt_line_init
@@ -59,7 +77,7 @@ typeset -g TTHEME_CONFIG=${XDG_CONFIG_HOME:-$HOME/.config}/ttheme/config.zsh
59
77
  [[ -r $TTHEME_CONFIG ]] && source $TTHEME_CONFIG
60
78
 
61
79
  typeset -g TTHEME_PINS_FILE=${TTHEME_CONFIG:h}/pins
62
- typeset -g TTHEME_PINS_RAW=""
80
+ typeset -g TTHEME_PINS_RAW="" TTHEME_PINS_AT=""
63
81
  typeset -gA TTHEME_PINS=()
64
82
  typeset -g TTHEME_PIN="" TTHEME_PIN_SPEC="" TTHEME_BASE_SPEC=""
65
83
 
@@ -69,6 +87,9 @@ __tt_pins_load() {
69
87
  emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
70
88
  setopt localoptions extendedglob
71
89
  local raw="" line key name
90
+ local -a at=("")
91
+ zstat -F %s.%N -A at +mtime -- $TTHEME_PINS_FILE 2>/dev/null
92
+ TTHEME_PINS_AT=$at[1]
72
93
  [[ -r $TTHEME_PINS_FILE ]] && raw="$(<$TTHEME_PINS_FILE)"
73
94
  [[ $raw == "$TTHEME_PINS_RAW" ]] && return 0
74
95
  TTHEME_PINS_RAW=$raw
@@ -140,7 +161,7 @@ __tt_active() {
140
161
  }
141
162
 
142
163
  typeset -g TTHEME_HEARD=""
143
- typeset -gi TTHEME_RECHECK=0 TTHEME_FOCUS=0
164
+ typeset -gi TTHEME_RECHECK=0 TTHEME_FOCUS=0 TTHEME_FRONT=-1
144
165
 
145
166
  __tt_put() {
146
167
  local f=${1:A}
@@ -292,20 +313,22 @@ __tt_dir_rule() {
292
313
  __tt_dir_sync() {
293
314
  local REPLY="" spec=""
294
315
  __tt_dir_rule "$PWD" || REPLY=""
295
- [[ $REPLY == "$TTHEME_PIN" ]] && return 0
296
316
  if [[ -n $REPLY ]]; then
297
- [[ -n $TTHEME_PIN ]] || TTHEME_BASE_SPEC=$TTHEME_SPEC
298
317
  spec=${TTHEME_PALETTE[$TTHEME_PINS[$REPLY]]}
299
- elif [[ $TTHEME_SPEC == "$TTHEME_PIN_SPEC" ]]; then
300
- spec=$TTHEME_BASE_SPEC
301
- [[ -n $spec ]] || { __tt_osc_reset; TTHEME_SPEC= }
318
+ [[ $REPLY == "$TTHEME_PIN" && $spec == "$TTHEME_PIN_SPEC" ]] && return 0
319
+ [[ -n $TTHEME_PIN ]] || TTHEME_BASE_SPEC=$TTHEME_SPEC
320
+ else
321
+ [[ -n $TTHEME_PIN ]] || return 0
322
+ if [[ $TTHEME_SPEC == "$TTHEME_PIN_SPEC" ]]; then
323
+ spec=$TTHEME_BASE_SPEC
324
+ [[ -n $spec ]] || { __tt_osc_reset; TTHEME_SPEC= }
325
+ fi
302
326
  fi
303
327
  TTHEME_PIN=$REPLY TTHEME_PIN_SPEC=$spec
304
328
  [[ -n $spec && $spec != "$TTHEME_SPEC" ]] || return 0
305
329
  __tt_apply "$spec"
306
330
  TTHEME_SPEC=$spec
307
- __tt_name_of "$spec"
308
- __tt_shown "$REPLY" && __tt_reload
331
+ __tt_sync
309
332
  }
310
333
 
311
334
  __tt_chpwd() {
@@ -314,14 +337,16 @@ __tt_chpwd() {
314
337
  __tt_dir_sync
315
338
  }
316
339
 
317
- __tt_sync() {
340
+ __tt_worn_shown() {
318
341
  local REPLY
319
- [[ -n $TTHEME_SPEC ]] || return 0
342
+ [[ -n $TTHEME_SPEC ]] || return 1
320
343
  __tt_name_of "$TTHEME_SPEC"
321
- [[ -n ${TTHEME_PALETTE[$REPLY]} ]] || return 0
322
- __tt_shown "$REPLY" && __tt_reload
344
+ [[ -n ${TTHEME_PALETTE[$REPLY]} ]] || return 1
345
+ __tt_shown "$REPLY" $1
323
346
  }
324
347
 
348
+ __tt_sync() { ! __tt_worn_shown || __tt_reload }
349
+
325
350
  __tt_precmd() {
326
351
  emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
327
352
  __tt_sync
@@ -335,16 +360,18 @@ __tt_preexec() {
335
360
  }
336
361
 
337
362
  __tt_rewear() {
338
- local REPLY
339
363
  __tt_repaint
340
- [[ -n $TTHEME_SPEC ]] || { __tt_unshown $1; return 0 }
341
- __tt_name_of "$TTHEME_SPEC"
342
- [[ -n ${TTHEME_PALETTE[$REPLY]} ]] || return 0
343
- __tt_shown "$REPLY" $1 && __tt_reload
364
+ if [[ -n $TTHEME_SPEC ]]; then
365
+ __tt_worn_shown $1 && __tt_reload
366
+ else
367
+ __tt_unshown $1
368
+ fi
369
+ return 0
344
370
  }
345
371
 
346
372
  __tt_focus() {
347
373
  emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
374
+ TTHEME_FRONT=1
348
375
  __tt_fresh
349
376
  if (( TTHEME_TMUX )); then
350
377
  __tt_rewear
@@ -367,7 +394,8 @@ __tt_unmux() {
367
394
 
368
395
  __tt_blur() {
369
396
  emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace}
370
- :
397
+ TTHEME_FRONT=0
398
+ __tt_blurred
371
399
  }
372
400
 
373
401
  __tt_line_init() {
@@ -402,12 +430,14 @@ __tt_pins_write() {
402
430
  done
403
431
  if (( ! ${#lines} )); then
404
432
  rm -f $TTHEME_PINS_FILE || return 1
405
- TTHEME_PINS_RAW=""
433
+ TTHEME_PINS_RAW="" TTHEME_PINS_AT=""
406
434
  return 0
407
435
  fi
408
436
  mkdir -p ${TTHEME_PINS_FILE:h} || return 1
409
437
  __tt_put $TTHEME_PINS_FILE "${lines[@]}" || return 1
410
438
  TTHEME_PINS_RAW="$(<$TTHEME_PINS_FILE)"
439
+ local -a at
440
+ zstat -F %s.%N -A at +mtime -- $TTHEME_PINS_FILE 2>/dev/null && TTHEME_PINS_AT=$at[1]
411
441
  }
412
442
 
413
443
  __tt_pin_base() { REPLY=${${${1%/\*\*}:-/}:a} }
@@ -1074,10 +1104,11 @@ __tt_pins_map() {
1074
1104
  }
1075
1105
 
1076
1106
  __tt_keep() {
1077
- local note
1107
+ local note was="$TTHEME_STARTUP ${TTHEME_PALETTE[$TTHEME_STARTUP]}"
1078
1108
  note=$(__tt_cli default "$1") || return 1
1079
- TTHEME_STARTUP=$1
1080
- __tt_shown "$1" force
1109
+ [[ -r $TTHEME_HOME/palettes.zsh ]] && __tt_palettes_load && __tt_reloaded
1110
+ __tt_follow "$was"
1111
+ __tt_worn_shown $2
1081
1112
  __tt_reload
1082
1113
  if __tt_color; then
1083
1114
  printf '\033[2m%s\033[0m\n' "${(@f)note}"
@@ -1189,7 +1220,10 @@ __tt_catalog() {
1189
1220
  [[ -r $TTHEME_HOME/palettes.zsh ]] || return 0
1190
1221
  was="$TTHEME_STARTUP ${TTHEME_PALETTE[$TTHEME_STARTUP]}"
1191
1222
  __tt_palettes_load && __tt_reloaded
1192
- [[ "$TTHEME_STARTUP ${TTHEME_PALETTE[$TTHEME_STARTUP]}" == "$was" ]] || __tt_reload
1223
+ [[ "$TTHEME_STARTUP ${TTHEME_PALETTE[$TTHEME_STARTUP]}" == "$was" ]] && return 0
1224
+ __tt_follow "$was"
1225
+ __tt_worn_shown
1226
+ __tt_reload
1193
1227
  }
1194
1228
 
1195
1229
  __tt_switch() {
@@ -1307,13 +1341,11 @@ __tt_next() {
1307
1341
  }
1308
1342
 
1309
1343
  __tt_rotate() {
1310
- local REPLY spec
1344
+ local REPLY
1311
1345
  __tt_next
1312
- spec=$REPLY
1313
- __tt_apply "$spec"
1314
- TTHEME_SPEC=$spec
1315
- __tt_name_of "$spec"
1316
- __tt_shown "$REPLY" force && __tt_reload
1346
+ __tt_apply "$REPLY"
1347
+ TTHEME_SPEC=$REPLY
1348
+ __tt_worn_shown force && __tt_reload
1317
1349
  __tt_announce
1318
1350
  }
1319
1351
 
@@ -2705,7 +2737,7 @@ __tt_preview() {
2705
2737
  __tt_sync
2706
2738
  elif (( picked == 2 )); then
2707
2739
  __tt_announce
2708
- __tt_keep "$sel"
2740
+ __tt_keep "$sel" force
2709
2741
  else
2710
2742
  __tt_announce
2711
2743
  __tt_shown "$sel" force && __tt_reload
@@ -2733,6 +2765,8 @@ ttheme() {
2733
2765
  print -u2 "ttheme: unknown command '$1' — see \`ttheme help\`"
2734
2766
  return 1
2735
2767
  fi
2768
+ __tt_fresh
2769
+ (( $+functions[ttheme] )) || { print -u2 "ttheme: uninstalled — \`npx @kecan0406/ttheme@latest init\` sets it up again"; return 1 }
2736
2770
  if ! __tt_paints && (( ! $# || ${TTHEME_TAB_VERBS[(Ie)$1]} )); then
2737
2771
  __tt_unpainted
2738
2772
  return 1
@@ -2746,6 +2780,7 @@ ttheme() {
2746
2780
  case $1 in
2747
2781
  browse|list|add|remove|update|market|new|edit|check|share) __tt_catalog "$@"; return ;;
2748
2782
  on|off) __tt_switch "$@"; return ;;
2783
+ info) TTHEME_ZSH=$ZSH_VERSION __tt_cli "$@"; return ;;
2749
2784
  esac
2750
2785
  __tt_arity "$@" || return
2751
2786
  [[ $1 == config ]] && { __tt_config; return }
@@ -2829,7 +2864,7 @@ fi
2829
2864
  zle -N __tt_line_init
2830
2865
  add-zle-hook-widget line-init __tt_line_init
2831
2866
  add-zsh-hook chpwd __tt_chpwd
2832
- add-zsh-hook precmd __tt_fresh
2867
+ add-zsh-hook precmd __tt_prompt
2833
2868
  if (( ! TTHEME_TMUX )); then
2834
2869
  add-zsh-hook preexec __tt_mux
2835
2870
  add-zsh-hook precmd __tt_unmux