okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

nekomimi.pettui: latex math through a glamour fork with node hooks, and colored markdown accents from the palette673fd0d

main
3.4 KiB139 linesraw
1// Streaming Markdown must render every partial reply exactly as its settled
2// form: the daemon e2e sees committed transcript text only, never the live
3// view, so it cannot sample the streaming boundaries this sweep does.
4package tui
5
6import (
7	"strings"
8	"testing"
9)
10
11var markdownSamples = []string{
12	"shown as source:\n\n```md\n[x]: https://example.com\n<!-- note -->\n```\n\nsee [x] and <pre>\n\nafter",
13	`fixed in ` + "`" + `25424ba` + "`" + ` "keep row backgrounds across lip gloss v2 resets". lipgloss v2 closes styled text with the short reset ` + "`" + `\x1b[m` + "`" + `, where v1 used ` + "`" + `\x1b[0m` + "`" + `.
14
15i also measured cpu over 45 seconds while you were testing:
16
17| pid | binary | cpu |
18|---|---|---|
19| 84082 | new (` + "`" + `cli/bin/albedo` + "`" + `, this session) | ~4% |
20| 58609 | old nix one | ~13.5% |
21
22don't read too much into the new binary's number.`,
23	`**what port-chat did:**
24- **paste:** ` + "`" + `chat.go` + "`" + ` never had a special case for paste. in v1, pasted text arrived as a key event.
25- **mouse:** it's one ` + "`" + `case tea.MouseMsg:` + "`" + ` with an inner switch.
26
27**things i'll change in my own pass:**
28- remove a porting-only comment.
29- run ` + "`" + `go mod tidy` + "`" + `.
30
31once port-forms reports back i'll do the full review.`,
32	`the migration is big but mostly mechanical. the main ones i expect:
33- ` + "`" + `tea.KeyMsg` + "`" + ` with ` + "`" + `.Type` + "`" + `/` + "`" + `.Runes` + "`" + ` becomes ` + "`" + `tea.KeyPressMsg` + "`" + `.
34- mouse messages get split up.
35
361. use a static cursor there too.
372. let the terminal blink its own cursor.
38
39` + "`" + `` + "`" + `` + "`" + `sh
40ps -o %cpu= -p $(pgrep -n albedo)
41` + "`" + `` + "`" + `` + "`" + `
42
43run it a few times.
44
45### heading three
46text under heading
47
48> a quote
49> continues
50
51after quote
52
53    indented code
54
55final *line* here
56`,
57	`- item
58
59  continued inside item
60
61- second item
62
63next para
64
651. one
66
67   nested para
68
692. two
70
71~~~
72tilde fence
73
74still fence
75~~~
76
77done`,
78	`intro
79
80` + "`" + `` + "`" + `` + "`" + `go
81func a() {
82
83	return
84}
85` + "`" + `` + "`" + `` + "`" + `
86## after code heading
87para
88
89---
90
91tail`,
92	`the roots are
93
94$$
95x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
96
97\text{for } a \neq 0
98$$
99and inline $e^{i\pi} + 1 = 0$, but $5 and $HOME/$USER stay text.
100
101- a sum \(\sum_{i=1}^{n} i\) in a list
102
103  \[
104  \sum_{i=1}^{n} i = \frac{n(n+1)}{2}
105  \]
106
107> **bold $\alpha$** in a quote
108
109done`,
110}
111
112// Block by block, every prefix renders exactly as the whole prefix does, and
113// no block boundary falls inside a code fence: a split fence renders the same
114// text but re-renders the whole tail on every streaming chunk.
115func TestMarkdownRendersTheSameBlockByBlock(t *testing.T) {
116	for _, width := range []int{40, 98} {
117		for i, sample := range markdownSamples {
118			blocks := markdownBlocks(sample)
119			if len(blocks) < 2 {
120				t.Fatalf("sample %d is one block, so it tests nothing", i)
121			}
122			fence := ""
123			for _, block := range blocks {
124				if fence != "" {
125					t.Fatalf("sample %d splits a code fence between blocks", i)
126				}
127				for line := range strings.SplitSeq(block, "\n") {
128					fence = fenceAfter(fence, line)
129				}
130			}
131			for end := 1; end <= len(sample); end += 7 {
132				text := sample[:end]
133				if got, want := RenderMarkdownAnsi(text, width), strings.Trim(renderMarkdown(text, width), " \n"); got != want {
134					t.Fatalf("sample %d at %d, width %d:\n got %q\nwant %q", i, end, width, got, want)
135				}
136			}
137		}
138	}
139}