package forester

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file LaTeX_pipeline.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(*
 * SPDX-FileCopyrightText: 2024 The Forester Project Contributors
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *)

open Forester_prelude
open Forester_core

module EP = Eio.Path

type env = Eio_unix.Stdenv.base

let indent_string string =
  string
  |> String.split_on_char '\n'
  |> List.map (Format.sprintf "\t%s")
  |> String.concat "\n"

(* TODO: When error occurs on stderr, there is nothing informative in the diagnostic*)
let pipe_latex_dvi ~env ~tex_source ?loc kont =
  let mgr = Eio.Stdenv.process_mgr env in
  let@ tmp = Eio_util.with_open_tmp_dir ~env in
  let tex_fn = "job.tex" in
  begin
    let@ tex_sink = EP.with_open_out ~create: (`Or_truncate 0o644) EP.(tmp / tex_fn) in
    Eio.Flow.copy tex_source tex_sink
  end;
  begin
    let out_buf = Buffer.create 1000 in
    let stdout = Eio.Flow.buffer_sink out_buf in
    let stderr = Eio_util.null_sink () in
    let cmd = ["latex"; "-halt-on-error"; "-interaction=nonstopmode"; tex_fn] in
    try
      Eio.Process.run ~cwd: tmp ~stdout ~stderr mgr cmd
    with
      | _ ->
        let formatted_output = Buffer.contents out_buf |> indent_string in
        Reporter.fatal
          External_error
          ~extra_remarks: [
            Asai.Diagnostic.loctextf
              ?loc
              "Encountered fatal LaTeX error: @.@.%s@.@. while running `%s` in directory `%s`."
              formatted_output
              (String.concat " " cmd)
              (Eio.Path.native_exn tmp)
          ]
  end;
  EP.with_open_in EP.(tmp / "job.dvi") kont

let pipe_dvi_svg ~env ?loc ~dvi_source ~svg_sink () =
  let cwd = Eio.Stdenv.cwd env in
  let mgr = Eio.Stdenv.process_mgr env in
  let err_buf = Buffer.create 1000 in
  let stderr = Eio.Flow.buffer_sink err_buf in
  let cmd = ["dvisvgm"; "--exact"; "--clipjoin"; "--font-format=woff"; "--bbox=papersize"; "--zoom=1.5"; "--stdin"; "--stdout"] in
  try
    Eio.Process.run ~cwd ~stdin: dvi_source ~stdout: svg_sink ~stderr mgr cmd
  with
    | _ ->
      Reporter.fatal
        External_error
        ~extra_remarks: [
          Asai.Diagnostic.loctextf
            ?loc
            "Encountered fatal error running `dvisvgm`: %s"
            (Buffer.contents err_buf)
        ]

let pipe_latex_svg ~env ?loc ~tex_source ~svg_sink () =
  let@ dvi_source = pipe_latex_dvi ~env ~tex_source ?loc in
  pipe_dvi_svg ~env ?loc ~dvi_source ~svg_sink ()

let latex_to_svg ~env ?loc code =
  let tex_source = Eio.Flow.string_source code in
  let svg_buf = Buffer.create 1000 in
  let svg_sink = Eio.Flow.buffer_sink svg_buf in
  pipe_latex_svg ~env ~tex_source ~svg_sink ?loc ();
  Buffer.contents svg_buf
OCaml

Innovation. Community. Security.