baxian 2.0.2 → 2.0.3

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.
Files changed (212) hide show
  1. package/dist/agent/branch.d.ts.map +1 -1
  2. package/dist/agent/branch.js +0 -7
  3. package/dist/agent/branch.js.map +1 -1
  4. package/dist/agent/detect/region.d.ts.map +1 -1
  5. package/dist/agent/detect/region.js +0 -3
  6. package/dist/agent/detect/region.js.map +1 -1
  7. package/dist/agent/dispatch-reconciler.d.ts.map +1 -1
  8. package/dist/agent/dispatch-reconciler.js +0 -51
  9. package/dist/agent/dispatch-reconciler.js.map +1 -1
  10. package/dist/agent/lineage.d.ts.map +1 -1
  11. package/dist/agent/lineage.js +0 -9
  12. package/dist/agent/lineage.js.map +1 -1
  13. package/dist/agent/manager.d.ts +1 -4
  14. package/dist/agent/manager.d.ts.map +1 -1
  15. package/dist/agent/manager.js +10 -298
  16. package/dist/agent/manager.js.map +1 -1
  17. package/dist/agent/net-exec.d.ts.map +1 -1
  18. package/dist/agent/net-exec.js +0 -5
  19. package/dist/agent/net-exec.js.map +1 -1
  20. package/dist/agent/pane-streamer-manager.d.ts.map +1 -1
  21. package/dist/agent/pane-streamer-manager.js +0 -36
  22. package/dist/agent/pane-streamer-manager.js.map +1 -1
  23. package/dist/agent/pane-streamer.d.ts +6 -0
  24. package/dist/agent/pane-streamer.d.ts.map +1 -1
  25. package/dist/agent/pane-streamer.js +126 -83
  26. package/dist/agent/pane-streamer.js.map +1 -1
  27. package/dist/agent/phase-signal-watcher.d.ts.map +1 -1
  28. package/dist/agent/phase-signal-watcher.js +2 -77
  29. package/dist/agent/phase-signal-watcher.js.map +1 -1
  30. package/dist/agent/phase-signal.d.ts +0 -1
  31. package/dist/agent/phase-signal.d.ts.map +1 -1
  32. package/dist/agent/phase-signal.js +0 -17
  33. package/dist/agent/phase-signal.js.map +1 -1
  34. package/dist/agent/preflight.d.ts.map +1 -1
  35. package/dist/agent/preflight.js +0 -18
  36. package/dist/agent/preflight.js.map +1 -1
  37. package/dist/agent/prompt.d.ts.map +1 -1
  38. package/dist/agent/prompt.js +0 -1
  39. package/dist/agent/prompt.js.map +1 -1
  40. package/dist/agent/repo-store.d.ts.map +1 -1
  41. package/dist/agent/repo-store.js +0 -38
  42. package/dist/agent/repo-store.js.map +1 -1
  43. package/dist/agent/runner.d.ts.map +1 -1
  44. package/dist/agent/runner.js +0 -2
  45. package/dist/agent/runner.js.map +1 -1
  46. package/dist/agent/tmux-install.js +0 -1
  47. package/dist/agent/tmux-install.js.map +1 -1
  48. package/dist/agent/tmux-probe-poller.d.ts.map +1 -1
  49. package/dist/agent/tmux-probe-poller.js +0 -7
  50. package/dist/agent/tmux-probe-poller.js.map +1 -1
  51. package/dist/agent/tmux.d.ts.map +1 -1
  52. package/dist/agent/tmux.js +0 -86
  53. package/dist/agent/tmux.js.map +1 -1
  54. package/dist/agent/vt-visible-text.d.ts +46 -1
  55. package/dist/agent/vt-visible-text.d.ts.map +1 -1
  56. package/dist/agent/vt-visible-text.js +639 -63
  57. package/dist/agent/vt-visible-text.js.map +1 -1
  58. package/dist/api/agents.d.ts.map +1 -1
  59. package/dist/api/agents.js +1 -42
  60. package/dist/api/agents.js.map +1 -1
  61. package/dist/api/config.d.ts.map +1 -1
  62. package/dist/api/config.js +3 -52
  63. package/dist/api/config.js.map +1 -1
  64. package/dist/api/hosts.d.ts.map +1 -1
  65. package/dist/api/hosts.js +2 -57
  66. package/dist/api/hosts.js.map +1 -1
  67. package/dist/api/platform-guard.d.ts.map +1 -1
  68. package/dist/api/platform-guard.js +0 -1
  69. package/dist/api/platform-guard.js.map +1 -1
  70. package/dist/api/probe.d.ts.map +1 -1
  71. package/dist/api/probe.js +0 -1
  72. package/dist/api/probe.js.map +1 -1
  73. package/dist/api/projects.d.ts.map +1 -1
  74. package/dist/api/projects.js +1 -14
  75. package/dist/api/projects.js.map +1 -1
  76. package/dist/api/tasks.d.ts.map +1 -1
  77. package/dist/api/tasks.js +0 -1
  78. package/dist/api/tasks.js.map +1 -1
  79. package/dist/app.d.ts +0 -2
  80. package/dist/app.d.ts.map +1 -1
  81. package/dist/app.js +0 -6
  82. package/dist/app.js.map +1 -1
  83. package/dist/cli.d.ts.map +1 -1
  84. package/dist/cli.js +4 -29
  85. package/dist/cli.js.map +1 -1
  86. package/dist/config/hot-reload.d.ts.map +1 -1
  87. package/dist/config/hot-reload.js +0 -4
  88. package/dist/config/hot-reload.js.map +1 -1
  89. package/dist/config/loader.d.ts.map +1 -1
  90. package/dist/config/loader.js +1 -24
  91. package/dist/config/loader.js.map +1 -1
  92. package/dist/config/normalizer.d.ts.map +1 -1
  93. package/dist/config/normalizer.js +0 -19
  94. package/dist/config/normalizer.js.map +1 -1
  95. package/dist/config/validator.d.ts.map +1 -1
  96. package/dist/config/validator.js +2 -200
  97. package/dist/config/validator.js.map +1 -1
  98. package/dist/event/handlers.d.ts.map +1 -1
  99. package/dist/event/handlers.js +0 -11
  100. package/dist/event/handlers.js.map +1 -1
  101. package/dist/event/log.js +0 -2
  102. package/dist/event/log.js.map +1 -1
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +0 -45
  105. package/dist/index.js.map +1 -1
  106. package/dist/platform/body-digest.d.ts.map +1 -1
  107. package/dist/platform/body-digest.js +0 -4
  108. package/dist/platform/body-digest.js.map +1 -1
  109. package/dist/platform/command-renderer.d.ts.map +1 -1
  110. package/dist/platform/command-renderer.js +0 -3
  111. package/dist/platform/command-renderer.js.map +1 -1
  112. package/dist/platform/comment-cursor.d.ts.map +1 -1
  113. package/dist/platform/comment-cursor.js +0 -21
  114. package/dist/platform/comment-cursor.js.map +1 -1
  115. package/dist/platform/driver-spec.d.ts.map +1 -1
  116. package/dist/platform/driver-spec.js +1 -42
  117. package/dist/platform/driver-spec.js.map +1 -1
  118. package/dist/platform/field-mapper.d.ts.map +1 -1
  119. package/dist/platform/field-mapper.js +3 -11
  120. package/dist/platform/field-mapper.js.map +1 -1
  121. package/dist/platform/git-driver.d.ts.map +1 -1
  122. package/dist/platform/git-driver.js +0 -20
  123. package/dist/platform/git-driver.js.map +1 -1
  124. package/dist/platform/manifest.d.ts.map +1 -1
  125. package/dist/platform/manifest.js +0 -3
  126. package/dist/platform/manifest.js.map +1 -1
  127. package/dist/platform/markers.d.ts.map +1 -1
  128. package/dist/platform/markers.js +0 -19
  129. package/dist/platform/markers.js.map +1 -1
  130. package/dist/platform/platform-poller.d.ts.map +1 -1
  131. package/dist/platform/platform-poller.js +0 -43
  132. package/dist/platform/platform-poller.js.map +1 -1
  133. package/dist/platform/plugin-registry.d.ts.map +1 -1
  134. package/dist/platform/plugin-registry.js +1 -12
  135. package/dist/platform/plugin-registry.js.map +1 -1
  136. package/dist/platform/pr-conversation-cache.d.ts.map +1 -1
  137. package/dist/platform/pr-conversation-cache.js +0 -17
  138. package/dist/platform/pr-conversation-cache.js.map +1 -1
  139. package/dist/platform/preflight-exec.d.ts.map +1 -1
  140. package/dist/platform/preflight-exec.js +0 -9
  141. package/dist/platform/preflight-exec.js.map +1 -1
  142. package/dist/platform/response-parser.d.ts.map +1 -1
  143. package/dist/platform/response-parser.js +0 -4
  144. package/dist/platform/response-parser.js.map +1 -1
  145. package/dist/platform/review-timeline.d.ts.map +1 -1
  146. package/dist/platform/review-timeline.js +0 -22
  147. package/dist/platform/review-timeline.js.map +1 -1
  148. package/dist/platform/row-schema.d.ts.map +1 -1
  149. package/dist/platform/row-schema.js +0 -11
  150. package/dist/platform/row-schema.js.map +1 -1
  151. package/dist/platform/startup.d.ts.map +1 -1
  152. package/dist/platform/startup.js +1 -12
  153. package/dist/platform/startup.js.map +1 -1
  154. package/dist/platform/types.d.ts.map +1 -1
  155. package/dist/platform/types.js +0 -5
  156. package/dist/platform/types.js.map +1 -1
  157. package/dist/platform/verdict-engine.d.ts.map +1 -1
  158. package/dist/platform/verdict-engine.js +0 -15
  159. package/dist/platform/verdict-engine.js.map +1 -1
  160. package/dist/shared/concurrency.d.ts.map +1 -1
  161. package/dist/shared/concurrency.js +0 -2
  162. package/dist/shared/concurrency.js.map +1 -1
  163. package/dist/shared/constants.d.ts +0 -2
  164. package/dist/shared/constants.d.ts.map +1 -1
  165. package/dist/shared/constants.js +0 -3
  166. package/dist/shared/constants.js.map +1 -1
  167. package/dist/shared/git-url.d.ts.map +1 -1
  168. package/dist/shared/git-url.js +0 -9
  169. package/dist/shared/git-url.js.map +1 -1
  170. package/dist/shared/types.d.ts +0 -11
  171. package/dist/shared/types.d.ts.map +1 -1
  172. package/dist/shared/types.js.map +1 -1
  173. package/dist/skill/registry.d.ts.map +1 -1
  174. package/dist/skill/registry.js +0 -5
  175. package/dist/skill/registry.js.map +1 -1
  176. package/dist/skills/baxian-signals/SKILL.md +0 -6
  177. package/dist/state/agent-store.d.ts.map +1 -1
  178. package/dist/state/agent-store.js +0 -6
  179. package/dist/state/agent-store.js.map +1 -1
  180. package/dist/state/error-record-store.d.ts.map +1 -1
  181. package/dist/state/error-record-store.js +0 -5
  182. package/dist/state/error-record-store.js.map +1 -1
  183. package/dist/state/init.d.ts.map +1 -1
  184. package/dist/state/init.js +0 -1
  185. package/dist/state/init.js.map +1 -1
  186. package/dist/state/lock.d.ts.map +1 -1
  187. package/dist/state/lock.js +0 -1
  188. package/dist/state/lock.js.map +1 -1
  189. package/dist/state/task-store.d.ts.map +1 -1
  190. package/dist/state/task-store.js +0 -3
  191. package/dist/state/task-store.js.map +1 -1
  192. package/dist/terminal/attach.d.ts.map +1 -1
  193. package/dist/terminal/attach.js +0 -4
  194. package/dist/terminal/attach.js.map +1 -1
  195. package/dist/terminal/stream-ws.js +0 -5
  196. package/dist/terminal/stream-ws.js.map +1 -1
  197. package/dist/web/assets/{index-BS2adAfI.css → index-yqxawAPJ.css} +1 -1
  198. package/dist/web/index.html +2 -2
  199. package/package.json +1 -1
  200. package/dist/agent/root-agent-runtime.d.ts +0 -80
  201. package/dist/agent/root-agent-runtime.d.ts.map +0 -1
  202. package/dist/agent/root-agent-runtime.js +0 -637
  203. package/dist/agent/root-agent-runtime.js.map +0 -1
  204. package/dist/agent/root-recovery-coordinator.d.ts +0 -124
  205. package/dist/agent/root-recovery-coordinator.d.ts.map +0 -1
  206. package/dist/agent/root-recovery-coordinator.js +0 -1557
  207. package/dist/agent/root-recovery-coordinator.js.map +0 -1
  208. package/dist/state/root-recovery-store.d.ts +0 -107
  209. package/dist/state/root-recovery-store.d.ts.map +0 -1
  210. package/dist/state/root-recovery-store.js +0 -400
  211. package/dist/state/root-recovery-store.js.map +0 -1
  212. /package/dist/web/assets/{index-BKiM0MSM.js → index-CiAnjs1_.js} +0 -0
@@ -1,4 +1,3 @@
1
- // 转移表按 https://vt100.net/emu/dec_ansi_parser
2
1
  const S = {
3
2
  ground: 0,
4
3
  escape: 1,
@@ -15,21 +14,15 @@ const S = {
15
14
  oscString: 12,
16
15
  sosPmApcString: 13,
17
16
  };
18
- // 这几个状态显式忽略 xterm 的 NON_ASCII_PRINTABLE 槽;其余状态无表项,走 ERROR 打回 ground。
19
17
  const NON_ASCII_IGNORED = new Set([
20
18
  S.oscString, S.dcsPassthrough, S.csiIgnore, S.dcsIgnore,
21
19
  ]);
22
- // 转移动作为 EXECUTE 的状态;Dcs*/Osc/SosPmApc 里是 ignore/put,屏幕无效果。
23
20
  const EXECUTES_C0 = new Set([
24
21
  S.ground, S.escape, S.escapeIntermediate,
25
22
  S.csiEntry, S.csiParam, S.csiIntermediate, S.csiIgnore,
26
23
  ]);
27
- // 保留原字节:属不属 \s 正好就编码了会不会隔断 marker——BS 隔断,HT/LF/CR 让软换行接得回去。
28
24
  const CURSOR_MOVING_C0 = new Set([0x08, 0x09, 0x0a, 0x0d]);
29
- // 被字符集改写的字节在屏幕上是别的字形,拼出来的 marker 终端根本不显示。既不能原样吐也不能丢
30
- // ——两者都会拼出 marker——所以吐一个 compact 删不掉、又不可能出现在 marker 里的分隔符。
31
25
  const REMAPPED = '\x00';
32
- // 必须精确到字节:UK('A') 只改 '#',把整套字符集判为不可见会漏掉屏幕上真实可见的 marker。
33
26
  const CHARSET_REMAPS = {
34
27
  '0': '`abcdefghijklmnopqrstuvwxyz{|}~',
35
28
  '4': '#@[\\]{|}~',
@@ -48,18 +41,17 @@ const CHARSET_REMAPS = {
48
41
  Z: '#@[\\]{|}',
49
42
  };
50
43
  const REMAPPED_CODES = new Map(Object.entries(CHARSET_REMAPS).map(([d, chars]) => [d, new Set([...chars].map(c => c.charCodeAt(0)))]));
51
- // 只有终端认得的 designator 才会改写槽位;认不出的整条 designation 被忽略、旧字符集留任。
52
44
  const RECOGNISED_DESIGNATORS = new Set([...Object.keys(CHARSET_REMAPS), 'B']);
53
45
  const MAX_CSI_PARAMS = 32;
54
46
  const MAX_CSI_PARAM = 0x7fffffff;
47
+ const DEFAULT_COLUMNS = 80;
48
+ const DEFAULT_ROWS = 24;
55
49
  const SGR_FINAL = 'm';
56
- // GR '-' '.' 与 GL 的 ')' '*' 落在同一批槽位上,后续 SO/LS2 会把它们选出来;'/' 被忽略。
50
+ const POSITIONING_CSI_FINALS = new Set([...'ABCDEFGHILMZ`abdefr']);
57
51
  const DESIGNATE_INTERMEDIATES = {
58
52
  '(': 0, ')': 1, '*': 2, '+': 3, '-': 1, '.': 2,
59
53
  };
60
- // xterm 5.5.0 把 LS1R/LS2R/LS3R 也当作 GL 移位处理,与标准的 GR 语义不同。
61
54
  const LOCKING_SHIFTS = { n: 2, o: 3, '|': 3, '}': 2, '~': 1 };
62
- // ESC、CAN/SUB 与全部 C1 控制取消进行中的序列,从任何状态生效。
63
55
  function anywhereTransition(code) {
64
56
  if (code === 0x1b)
65
57
  return S.escape;
@@ -80,21 +72,28 @@ function anywhereTransition(code) {
80
72
  export class VisibleTextExtractor {
81
73
  state = S.ground;
82
74
  pendingHigh = '';
83
- // 装载的那张表与槽位是两样东西:DECSC/DECRC 只存取 active,移位则从 charsets 重新装载。
84
75
  active;
85
76
  charsets = [undefined, undefined, undefined, undefined];
86
77
  gl = 0;
87
- // 每个缓冲区各存一份(`CSI ?1049h` 进备用屏时存的是主屏那份);
88
- // 存了 undefined 与没存过是两回事,故用外层 undefined 表示"没存过"。
89
78
  savedByBuffer = [undefined, undefined];
79
+ cursorByBuffer = [
80
+ { row: 0, column: 0 },
81
+ { row: 0, column: 0 },
82
+ ];
83
+ cursorReliableByBuffer = [true, true];
84
+ tabStopsReliableByBuffer = [true, true];
85
+ scrollRegionByBuffer;
86
+ continuation;
87
+ carriageReturnContinuation;
88
+ contentInvalidatedByBuffer = [false, false];
89
+ printSequenceByBuffer = [0, 0];
90
+ wraparound = true;
91
+ originMode = false;
90
92
  conceal = false;
91
93
  altBuffer = 0;
92
94
  pendingIntermediate;
93
- // 私有前缀要留原字节:只有 '?' 是 DEC private mode,'<' '=' '>' 各有别的含义。
94
95
  csiPrefix = '';
95
96
  csiIntermediates = '';
96
- // 按 xterm 的 Params 语义收数值主参数:前导零归一、冒号子参数只取冒号前的值、
97
- // 容量算的是**参数个数**(超出的丢弃,已收下的照常派发),不是原始字符数。
98
97
  csiParamValues = [];
99
98
  csiParamHasSub = [];
100
99
  csiParamValue = 0;
@@ -102,6 +101,28 @@ export class VisibleTextExtractor {
102
101
  csiInSubParam = false;
103
102
  csiOverflowed = false;
104
103
  csiEightBit = false;
104
+ columns;
105
+ rows;
106
+ constructor(columns = DEFAULT_COLUMNS, rows = DEFAULT_ROWS) {
107
+ this.columns = this.normalizeColumns(columns);
108
+ this.rows = this.normalizeRows(rows);
109
+ this.scrollRegionByBuffer = [this.fullScrollRegion(), this.fullScrollRegion()];
110
+ }
111
+ resize(columns, rows = this.rows) {
112
+ const normalizedColumns = this.normalizeColumns(columns);
113
+ const normalizedRows = this.normalizeRows(rows);
114
+ if (normalizedColumns === this.columns && normalizedRows === this.rows)
115
+ return;
116
+ this.columns = normalizedColumns;
117
+ this.rows = normalizedRows;
118
+ this.scrollRegionByBuffer = [this.fullScrollRegion(), this.fullScrollRegion()];
119
+ for (const cursor of this.cursorByBuffer) {
120
+ cursor.column = Math.min(cursor.column, this.columns - 1);
121
+ cursor.row = Math.min(cursor.row, this.rows - 1);
122
+ }
123
+ this.contentInvalidatedByBuffer = [true, true];
124
+ this.cursorReliableByBuffer = [false, false];
125
+ }
105
126
  reset() {
106
127
  this.state = S.ground;
107
128
  this.pendingHigh = '';
@@ -110,6 +131,19 @@ export class VisibleTextExtractor {
110
131
  this.pendingIntermediate = undefined;
111
132
  this.clearCsiCollect();
112
133
  }
134
+ normalizeColumns(columns) {
135
+ if (!Number.isFinite(columns) || columns < 1)
136
+ return DEFAULT_COLUMNS;
137
+ return Math.min(Math.trunc(columns), MAX_CSI_PARAM);
138
+ }
139
+ normalizeRows(rows) {
140
+ if (!Number.isFinite(rows) || rows < 1)
141
+ return DEFAULT_ROWS;
142
+ return Math.min(Math.trunc(rows), MAX_CSI_PARAM);
143
+ }
144
+ fullScrollRegion() {
145
+ return { top: 0, bottom: this.rows - 1 };
146
+ }
113
147
  collectCsiParam(ch) {
114
148
  if (ch === ';') {
115
149
  this.flushCsiParam();
@@ -166,40 +200,75 @@ export class VisibleTextExtractor {
166
200
  this.gl = slot;
167
201
  this.active = this.charsets[slot];
168
202
  }
169
- // `CSI ?2h` 只重指定 G0-G3,不碰 GL,也不碰已保存的那份。
170
203
  resetCharsetSlots() {
171
204
  this.charsets.fill(undefined);
172
205
  this.active = undefined;
173
206
  }
174
- // DECSTR 连 GL 与**当前 buffer** 保存的那份一起清;另一个 buffer 的存档不归它管。
175
207
  softReset() {
176
208
  this.resetCharsetSlots();
177
209
  this.gl = 0;
178
210
  this.conceal = false;
211
+ this.wraparound = true;
212
+ this.originMode = false;
213
+ this.scrollRegionByBuffer[this.altBuffer] = this.fullScrollRegion();
179
214
  this.savedByBuffer[this.altBuffer] = undefined;
180
215
  }
181
- // RIS 是整机复位:连 buffer 身份与两份存档一起回到初始。
182
216
  fullReset() {
183
217
  this.resetCharsetSlots();
184
218
  this.gl = 0;
185
219
  this.conceal = false;
220
+ this.wraparound = true;
186
221
  this.savedByBuffer = [undefined, undefined];
222
+ this.cursorByBuffer = [
223
+ { row: 0, column: 0 },
224
+ { row: 0, column: 0 },
225
+ ];
226
+ this.cursorReliableByBuffer = [true, true];
227
+ this.tabStopsReliableByBuffer = [true, true];
228
+ this.scrollRegionByBuffer = [this.fullScrollRegion(), this.fullScrollRegion()];
229
+ this.continuation = undefined;
230
+ this.carriageReturnContinuation = undefined;
231
+ this.contentInvalidatedByBuffer = [false, false];
232
+ this.printSequenceByBuffer = [0, 0];
233
+ this.originMode = false;
187
234
  this.altBuffer = 0;
188
235
  }
189
- // ESC % G/@ 只是"选回默认":动 G0 与 GL,不碰 G1-G3。
190
236
  selectDefaultCharset() {
191
237
  this.setgCharset(0, undefined);
192
238
  this.setgLevel(0);
193
239
  }
194
240
  saveCursorState() {
195
- this.savedByBuffer[this.altBuffer] = { charset: this.active, conceal: this.conceal };
241
+ const cursor = this.cursorByBuffer[this.altBuffer];
242
+ const continuation = this.continuation?.buffer === this.altBuffer
243
+ ? { ...this.continuation }
244
+ : undefined;
245
+ this.savedByBuffer[this.altBuffer] = {
246
+ charset: this.active,
247
+ conceal: this.conceal,
248
+ continuation,
249
+ printSequence: this.printSequenceByBuffer[this.altBuffer],
250
+ row: cursor.row,
251
+ column: cursor.column,
252
+ reliable: this.cursorReliableByBuffer[this.altBuffer],
253
+ };
196
254
  }
197
255
  restoreCursorState() {
198
256
  const saved = this.savedByBuffer[this.altBuffer];
199
257
  this.active = saved?.charset;
200
258
  this.conceal = saved?.conceal ?? false;
259
+ const reliable = saved?.reliable ?? true;
260
+ if (!reliable || !this.cursorReliableByBuffer[this.altBuffer])
261
+ this.contentInvalidated = true;
262
+ const printedSinceSave = saved !== undefined
263
+ && saved.printSequence !== this.printSequenceByBuffer[this.altBuffer];
264
+ if (printedSinceSave && saved.continuation !== undefined)
265
+ this.contentInvalidated = true;
266
+ this.assignCursor(saved?.column ?? 0, saved?.row ?? 0);
267
+ this.cursorReliableByBuffer[this.altBuffer] = reliable;
268
+ if (saved?.continuation !== undefined && !printedSinceSave && !this.contentInvalidated) {
269
+ this.continuation = { ...saved.continuation };
270
+ }
201
271
  }
202
- // SGR 8 让字形在屏幕上消失,单元格里却还留着字符——和字符集重映射是同一类问题。
203
272
  dispatchSgr() {
204
273
  for (let i = 0; i < this.csiParamValues.length; i++) {
205
274
  const param = this.csiParamValues[i];
@@ -212,7 +281,6 @@ export class VisibleTextExtractor {
212
281
  this.conceal = false;
213
282
  }
214
283
  }
215
- // 照搬 xterm 的 _extractColor 推进量:颜色载荷里的 8/28 是分量值,当成独立参数两个方向都会错。
216
284
  extendedColourSpan(leader) {
217
285
  let advance = 0;
218
286
  let cSpace = 0;
@@ -229,42 +297,506 @@ export class VisibleTextExtractor {
229
297
  return advance;
230
298
  }
231
299
  }
232
- dispatchCsi(final) {
233
- this.flushCsiParam();
234
- if (this.csiOverflowed) {
235
- // fall through to the reset below
300
+ csiParam(index = 0) {
301
+ return this.csiParamValues[index] || 1;
302
+ }
303
+ activeScrollRegion() {
304
+ return this.scrollRegionByBuffer[this.altBuffer];
305
+ }
306
+ get contentInvalidated() {
307
+ return this.contentInvalidatedByBuffer[this.altBuffer];
308
+ }
309
+ set contentInvalidated(value) {
310
+ this.contentInvalidatedByBuffer[this.altBuffer] = value;
311
+ }
312
+ assignCursor(column, row) {
313
+ const cursor = this.cursorByBuffer[this.altBuffer];
314
+ const region = this.activeScrollRegion();
315
+ const top = this.originMode ? region.top : 0;
316
+ const bottom = this.originMode ? region.bottom : this.rows - 1;
317
+ cursor.column = Math.max(0, Math.min(column, this.columns - 1));
318
+ cursor.row = Math.max(top, Math.min(row, bottom));
319
+ }
320
+ setAbsoluteCursor(column, row) {
321
+ const region = this.activeScrollRegion();
322
+ this.assignCursor(column, row + (this.originMode ? region.top : 0));
323
+ this.cursorReliableByBuffer[this.altBuffer] = true;
324
+ }
325
+ moveCursor(columns, rows) {
326
+ const cursor = this.cursorByBuffer[this.altBuffer];
327
+ this.assignCursor(Math.min(cursor.column, this.columns - 1) + columns, cursor.row + rows);
328
+ }
329
+ moveCursorToVerticalMargin(count, direction) {
330
+ const cursor = this.cursorByBuffer[this.altBuffer];
331
+ const region = this.activeScrollRegion();
332
+ const margin = direction === 1 ? region.bottom : region.top;
333
+ const inside = direction === 1 ? cursor.row <= margin : cursor.row >= margin;
334
+ const row = inside
335
+ ? direction === 1
336
+ ? Math.min(cursor.row + count, margin)
337
+ : Math.max(cursor.row - count, margin)
338
+ : cursor.row + direction * count;
339
+ this.assignCursor(cursor.column, row);
340
+ }
341
+ moveToTab(direction, count) {
342
+ const cursor = this.cursorByBuffer[this.altBuffer];
343
+ if (!this.tabStopsReliableByBuffer[this.altBuffer]) {
344
+ this.contentInvalidated = true;
345
+ this.cursorReliableByBuffer[this.altBuffer] = false;
346
+ return;
347
+ }
348
+ cursor.column = direction === 1
349
+ ? Math.min((Math.floor(cursor.column / 8) + count) * 8, this.columns - 1)
350
+ : Math.max(Math.ceil(cursor.column / 8) * 8 - 8 * count, 0);
351
+ }
352
+ invalidateTabStops() {
353
+ this.tabStopsReliableByBuffer[this.altBuffer] = false;
354
+ }
355
+ shiftContinuationForScroll(region, shiftPosition) {
356
+ const continuation = this.continuation;
357
+ if (continuation?.buffer !== this.altBuffer)
358
+ return;
359
+ if (region.top === 0
360
+ && region.bottom === this.rows - 1
361
+ && continuation.firstPrintedRow === region.top) {
362
+ if (this.altBuffer === 1) {
363
+ this.contentInvalidated = true;
364
+ return;
365
+ }
366
+ continuation.printedInScrollback = true;
367
+ }
368
+ const positionInRegion = continuation.row >= region.top && continuation.row <= region.bottom;
369
+ if (positionInRegion && continuation.row === region.top) {
370
+ this.contentInvalidated = true;
371
+ return;
372
+ }
373
+ if (positionInRegion && shiftPosition)
374
+ continuation.row--;
375
+ if (continuation.firstPrintedRow > region.top
376
+ && continuation.firstPrintedRow <= region.bottom) {
377
+ continuation.firstPrintedRow--;
378
+ }
379
+ if (continuation.lastPrintedRow > region.top
380
+ && continuation.lastPrintedRow <= region.bottom) {
381
+ continuation.lastPrintedRow--;
382
+ }
383
+ }
384
+ indexCursor(scrollContinuation) {
385
+ const cursor = this.cursorByBuffer[this.altBuffer];
386
+ const region = this.activeScrollRegion();
387
+ if (cursor.row === region.bottom) {
388
+ this.shiftContinuationForScroll(region, scrollContinuation);
389
+ return true;
390
+ }
391
+ if (cursor.row === this.rows - 1) {
392
+ if (!scrollContinuation)
393
+ this.contentInvalidated = true;
394
+ return false;
395
+ }
396
+ this.assignCursor(cursor.column, cursor.row + 1);
397
+ return true;
398
+ }
399
+ setScrollRegion() {
400
+ const top = this.csiParamValues[0] || 1;
401
+ const requestedBottom = this.csiParamValues[1] || this.rows;
402
+ const bottom = requestedBottom > this.rows ? this.rows : requestedBottom;
403
+ if (bottom <= top)
404
+ return;
405
+ this.scrollRegionByBuffer[this.altBuffer] = { top: top - 1, bottom: bottom - 1 };
406
+ this.setAbsoluteCursor(0, 0);
407
+ }
408
+ printedColumnsOnRow(continuation, row) {
409
+ if (row < continuation.firstPrintedRow || row > continuation.lastPrintedRow)
410
+ return undefined;
411
+ return [
412
+ row === continuation.firstPrintedRow ? continuation.firstPrintedColumn : 0,
413
+ row === continuation.lastPrintedRow ? continuation.lastPrintedColumn : this.columns - 1,
414
+ ];
415
+ }
416
+ eraseLineTouchesContinuation(mode) {
417
+ const continuation = this.continuation;
418
+ if (continuation?.buffer !== this.altBuffer)
419
+ return false;
420
+ if (!continuation.reliable || !this.cursorReliableByBuffer[this.altBuffer])
421
+ return true;
422
+ const cursor = this.cursorByBuffer[this.altBuffer];
423
+ const printed = this.printedColumnsOnRow(continuation, cursor.row);
424
+ if (printed === undefined)
425
+ return false;
426
+ if (mode === 2)
427
+ return true;
428
+ if (mode === 1)
429
+ return cursor.column >= printed[0];
430
+ if (mode !== 0 || cursor.column >= this.columns)
431
+ return false;
432
+ return cursor.column <= printed[1];
433
+ }
434
+ characterEditTouchesContinuation(final) {
435
+ const continuation = this.continuation;
436
+ if (continuation?.buffer !== this.altBuffer)
437
+ return false;
438
+ if (!continuation.reliable || !this.cursorReliableByBuffer[this.altBuffer])
439
+ return true;
440
+ const cursor = this.cursorByBuffer[this.altBuffer];
441
+ const printed = this.printedColumnsOnRow(continuation, cursor.row);
442
+ if (printed === undefined)
443
+ return false;
444
+ const start = Math.min(cursor.column, this.columns - 1);
445
+ if (final !== 'X')
446
+ return start <= printed[1];
447
+ const end = Math.min(start + this.csiParam() - 1, this.columns - 1);
448
+ return start <= printed[1] && end >= printed[0];
449
+ }
450
+ lineEditTouchesContinuation() {
451
+ const continuation = this.continuation;
452
+ if (continuation?.buffer !== this.altBuffer)
453
+ return false;
454
+ if (!continuation.reliable || !this.cursorReliableByBuffer[this.altBuffer])
455
+ return true;
456
+ const cursor = this.cursorByBuffer[this.altBuffer];
457
+ const region = this.activeScrollRegion();
458
+ if (cursor.row < region.top || cursor.row > region.bottom)
459
+ return false;
460
+ return continuation.firstPrintedRow <= region.bottom
461
+ && continuation.lastPrintedRow >= cursor.row;
462
+ }
463
+ columnEditTouchesContinuation() {
464
+ const continuation = this.continuation;
465
+ if (continuation?.buffer !== this.altBuffer)
466
+ return false;
467
+ if (!continuation.reliable || !this.cursorReliableByBuffer[this.altBuffer])
468
+ return true;
469
+ const cursor = this.cursorByBuffer[this.altBuffer];
470
+ const region = this.activeScrollRegion();
471
+ if (cursor.row < region.top || cursor.row > region.bottom)
472
+ return false;
473
+ const firstAffectedRow = Math.max(continuation.firstPrintedRow, region.top);
474
+ const lastAffectedRow = Math.min(continuation.lastPrintedRow, region.bottom);
475
+ if (firstAffectedRow > lastAffectedRow)
476
+ return false;
477
+ const start = Math.min(cursor.column, this.columns - 1);
478
+ return firstAffectedRow < continuation.lastPrintedRow
479
+ || start <= continuation.lastPrintedColumn;
480
+ }
481
+ eraseDisplayToEndTouchesContinuation() {
482
+ const continuation = this.continuation;
483
+ if (continuation?.buffer !== this.altBuffer)
484
+ return false;
485
+ if (!continuation.reliable || !this.cursorReliableByBuffer[this.altBuffer])
486
+ return true;
487
+ const cursor = this.cursorByBuffer[this.altBuffer];
488
+ if (cursor.column >= this.columns)
489
+ return false;
490
+ return cursor.row < continuation.lastPrintedRow
491
+ || (cursor.row === continuation.lastPrintedRow
492
+ && cursor.column <= continuation.lastPrintedColumn);
493
+ }
494
+ eraseDisplayToStartTouchesContinuation() {
495
+ const continuation = this.continuation;
496
+ if (continuation?.buffer !== this.altBuffer)
497
+ return false;
498
+ if (!continuation.reliable || !this.cursorReliableByBuffer[this.altBuffer])
499
+ return true;
500
+ const cursor = this.cursorByBuffer[this.altBuffer];
501
+ const column = Math.min(cursor.column, this.columns - 1);
502
+ return continuation.firstPrintedRow < cursor.row
503
+ || (continuation.firstPrintedRow === cursor.row
504
+ && continuation.firstPrintedColumn <= column);
505
+ }
506
+ dispatchCursorCsi(final) {
507
+ if (!this.cursorReliableByBuffer[this.altBuffer] && POSITIONING_CSI_FINALS.has(final)) {
508
+ this.contentInvalidated = true;
509
+ }
510
+ const cursor = this.cursorByBuffer[this.altBuffer];
511
+ switch (final) {
512
+ case '@':
513
+ case 'P':
514
+ case 'X':
515
+ if (this.characterEditTouchesContinuation(final))
516
+ this.contentInvalidated = true;
517
+ this.assignCursor(Math.min(cursor.column, this.columns - 1), cursor.row);
518
+ break;
519
+ case 'A':
520
+ this.moveCursorToVerticalMargin(this.csiParam(), -1);
521
+ break;
522
+ case 'B':
523
+ this.moveCursorToVerticalMargin(this.csiParam(), 1);
524
+ break;
525
+ case 'C':
526
+ case 'a':
527
+ this.moveCursor(this.csiParam(), 0);
528
+ break;
529
+ case 'D':
530
+ this.moveCursor(-this.csiParam(), 0);
531
+ break;
532
+ case 'E':
533
+ this.moveCursorToVerticalMargin(this.csiParam(), 1);
534
+ this.assignCursor(0, cursor.row);
535
+ break;
536
+ case 'F':
537
+ this.moveCursorToVerticalMargin(this.csiParam(), -1);
538
+ this.assignCursor(0, cursor.row);
539
+ break;
540
+ case 'G':
541
+ case '`':
542
+ this.assignCursor(this.csiParam() - 1, cursor.row);
543
+ break;
544
+ case 'H':
545
+ case 'f':
546
+ this.setAbsoluteCursor(this.csiParam(1) - 1, this.csiParam(0) - 1);
547
+ break;
548
+ case 'I':
549
+ this.moveToTab(1, this.csiParam());
550
+ break;
551
+ case 'J':
552
+ case 'K': {
553
+ const mode = this.csiParamValues[0] ?? 0;
554
+ const touches = final === 'K'
555
+ ? this.eraseLineTouchesContinuation(mode)
556
+ : mode === 2
557
+ || (mode === 0 && this.eraseDisplayToEndTouchesContinuation())
558
+ || (mode === 1 && this.eraseDisplayToStartTouchesContinuation())
559
+ || (mode === 3
560
+ && this.continuation?.buffer === this.altBuffer
561
+ && this.continuation.printedInScrollback);
562
+ if (touches) {
563
+ this.contentInvalidated = true;
564
+ }
565
+ break;
566
+ }
567
+ case 'L':
568
+ case 'M': {
569
+ const region = this.activeScrollRegion();
570
+ this.assignCursor(Math.min(cursor.column, this.columns - 1), cursor.row);
571
+ if (cursor.row >= region.top && cursor.row <= region.bottom) {
572
+ if (this.lineEditTouchesContinuation())
573
+ this.contentInvalidated = true;
574
+ this.assignCursor(0, cursor.row);
575
+ }
576
+ break;
577
+ }
578
+ case 'S':
579
+ case 'T':
580
+ this.contentInvalidated = true;
581
+ break;
582
+ case 'Z':
583
+ this.moveToTab(-1, this.csiParam());
584
+ break;
585
+ case 'b':
586
+ this.moveCursor(this.csiParam(), 0);
587
+ break;
588
+ case 'd':
589
+ this.assignCursor(cursor.column, this.csiParam() - 1 + (this.originMode ? this.activeScrollRegion().top : 0));
590
+ break;
591
+ case 'e':
592
+ this.moveCursor(0, this.csiParam());
593
+ break;
594
+ case 'g':
595
+ if (this.csiParamValues[0] === 0 || this.csiParamValues[0] === 3)
596
+ this.invalidateTabStops();
597
+ break;
598
+ case 'r':
599
+ this.setScrollRegion();
600
+ break;
601
+ default: break;
602
+ }
603
+ }
604
+ emitPrint(text, widthReliable = true) {
605
+ this.carriageReturnContinuation = undefined;
606
+ const cursor = this.cursorByBuffer[this.altBuffer];
607
+ const reliable = this.cursorReliableByBuffer[this.altBuffer];
608
+ const consumesPendingWrap = reliable && cursor.column >= this.columns && this.wraparound;
609
+ if (reliable && cursor.column >= this.columns) {
610
+ if (this.wraparound) {
611
+ cursor.column = 0;
612
+ this.indexCursor(false);
613
+ }
614
+ else {
615
+ cursor.column = this.columns - 1;
616
+ }
236
617
  }
237
- else if (this.csiPrefix === '?') {
238
- if (this.csiIntermediates === '')
239
- this.dispatchPrivateMode(final);
618
+ const printedRow = cursor.row;
619
+ const printedColumn = cursor.column;
620
+ const previous = this.continuation;
621
+ const continuous = this.continuation === undefined
622
+ || (this.continuation.buffer === this.altBuffer
623
+ && this.continuation.reliable === reliable
624
+ && (!this.continuation.wrapPending || consumesPendingWrap)
625
+ && ((this.continuation.row === cursor.row && this.continuation.column === cursor.column)
626
+ || (cursor.row === this.continuation.row + 1 && cursor.column === 0)));
627
+ const boundary = this.contentInvalidated || !continuous ? REMAPPED : '';
628
+ this.contentInvalidated = false;
629
+ this.printSequenceByBuffer[this.altBuffer]++;
630
+ const nextColumn = cursor.column + 1;
631
+ if (reliable) {
632
+ cursor.column = this.wraparound ? nextColumn : Math.min(nextColumn, this.columns - 1);
240
633
  }
241
- else if (this.csiPrefix === '' && this.csiIntermediates === '' && final === 's') {
242
- this.saveCursorState();
634
+ else {
635
+ cursor.column = Math.min(nextColumn, MAX_CSI_PARAM);
243
636
  }
244
- else if (this.csiPrefix === '' && this.csiIntermediates === '' && final === 'u') {
245
- this.restoreCursorState();
637
+ const nextReliable = reliable && widthReliable;
638
+ this.cursorReliableByBuffer[this.altBuffer] = nextReliable;
639
+ const region = this.activeScrollRegion();
640
+ const wraps = nextReliable && this.wraparound && nextColumn === this.columns;
641
+ const nextRow = wraps
642
+ ? cursor.row === region.bottom || cursor.row === this.rows - 1
643
+ ? cursor.row
644
+ : cursor.row + 1
645
+ : cursor.row;
646
+ this.continuation = {
647
+ buffer: this.altBuffer,
648
+ firstPrintedColumn: boundary === '' && previous?.buffer === this.altBuffer
649
+ ? previous.firstPrintedColumn
650
+ : printedColumn,
651
+ firstPrintedRow: boundary === '' && previous?.buffer === this.altBuffer
652
+ ? previous.firstPrintedRow
653
+ : printedRow,
654
+ lastPrintedColumn: printedColumn,
655
+ lastPrintedRow: printedRow,
656
+ printedInScrollback: boundary === '' && previous?.buffer === this.altBuffer
657
+ ? previous.printedInScrollback
658
+ : false,
659
+ row: nextRow,
660
+ column: wraps ? 0 : nextColumn,
661
+ reliable: nextReliable,
662
+ wrapPending: wraps && nextRow === cursor.row,
663
+ };
664
+ return boundary + text;
665
+ }
666
+ acceptCursorMovement() {
667
+ if (this.continuation?.buffer !== this.altBuffer)
668
+ return;
669
+ const cursor = this.cursorByBuffer[this.altBuffer];
670
+ this.continuation = {
671
+ ...this.continuation,
672
+ row: cursor.row,
673
+ column: cursor.column,
674
+ reliable: this.cursorReliableByBuffer[this.altBuffer],
675
+ wrapPending: false,
676
+ };
677
+ }
678
+ cursorIsAtContinuation() {
679
+ const continuation = this.continuation;
680
+ const cursor = this.cursorByBuffer[this.altBuffer];
681
+ return continuation?.buffer === this.altBuffer
682
+ && continuation.reliable === this.cursorReliableByBuffer[this.altBuffer]
683
+ && continuation.row === cursor.row
684
+ && continuation.column === cursor.column;
685
+ }
686
+ canAcceptVerticalMovement() {
687
+ if (this.cursorIsAtContinuation())
688
+ return true;
689
+ const continuation = this.continuation;
690
+ const cursor = this.cursorByBuffer[this.altBuffer];
691
+ return continuation !== undefined
692
+ && continuation === this.carriageReturnContinuation
693
+ && continuation.buffer === this.altBuffer
694
+ && continuation.reliable === this.cursorReliableByBuffer[this.altBuffer]
695
+ && continuation.row === cursor.row
696
+ && cursor.column === 0;
697
+ }
698
+ executeCursorC0(code, acceptMovement) {
699
+ const cursor = this.cursorByBuffer[this.altBuffer];
700
+ let moved = true;
701
+ let acceptsVerticalMovement = true;
702
+ if (code === 0x08)
703
+ this.moveCursor(-1, 0);
704
+ else if (code === 0x09)
705
+ this.moveToTab(1, 1);
706
+ else if (code === 0x0a || code === 0x0b || code === 0x0c) {
707
+ acceptsVerticalMovement = this.canAcceptVerticalMovement();
708
+ moved = this.indexCursor(true);
709
+ this.carriageReturnContinuation = undefined;
246
710
  }
247
- else if (this.csiPrefix === '' && this.csiIntermediates === '' && final === SGR_FINAL) {
248
- this.dispatchSgr();
711
+ else if (code === 0x0d) {
712
+ this.carriageReturnContinuation = this.cursorIsAtContinuation()
713
+ ? this.continuation
714
+ : undefined;
715
+ this.assignCursor(0, cursor.row);
249
716
  }
250
- else if (this.csiPrefix === '' && this.csiIntermediates === '!' && final === 'p') {
251
- this.softReset(); // DECSTR
717
+ if (acceptMovement && moved && acceptsVerticalMovement)
718
+ this.acceptCursorMovement();
719
+ }
720
+ dispatchCsi(final) {
721
+ this.flushCsiParam();
722
+ if (!this.csiOverflowed) {
723
+ if (this.csiPrefix === '?' && this.csiIntermediates === '') {
724
+ if (final === 'J' || final === 'K')
725
+ this.dispatchCursorCsi(final);
726
+ else
727
+ this.dispatchPrivateMode(final);
728
+ }
729
+ else if (this.csiPrefix === '' && this.csiIntermediates === '' && final === 's') {
730
+ this.saveCursorState();
731
+ }
732
+ else if (this.csiPrefix === '' && this.csiIntermediates === '' && final === 'u') {
733
+ this.restoreCursorState();
734
+ }
735
+ else if (this.csiPrefix === '' && this.csiIntermediates === '' && final === SGR_FINAL) {
736
+ this.dispatchSgr();
737
+ }
738
+ else if (this.csiPrefix === '' && this.csiIntermediates === '') {
739
+ this.dispatchCursorCsi(final);
740
+ }
741
+ else if (this.csiPrefix === ''
742
+ && this.csiIntermediates === "'"
743
+ && (final === '}' || final === '~')) {
744
+ if (this.columnEditTouchesContinuation())
745
+ this.contentInvalidated = true;
746
+ }
747
+ else if (this.csiPrefix === '' && this.csiIntermediates === '!' && final === 'p') {
748
+ this.softReset();
749
+ }
750
+ else if (this.csiPrefix === '' && this.csiIntermediates === ' ' && (final === '@' || final === 'A')) {
751
+ this.contentInvalidated = true;
752
+ }
252
753
  }
253
- // 派发出去的 8-bit CSI 真会动屏幕,而 main 的正则不认 0x9b、天然隔开 marker——只有 SGR 例外,
254
- // 它唯一的可见性影响(conceal)已经建模。取消/ignore 的序列 xterm 整条丢弃,不在此列。
255
754
  const transparent = this.csiPrefix === '' && this.csiIntermediates === '' && final === SGR_FINAL;
256
755
  const boundary = this.csiEightBit && !transparent ? REMAPPED : '';
257
756
  this.clearCsiCollect();
258
757
  this.state = S.ground;
259
758
  return boundary;
260
759
  }
760
+ activateAltBuffer() {
761
+ if (this.altBuffer === 1)
762
+ return;
763
+ const saved = this.savedByBuffer[1];
764
+ if (saved !== undefined) {
765
+ this.savedByBuffer[1] = { ...saved, continuation: undefined };
766
+ }
767
+ if (this.continuation?.buffer === 1) {
768
+ this.continuation = undefined;
769
+ this.contentInvalidatedByBuffer[1] = true;
770
+ }
771
+ else {
772
+ this.contentInvalidatedByBuffer[1] = false;
773
+ }
774
+ const cursor = this.cursorByBuffer[0];
775
+ this.altBuffer = 1;
776
+ this.cursorByBuffer[1] = { ...cursor };
777
+ this.cursorReliableByBuffer[1] = this.cursorReliableByBuffer[0];
778
+ this.tabStopsReliableByBuffer[1] = true;
779
+ this.scrollRegionByBuffer[1] = this.fullScrollRegion();
780
+ }
781
+ activateMainBuffer() {
782
+ if (this.altBuffer === 0)
783
+ return;
784
+ const cursor = this.cursorByBuffer[1];
785
+ const cursorReliable = this.cursorReliableByBuffer[1];
786
+ this.altBuffer = 0;
787
+ this.cursorByBuffer[0] = { ...cursor };
788
+ this.cursorReliableByBuffer[0] = cursorReliable;
789
+ this.contentInvalidatedByBuffer[1] = false;
790
+ this.cursorByBuffer[1] = { row: 0, column: 0 };
791
+ this.cursorReliableByBuffer[1] = true;
792
+ this.tabStopsReliableByBuffer[1] = true;
793
+ this.scrollRegionByBuffer[1] = this.fullScrollRegion();
794
+ }
261
795
  dispatchPrivateMode(final) {
262
796
  if (final !== 'h' && final !== 'l')
263
797
  return;
264
798
  const set = final === 'h';
265
799
  for (const param of this.csiParamValues) {
266
- // 保存/恢复与切屏是两件事:1048 只在当前 buffer 存取游标字符集、不切屏;
267
- // 47/1047 只切屏、不存取;1049 两件都做。
268
800
  if (param === 1048) {
269
801
  if (set)
270
802
  this.saveCursorState();
@@ -274,15 +806,27 @@ export class VisibleTextExtractor {
274
806
  else if (param === 1049) {
275
807
  if (set) {
276
808
  this.saveCursorState();
277
- this.altBuffer = 1;
809
+ this.activateAltBuffer();
278
810
  }
279
811
  else {
280
- this.altBuffer = 0;
812
+ this.activateMainBuffer();
281
813
  this.restoreCursorState();
282
814
  }
283
815
  }
284
816
  else if (param === 47 || param === 1047) {
285
- this.altBuffer = set ? 1 : 0;
817
+ if (set)
818
+ this.activateAltBuffer();
819
+ else
820
+ this.activateMainBuffer();
821
+ }
822
+ else if (param === 6) {
823
+ if (!this.cursorReliableByBuffer[this.altBuffer])
824
+ this.contentInvalidated = true;
825
+ this.originMode = set;
826
+ this.setAbsoluteCursor(0, 0);
827
+ }
828
+ else if (param === 7) {
829
+ this.wraparound = set;
286
830
  }
287
831
  else if (param === 2 && set) {
288
832
  this.resetCharsetSlots();
@@ -293,7 +837,6 @@ export class VisibleTextExtractor {
293
837
  return this.active !== undefined && (REMAPPED_CODES.get(this.active)?.has(code) ?? false);
294
838
  }
295
839
  write(rawChunk) {
296
- // 按码点解析:跨 write 拆开的代理对要缝回去,否则低代理会落在与高代理不同的状态里。
297
840
  const chunk = this.pendingHigh + rawChunk;
298
841
  this.pendingHigh = '';
299
842
  let out = '';
@@ -311,10 +854,11 @@ export class VisibleTextExtractor {
311
854
  }
312
855
  }
313
856
  if (code === 0xfeff)
314
- continue; // xterm 的 StringToUtf32 在喂进转移表前就丢掉 BOM
857
+ continue;
315
858
  if (code >= 0xa0) {
316
- if (this.state === S.ground)
317
- out += this.conceal ? REMAPPED : chunk.slice(i, i + width);
859
+ if (this.state === S.ground) {
860
+ out += this.emitPrint(this.conceal ? REMAPPED : chunk.slice(i, i + width), false);
861
+ }
318
862
  else if (!NON_ASCII_IGNORED.has(this.state)) {
319
863
  this.pendingIntermediate = undefined;
320
864
  this.state = S.ground;
@@ -323,16 +867,27 @@ export class VisibleTextExtractor {
323
867
  continue;
324
868
  }
325
869
  if (CURSOR_MOVING_C0.has(code)) {
326
- // 序列里的 CR 不是软换行的一半,而是真把后半段重画到行首。
327
- if (EXECUTES_C0.has(this.state))
870
+ if (EXECUTES_C0.has(this.state)) {
328
871
  out += code === 0x0d && this.state !== S.ground ? REMAPPED : chunk[i];
329
- continue; // EXECUTE ignore 都保持当前状态
872
+ this.executeCursorC0(code, code !== 0x0d && code !== 0x09);
873
+ }
874
+ continue;
875
+ }
876
+ if ((code === 0x0b || code === 0x0c) && EXECUTES_C0.has(this.state)) {
877
+ this.executeCursorC0(code, true);
878
+ continue;
330
879
  }
331
880
  if (code === 0x0e || code === 0x0f) {
332
881
  if (EXECUTES_C0.has(this.state))
333
882
  this.setgLevel(code === 0x0e ? 1 : 0);
334
883
  continue;
335
884
  }
885
+ if (code === 0x88) {
886
+ this.invalidateTabStops();
887
+ this.pendingIntermediate = undefined;
888
+ this.state = S.ground;
889
+ continue;
890
+ }
336
891
  const jump = anywhereTransition(code);
337
892
  if (jump !== undefined) {
338
893
  this.pendingIntermediate = undefined;
@@ -346,7 +901,7 @@ export class VisibleTextExtractor {
346
901
  switch (this.state) {
347
902
  case S.ground:
348
903
  if (code >= 0x20 && code <= 0x7e) {
349
- out += this.conceal || this.remapsCode(code) ? REMAPPED : chunk[i];
904
+ out += this.emitPrint(this.conceal || this.remapsCode(code) ? REMAPPED : chunk[i]);
350
905
  }
351
906
  break;
352
907
  case S.escape:
@@ -378,9 +933,30 @@ export class VisibleTextExtractor {
378
933
  else if (code === 0x63) {
379
934
  this.fullReset();
380
935
  out += REMAPPED;
381
- } // RIS wipes the screen
382
- else if (code === 0x4d)
383
- out += REMAPPED; // RI 把后半段挪到前半段上一行
936
+ }
937
+ else if (code === 0x44) {
938
+ const acceptsMovement = this.canAcceptVerticalMovement();
939
+ const moved = this.indexCursor(true);
940
+ this.carriageReturnContinuation = undefined;
941
+ if (moved && acceptsMovement)
942
+ this.acceptCursorMovement();
943
+ }
944
+ else if (code === 0x45) {
945
+ const cursor = this.cursorByBuffer[this.altBuffer];
946
+ const acceptsMovement = this.canAcceptVerticalMovement();
947
+ const moved = this.indexCursor(true);
948
+ this.assignCursor(0, cursor.row);
949
+ this.carriageReturnContinuation = undefined;
950
+ if (moved && acceptsMovement)
951
+ this.acceptCursorMovement();
952
+ }
953
+ else if (code === 0x4d) {
954
+ this.moveCursor(0, -1);
955
+ out += REMAPPED;
956
+ this.continuation = undefined;
957
+ }
958
+ else if (code === 0x48)
959
+ this.invalidateTabStops();
384
960
  this.state = S.ground;
385
961
  }
386
962
  break;
@@ -394,10 +970,10 @@ export class VisibleTextExtractor {
394
970
  this.setgCharset(slot, chunk[i]);
395
971
  }
396
972
  else if (intermediate === '%' && (code === 0x47 || code === 0x40)) {
397
- this.selectDefaultCharset(); // only ESC % G / ESC % @; other finals are ignored
973
+ this.selectDefaultCharset();
398
974
  }
399
975
  else if (intermediate === '#' && code === 0x38)
400
- out += REMAPPED; // DECALN wipes the screen
976
+ out += REMAPPED;
401
977
  this.state = S.ground;
402
978
  }
403
979
  else if (code >= 0x20 && code <= 0x2f) {
@@ -430,7 +1006,7 @@ export class VisibleTextExtractor {
430
1006
  }
431
1007
  else if (code >= 0x30 && code <= 0x3b)
432
1008
  this.collectCsiParam(chunk[i]);
433
- break; // 剩下的 C0/DEL 在参数态是 execute/ignore,不能当数字累进参数
1009
+ break;
434
1010
  case S.csiIntermediate:
435
1011
  if (code >= 0x40 && code <= 0x7e)
436
1012
  out += this.dispatchCsi(chunk[i]);
@@ -467,7 +1043,7 @@ export class VisibleTextExtractor {
467
1043
  break;
468
1044
  case S.oscString:
469
1045
  if (code === 0x07)
470
- this.state = S.ground; // BEL 只终结 OSC,其余控制串忽略它
1046
+ this.state = S.ground;
471
1047
  break;
472
1048
  default:
473
1049
  break;
@@ -476,7 +1052,7 @@ export class VisibleTextExtractor {
476
1052
  return out;
477
1053
  }
478
1054
  }
479
- export function visibleText(text) {
480
- return new VisibleTextExtractor().write(text);
1055
+ export function visibleText(text, columns = DEFAULT_COLUMNS, rows = DEFAULT_ROWS) {
1056
+ return new VisibleTextExtractor(columns, rows).write(text);
481
1057
  }
482
1058
  //# sourceMappingURL=vt-visible-text.js.map