From abc5a00c2fb36622f25d92781fa3b91a598dd8f4 Mon Sep 17 00:00:00 2001 From: Louis Gesbert Date: Tue, 14 Mar 2023 16:57:14 +0100 Subject: [PATCH 1/2] Compile LaTeX code using minted without the Python venv This is a hack, but not a dirty one: a new command `catala pygmentize` is added, which is just a wrapper around `pygmentize` that calls it with the proper lexers defined. The point is that this needs no installation, just a stock `pygmentize` installation and the `catala` binary. --- INSTALL.md | 7 ++-- compiler/catala_utils/cli.ml | 4 ++ compiler/driver.ml | 4 ++ compiler/literate/literate_common.ml | 21 ++++++----- compiler/literate/literate_common.mli | 4 ++ compiler/literate/pygmentize.ml | 54 +++++++++++++++++++++++++++ compiler/literate/pygmentize.mli | 19 ++++++++++ doc/syntax/syntax_en.tex | 2 + doc/syntax/syntax_fr.tex | 2 + 9 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 compiler/literate/pygmentize.ml create mode 100644 compiler/literate/pygmentize.mli diff --git a/INSTALL.md b/INSTALL.md index ec25ac4a..e10ff1a3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -72,11 +72,10 @@ Next, install all the packages that Catala depends on with make dependencies This should ensure everything is set up for developing on the Catala compiler! + The Python dependencies are installed inside a local virtual environment -(`venv`). The Makefile rules will use it automatically when building the syntax -cheat-sheet, for example, but if you need to otherwise colorise Catala code, or -use generated Python code, you should run the following command once in every -new shell session: +(`venv`). To use it, for example to run Python code generated by Catala, you +should run the following command once in every new shell session: . _python_venv/bin/activate diff --git a/compiler/catala_utils/cli.ml b/compiler/catala_utils/cli.ml index bf177021..b00d5f26 100644 --- a/compiler/catala_utils/cli.ml +++ b/compiler/catala_utils/cli.ml @@ -378,6 +378,10 @@ let info = "Prints a debugging verbatim of the statement calculus intermediate \ representation of the Catala program. Use the $(b,-s) option to \ restrict the output to a particular scope." ); + `I + ( "$(b,pygmentize)", + "This special command is a wrapper around the $(b,pygmentize) \ + command that enables support for colorising Catala code." ); `S Manpage.s_authors; `P "The authors are listed by alphabetical order."; `P "Nicolas Chataing "; diff --git a/compiler/driver.ml b/compiler/driver.ml index c72fb3c1..a29f4e5c 100644 --- a/compiler/driver.ml +++ b/compiler/driver.ml @@ -403,6 +403,10 @@ let driver source_file (options : Cli.options) : int = -1 let main () = + if + Array.length Sys.argv >= 2 + && String.lowercase_ascii Sys.argv.(1) = "pygmentize" + then Literate.Pygmentize.exec (); let return_code = Cmdliner.Cmd.eval' (Cmdliner.Cmd.v Cli.info (Cli.catala_t (fun f -> driver (FileName f)))) diff --git a/compiler/literate/literate_common.ml b/compiler/literate/literate_common.ml index e089f07a..278c529b 100644 --- a/compiler/literate/literate_common.ml +++ b/compiler/literate/literate_common.ml @@ -125,6 +125,16 @@ let check_exceeding_lines "%s" String.(sub s max_len (len_s - max_len))))) +let with_pygmentize_lexer lang f = + let lexer_py = + let lexer_fname = "lexer_" ^ Cli.language_code lang ^ ".py" in + match Pygment_lexers.read lexer_fname with + | None -> failwith "Pygments lexer not found for this language" + | Some lexer -> lexer + in + File.with_temp_file "pygments_lexer_" ".py" ~contents:lexer_py + @@ fun pyg_lexer -> f ["-l"; pyg_lexer; "-x"] + let call_pygmentize ?lang args = let cmd = "pygmentize" in let check_exit n = @@ -137,12 +147,5 @@ let call_pygmentize ?lang args = match lang with | None -> File.process_out ~check_exit cmd args | Some lang -> - let lexer_py = - let lexer_fname = "lexer_" ^ Cli.language_code lang ^ ".py" in - match Pygment_lexers.read lexer_fname with - | None -> failwith "Pygments lexer not found for this language" - | Some lexer -> lexer - in - File.with_temp_file "pygments_lexer_" ".py" ~contents:lexer_py - @@ fun pyg_lexer -> - File.process_out ~check_exit cmd ("-l" :: pyg_lexer :: "-x" :: args) + with_pygmentize_lexer lang + @@ fun lex_args -> File.process_out ~check_exit cmd (lex_args @ args) diff --git a/compiler/literate/literate_common.mli b/compiler/literate/literate_common.mli index 4164a2fa..f7f62194 100644 --- a/compiler/literate/literate_common.mli +++ b/compiler/literate/literate_common.mli @@ -51,3 +51,7 @@ val call_pygmentize : ?lang:Cli.backend_lang -> string list -> string (** Calls the [pygmentize] command with the given arguments, and returns the results as a string. If [lang] is specified, the proper arguments for the Catala lexer are already passed. *) + +val with_pygmentize_lexer : Cli.backend_lang -> (string list -> 'a) -> 'a +(** Creates the required lexer file and returns the corresponding [pygmentize] + command-line arguments *) diff --git a/compiler/literate/pygmentize.ml b/compiler/literate/pygmentize.ml new file mode 100644 index 00000000..c7e002b5 --- /dev/null +++ b/compiler/literate/pygmentize.ml @@ -0,0 +1,54 @@ +(* This file is part of the Catala compiler, a specification language for tax + and social benefits computation rules. Copyright (C) 2020 Inria, contributor: + Louis Gesbert + + Licensed under the Apache License, Version 2.0 (the "License"); you may not + use this file except in compliance with the License. You may obtain a copy of + the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and limitations under + the License. *) + +open Catala_utils +open Literate_common + +let lang_of_ext s = + if String.starts_with ~prefix:"catala_" s then + match s with + | "catala_en" -> Some Cli.En + | "catala_fr" -> Some Cli.Fr + | "catala_pl" -> Some Cli.Pl + | _ -> failwith "Unknown Catala dialect" + else None + +let exec () = + let args = List.tl (Array.to_list Sys.argv) in + let rec find_lang acc = function + | "-l" :: lang :: r -> Some lang, List.rev_append acc r + | x :: r -> find_lang (x :: acc) r + | [] -> None, List.rev acc + in + let lang, args = find_lang [] args in + let catala_lang = + match lang with + | Some l -> lang_of_ext l + | None -> + List.find_map + (fun s -> + match Filename.extension s with + | "" -> None + | e -> lang_of_ext (String.sub e 1 (String.length e - 1))) + args + in + match catala_lang with + | None -> Unix.execvp "pygmentize" (Array.of_list args) + | Some lang -> + with_pygmentize_lexer lang + @@ fun lex_args -> + Unix.execvp "pygmentize" + (Array.of_list (("pygmentize" :: lex_args) @ List.tl args)) diff --git a/compiler/literate/pygmentize.mli b/compiler/literate/pygmentize.mli new file mode 100644 index 00000000..ca0ed472 --- /dev/null +++ b/compiler/literate/pygmentize.mli @@ -0,0 +1,19 @@ +(* This file is part of the Catala compiler, a specification language for tax + and social benefits computation rules. Copyright (C) 2020 Inria, contributor: + Louis Gesbert + + Licensed under the Apache License, Version 2.0 (the "License"); you may not + use this file except in compliance with the License. You may obtain a copy of + the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and limitations under + the License. *) + +val exec : unit -> unit +(** Wrapper around the [pygmentize] binary with support for Catala. Reads the + arguments directly from Sys.argv *) diff --git a/doc/syntax/syntax_en.tex b/doc/syntax/syntax_en.tex index 7fbce6b0..df32c3ac 100644 --- a/doc/syntax/syntax_en.tex +++ b/doc/syntax/syntax_en.tex @@ -26,6 +26,8 @@ \setlist[itemize]{noitemsep, topsep=0pt} +\renewcommand{\MintedPygmentize}{../../_build/default/compiler/catala.exe pygmentize} + % backquote dejavu fix \makeatletter \chardef\straightquote@code=\catcode`' diff --git a/doc/syntax/syntax_fr.tex b/doc/syntax/syntax_fr.tex index 7aec5a4b..ee0a5100 100644 --- a/doc/syntax/syntax_fr.tex +++ b/doc/syntax/syntax_fr.tex @@ -26,6 +26,8 @@ \setlist[itemize]{noitemsep, topsep=0pt} +\renewcommand{\MintedPygmentize}{../../_build/default/compiler/catala.exe pygmentize} + % backquote dejavu fix \makeatletter \chardef\straightquote@code=\catcode`' From ebf957008d29bd8f60c608ad7417fb412229fdce Mon Sep 17 00:00:00 2001 From: Louis Gesbert Date: Tue, 14 Mar 2023 17:24:29 +0100 Subject: [PATCH 2/2] Makefile: loading venv is no longer required for most rules --- Makefile | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 54abf508..6f410c40 100644 --- a/Makefile +++ b/Makefile @@ -52,9 +52,6 @@ $(PY_VENV_DIR)/stamp: \ -e syntax_highlighting/pl/pygments touch $@ -# Run sub-make within the Python venv -MAKEP = $(PY_VENV_ACTIVATE) $(MAKE) - dependencies-python: $(PY_VENV_DIR) #> dependencies : Install the Catala OCaml, JS and Git dependencies @@ -171,7 +168,7 @@ vscode: vscode_fr vscode_en ########################################## syntax: - $(MAKEP) -C doc/syntax + $(MAKE) -C doc/syntax ########################################## # Literate programming and examples @@ -187,32 +184,32 @@ TUTORIEL_FR_DIR=$(EXAMPLES_DIR)/tutoriel_fr POLISH_TAXES_DIR=$(EXAMPLES_DIR)/polish_taxes literate_aides_logement: build $(PY_VENV_DIR) - $(MAKEP) -C $(AIDES_LOGEMENT_DIR) aides_logement.tex - $(MAKEP) -C $(AIDES_LOGEMENT_DIR) aides_logement.html + $(MAKE) -C $(AIDES_LOGEMENT_DIR) aides_logement.tex + $(MAKE) -C $(AIDES_LOGEMENT_DIR) aides_logement.html literate_allocations_familiales: build - $(MAKEP) -C $(ALLOCATIONS_FAMILIALES_DIR) allocations_familiales.tex - $(MAKEP) -C $(ALLOCATIONS_FAMILIALES_DIR) allocations_familiales.html + $(MAKE) -C $(ALLOCATIONS_FAMILIALES_DIR) allocations_familiales.tex + $(MAKE) -C $(ALLOCATIONS_FAMILIALES_DIR) allocations_familiales.html literate_code_general_impots: build - $(MAKEP) -C $(CODE_GENERAL_IMPOTS_DIR) code_general_impots.tex - $(MAKEP) -C $(CODE_GENERAL_IMPOTS_DIR) code_general_impots.html + $(MAKE) -C $(CODE_GENERAL_IMPOTS_DIR) code_general_impots.tex + $(MAKE) -C $(CODE_GENERAL_IMPOTS_DIR) code_general_impots.html literate_us_tax_code: build - $(MAKEP) -C $(US_TAX_CODE_DIR) us_tax_code.tex - $(MAKEP) -C $(US_TAX_CODE_DIR) us_tax_code.html + $(MAKE) -C $(US_TAX_CODE_DIR) us_tax_code.tex + $(MAKE) -C $(US_TAX_CODE_DIR) us_tax_code.html literate_tutorial_en: build - $(MAKEP) -C $(TUTORIAL_EN_DIR) tutorial_en.tex - $(MAKEP) -C $(TUTORIAL_EN_DIR) tutorial_en.html + $(MAKE) -C $(TUTORIAL_EN_DIR) tutorial_en.tex + $(MAKE) -C $(TUTORIAL_EN_DIR) tutorial_en.html literate_tutoriel_fr: build - $(MAKEP) -C $(TUTORIEL_FR_DIR) tutoriel_fr.tex - $(MAKEP) -C $(TUTORIEL_FR_DIR) tutoriel_fr.html + $(MAKE) -C $(TUTORIEL_FR_DIR) tutoriel_fr.tex + $(MAKE) -C $(TUTORIEL_FR_DIR) tutoriel_fr.html literate_polish_taxes: build - $(MAKEP) -C $(POLISH_TAXES_DIR) polish_taxes.tex - $(MAKEP) -C $(POLISH_TAXES_DIR) polish_taxes.html + $(MAKE) -C $(POLISH_TAXES_DIR) polish_taxes.tex + $(MAKE) -C $(POLISH_TAXES_DIR) polish_taxes.html #> literate_examples : Builds the .tex and .html versions of the examples code. Needs pygments to be installed and patched with Catala. literate_examples: literate_allocations_familiales literate_code_general_impots \ @@ -301,10 +298,10 @@ generate_french_law_library_python: #> type_french_law_library_python : Types the French law library Python sources with mypy type_french_law_library_python: $(PY_VENV_DIR) generate_french_law_library_python - $(MAKEP) -C $(FRENCH_LAW_PYTHON_LIB_DIR) type + $(PY_VENV_ACTIVATE) $(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) type run_french_law_library_benchmark_python: $(PY_ENV_DIR) type_french_law_library_python - $(MAKEP) -C $(FRENCH_LAW_PYTHON_LIB_DIR) bench + $(PY_VENV_ACTIVATE) $(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) bench ########################################## # High-level test and benchmarks commands