@mailwoman/map-tui 9.1.1 → 9.2.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.
@@ -0,0 +1,168 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ /**
7
+ * Argument parsing for the `map-tui` bin.
8
+ *
9
+ * `parseCLIArgs` is pure: it takes the argv slice and an environment record, and answers with a discriminated result
10
+ * (`help` / `version` / `browse`) or throws {@link CLIArgsError}. Reading `process.argv` / `process.env` is the bin's
11
+ * job (./cli.ts), which keeps every rejection path testable without a subprocess.
12
+ */
13
+ import { parseArgs } from "node:util";
14
+ /**
15
+ * Center longitude when `--lon` is omitted — the world view mapscii opens on.
16
+ */
17
+ const DEFAULT_LON = 0;
18
+ /**
19
+ * Center latitude when `--lat` is omitted.
20
+ */
21
+ const DEFAULT_LAT = 0;
22
+ /**
23
+ * Zoom when `--zoom` is omitted. z2 shows a full hemisphere in a typical terminal, so a planet archive opens on
24
+ * something recognizable rather than a single ocean tile.
25
+ */
26
+ const DEFAULT_ZOOM = 2;
27
+ /**
28
+ * Widest zoom any tile archive uses.
29
+ */
30
+ const MIN_ZOOM = 0;
31
+ /**
32
+ * Deepest zoom the Web-Mercator tile pyramid is defined for. The archive's own `maxZoom` clamps further at runtime;
33
+ * this is only the range a flag value must fall inside to be meaningful at all.
34
+ */
35
+ const MAX_ZOOM = 24;
36
+ const MIN_LAT = -90;
37
+ const MAX_LAT = 90;
38
+ const MIN_LON = -180;
39
+ const MAX_LON = 180;
40
+ /**
41
+ * A rejected command line. The message is user-facing: it says what was wrong AND what to pass instead, since the bin
42
+ * prints it verbatim to stderr.
43
+ */
44
+ export class CLIArgsError extends Error {
45
+ name = "CLIArgsError";
46
+ }
47
+ /**
48
+ * `--help` output. It doubles as the package's key reference, so the bindings listed here and the ones ./input.ts
49
+ * decodes are the same list said twice — a key added there without a line here is a key nobody finds.
50
+ */
51
+ export const HELP_TEXT = `map-tui — the whole world in your terminal
52
+
53
+ Usage
54
+ npx @mailwoman/map-tui --tiles <archive.pmtiles> [options]
55
+
56
+ Options
57
+ --tiles <path|url> PMTiles archive — local path or https:// URL (default: $MAILWOMAN_TILES)
58
+ --lat <degrees> Initial center latitude, -90..90 (default: ${DEFAULT_LAT})
59
+ --lon <degrees> Initial center longitude, -180..180 (default: ${DEFAULT_LON})
60
+ --zoom <level> Initial zoom, ${MIN_ZOOM}..${MAX_ZOOM} (default: ${DEFAULT_ZOOM})
61
+ -h, --help Print this help and exit
62
+ -v, --version Print the package version and exit
63
+
64
+ Keys
65
+ arrows, hjkl Pan
66
+ +, =, a Zoom in
67
+ -, _, z Zoom out
68
+ q, Esc, Ctrl+C Quit
69
+
70
+ Mouse
71
+ Wheel zooms toward the pointer, drag pans, click centers.
72
+
73
+ Tiles are never bundled with this package. Download a planet or region
74
+ archive from https://protomaps.com/downloads and point --tiles at it.
75
+ `;
76
+ /**
77
+ * Reads one numeric flag, rejecting anything `Number` would quietly accept as garbage (empty string, whitespace,
78
+ * `Infinity`) as well as out-of-range values.
79
+ */
80
+ function numericFlag(name, raw, fallback, min, max) {
81
+ if (raw == null)
82
+ return fallback;
83
+ const value = Number(raw.trim());
84
+ if (!Number.isFinite(value) || !raw.trim().length) {
85
+ throw new CLIArgsError(`--${name} expects a number, got ${JSON.stringify(raw)}`);
86
+ }
87
+ if (value < min || value > max) {
88
+ throw new CLIArgsError(`--${name} must be between ${min} and ${max}, got ${value}`);
89
+ }
90
+ return value;
91
+ }
92
+ /**
93
+ * Flags whose value is a number, and may therefore start with a dash.
94
+ */
95
+ const NUMERIC_FLAGS = new Set(["--lat", "--lon", "--zoom"]);
96
+ /**
97
+ * Joins `--lon -122.6` into `--lon=-122.6` before `parseArgs` sees it.
98
+ *
99
+ * `node:util`'s parser refuses a separate value that starts with a dash — it cannot tell a negative number from a
100
+ * mistyped flag, and says so ("argument is ambiguous"). Half the planet has a negative longitude, so the space-form has
101
+ * to work. The join is conditional on the next token parsing as a finite number, which leaves a genuinely missing value
102
+ * (`--lon --zoom 3`) to `parseArgs` and its own error.
103
+ */
104
+ function joinNegativeNumbers(argv) {
105
+ const joined = [];
106
+ for (let index = 0; index < argv.length; index++) {
107
+ const token = argv[index];
108
+ const next = argv[index + 1];
109
+ if (NUMERIC_FLAGS.has(token) && next?.startsWith("-") && Number.isFinite(Number(next))) {
110
+ joined.push(`${token}=${next}`);
111
+ index += 1;
112
+ continue;
113
+ }
114
+ joined.push(token);
115
+ }
116
+ return joined;
117
+ }
118
+ /**
119
+ * `node:util`'s own rejections (unknown flag, missing value) name the flag but not the remedy, so they're re-thrown as
120
+ * a {@link CLIArgsError} pointing at `--help`.
121
+ */
122
+ function readFlags(argv) {
123
+ try {
124
+ const { values } = parseArgs({
125
+ args: joinNegativeNumbers(argv),
126
+ options: {
127
+ tiles: { type: "string" },
128
+ lat: { type: "string" },
129
+ lon: { type: "string" },
130
+ zoom: { type: "string" },
131
+ help: { type: "boolean", short: "h" },
132
+ version: { type: "boolean", short: "v" },
133
+ },
134
+ allowPositionals: false,
135
+ strict: true,
136
+ });
137
+ return values;
138
+ }
139
+ catch (error) {
140
+ const detail = error instanceof Error ? error.message : String(error);
141
+ throw new CLIArgsError(`${detail}\nRun \`map-tui --help\` for the supported flags.`);
142
+ }
143
+ }
144
+ /**
145
+ * Parses a `map-tui` command line.
146
+ *
147
+ * @throws {CLIArgsError} On an unknown flag, an unparseable or out-of-range number, or a missing archive path.
148
+ */
149
+ export function parseCLIArgs(argv, environment = {}) {
150
+ const values = readFlags(argv);
151
+ if (values.help)
152
+ return { mode: "help" };
153
+ if (values.version)
154
+ return { mode: "version" };
155
+ const tiles = (values.tiles ?? environment.MAILWOMAN_TILES ?? "").trim();
156
+ if (!tiles.length) {
157
+ throw new CLIArgsError("No tile archive: pass --tiles <archive.pmtiles> or set MAILWOMAN_TILES.\n" +
158
+ "Planet and region archives: https://protomaps.com/downloads");
159
+ }
160
+ return {
161
+ mode: "browse",
162
+ tiles,
163
+ lat: numericFlag("lat", values.lat, DEFAULT_LAT, MIN_LAT, MAX_LAT),
164
+ lon: numericFlag("lon", values.lon, DEFAULT_LON, MIN_LON, MAX_LON),
165
+ zoom: Math.round(numericFlag("zoom", values.zoom, DEFAULT_ZOOM, MIN_ZOOM, MAX_ZOOM)),
166
+ };
167
+ }
168
+ //# sourceMappingURL=cli-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-args.js","sourceRoot":"","sources":["../cli-args.ts"],"names":[],"mappings":"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"}
package/out/cli.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @copyright Sister Software.
4
+ * @license AGPL-3.0
5
+ * @author Teffen Ellis, et al.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}
package/out/cli.js ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @copyright Sister Software.
4
+ * @license AGPL-3.0
5
+ * @author Teffen Ellis, et al.
6
+ */
7
+ /**
8
+ * The `map-tui` bin — `npx @mailwoman/map-tui` opens a PMTiles archive as a full-screen terminal map.
9
+ *
10
+ * This file owns everything process-shaped so the rest of the package stays testable without one: argv and the
11
+ * environment (parsed by ./cli-args.ts), the archive handle, signal handlers, and the exit code. `MapBrowser` takes
12
+ * streams rather than reaching for `process` itself, which is what lets the PTY smoke test drive the real bin and a
13
+ * unit test drive the parser with neither.
14
+ *
15
+ * Signal handling is not optional here. This is a raw-mode app on the alternate screen with mouse reporting on, and
16
+ * there is no framework underneath to put any of that back — a process killed between `start` and `restore` leaves the
17
+ * user with an unusable shell. So `restore` is wired to SIGINT, SIGTERM and `exit`, and it is idempotent for exactly
18
+ * that reason.
19
+ */
20
+ import { createRequire } from "node:module";
21
+ import { MapBrowser } from "./browser.js";
22
+ import { CLIArgsError, HELP_TEXT, parseCLIArgs } from "./cli-args.js";
23
+ import { TileSource } from "./tile-source.js";
24
+ /**
25
+ * Exit code for a command line that could not be parsed.
26
+ */
27
+ const EXIT_USAGE = 1;
28
+ /**
29
+ * Reads the package's own version.
30
+ *
31
+ * Self-reference (`@mailwoman/map-tui/...`, which the package's `exports` publishes) rather than a path relative to
32
+ * this file: the bin runs from `out/` when installed and from the workspace root in development, and only the package
33
+ * graph knows which. `createRequire` parses the JSON itself, so no reader here has to.
34
+ */
35
+ function readVersion() {
36
+ const require = createRequire(import.meta.url);
37
+ const manifest = require("@mailwoman/map-tui/package.json");
38
+ return manifest.version ?? "0.0.0";
39
+ }
40
+ /**
41
+ * Opens the archive, translating the filesystem's error into something that names the flag that was wrong.
42
+ */
43
+ async function openTiles(path) {
44
+ try {
45
+ return await TileSource.open(path);
46
+ }
47
+ catch (error) {
48
+ const detail = error instanceof Error ? error.message : String(error);
49
+ throw new CLIArgsError(`Could not open the tile archive at ${path}: ${detail}\n` +
50
+ "Pass --tiles <archive.pmtiles>, or download one from https://protomaps.com/downloads");
51
+ }
52
+ }
53
+ /**
54
+ * Runs the interactive browser against an already-open archive, resolving with its exit code.
55
+ */
56
+ async function browse(source, args) {
57
+ const browser = new MapBrowser({
58
+ source,
59
+ input: process.stdin,
60
+ output: process.stdout,
61
+ lat: args.lat,
62
+ lon: args.lon,
63
+ zoom: args.zoom,
64
+ });
65
+ const onSignal = () => browser.requestExit(130);
66
+ const onExit = () => browser.restore();
67
+ process.on("SIGINT", onSignal);
68
+ process.on("SIGTERM", onSignal);
69
+ process.on("exit", onExit);
70
+ try {
71
+ return await browser.run();
72
+ }
73
+ finally {
74
+ browser.restore();
75
+ process.off("SIGINT", onSignal);
76
+ process.off("SIGTERM", onSignal);
77
+ process.off("exit", onExit);
78
+ }
79
+ }
80
+ async function main() {
81
+ let args;
82
+ try {
83
+ /**
84
+ * This package takes no `@mailwoman` dependency by design (see ./mercator.ts), so the blessed readers are out of
85
+ * reach: `@mailwoman/core/env` would pull core's shipped data behind a CLI whose whole premise is `npx`.
86
+ * `parseCLIArgs` is the local equivalent — argv and the environment are read on this one line, and nowhere else in
87
+ * the package.
88
+ */
89
+ // oxlint-disable-next-line sister-software/no-process-globals -- see above.
90
+ args = parseCLIArgs(process.argv.slice(2), process.env);
91
+ }
92
+ catch (error) {
93
+ if (!(error instanceof CLIArgsError))
94
+ throw error;
95
+ process.stderr.write(`${error.message}\n`);
96
+ return EXIT_USAGE;
97
+ }
98
+ if (args.mode === "help") {
99
+ process.stdout.write(HELP_TEXT);
100
+ return 0;
101
+ }
102
+ if (args.mode === "version") {
103
+ process.stdout.write(`${readVersion()}\n`);
104
+ return 0;
105
+ }
106
+ let source;
107
+ try {
108
+ source = await openTiles(args.tiles);
109
+ }
110
+ catch (error) {
111
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
112
+ return EXIT_USAGE;
113
+ }
114
+ try {
115
+ return await browse(source, args);
116
+ }
117
+ finally {
118
+ await source.close();
119
+ }
120
+ }
121
+ process.exitCode = await main();
122
+ //# sourceMappingURL=cli.js.map
package/out/cli.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":"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"}
package/out/frame.d.ts CHANGED
@@ -3,6 +3,16 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
+ /**
7
+ * Braille frame value + conversion for map-tui's debug view.
8
+ *
9
+ * `rasterizeToFrame` turns an `RGBAGrid` (drawn by ./raster.ts) into a `MapFrame`: one codepoint and one packed color
10
+ * per cell. The braille dither/luminance work is asciify's — `FrameRasterizer` subclasses `AsciifyTerminal` with a
11
+ * no-op sink purely to reach its protected `_computeBrailleCells`, `_cellChars`, `_cellColors`, so this module never
12
+ * re-implements the dot math. `frameToANSILines` and `overlayText` then work on the plain `MapFrame` value, with no
13
+ * further asciify dependency; `blitFrame` is the seam back the other way, for callers driving a live terminal.
14
+ */
15
+ import { AsciifyTerminal } from "@sister.software/asciify/tui";
6
16
  import type { RGBAGrid } from "./raster.ts";
7
17
  import type { RGB } from "./style.ts";
8
18
  /**
@@ -51,4 +61,12 @@ export declare function overlayText(frame: MapFrame, column: number, row: number
51
61
  * of the frame boundary agree on the packing.
52
62
  */
53
63
  export declare function rgbToPacked(color: RGB): number;
64
+ /**
65
+ * Writes a frame's cells into an `AsciifyTerminal`'s current frame. Call `flush()` afterwards to emit the damage.
66
+ *
67
+ * The frame's packed color is the exact representation asciify canonicalizes truecolor to, so this is a copy and not a
68
+ * conversion — the channels are unpacked here only because {@linkcode AsciifyTerminal.setCell} takes them apart. Cells
69
+ * beyond the terminal's own grid are dropped by `setCell`, so a frame larger than the pane clips rather than throws.
70
+ */
71
+ export declare function blitFrame(terminal: AsciifyTerminal, frame: MapFrame): void;
54
72
  //# sourceMappingURL=frame.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../frame.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAIrC;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;IAClB;;OAEG;IACH,MAAM,EAAE,WAAW,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACnB;AAoBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAW7G;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CA0BzF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAC1B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,UAAU,GACnB,OAAO,CAmCT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAE9C"}
1
+ {"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../frame.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAIrC;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;IAClB;;OAEG;IACH,MAAM,EAAE,WAAW,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACnB;AAoBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAW7G;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CA0BzF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAC1B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,UAAU,GACnB,OAAO,CAmCT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAE9C;AAQD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAc1E"}
package/out/frame.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * per cell. The braille dither/luminance work is asciify's — `FrameRasterizer` subclasses `AsciifyTerminal` with a
11
11
  * no-op sink purely to reach its protected `_computeBrailleCells`, `_cellChars`, `_cellColors`, so this module never
12
12
  * re-implements the dot math. `frameToANSILines` and `overlayText` then work on the plain `MapFrame` value, with no
13
- * further asciify dependency.
13
+ * further asciify dependency; `blitFrame` is the seam back the other way, for callers driving a live terminal.
14
14
  */
15
15
  import { AsciifyTerminal } from "@sister.software/asciify/tui";
16
16
  const SGR_RESET = "\u001B[0m";
@@ -114,4 +114,30 @@ export function overlayText(frame, column, row, text, color, occupied) {
114
114
  export function rgbToPacked(color) {
115
115
  return (color[0] << 16) | (color[1] << 8) | color[2];
116
116
  }
117
+ /**
118
+ * Codepoint written for a cell the frame left empty. `MapFrame` stores 0 there; `AsciifyTerminal` expects a real
119
+ * character, and normalizes a space to the inkless color itself.
120
+ */
121
+ const SPACE_CODEPOINT = 0x20;
122
+ /**
123
+ * Writes a frame's cells into an `AsciifyTerminal`'s current frame. Call `flush()` afterwards to emit the damage.
124
+ *
125
+ * The frame's packed color is the exact representation asciify canonicalizes truecolor to, so this is a copy and not a
126
+ * conversion — the channels are unpacked here only because {@linkcode AsciifyTerminal.setCell} takes them apart. Cells
127
+ * beyond the terminal's own grid are dropped by `setCell`, so a frame larger than the pane clips rather than throws.
128
+ */
129
+ export function blitFrame(terminal, frame) {
130
+ for (let row = 0; row < frame.rows; row++) {
131
+ for (let column = 0; column < frame.columns; column++) {
132
+ const cellIndex = row * frame.columns + column;
133
+ const char = frame.chars[cellIndex];
134
+ const color = frame.colors[cellIndex];
135
+ terminal.setCell(column, row, char === 0 ? SPACE_CODEPOINT : char, [
136
+ (color >> 16) & 0xff,
137
+ (color >> 8) & 0xff,
138
+ color & 0xff,
139
+ ]);
140
+ }
141
+ }
142
+ }
117
143
  //# sourceMappingURL=frame.js.map
package/out/frame.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"frame.js","sourceRoot":"","sources":["../frame.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frame.js","sourceRoot":"","sources":["../frame.ts"],"names":[],"mappings":"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"}
package/out/input.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ /**
7
+ * Terminal input decoding for the interactive map browser.
8
+ *
9
+ * `decodeInputChunk` turns a raw-mode stdin chunk into zero or more {@link MapTUIInput} events. It stays pure — the
10
+ * caller owns the only state there is, the unresolved trailing fragment the function hands back — so one chunk in gives
11
+ * the same events out every time.
12
+ *
13
+ * THE FALLBACK IS THE DANGEROUS PART. An ESC this decoder had no rule for used to mean "the Esc key", i.e. QUIT, which
14
+ * made every unrecognized escape sequence a quit: F1 (`ESC O P`), an OSC reply the terminal sends unasked (`ESC ] 11 ;
15
+ * rgb:… BEL`), and — worst, because it needs no exotic key at all — a mouse report split across two stdin reads, whose
16
+ * first half ends inside the sequence. So the fallback now separates three cases:
17
+ *
18
+ * - A sequence this decoder recognizes is consumed and acted on (arrows, SGR mouse).
19
+ * - A sequence it does NOT recognize is consumed WHOLE and ignored: CSI (`ESC [ … final`), SS3 (`ESC O final`), and the
20
+ * string family (OSC/DCS/SOS/PM/APC, terminated by BEL or ST). Re-scanning their bodies as characters is how a `q`
21
+ * inside a cursor-position report quit the app.
22
+ * - A chunk that ENDS mid-sequence — including a lone trailing ESC, which is byte-for-byte the start of one — is not
23
+ * decoded at all: it comes back as {@link DecodedInput.pending} for the caller to prepend to the next chunk. Quit is
24
+ * emitted only for an ESC that is neither, i.e. one whose following byte cannot continue a sequence.
25
+ *
26
+ * Holding costs a lone Esc keypress its effect until the next byte arrives. That is the right side of the trade for a
27
+ * browser whose advertised quit keys are `q` and Ctrl+C: the alternative is a drag ending the session because the
28
+ * kernel split a read.
29
+ *
30
+ * Mouse reports are SGR-encoded (DEC private mode 1006), which is what {@link MOUSE_ENABLE} asks for. Their coordinates
31
+ * are 1-based on the wire and 0-based in every event here — the off-by-one lives at this boundary and nowhere else.
32
+ */
33
+ /**
34
+ * Enables mouse reporting: button events (1000), drag/button-motion tracking (1002), and SGR extended coordinates
35
+ * (1006) so columns past 223 survive.
36
+ */
37
+ export declare const MOUSE_ENABLE = "\u001B[?1000h\u001B[?1002h\u001B[?1006h";
38
+ /**
39
+ * Disables mouse reporting, in the reverse order it was enabled.
40
+ */
41
+ export declare const MOUSE_DISABLE = "\u001B[?1006l\u001B[?1002l\u001B[?1000l";
42
+ /**
43
+ * A decoded input event. Pan and zoom carry direction and magnitude only — how far a step moves the map is the
44
+ * browser's decision, not the decoder's.
45
+ */
46
+ export type MapTUIInput = {
47
+ kind: "quit";
48
+ }
49
+ /**
50
+ * Ctrl+C. Distinct from `quit` because the process must exit 130, and because raw mode means no SIGINT is raised.
51
+ */
52
+ | {
53
+ kind: "interrupt";
54
+ } | {
55
+ kind: "pan";
56
+ dx: number;
57
+ dy: number;
58
+ } | {
59
+ kind: "zoom";
60
+ delta: number;
61
+ } | {
62
+ kind: "wheel";
63
+ delta: number;
64
+ column: number;
65
+ row: number;
66
+ } | {
67
+ kind: "press";
68
+ column: number;
69
+ row: number;
70
+ } | {
71
+ kind: "drag";
72
+ column: number;
73
+ row: number;
74
+ } | {
75
+ kind: "release";
76
+ };
77
+ /**
78
+ * One decoded chunk: its events, plus whatever trailing bytes could not be decoded YET.
79
+ */
80
+ export interface DecodedInput {
81
+ events: MapTUIInput[];
82
+ /**
83
+ * An unresolved escape fragment from the end of the chunk — prepend it to the next one. Empty when the chunk ended
84
+ * cleanly, which is the overwhelmingly common case.
85
+ */
86
+ pending: string;
87
+ }
88
+ /**
89
+ * Decodes one raw-mode stdin chunk into input events. Unrecognized bytes are dropped; an unresolved trailing escape
90
+ * fragment is returned rather than decoded, and the caller passes it back as `pending` with the next chunk.
91
+ */
92
+ export declare function decodeInputChunk(chunk: string, pending?: string): DecodedInput;
93
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../input.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;GAGG;AACH,eAAO,MAAM,YAAY,4CAA4C,CAAA;AAErE;;GAEG;AACH,eAAO,MAAM,aAAa,4CAA4C,CAAA;AAEtE;;;GAGG;AACH,MAAM,MAAM,WAAW,GACpB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB;;GAEG;GACD;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAmGtB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;CACf;AA4CD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,YAAY,CAsE1E"}