Skip to content

Commit b4150da

Browse files
fix: Lean blocks/inlines in TeX (#706)
Fixes inline Lean blocks/inlines, esp. the display of the | character. Adds tests to keep this working, and updates the integration tests to run lualatex on the output if requested.
1 parent dbe83a1 commit b4150da

File tree

10 files changed

+344
-52
lines changed

10 files changed

+344
-52
lines changed

.github/workflows/ci.yml

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -64,32 +64,6 @@ jobs:
6464
run: |
6565
lake build
6666
67-
- name: Run tests
68-
run: |
69-
lake test
70-
71-
- name: Generate the test website
72-
run: |
73-
lake exe demosite --output _out/test-projects/demosite
74-
75-
- name: Generate the test genre's document
76-
run: |
77-
lake exe simplepage
78-
79-
- name: Generate some source HTML
80-
run: |
81-
lake build Verso.Hover:literate
82-
lake exe verso-html .lake/build/literate htmlout
83-
84-
- name: Check internal links on the test website
85-
uses: lycheeverse/[email protected]
86-
with:
87-
format: markdown
88-
jobSummary: true
89-
args:
90-
--base './_out/test-projects/demosite' --no-progress --offline
91-
'./_out/test-projects/demosite/**/*.html'
92-
9367
- name: Install PDF Dependencies
9468
uses: zauguin/install-texlive@v4
9569
with:
@@ -136,6 +110,32 @@ jobs:
136110
- name: Check `tlmgr` version
137111
run: tlmgr --version
138112

113+
- name: Run tests
114+
run: |
115+
lake test -- --verbose --check-tex
116+
117+
- name: Generate the test website
118+
run: |
119+
lake exe demosite --output _out/test-projects/demosite
120+
121+
- name: Generate the test genre's document
122+
run: |
123+
lake exe simplepage
124+
125+
- name: Generate some source HTML
126+
run: |
127+
lake build Verso.Hover:literate
128+
lake exe verso-html .lake/build/literate htmlout
129+
130+
- name: Check internal links on the test website
131+
uses: lycheeverse/[email protected]
132+
with:
133+
format: markdown
134+
jobSummary: true
135+
args:
136+
--base './_out/test-projects/demosite' --no-progress --offline
137+
'./_out/test-projects/demosite/**/*.html'
138+
139139
- name: Generate the manual
140140
run: |
141141
./generate.sh

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ _out
1212
*.hash
1313
profile.json
1414
profile.json.gz
15+
/src/tests/integration/**/*.log
16+
/src/tests/integration/**/*.aux
17+
/src/tests/integration/**/*.out
18+
/src/tests/integration/**/*.pdf
19+
/src/tests/integration/**/*.toc
20+

src/tests/TestMain.lean

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import VersoUtil.LzCompress
1111
import Tests
1212

1313
structure Config where
14+
verbose : Bool := false
1415
updateExpected : Bool := false
16+
checkTeX : Bool := false
1517

1618
open Verso.Search.Stemmer.Porter in
1719
def testStemmer (_ : Config) : IO Unit := do
@@ -37,8 +39,10 @@ Tests manual-genre TeX generation. `dir` is a subdirectory specific to a particu
3739
which is where actual output should go, and which contains the expected output directory.
3840
`doc` is the document to be rendered.
3941
-/
40-
def testTexOutput (dir : System.FilePath) (doc : Verso.Doc.VersoDoc Verso.Genre.Manual) :
41-
Config → IO Unit := fun config =>
42+
def testTexOutput
43+
(dir : System.FilePath)
44+
(doc : Verso.Doc.VersoDoc Verso.Genre.Manual)
45+
(config : Config) : IO Unit := do
4246
let versoConfig : Verso.Genre.Manual.Config := {
4347
destination := "src/tests/integration" / dir / "output",
4448
emitTeX := true,
@@ -50,13 +54,13 @@ def testTexOutput (dir : System.FilePath) (doc : Verso.Doc.VersoDoc Verso.Genre.
5054
let logError (msg : String) := IO.eprintln msg
5155
ReaderT.run (emitTeX logError versoConfig doc.toPart) extension_impls%
5256

53-
Verso.Integration.runTests {
57+
Verso.Integration.runTests { config with
5458
testDir := "src/tests/integration" / dir,
5559
updateExpected := config.updateExpected,
5660
runTest
5761
}
5862

59-
def testZip (_ : Config) : IO Unit := do
63+
def testZip (cfg : Config) : IO Unit := do
6064
IO.println "Running zip tests with fixed files..."
6165
testExtract #[] .store
6266
testExtract #[] .deflate
@@ -74,16 +78,21 @@ def testZip (_ : Config) : IO Unit := do
7478
testExtract #[("T2.lean", me), ("other", bwd)] .store
7579
testExtract #[("T2.lean", me), ("other", bwd)] .deflate
7680
for _ in (0 : Nat)...10 do
77-
IO.setRandSeed (← IO.monoNanosNow)
81+
let seedValue ← IO.monoNanosNow
82+
if cfg.verbose then IO.println s!"Seed is {seedValue}"
83+
IO.setRandSeed seedValue
7884
let mut randFiles := #[]
7985
for _ in 0...(← IO.rand 0 15) do
8086
let name ← randName
8187
let size ← IO.rand 0 50000
8288
let content ← IO.getRandomBytes <| .ofNat size
8389
randFiles := randFiles.push (name, content)
84-
IO.println s!"Running random zip test with {randFiles.size} files, sizes:"
85-
for (x, y) in randFiles do
86-
IO.println s!" * {x}: {y.size} bytes"
90+
if cfg.verbose then
91+
IO.println s!"Running random zip test with {randFiles.size} files, sizes:"
92+
for (x, y) in randFiles do
93+
IO.println s!" * {x}: {y.size} bytes"
94+
else
95+
IO.println s!"Running random zip test with {randFiles.size} files"
8796
testExtract randFiles .store
8897
testExtract randFiles .deflate
8998

@@ -147,12 +156,15 @@ def tests := [
147156
testStemmer,
148157
testTexOutput "sample-doc" SampleDoc.doc,
149158
testTexOutput "inheritance-doc" InheritanceDoc.doc,
159+
testTexOutput "code-content-doc" CodeContent.doc,
150160
testZip
151161
]
152162

153163
def getConfig (config : Config) : List String → IO Config
154164
| [] => pure config
155165
| "--update-expected" :: args => getConfig { config with updateExpected := true } args
166+
| "--verbose" :: args | "-v" :: args => getConfig { config with verbose := true } args
167+
| "--check-tex" :: args => getConfig { config with checkTeX := true } args
156168
| other :: _ => throw <| .userError s!"Didn't understand {other}"
157169

158170
def main (args : List String) : IO UInt32 := do

src/tests/Tests.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Tests.HighlightedToTeX
1212
import Tests.HtmlEntities
1313
import Tests.Integration
1414
import Tests.Integration.SampleDoc
15+
import Tests.Integration.CodeContent
1516
import Tests.LeanCode
1617
import Tests.Integration.InheritanceDoc
1718
import Tests.ParserRegression

src/tests/Tests/Integration.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ structure Config where
1717
updateExpected : Bool := false
1818
/-- How to run the test -/
1919
runTest : IO Unit
20+
/-- Whether to see if lualatex builds the file -/
21+
checkTeX : Bool
2022

2123
/--
2224
Returns all non-directory filepaths that are children of `root`, which
@@ -87,4 +89,11 @@ def runTests (config : Config) : IO Unit := do
8789
IO.println (Lean.Diff.linesToString d)
8890
throw <| .userError s!"Test in {config.testDir} failed"
8991

92+
if config.checkTeX then
93+
discard <| IO.Process.run {
94+
cwd := outputRoot / "tex",
95+
cmd := "lualatex",
96+
args := #["-halt-on-error", "-interaction=nonstopmode", "main.tex"]
97+
}
98+
9099
return
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/-
2+
Copyright (c) 2025 Lean FRO LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Jason Reed
5+
-/
6+
import Verso
7+
import VersoManual
8+
9+
namespace Verso.Integration.CodeContent
10+
11+
open Verso Genre Manual InlineLean
12+
13+
--------------------
14+
15+
#docs (Manual) doc "Title of the Doc" :=
16+
:::::::
17+
18+
%%%
19+
authors := ["Harry Q. Bovik"]
20+
%%%
21+
22+
Here is some code with vertical bars:
23+
```lean
24+
def or := (· || ·)
25+
```
26+
27+
Here is some with a variety of interesting Unicode, including characters where UTF-16 is funky:
28+
```lean
29+
def Set (α : Type u) : Type u := α → Prop
30+
31+
instance : EmptyCollection (Set α) where
32+
emptyCollection := fun _ => False
33+
34+
instance : Union (Set α) where
35+
union a b := fun x => a x ∨ b x
36+
37+
instance : Inter (Set α) where
38+
inter a b := fun x => a x ∧ b x
39+
40+
instance : Membership α (Set α) where
41+
mem a x := a x
42+
43+
@[ext]
44+
theorem Set.ext {a b : Set α} :
45+
(∀ x, x ∈ a ↔ x ∈ b) → a = b := by
46+
intro h
47+
funext x
48+
exact propext (h x)
49+
50+
instance : HasSubset (Set α) where
51+
Subset a b := ∀ x, x ∈ a → x ∈ b
52+
53+
@[simp, grind .]
54+
theorem Set.subset_refl {a : Set α} : a ⊆ a := by
55+
simp [(· ⊆ ·)]
56+
57+
@[grind ←]
58+
theorem Set.subset_union {a b c : Set α} :
59+
a ⊆ b → a ⊆ b ∪ c := by
60+
simp [(· ⊆ ·), (· ∪ ·), (· ∈ ·)]
61+
intro h
62+
solve_by_elim
63+
64+
def Set.powerset (a : Set α) : Set (Set α) :=
65+
fun (x : Set α) => x ⊆ a
66+
67+
notation "𝒫 " x => Set.powerset x
68+
69+
theorem Set.powerset_empty_nonempty :
70+
∃ (a : Set α), a ∈ 𝒫 {} := by
71+
constructor
72+
case w => exact {}
73+
simp [(· ∈ ·), powerset]
74+
75+
@[grind? →]
76+
theorem Set.powerset_empty_unique (x y : Set α) :
77+
x ∈ (𝒫 {}) → y ∈ (𝒫 {}) → x = y := by
78+
intro hx hy
79+
ext x'
80+
exact (iff_false_right (hy x')).mpr (hx x')
81+
```
82+
83+
And now some inline code:
84+
85+
* {lean}`∀x y : Set _, x ∈ ((𝒫 x) ∪ (𝒫 y))`
86+
* {lean}`true || false`
87+
* {lean}`False → True`
88+
89+
:::::::

0 commit comments

Comments
 (0)