Commit graph

201 commits

Author SHA1 Message Date
Pagwin
96db1f999c
fix three parser bugs the property tests turned up
fencedCodeBlock had its language test inverted, reporting Nothing for a
fence that names a language and Just "" for one that doesn't.

listBlock's child parser needed a try. optional only recovers from a
failure that consumed nothing, and the child parser eats the next item's
indentation before finding out the item belongs to this list's level
rather than the child's, so any nested list with two or more items killed
the enclosing list and the whole thing came back as a paragraph.

element required a blockEnding, so every block had to be followed by a
blank line or EOF. Paragraphs and headings hid that by swallowing the
following line into their own text; a list has nowhere to put it, and
since listItem already consumed its trailing newline the failure came
with input consumed and escaped document's many, failing the entire
parse. "- a\n:" was a hard error. The ending is optional now and a block
that ends without a blank line is the next block's problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 16:39:09 -04:00
Pagwin
628f01217e
restructure the tests and assert on whole trees
The suite is now one tasty binary over shared modules, so the Djot
tests can sit next to the Markdown ones without another copy of the
harness:

  tests/Main.hs             the TestTree
  tests/Test/Harness.hs     running a parser inside a property
  tests/Test/Gen.hs         generators, shrinkers, escaping
  tests/Test/Gen/Document.hs  whole document generation
  tests/Markdown/Parse.hs   the Markdown properties

Generated values moved from `pick` to `Arbitrary` instances on
newtypes. `pick` embeds its value with `forAll (return a)` and cannot
shrink; going through Arbitrary gets shrinking back at the cost of
hand written shrinkers, which have to preserve the invariants their
generator established.

IR now derives Eq, and the properties assert against a complete
expected tree rather than pattern matching. The old patterns bound
fresh names that shadowed the generated ones, so they only ever
checked the shape of the tree and never its content.

Test.Gen.Document generates a description of a document which renders
to source and derives its own expected tree, so the two stay in step
while shrinking. Rendering goes through a Syntax record so Djot can
reuse the spec and the expectations. Escaping is a generator level
concern: an Escaper says which characters are special and how (or
whether) they can be written literally.

Two properties fail, both on parser bugs rather than test bugs:

  code_block          fencedCodeBlock inverts its language test, so a
                      fence naming a language reports Nothing. Djot.hs
                      gets this right at src/Djot.hs:354.
  document_round_trip a nested list with more than one item makes the
                      whole list fail to parse and fall back to a
                      paragraph. In listBlock's child parser the second
                      alternative has no `try`, so it fails having
                      consumed the first item's indentation. The
                      existing nesting tests only ever used one nested
                      item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 16:15:33 -04:00
Pagwin
d31bf0233e
swap hedgehog out for QuickCheck
The test suite now runs on tasty + tasty-quickcheck. Translation is
mechanical: `property`/`forAll`/`lift` become
`monadicIO`/`pick`/`run`, `success`/`fail` become `pure ()`/`stop`
with a counterexample, and Hedgehog's ranged generators are replaced
by a `linear` helper that scales with QuickCheck's size parameter.
Shrinking is dropped since QuickCheck can't shrink these while keeping
the generated text within the ranges the assertions assume.

The expected-value patterns were also stale relative to the IR
(`LI`'s `child` field is gone, blocks carry a trailing `Attrs`, list
types carry a `style`), so they've been updated to match. The
structural checks are otherwise unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 15:39:36 -04:00
Pagwin
7a0032c7d3
add ReferenceImage to the IR and use it for ![alt][ref]
The reference form of the image syntax had nowhere to go: Image only has a
url, so the parser was putting the label there and `![a][b]` came out
identical to `![a](b)`, with nothing downstream aware the url still needed
resolving against a RefDef.

Adds a ReferenceImage constructor mirroring ReferenceLink and has the djot
parser emit it. As with reference links, an empty label falls back to the
alt text.

Note HTML.hs still renders neither reference form.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 15:21:46 -04:00
Pagwin
d695910c7c
implement the djot parser
Fills out src/Djot.hs, which was a skeleton of `error "todo"` stubs.

Three layers, so container prefixes and indentation never have to be
threaded through the parser state:

  - line primitives (rawLine/peekLine/lineWhen/dedent): block parsers peek
    at the next line, decide whether they want it, then consume it
  - container blocks strip their prefix off the lines they own and re-parse
    the result with subParse, a rank-2 helper that runs a polymorphic parser
    at Identity and shifts error offsets back into the outer input
  - inline content is a second pass over the text a block collected

Blocks: headings, paragraphs, block quotes, fenced code, raw blocks, divs,
tables (alignments, `^` captions, escaped pipes), footnote and reference
definitions, block attributes, thematic breaks, and lists -- bullet,
ordered (decimal/alpha/roman, `.`/`)`/`(n)`), task, and definition. Tight
lists unwrap their paragraphs to Transparent.

Inlines: emphasis and its braced forms, verbatim, raw inline, math, links,
reference links, images, autolinks, spans, footnote references, symbols,
escapes, hard breaks, attribute sets, and smart punctuation.

Two spots where the IR came up short:

  - there is no reference image, so for `![alt][ref]` the label lands in
    the url field
  - unordered lists get style = Nothing rather than the bullet character,
    which HTML.hs would otherwise emit as an invalid type="-"

Also includes the psb.cabal fix dropping OverloadedRecordUpdate, without
which Psb.Main does not build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 15:15:33 -04:00
Pagwin
85ce3ee34a
??? 2026-09-04 14:37:17 -04:00
Pagwin
b9b7eb98f1
some TODO planning 2026-05-05 15:07:27 -04:00
Pagwin
f062d2c1dc
convenient extension 2026-05-05 14:32:56 -04:00
Pagwin
ef61e282d2
started scaffolding out a new way to do lists 2026-04-13 15:09:26 -04:00
Pagwin
aa69b3f6ef
removed LLM code, unfortunately the only way to do lists correctly so I can pull out structure is to do it myself 2026-04-13 14:07:38 -04:00
Pagwin
4db3e8f912
realizing LLM code is inadequate 2026-04-13 14:06:44 -04:00
Pagwin
b6a689868b
Brought in code by Gemini for handling lists and Task lists
lists and task lists are a PITA to handle, I may need to handle them
myself in the future but that'll probably become clear via testing
rather than simply doing it as is because the parsing logic is annoying
2026-04-10 16:17:37 -04:00
Pagwin
1a2feb95e9
bunch of work on djot 2026-04-10 15:22:06 -04:00
Pagwin
cc4f0b7672
started work on inline elements 2026-04-08 17:16:25 -04:00
Pagwin
abf93fbd8b
all block level elements other than paragraph are handled 2026-04-08 15:55:23 -04:00
Pagwin
12280ef761
lots of block level work for djot 2026-04-07 17:26:19 -04:00
Pagwin
4bf7614eda
fixed with mempty and simplified working with attrs a bit 2026-04-06 22:37:14 -04:00
Pagwin
5073fdb04b
started on Djot implementation 2026-04-06 21:18:15 -04:00
Pagwin
b3d9999479
fixed minor bugs 2026-04-06 16:29:01 -04:00
Pagwin
eaf5d9408c
Began using Transparent 2026-04-06 15:36:36 -04:00
Pagwin
22f4f89137
naive refactor of markdown generation for the new IR 2026-04-06 15:17:39 -04:00
Pagwin
24606a9204
preliminary djot changes to IR made 2026-04-06 13:41:12 -04:00
Pagwin
c90d2e45b8
todo stuff and fixing images 2026-04-03 17:48:26 -04:00
Pagwin
1e5911b68f
TODO stuff 2026-03-07 21:10:33 -05:00
Pagwin
2a87e61a05
oop html block got parsed correct and then didn't do correct whitespace 2026-02-27 22:51:28 -05:00
Pagwin
8f31672b0f
fixed docker issues 2026-02-26 01:32:12 -05:00
Pagwin
d3096bb9cf
forgor workdir but also wtf 2026-02-25 01:00:48 -05:00
Pagwin
75810c269b
redid dockerfile to bring in esbuild 2026-02-24 02:13:22 -05:00
Pagwin
7ad4b2b98b
got a bit more ambitious 2026-02-23 22:05:46 -05:00
Pagwin
9e91dcb1d9
redid TODO a bit 2026-02-23 22:03:02 -05:00
Pagwin
4eaa44b4f1
handled leading slash 2026-02-23 21:59:20 -05:00
Pagwin
c447aab1b9
fixed what gets passed into our templates file bundling wise 2026-02-23 21:57:11 -05:00
Pagwin
009806c2b0
esbuild stdout and stderr are yeeted for now, may make use of exit code as circumstance to emit them again in future 2026-02-23 21:20:04 -05:00
Pagwin
b3808f4136
MVP Bundling is now implemented
This commit gets bundling to the point where it can be used now

TODO:
- Get ESBuild Stdout/stderr to not pop up in psb output
- figure out how to split off map files so I'm not shunting them into
  script tags
2026-02-23 17:14:31 -05:00
Pagwin
8082f95491
swapped to a single js and single css entrypoint and my brain hurts 2026-02-05 00:27:46 -05:00
Pagwin
b8064a8d3e
more work to get esbuild up 2026-02-02 22:22:27 -05:00
Pagwin
c3637bd12d
added a module for bundling 2026-01-31 19:53:20 -05:00
Pagwin
e7dfb662ed
fix type errors in javascript tokenizer
Fixed three type errors preventing compilation:
- template_char: properly convert Tokens s to s for string literals and eol
- regex_literal: correctly apply fromString to parser result, not parser itself
- reg_first_char: use explicit list notation to resolve noneOf ambiguity

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 15:09:45 -05:00
Pagwin
cf4f35f997
all of javascript tokenizer is done other than compiler errors 2026-01-31 01:35:08 -05:00
Pagwin
dea8577f14
regex is all that remains 2026-01-03 21:08:26 -05:00
Pagwin
11d2228362
just string and regex literals left barring me fucking up implementation of integer literals 2026-01-02 20:49:57 -05:00
Pagwin
1f89316fdf
trying to do more for js parser 2026-01-01 17:03:46 -05:00
Pagwin
2d2d0c0969
TODO update 2026-01-01 17:03:22 -05:00
Pagwin
cd5e094eca
handled reserved words whether an expression is allowed or not 2025-12-31 15:16:55 -05:00
Pagwin
7388aee8d1
did a lot of the work for handling slashes 2025-12-30 23:48:20 -05:00
Pagwin
83d99c84af
fixed compilation error(s) 2025-12-30 21:07:17 -05:00
Pagwin
4894bf8ff7
more progress into compile error 2025-12-30 19:33:24 -05:00
Pagwin
3c2871217e
forward slash handling and literal handling are all that's left 2025-12-30 01:19:38 -05:00
Pagwin
8bc5c481c1
added a function for future convenience with mustache 2025-12-30 00:45:42 -05:00
Pagwin
27e08cbc7a
refactored to use ToMustache instead of ToJSON 2025-12-29 19:28:55 -05:00