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 CHANGED
@@ -1 +1 @@
1
- 2.3.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",
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": {
@@ -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
- _tai_query "$BUFFER" "$_TAI_LAST"
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