@profullstack/readm3 0.1.1 → 0.3.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.
package/README.md CHANGED
@@ -1,7 +1,12 @@
1
1
  # readm3
2
2
 
3
- A terminal markdown reader. File browser on the left, the rendered document on
4
- the right, and nothing else in the way.
3
+ A terminal markdown reader and editor. File browser on the left, the rendered
4
+ document on the right, and nothing else in the way. Press `e` to edit the file
5
+ you are looking at, `esc` to see it rendered again.
6
+
7
+ CommonMark and GitHub Flavored Markdown, plus the extras each dialect added on
8
+ top: GitHub alerts, footnotes and `:emoji:`, and Reddit spoilers, superscript
9
+ and `r/` `u/` links.
5
10
 
6
11
  Built on [HQTUI](https://github.com/profullstack/hqtui) — truecolor, mouse, and
7
12
  a terminal that gets restored no matter how the process dies.
@@ -47,6 +52,23 @@ readm3 CHANGELOG.md # open a file, browse its directory
47
52
  readm3 --theme nord # pick a palette
48
53
  ```
49
54
 
55
+ ### Printing
56
+
57
+ `--print` renders straight to stdout and exits, so it works in a pipe and as a
58
+ `cat` for markdown:
59
+
60
+ ```bash
61
+ readm3 --print CHANGELOG.md # rendered, colored, to the terminal
62
+ readm3 --print README.md | less -R # into a pager
63
+ curl -s https://example.com/x.md | readm3 --print
64
+ readm3 --print notes.md | grep TODO # no escapes when stdout is a pipe
65
+ ```
66
+
67
+ Color follows the usual rules: on when stdout is a terminal, off when it is not,
68
+ and `NO_COLOR` / `FORCE_COLOR` are honored. `--color always|never|auto` overrides
69
+ that either way. With `--print`, `--width` sets the render width rather than the
70
+ sidebar.
71
+
50
72
  The browser only shows markdown. Directories with nothing beneath them are
51
73
  pruned, `node_modules` and friends are never walked, and README sorts first.
52
74
 
@@ -59,29 +81,87 @@ pruned, `node_modules` and friends are never walked, and README sorts first.
59
81
  | `enter` | open the file | `esc` | clear the filter |
60
82
  | `space` `b` | page down / up | `r` | rescan and reload |
61
83
  | `g` `G` | top / bottom | `[` `]` | sidebar width |
62
- | `?` | help | `q` `ctrl+c` | quit |
84
+ | `e` `i` | edit this file | `s` | reveal spoilers |
85
+ | `ctrl+s` | save | `?` | help |
86
+ | | | `q` `ctrl+c` | quit |
63
87
 
64
88
  The mouse works too: the wheel scrolls whichever pane it is over, and a click
65
89
  opens a file.
66
90
 
91
+ ### Editing
92
+
93
+ `e` puts the caret in the file. `esc` takes it out, and the preview re-renders
94
+ what you just typed — there is no separate preview pane to keep in step,
95
+ because both modes read the same buffer.
96
+
97
+ | | | | |
98
+ |---|---|---|---|
99
+ | `esc` | back to the preview | `ctrl+s` | save |
100
+ | `ctrl+z` `ctrl+y` | undo / redo | `ctrl+g` | keys |
101
+ | `ctrl+a` `ctrl+e` | line start / end | `ctrl+k` | kill to end of line |
102
+ | `ctrl+←` `ctrl+→` | move by word | `ctrl+u` | kill to start of line |
103
+ | `ctrl+home` `ctrl+end` | top / bottom | `tab` | indent two spaces |
104
+
105
+ `enter` continues the list you are in — the same bullet, the next number, an
106
+ unchecked box for a task — and ends it when you press it on an empty item.
107
+ Quitting or switching files with unsaved changes asks first. `--read-only`
108
+ turns editing off entirely, for use as a pager.
109
+
110
+ There is no selection, and so no cut and paste: this is a place to fix a typo
111
+ and add a paragraph, not a replacement for your editor. `$EDITOR` is still
112
+ `$EDITOR`.
113
+
67
114
  ## What it renders
68
115
 
69
- Headings, **bold**, *italic*, `inline code`, links, fenced and indented code
70
- blocks with a language label, ordered and unordered lists, nested lists, task
71
- lists, blockquotes, tables with per-column alignment, horizontal rules, images
72
- as labelled placeholders, and YAML front matter — shown rather than hidden,
73
- because it is usually what you opened the file for.
116
+ Parsing is [marked](https://github.com/markedjs/marked) — CommonMark and GFM,
117
+ zero dependencies of its own — so readm3 has two dependencies in total.
118
+
119
+ Headings, **bold**, *italic*, `inline code`, links, reference links, bare URLs,
120
+ fenced and indented code blocks with a language label, ordered and unordered
121
+ lists, nested lists, task lists, blockquotes, tables with per-column alignment,
122
+ strikethrough, hard line breaks, horizontal rules, images as labelled
123
+ placeholders, and YAML front matter — shown rather than hidden, because it is
124
+ usually what you opened the file for.
74
125
 
75
126
  The HTML that real READMEs are full of is folded back into markdown rather than
76
- printed as tags, and inline code is held out of that, so `Array<string>`
77
- survives.
127
+ printed as tags, and code is held out of that, so `Array<string>` survives.
128
+
129
+ ### Flavors
130
+
131
+ `--flavor` picks which dialect's extras are honored. The default is `github`.
132
+
133
+ | flavor | adds |
134
+ |---|---|
135
+ | `commonmark` | nothing beyond CommonMark |
136
+ | `github` | GFM, alerts (`> [!WARNING]`), footnotes (`[^1]`), `:emoji:` |
137
+ | `reddit` | GFM, spoilers (`>!hidden!<`), superscript (`^(text)`), `r/` and `u/` links |
138
+ | `all` | both dialects at once |
139
+
140
+ It matters which one you pick. `2^32` is a number in a README and a superscript
141
+ on Reddit, and `>!spoiler!<` is a blockquote everywhere except Reddit — so the
142
+ flavor decides, rather than every document getting every rule.
143
+
144
+ Alerts get a gutter colored by severity. Footnotes are numbered in order of
145
+ first reference and collected under a rule at the foot of the document.
146
+ Superscript uses real Unicode glyphs when every character has one (`mc^2`
147
+ becomes mc²) and keeps its caret when they do not, because there is no
148
+ superscript `q`. Spoilers are blocked out with `█` rather than colored out, so
149
+ they stay hidden in a pipe and with `--color never`; `s` reveals them in the
150
+ reader, `--spoilers` in `--print`.
78
151
 
79
152
  ## Options
80
153
 
81
154
  ```
155
+ -p, --print render to stdout and exit; reads stdin when given no path
156
+ or "-"
157
+ --color <when> always, never, or auto (default)
82
158
  -t, --theme <name> dark, dracula, nord, tokyo-night, gruvbox, matrix,
83
159
  monochrome, high-contrast, light
84
- -w, --width <n> sidebar width in columns (default: 28% of the terminal)
160
+ -w, --width <n> sidebar width in columns, or the render width with --print
161
+ (default: 28% of the terminal, its full width printing)
162
+ -f, --flavor <name> commonmark, github (default), reddit, or all
163
+ --spoilers reveal spoiler text instead of blocking it out
164
+ -R, --read-only refuse to edit, for use as a pager
85
165
  -a, --all include dot-directories and dotfiles
86
166
  -M, --no-mouse disable mouse tracking
87
167
  -v, --version
@@ -90,22 +170,40 @@ survives.
90
170
 
91
171
  ## As a library
92
172
 
93
- The renderer and the file tree are pure and need no terminal, so they can be
94
- reused on their own:
173
+ The renderer, the file tree and the edit buffer are pure and need no terminal,
174
+ so they can be reused on their own:
95
175
 
96
176
  ```ts
97
- import { renderMarkdown, toText, scan, files } from "@profullstack/readm3";
177
+ import { renderMarkdown, toText, renderAnsi, scan, files } from "@profullstack/readm3";
98
178
 
99
179
  const lines = renderMarkdown("# Hello\n\nSome **text**.", 60);
100
180
  console.log(toText(lines));
101
181
  // [ 'Hello', '━━━…', '', 'Some text.' ]
102
182
 
183
+ // A flavor, and spoilers revealed.
184
+ renderMarkdown(post, 60, { flavor: "reddit", spoilers: true });
185
+
103
186
  for (const file of files(scan("./docs"))) console.log(file.path);
104
187
  ```
105
188
 
189
+ The edit buffer is a plain object with functions over it, so the editing rules
190
+ can be tested without a screen:
191
+
192
+ ```ts
193
+ import { createEditor, insert, newline, undo, text } from "@profullstack/readm3";
194
+
195
+ const ed = createEditor("- first");
196
+ ed.col = 7;
197
+ newline(ed); // continues the list
198
+ insert(ed, "second");
199
+ console.log(text(ed)); // "- first\n- second"
200
+ undo(ed);
201
+ ```
202
+
106
203
  `renderMarkdown` returns lines of spans carrying a semantic `role` — `h1`,
107
204
  `code`, `link`, `quote` and so on — rather than colors, so the same document can
108
- be re-themed without re-parsing.
205
+ be re-themed without re-parsing. `renderAnsi(source, width, theme, depth)` is
206
+ what `--print` uses to turn those spans into an escaped string.
109
207
 
110
208
  ## Runtimes
111
209
 
@@ -117,11 +215,24 @@ Windows Terminal.
117
215
  ```bash
118
216
  bun install
119
217
  bun src/cli.ts . # run it against its own repo
120
- bun test test/ # 48 tests, no TTY needed
218
+ bun test test/ # 68 tests, no TTY needed
219
+ npm test # the same tests on node
121
220
  bun run typecheck
122
221
  bun run build
123
222
  ```
124
223
 
224
+ ## The website
225
+
226
+ [readm3.com](https://readm3.com) is built from this repository by `site/build.ts`,
227
+ which renders every document on the page through `renderMarkdown` and takes every
228
+ color from a real HQTUI theme. There is no second implementation to keep in sync:
229
+ change the parser and the site changes with it.
230
+
231
+ ```bash
232
+ bun run site:build # writes site/dist
233
+ bun run site:start # serves it on $PORT, default 3000
234
+ ```
235
+
125
236
  ## License
126
237
 
127
238
  MIT.
package/dist/cli.d.ts CHANGED
@@ -1,8 +1,16 @@
1
+ import { type ColorMode } from "./print.ts";
1
2
  import { type ViewerOptions } from "./viewer.ts";
2
- export declare const VERSION = "0.1.1";
3
+ export declare const VERSION = "0.3.0";
4
+ /** The help text, exported so a test can hold it to the flags it documents. */
5
+ export declare const USAGE: string;
3
6
  export interface ParsedArgs extends ViewerOptions {
4
7
  help: boolean;
5
8
  version: boolean;
9
+ /** Render to stdout instead of opening the reader. */
10
+ print: boolean;
11
+ color: ColorMode;
12
+ /** Reveal spoiler text rather than blocking it out. */
13
+ spoilers: boolean;
6
14
  }
7
15
  export declare function parseArgs(argv: string[]): ParsedArgs;
8
16
  export declare function main(argv?: string[]): Promise<void>;
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,OAAO,EAAO,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtD,eAAO,MAAM,OAAO,UAAU,CAAC;AA2B/B,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAID,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAuEpD;AAED,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhF"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAQA,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAO,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtD,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,+EAA+E;AAC/E,eAAO,MAAM,KAAK,QA0CjB,CAAC;AAEF,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,uDAAuD;IACvD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA6GpD;AAED,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAwChF"}
package/dist/cli.js CHANGED
@@ -5,9 +5,12 @@ import { statSync } from "node:fs";
5
5
  import { dirname, resolve } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import { themeList } from "@profullstack/hqtui";
8
+ import { FLAVORS, isFlavor } from "./flavors.js";
9
+ import { printDocument, COLOR_MODES } from "./print.js";
8
10
  import { run } from "./viewer.js";
9
- export const VERSION = "0.1.1";
10
- const USAGE = `readm3 — a terminal markdown reader
11
+ export const VERSION = "0.3.0";
12
+ /** The help text, exported so a test can hold it to the flags it documents. */
13
+ export const USAGE = `readm3 — a terminal markdown reader and editor
11
14
 
12
15
  Usage
13
16
  readm3 [path] [options]
@@ -16,8 +19,19 @@ Usage
16
19
  current directory.
17
20
 
18
21
  Options
22
+ -p, --print Render to stdout and exit, instead of opening the reader.
23
+ Reads stdin when no path is given, or the path is "-"
24
+ --color <when> always, never, or auto (the default): color when stdout
25
+ is a terminal. NO_COLOR and FORCE_COLOR are honored
19
26
  -t, --theme <name> Color theme. One of: ${themeList.map((t) => t.name).join(", ")}
20
- -w, --width <n> Sidebar width in columns. Default: 28% of the terminal
27
+ -w, --width <n> Sidebar width in columns, or the render width with
28
+ --print. Default: 28% of the terminal, and its full
29
+ width when printing
30
+ -f, --flavor <name> Markdown dialect. One of: ${FLAVORS.join(", ")}.
31
+ Default: github (GFM, alerts, footnotes, :emoji:).
32
+ reddit adds spoilers, superscript and r/ u/ links
33
+ --spoilers Reveal spoiler text instead of blocking it out
34
+ -R, --read-only Refuse to edit, for use as a pager
21
35
  -a, --all Include dot-directories and dotfiles
22
36
  -M, --no-mouse Disable mouse tracking
23
37
  -v, --version Print the version
@@ -28,8 +42,16 @@ Keys
28
42
  right/left l h expand or collapse / filter files
29
43
  enter open the file r rescan and reload
30
44
  space / b page down / up [ ] sidebar width
31
- g / G top / bottom ? help
32
- q quit
45
+ g / G top / bottom s reveal spoilers
46
+ e / i edit this file ? help
47
+ ctrl+s save q quit
48
+
49
+ Editing
50
+ esc back to the preview, which re-renders as you left it
51
+ ctrl+z ctrl+y undo / redo ctrl+k kill to end of line
52
+ ctrl+a ctrl+e line start / end ctrl+u kill to start of line
53
+ ctrl+arrow move by word enter split, continuing a list
54
+ ctrl+g keys for editing tab indent two spaces
33
55
  `;
34
56
  class UsageError extends Error {
35
57
  }
@@ -38,8 +60,12 @@ export function parseArgs(argv) {
38
60
  root: process.cwd(),
39
61
  help: false,
40
62
  version: false,
63
+ print: false,
64
+ color: "auto",
65
+ spoilers: false,
41
66
  mouse: true,
42
67
  all: false,
68
+ readOnly: false,
43
69
  };
44
70
  let target;
45
71
  for (let i = 0; i < argv.length; i++) {
@@ -71,6 +97,34 @@ export function parseArgs(argv) {
71
97
  parsed.sidebar = value;
72
98
  break;
73
99
  }
100
+ case "-p":
101
+ case "--print":
102
+ parsed.print = true;
103
+ break;
104
+ case "--color": {
105
+ const value = next();
106
+ if (!COLOR_MODES.includes(value)) {
107
+ throw new UsageError(`--color must be one of: ${COLOR_MODES.join(", ")}`);
108
+ }
109
+ parsed.color = value;
110
+ break;
111
+ }
112
+ case "-f":
113
+ case "--flavor": {
114
+ const value = next();
115
+ if (!isFlavor(value)) {
116
+ throw new UsageError(`--flavor must be one of: ${FLAVORS.join(", ")}`);
117
+ }
118
+ parsed.flavor = value;
119
+ break;
120
+ }
121
+ case "--spoilers":
122
+ parsed.spoilers = true;
123
+ break;
124
+ case "-R":
125
+ case "--read-only":
126
+ parsed.readOnly = true;
127
+ break;
74
128
  case "-a":
75
129
  case "--all":
76
130
  parsed.all = true;
@@ -88,6 +142,11 @@ export function parseArgs(argv) {
88
142
  break;
89
143
  }
90
144
  }
145
+ if (target === "-") {
146
+ if (!parsed.print)
147
+ throw new UsageError('"-" only makes sense with --print');
148
+ return parsed;
149
+ }
91
150
  if (target !== undefined) {
92
151
  const path = resolve(target);
93
152
  let isDir;
@@ -98,6 +157,8 @@ export function parseArgs(argv) {
98
157
  throw new UsageError(`No such file or directory: ${target}`);
99
158
  }
100
159
  if (isDir) {
160
+ if (parsed.print)
161
+ throw new UsageError("--print needs a file, not a directory");
101
162
  parsed.root = path;
102
163
  }
103
164
  else {
@@ -128,6 +189,17 @@ export async function main(argv = process.argv.slice(2)) {
128
189
  process.stdout.write(`${VERSION}\n`);
129
190
  return;
130
191
  }
192
+ if (args.print) {
193
+ printDocument({
194
+ path: args.open,
195
+ width: args.sidebar,
196
+ theme: args.theme,
197
+ color: args.color,
198
+ flavor: args.flavor,
199
+ spoilers: args.spoilers,
200
+ });
201
+ return;
202
+ }
131
203
  if (!process.stdout.isTTY) {
132
204
  process.stderr.write("readm3: needs a terminal. Try `readm3 --help`.\n");
133
205
  process.exitCode = 1;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The edit buffer: lines, a caret, and undo.
3
+ *
4
+ * Nothing here touches a terminal. The viewer owns the keys and the drawing;
5
+ * this owns what the text is, which is the part worth testing — the same split
6
+ * `markdown.ts` makes between parsing and painting.
7
+ *
8
+ * Functions mutate the state they are given and return it. A buffer is a few
9
+ * thousand lines at most, but copying the array on every keystroke to look
10
+ * functional would buy nothing a snapshot in `undo` does not already give.
11
+ */
12
+ /** What the last edit was, so a run of typing collapses into one undo step. */
13
+ export type EditKind = "none" | "insert" | "delete" | "newline" | "other";
14
+ export interface Snapshot {
15
+ lines: string[];
16
+ row: number;
17
+ col: number;
18
+ }
19
+ export interface Editor {
20
+ lines: string[];
21
+ row: number;
22
+ col: number;
23
+ /** Column to aim for on vertical motion, so crossing a short line keeps place. */
24
+ goal: number;
25
+ dirty: boolean;
26
+ undo: Snapshot[];
27
+ redo: Snapshot[];
28
+ last: EditKind;
29
+ }
30
+ export declare function createEditor(source: string): Editor;
31
+ /** The buffer as one string. Round-trips whatever `createEditor` was given. */
32
+ export declare function text(ed: Editor): string;
33
+ export declare function lineAt(ed: Editor, row: number): string;
34
+ /** Break the current undo run, so the next edit starts a new step. */
35
+ export declare function breakRun(ed: Editor): Editor;
36
+ export declare function undo(ed: Editor): Editor;
37
+ export declare function redo(ed: Editor): Editor;
38
+ export declare function moveLeft(ed: Editor): Editor;
39
+ export declare function moveRight(ed: Editor): Editor;
40
+ /** Vertical motion aims at `goal`, so a short line in the way is passed over. */
41
+ export declare function moveVertical(ed: Editor, delta: number): Editor;
42
+ export declare const moveUp: (ed: Editor) => Editor;
43
+ export declare const moveDown: (ed: Editor) => Editor;
44
+ /** Home, but to the first non-blank first — the second press goes to column 0. */
45
+ export declare function moveHome(ed: Editor): Editor;
46
+ export declare function moveEnd(ed: Editor): Editor;
47
+ export declare function moveDocStart(ed: Editor): Editor;
48
+ export declare function moveDocEnd(ed: Editor): Editor;
49
+ export declare function moveWordLeft(ed: Editor): Editor;
50
+ export declare function moveWordRight(ed: Editor): Editor;
51
+ /** Insert text at the caret. Newlines in it split lines, so paste works. */
52
+ export declare function insert(ed: Editor, str: string): Editor;
53
+ /**
54
+ * The prefix a new line should inherit: the indent, and the list marker when
55
+ * the caret is leaving one.
56
+ *
57
+ * Returns `null` for an item that has no content, which is the signal to clear
58
+ * it instead — pressing enter twice is how a list ends.
59
+ */
60
+ export declare function continuation(line: string): {
61
+ prefix: string;
62
+ clear: boolean;
63
+ };
64
+ /** Split the line at the caret, carrying indentation and list markers over. */
65
+ export declare function newline(ed: Editor): Editor;
66
+ export declare function backspace(ed: Editor): Editor;
67
+ /** Delete forward. Joins the next line when the caret is at the end. */
68
+ export declare function del(ed: Editor): Editor;
69
+ /** Delete to the end of the line, or join the next when already there. */
70
+ export declare function killToLineEnd(ed: Editor): Editor;
71
+ /** Delete from the caret back to the start of the line's text. */
72
+ export declare function killToLineStart(ed: Editor): Editor;
73
+ /** Two spaces, the indent the renderer reads back as one list level. */
74
+ export declare function indent(ed: Editor): Editor;
75
+ /** Mark the buffer as matching what is on disk. */
76
+ export declare function markSaved(ed: Editor): Editor;
77
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"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"}