terminal-ai-helper 2.3.3 → 2.3.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.
- package/VERSION +1 -1
- package/package.json +1 -1
- package/plugins/zsh/widgets.zsh +105 -4
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.3.
|
|
1
|
+
2.3.4
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminal-ai-helper",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.4",
|
|
4
4
|
"description": "The terminal that knows your next command Bash/Zsh suggestions that learn from your own history Offline and private with no account required",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/plugins/zsh/widgets.zsh
CHANGED
|
@@ -29,6 +29,29 @@ typeset -g _TAI_PASTE_PREV=""
|
|
|
29
29
|
typeset -gi _TAI_PASTE_QUIET=0
|
|
30
30
|
typeset -gi _TAI_PASTE_JUMP=25
|
|
31
31
|
|
|
32
|
+
# The clock the chunk rule reads, the redraw that raised the quiet, and the
|
|
33
|
+
# query an arrival skipped. zsh/datetime is what makes $EPOCHREALTIME exist;
|
|
34
|
+
# on a zsh too old for it the chunk rule is inert and the two bounds above
|
|
35
|
+
# keep the behaviour this file was shipped with — the module load is best-
|
|
36
|
+
# effort on purpose.
|
|
37
|
+
zmodload zsh/datetime 2>/dev/null
|
|
38
|
+
# A fiftieth of a second, in microseconds. The fastest coalesced burst of
|
|
39
|
+
# ordinary typing is a read every few tens of milliseconds (a hand, not a
|
|
40
|
+
# terminal, is the thing being told apart), and the harness's own quiet
|
|
41
|
+
# window is built on the same arithmetic.
|
|
42
|
+
typeset -gi _TAI_PASTE_CHUNK_US=20000
|
|
43
|
+
# How many edit events at terminal speed make a paste. Five insertions in a
|
|
44
|
+
# row, each within a fiftieth of a second of the last, is 250 characters a
|
|
45
|
+
# second — no hand does that; keyboard auto-repeat at its fastest stock rate
|
|
46
|
+
# (about 30 a second) does not either, and a rate set past 50 a second only
|
|
47
|
+
# holds the quiet while the key is held, which costs one stale hint.
|
|
48
|
+
typeset -gi _TAI_PASTE_MIN_RUN=5
|
|
49
|
+
typeset -g _TAI_PASTE_TICK=""
|
|
50
|
+
typeset -gi _TAI_PASTE_RUN=0
|
|
51
|
+
typeset -gi _TAI_PASTE_NEW=0
|
|
52
|
+
typeset -gi _TAI_PASTE_FAST=0
|
|
53
|
+
typeset -gi _TAI_Q_OWED=0
|
|
54
|
+
|
|
32
55
|
# Is the line *typed*? A history line is not: Up fills the buffer with a
|
|
33
56
|
# command the user ran once, and on that buffer Down means "the next history
|
|
34
57
|
# entry" — it did not mean "open the list" until something was typed. The flag
|
|
@@ -39,18 +62,71 @@ typeset -gi _TAI_PASTE_JUMP=25
|
|
|
39
62
|
# a line nobody typed, with the line itself as its only row.
|
|
40
63
|
typeset -gi _TAI_TYPED=0
|
|
41
64
|
|
|
65
|
+
# $EPOCHREALTIME as whole microseconds in REPLY, and false where there is no
|
|
66
|
+
# clock. String surgery, not arithmetic on the float: the fraction is padded
|
|
67
|
+
# and cut to six digits by hand, and `10#` keeps a fraction that opens in a
|
|
68
|
+
# zero from being read as octal. This build's fraction runs longer than six
|
|
69
|
+
# digits, which is why the cut is there at all.
|
|
70
|
+
_tai_now_us() {
|
|
71
|
+
REPLY=0
|
|
72
|
+
[[ -n "$EPOCHREALTIME" ]] || return 1
|
|
73
|
+
local fr="${EPOCHREALTIME#*.}"
|
|
74
|
+
REPLY=$(( ${EPOCHREALTIME%%.*} * 1000000 + 10#${(r:6::0:)fr} ))
|
|
75
|
+
}
|
|
76
|
+
|
|
42
77
|
_tai_paste_state() {
|
|
43
78
|
# The unwrapped case: how far the buffer moved since the last redraw. One
|
|
44
79
|
# character in either direction is a keystroke — typed or removed — and ends
|
|
45
80
|
# the quiet; more than _TAI_PASTE_JUMP at once is an arrival and starts it.
|
|
46
|
-
# Everything between leaves the flag as it is
|
|
81
|
+
# Everything between leaves the flag as it is — unless the clock says it is
|
|
82
|
+
# a chunk of a paste, which is the branch below.
|
|
83
|
+
_TAI_PASTE_NEW=0
|
|
47
84
|
local -i d=$(( ${#BUFFER} - ${#_TAI_PASTE_PREV} ))
|
|
48
85
|
(( d < 0 )) && d=$(( -d ))
|
|
86
|
+
local -i now_us=0
|
|
87
|
+
_tai_now_us && now_us=$REPLY
|
|
88
|
+
# Terminal speed, judged against the previous redraw: an insertion within a
|
|
89
|
+
# fiftieth of a second of the last one is not a hand. The hook fires per
|
|
90
|
+
# widget, so a three-character chunk is three calls — two of them one
|
|
91
|
+
# character apart, microseconds together — and the last character of every
|
|
92
|
+
# chunk looks exactly like a keystroke. Without the clock, the tail of a
|
|
93
|
+
# paste would end the quiet that the middle of the same paste raised.
|
|
94
|
+
local -i fast=0
|
|
95
|
+
(( now_us && ${#_TAI_PASTE_TICK} )) && \
|
|
96
|
+
(( now_us - _TAI_PASTE_TICK < _TAI_PASTE_CHUNK_US )) && fast=1
|
|
97
|
+
_TAI_PASTE_FAST=$fast
|
|
98
|
+
# The run: consecutive edit events at terminal speed. The hook fires per
|
|
99
|
+
# widget, so a pasted character and a typed character both arrive as d==1 —
|
|
100
|
+
# the buffer cannot tell them apart, and neither bound above sees anything
|
|
101
|
+
# but one keystroke at a time. Only the clock separates a hand from a
|
|
102
|
+
# terminal, and only a run of them separates a paste from one lucky
|
|
103
|
+
# keystroke: two fast keys in a row happens to hands (rollover), twenty in
|
|
104
|
+
# a row does not.
|
|
105
|
+
if (( d != 0 )) && (( fast )); then
|
|
106
|
+
_TAI_PASTE_RUN+=1
|
|
107
|
+
else
|
|
108
|
+
_TAI_PASTE_RUN=0
|
|
109
|
+
fi
|
|
49
110
|
if (( d == 1 )); then
|
|
50
|
-
_TAI_PASTE_QUIET=0
|
|
111
|
+
(( fast )) || _TAI_PASTE_QUIET=0
|
|
51
112
|
elif (( d > _TAI_PASTE_JUMP )); then
|
|
113
|
+
(( _TAI_PASTE_QUIET )) || { _TAI_PASTE_QUIET=1; _TAI_PASTE_NEW=1; }
|
|
114
|
+
elif (( d > 1 )); then
|
|
115
|
+
# A coalesced insertion — several characters in one read — is one event
|
|
116
|
+
# that moved more than a keystroke and less than an arrival. At human
|
|
117
|
+
# speed it is a typing burst like any other; at terminal speed it is a
|
|
118
|
+
# chunk of a paste, and the run below will agree with it.
|
|
119
|
+
(( fast && ! _TAI_PASTE_QUIET )) && { _TAI_PASTE_QUIET=1; _TAI_PASTE_NEW=1; }
|
|
120
|
+
fi
|
|
121
|
+
# Enough of a run is a paste, whoever delivered it. Raised once — the
|
|
122
|
+
# crossing is the arrival, and everything after it rides the same quiet —
|
|
123
|
+
# and ended by the next edit at human speed, which is the keystroke rule
|
|
124
|
+
# above doing what it always did.
|
|
125
|
+
if (( _TAI_PASTE_RUN >= _TAI_PASTE_MIN_RUN && ! _TAI_PASTE_QUIET )); then
|
|
52
126
|
_TAI_PASTE_QUIET=1
|
|
127
|
+
_TAI_PASTE_NEW=1
|
|
53
128
|
fi
|
|
129
|
+
(( now_us )) && _TAI_PASTE_TICK=$now_us
|
|
54
130
|
_TAI_PASTE_PREV="$BUFFER"
|
|
55
131
|
}
|
|
56
132
|
|
|
@@ -158,7 +234,27 @@ _tai_update() {
|
|
|
158
234
|
(( ours_was )) && POSTDISPLAY=""
|
|
159
235
|
fi
|
|
160
236
|
_tai_paste_state
|
|
161
|
-
|
|
237
|
+
# A paste is not a query — all of it, not only its menu. The redraw that
|
|
238
|
+
# raised the quiet answers nothing: the line is still arriving, and a full
|
|
239
|
+
# query on a real index for a line nobody has read is the cost the chunk
|
|
240
|
+
# rule exists to stop. What it skips it owes — one query, at the first
|
|
241
|
+
# redraw that is not itself arriving at terminal speed, the keystroke that
|
|
242
|
+
# ends the paste or any edit after it — by which time the buffer is the
|
|
243
|
+
# line the user is reading, so the answer is the one they would have asked
|
|
244
|
+
# for. The hook fires per widget, so the middle of a paste owes and the
|
|
245
|
+
# tail of it is still fast: paying at any fast redraw would put the storm
|
|
246
|
+
# back one chunk at a time. The envelope keeps its single query: quiet
|
|
247
|
+
# raised by the paste widget is not an arrival this hook raised, and one
|
|
248
|
+
# query for a line that arrived at once is the deal the bracketed-paste
|
|
249
|
+
# tests have always held.
|
|
250
|
+
if (( _TAI_PASTE_NEW )); then
|
|
251
|
+
_TAI_Q_OWED=1
|
|
252
|
+
elif (( _TAI_Q_OWED )) && (( ! _TAI_PASTE_FAST )); then
|
|
253
|
+
_TAI_Q_OWED=0
|
|
254
|
+
_tai_query "$BUFFER" "$_TAI_LAST"
|
|
255
|
+
elif (( ! _TAI_Q_OWED )); then
|
|
256
|
+
_tai_query "$BUFFER" "$_TAI_LAST"
|
|
257
|
+
fi
|
|
162
258
|
# The extends test folds case — the lookup that filled _TAI_BEST does, and
|
|
163
259
|
# `ls down` reaching `ls Downloads` is the point of it — and the strip is
|
|
164
260
|
# positional: the head of the best line that matched is the buffer's own
|
|
@@ -589,9 +685,14 @@ _tai_line_init() {
|
|
|
589
685
|
_TAI_DREW=0
|
|
590
686
|
_TAI_MENU_DISMISS=""
|
|
591
687
|
# A new line is a new story: no paste has arrived on it yet, and nothing
|
|
592
|
-
# on it is typed.
|
|
688
|
+
# on it is typed. An owed query belongs to the line that skipped it — a
|
|
689
|
+
# debt carried past the prompt would be paid against a line nobody pasted.
|
|
593
690
|
_TAI_PASTE_PREV=""
|
|
594
691
|
_TAI_PASTE_QUIET=0
|
|
692
|
+
_TAI_PASTE_TICK=""
|
|
693
|
+
_TAI_PASTE_NEW=0
|
|
694
|
+
_TAI_PASTE_FAST=0
|
|
695
|
+
_TAI_Q_OWED=0
|
|
595
696
|
_TAI_TYPED=0
|
|
596
697
|
# And no directory snapshot is worth keeping either: the file answer reads
|
|
597
698
|
# its snapshots for a second after taking them, and a line that starts now
|