From 95f069193c541d45c97879c9cb64c910cd43dd54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Richard?= Date: Tue, 30 Jan 2024 18:20:41 +0100 Subject: [PATCH 1/5] Modify parser --- src/MathTeXEngine.jl | 1 + src/parser/parser.jl | 20 +++++++++++++++++++- src/parser/tokenizer.jl | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/MathTeXEngine.jl b/src/MathTeXEngine.jl index 18540dd..a3b184c 100644 --- a/src/MathTeXEngine.jl +++ b/src/MathTeXEngine.jl @@ -19,6 +19,7 @@ import FreeTypeAbstraction: height_insensitive_boundingbox, leftinkbound, rightinkbound, topinkbound, bottominkbound +export TeXToken, tokenize export TeXExpr, texparse, TeXParseError, manual_texexpr export TeXElement, TeXChar, VLine, HLine, generate_tex_elements export texfont diff --git a/src/parser/parser.jl b/src/parser/parser.jl index 5ccbae8..4f6335b 100644 --- a/src/parser/parser.jl +++ b/src/parser/parser.jl @@ -110,9 +110,16 @@ arguments. Setting `showdebug` to `true` show a very verbose break down of the parsing. """ -function texparse(tex ; root = TeXExpr(:expr), showdebug = false) +function texparse(tex ; root = TeXExpr(:lines), showdebug = false) + if tex[1] == '$' && tex[end] == '$' && !('$' in tex[2:end-1]) + @info "Just one latex equation" + tex = tex[2:end-1] + end + @show tex + stack = Stack{Any}() push!(stack, root) + push!(stack, TeXExpr(:line)) for (pos, len, token) in tokenize(TeXToken, tex) if showdebug @@ -128,6 +135,13 @@ function texparse(tex ; root = TeXExpr(:expr), showdebug = false) else push!(stack, TeXExpr(:inline_math)) end + elseif token == newline + if length(stack) > 2 + throw(TeXParseError("unexpected new line", stack, length(tex), tex)) + end + + push_down!(stack) + push!(stack, TeXExpr(:line)) elseif token == lcurly push!(stack, TeXExpr(:group)) elseif token == rcurly @@ -188,6 +202,10 @@ function texparse(tex ; root = TeXExpr(:expr), showdebug = false) end end + if head(first(stack)) == :line + push_down!(stack) + end + if length(stack) > 1 throw(TeXParseError("unexpected end of input", stack, length(tex), tex)) end diff --git a/src/parser/tokenizer.jl b/src/parser/tokenizer.jl index 2c9df8b..9619622 100644 --- a/src/parser/tokenizer.jl +++ b/src/parser/tokenizer.jl @@ -8,6 +8,7 @@ tex_tokens = [ :command => re"\\[a-zA-Z]+" | re"\\.", :right => re"\\right.", :left => re"\\left.", + :newline => (re"\\" * re"\\") | re"\\n", :dollar => re"$" ] From c09e7b9fa759057e9a474df18729688ce114fbb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Richard?= Date: Mon, 22 Apr 2024 15:56:50 +0200 Subject: [PATCH 2/5] Fix single line expr --- src/engine/layout.jl | 28 +++++++--------------------- src/engine/layout_context.jl | 4 ++++ src/parser/parser.jl | 6 ------ 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/engine/layout.jl b/src/engine/layout.jl index 509395d..3d4b5b6 100644 --- a/src/engine/layout.jl +++ b/src/engine/layout.jl @@ -29,8 +29,7 @@ function tex_layout(expr, state) if char == ' ' && state.tex_mode == :inline_math return Space(0.0) end - texchar = TeXChar(char, state, head) - return texchar + return TeXChar(char, state, head) elseif head == :combining_accent accent, core = tex_layout.(args, state) @@ -134,8 +133,8 @@ function tex_layout(expr, state) name = args[1] elements = TeXChar.(collect(name), state, Ref(:function)) return horizontal_layout(elements) - elseif head == :group || head == :expr || head == :inline_math - mode = head == :inline_math ? :inline_math : state.tex_mode + elseif head in (:group, :inline_math, :line) + mode = (head == :inline_math) ? :inline_math : state.tex_mode elements = tex_layout.(args, change_mode(state, mode)) if isempty(elements) return Space(0.0) @@ -160,6 +159,8 @@ function tex_layout(expr, state) ], [1, shrink, shrink] ) + elseif head == :lines + length(args) == 1 && return tex_layout(only(args), state) elseif head == :overline content = tex_layout(args[1], state) @@ -248,7 +249,7 @@ function tex_layout(expr, state) @error "Error while layouting expr" end - @error "Unsupported head $(head) in expr:\n$expr" + throw(ArgumentError("Unsupported head :$(head) in TeXExpr\n$expr")) end tex_layout(::Nothing, state) = Space(0) @@ -310,19 +311,4 @@ function generate_tex_elements(str, font_family=FontFamily()) expr = texparse(str) layout = tex_layout(expr, font_family) return unravel(layout) -end - -#= -# Still hacky as hell -function generate_tex_elements(str::LaTeXString, font_family=FontFamily()) - parts = String.(split(str, raw"$")) - groups = Vector{TeXElement}(undef, length(parts)) - texts = parts[1:2:end] - maths = parts[2:2:end] - - groups[1:2:end] = layout_text.(texts, Ref(font_family)) - groups[2:2:end] = tex_layout.(texparse.(maths), Ref(font_family)) - - return unravel(horizontal_layout(groups)) -end -=# \ No newline at end of file +end \ No newline at end of file diff --git a/src/engine/layout_context.jl b/src/engine/layout_context.jl index f514e8c..0886e07 100644 --- a/src/engine/layout_context.jl +++ b/src/engine/layout_context.jl @@ -20,6 +20,10 @@ function add_font_modifier(state::LayoutState, modifier) end function get_font(state::LayoutState, char_type) + if state.tex_mode == :text + char_type = :text + end + font_family = state.font_family font_id = font_family.font_mapping[char_type] diff --git a/src/parser/parser.jl b/src/parser/parser.jl index 4f6335b..8631b63 100644 --- a/src/parser/parser.jl +++ b/src/parser/parser.jl @@ -111,12 +111,6 @@ arguments. Setting `showdebug` to `true` show a very verbose break down of the parsing. """ function texparse(tex ; root = TeXExpr(:lines), showdebug = false) - if tex[1] == '$' && tex[end] == '$' && !('$' in tex[2:end-1]) - @info "Just one latex equation" - tex = tex[2:end-1] - end - @show tex - stack = Stack{Any}() push!(stack, root) push!(stack, TeXExpr(:line)) From 55328667d760ed476257e73b3c6f32b3cc4c3cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Richard?= Date: Mon, 22 Apr 2024 18:26:09 +0200 Subject: [PATCH 3/5] small ref change --- reference/references.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/references.jl b/reference/references.jl index 8fdf6b2..fd17910 100644 --- a/reference/references.jl +++ b/reference/references.jl @@ -115,7 +115,7 @@ function single_figure(exprs) failures = Dict() for (i, expr) in enumerate(exprs) try - fig[i, 1] = Label(fig, expr) + Label(fig[i, 1], expr) catch e failures[expr] = e end From c879c8b419136f9b7822bc516c671d58f8203a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Richard?= Date: Mon, 22 Apr 2024 18:36:33 +0200 Subject: [PATCH 4/5] Layout for multiline --- src/engine/layout.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/engine/layout.jl b/src/engine/layout.jl index 3d4b5b6..0b77a84 100644 --- a/src/engine/layout.jl +++ b/src/engine/layout.jl @@ -161,6 +161,15 @@ function tex_layout(expr, state) ) elseif head == :lines length(args) == 1 && return tex_layout(only(args), state) + lineheight = 1.3 + lines = tex_layout.(args, state) + points = map(enumerate(lines)) do (k, line) + x = -inkwidth(line) / 2 + y = (1 - k)*lineheight + return Point2f(x, y) + end + + return Group(lines, points) elseif head == :overline content = tex_layout(args[1], state) From ba8e0433c2990d241c3684f23dcbd79ecf91d328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Richard?= Date: Mon, 22 Apr 2024 18:46:38 +0200 Subject: [PATCH 5/5] Add and fix tests --- reference/references.jl | 4 ++++ src/parser/parser.jl | 8 +++++++- test/parser.jl | 8 +++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/reference/references.jl b/reference/references.jl index fd17910..b3bf399 100644 --- a/reference/references.jl +++ b/reference/references.jl @@ -49,6 +49,10 @@ inputs["integrals"] = [ L"\int \int \int" ] +input["linebreaks"] = [ + L"we clearly see $x = 22$\\and $y > x^2$" +] + inputs["punctuation"] = [ L"x!", L"23.17", diff --git a/src/parser/parser.jl b/src/parser/parser.jl index 8631b63..7e417da 100644 --- a/src/parser/parser.jl +++ b/src/parser/parser.jl @@ -203,5 +203,11 @@ function texparse(tex ; root = TeXExpr(:lines), showdebug = false) if length(stack) > 1 throw(TeXParseError("unexpected end of input", stack, length(tex), tex)) end - return only(stack) + + lines = only(stack) + if length(lines.args) == 1 + return only(lines.args) + else + return lines + end end \ No newline at end of file diff --git a/test/parser.jl b/test/parser.jl index 59d1002..848578f 100644 --- a/test/parser.jl +++ b/test/parser.jl @@ -1,5 +1,5 @@ function test_parse(input, args... ; broken=false) - arg = (:expr, args...) + arg = (:line, args...) if broken @test_broken texparse(input) == manual_texexpr(arg) else @@ -114,6 +114,12 @@ end ) end + @testset "Linebreak" begin + expr = texparse(L"$A$\\$B$\\$C$") + @test expr.head == :lines + @test length(expr.args) == 3 + end + @testset "LaTeXString input" begin @test texparse(raw"$\gamma$") == texparse(L"\gamma") end