@textui/terminal 0.3.0 → 0.5.0

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 +1 @@
1
- {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAO,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AA8BzD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,GAAG,MAAM,CAU3F;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,GAAG,MAAM,CAU3F;AAED,eAAO,MAAM,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EASrC,CAAC;AAMF,qBAAa,MAAM;IAGL,OAAO,CAAC,YAAY;IAFhC,OAAO,CAAC,KAAK,CAAgB;gBAET,YAAY,EAAE,oBAAoB;IAEtD,eAAe,CAAC,YAAY,EAAE,oBAAoB,GAAG,IAAI;IAKzD,yEAAyE;IACzE,UAAU,IAAI,IAAI;IAIlB,oEAAoE;IACpE,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IA8B3B,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,WAAW;CA6CpB;AAYD,wBAAgB,YAAY,CAAC,YAAY,EAAE,oBAAoB,GAAG,MAAM,CAEvE"}
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAO,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AA0CzD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,GAAG,MAAM,CAU3F;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,GAAG,MAAM,CAU3F;AAED,eAAO,MAAM,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EASrC,CAAC;AAMF,qBAAa,MAAM;IAGL,OAAO,CAAC,YAAY;IAFhC,OAAO,CAAC,KAAK,CAAgB;gBAET,YAAY,EAAE,oBAAoB;IAEtD,eAAe,CAAC,YAAY,EAAE,oBAAoB,GAAG,IAAI;IAKzD,yEAAyE;IACzE,UAAU,IAAI,IAAI;IAIlB,oEAAoE;IACpE,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAuC3B,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,WAAW;CA6CpB;AAYD,wBAAgB,YAAY,CAAC,YAAY,EAAE,oBAAoB,GAAG,MAAM,CAEvE"}
package/dist/writer.js CHANGED
@@ -2,7 +2,10 @@ import { COLOR_DEFAULT, downsample, isRgb, unpackRgb } from '@textui/core';
2
2
  import { ATTR_BLINK, ATTR_BOLD, ATTR_DIM, ATTR_HIDDEN, ATTR_INVERSE, ATTR_ITALIC, ATTR_STRIKE, ATTR_UNDERLINE, } from '@textui/core';
3
3
  import * as ansi from './ansi.js';
4
4
  function freshState() {
5
- return { fg: COLOR_DEFAULT, bg: COLOR_DEFAULT, attrs: 0, link: undefined, x: -1, y: -1, valid: false };
5
+ return {
6
+ fg: COLOR_DEFAULT, bg: COLOR_DEFAULT, attrs: 0, link: undefined,
7
+ x: -1, y: -1, valid: false, cursorShown: false,
8
+ };
6
9
  }
7
10
  export function fgSequence(color, depth) {
8
11
  const c = downsample(color, depth);
@@ -61,7 +64,9 @@ export class Writer {
61
64
  }
62
65
  /** Encode a frame. Returns an empty string when nothing changed. */
63
66
  write(frame) {
64
- if (frame.runs.length === 0 && !frame.cursor)
67
+ // Nothing to paint, nowhere to put the caret, and none on screen to take
68
+ // away. A frame that has to *hide* one still has work to do.
69
+ if (frame.runs.length === 0 && !frame.cursor && !this.state.cursorShown)
65
70
  return '';
66
71
  const out = [];
67
72
  const sync = this.capabilities.synchronizedOutput;
@@ -69,9 +74,12 @@ export class Writer {
69
74
  out.push(ansi.syncStart);
70
75
  // A frame is painted with the cursor hidden; showing it once at the end
71
76
  // is the difference between a steady caret and one that streaks.
72
- const hideForPaint = this.capabilities.cursor && frame.runs.length > 0;
73
- if (hideForPaint)
77
+ const hideForPaint = this.capabilities.cursor
78
+ && (frame.runs.length > 0 || (this.state.cursorShown && !frame.cursor));
79
+ if (hideForPaint) {
74
80
  out.push(ansi.cursorHide);
81
+ this.state.cursorShown = false;
82
+ }
75
83
  for (const run of frame.runs)
76
84
  out.push(this.encodeRun(run));
77
85
  if (this.state.link !== undefined) {
@@ -82,8 +90,10 @@ export class Writer {
82
90
  out.push(ansi.cursorTo(frame.cursor.x, frame.cursor.y));
83
91
  this.state.x = frame.cursor.x;
84
92
  this.state.y = frame.cursor.y;
85
- if (frame.cursor.visible)
93
+ if (frame.cursor.visible) {
86
94
  out.push(ansi.cursorShow);
95
+ this.state.cursorShown = true;
96
+ }
87
97
  }
88
98
  if (sync)
89
99
  out.push(ansi.syncEnd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@textui/terminal",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Terminal adapters, capability detection, ANSI writing and input decoding for TextUI",
5
5
  "keywords": [
6
6
  "terminal",
@@ -54,7 +54,7 @@
54
54
  "test": "vitest run"
55
55
  },
56
56
  "dependencies": {
57
- "@textui/core": "^0.3.0"
57
+ "@textui/core": "^0.5.0"
58
58
  },
59
59
  "publishConfig": {
60
60
  "access": "public"
package/src/writer.ts CHANGED
@@ -23,10 +23,22 @@ interface WriterState {
23
23
  x: number;
24
24
  y: number;
25
25
  valid: boolean;
26
+ /**
27
+ * Whether the terminal is currently showing its cursor.
28
+ *
29
+ * Tracked because a frame can need the cursor *taken away* without painting
30
+ * anything: focus moving from a text field to a control that has no caret
31
+ * changes no cell the field did not already own, and the cursor was left
32
+ * sitting in the field somebody had just tabbed out of.
33
+ */
34
+ cursorShown: boolean;
26
35
  }
27
36
 
28
37
  function freshState(): WriterState {
29
- return { fg: COLOR_DEFAULT, bg: COLOR_DEFAULT, attrs: 0, link: undefined, x: -1, y: -1, valid: false };
38
+ return {
39
+ fg: COLOR_DEFAULT, bg: COLOR_DEFAULT, attrs: 0, link: undefined,
40
+ x: -1, y: -1, valid: false, cursorShown: false,
41
+ };
30
42
  }
31
43
 
32
44
  export function fgSequence(color: number, depth: TerminalCapabilities['colorDepth']): string {
@@ -85,7 +97,9 @@ export class Writer {
85
97
 
86
98
  /** Encode a frame. Returns an empty string when nothing changed. */
87
99
  write(frame: Frame): string {
88
- if (frame.runs.length === 0 && !frame.cursor) return '';
100
+ // Nothing to paint, nowhere to put the caret, and none on screen to take
101
+ // away. A frame that has to *hide* one still has work to do.
102
+ if (frame.runs.length === 0 && !frame.cursor && !this.state.cursorShown) return '';
89
103
 
90
104
  const out: string[] = [];
91
105
  const sync = this.capabilities.synchronizedOutput;
@@ -93,8 +107,12 @@ export class Writer {
93
107
 
94
108
  // A frame is painted with the cursor hidden; showing it once at the end
95
109
  // is the difference between a steady caret and one that streaks.
96
- const hideForPaint = this.capabilities.cursor && frame.runs.length > 0;
97
- if (hideForPaint) out.push(ansi.cursorHide);
110
+ const hideForPaint = this.capabilities.cursor
111
+ && (frame.runs.length > 0 || (this.state.cursorShown && !frame.cursor));
112
+ if (hideForPaint) {
113
+ out.push(ansi.cursorHide);
114
+ this.state.cursorShown = false;
115
+ }
98
116
 
99
117
  for (const run of frame.runs) out.push(this.encodeRun(run));
100
118
 
@@ -107,7 +125,10 @@ export class Writer {
107
125
  out.push(ansi.cursorTo(frame.cursor.x, frame.cursor.y));
108
126
  this.state.x = frame.cursor.x;
109
127
  this.state.y = frame.cursor.y;
110
- if (frame.cursor.visible) out.push(ansi.cursorShow);
128
+ if (frame.cursor.visible) {
129
+ out.push(ansi.cursorShow);
130
+ this.state.cursorShown = true;
131
+ }
111
132
  }
112
133
 
113
134
  if (sync) out.push(ansi.syncEnd);