Skip to content

Commit

Permalink
Improve pandoc-include.
Browse files Browse the repository at this point in the history
  • Loading branch information
smimram committed Nov 13, 2023
1 parent a7a176a commit ebc19bc
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

- Switch to dune 3.0.
- pandoc-include now fails if the file to include does not exist.
- pandoc-include now supports string boundaries.

0.2.0 (2023-11-10)
=====
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,29 @@ convenience (or because I needed those).
!include "file"
```

by the contents of the file `file` and
by the contents of the file `file`, it replaces

~~~
```{.ocaml include="test.ml" from=2 to=5}
```
~~~

by the contents of the file `test.ml` between lines 2 and 5 (negative values
for `to` are counted from the end of the file). Useful for including small
code snippets.
by the contents of the file `test.ml` between lines 2 and 5, it replaces

~~~
```{.ocaml include="test.ml" from=2 to=-1}
```
~~~

by the content from line 2 to last but one line, it replaces

~~~
```{.ocaml include="test.ml" from="BEGIN" to="TO"}
```
~~~

by the content between lines containing "BEGIN" and "END", excluded. Useful
for including small code snippets.
- `pandoc-inspect`: acts as the identity plugin, but prints the JSON output
given by pandoc on the standard error. Useful for debugging and adding missing
features to the library.
Expand Down
97 changes: 76 additions & 21 deletions examples/include.ml
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
(** Pandoc extension to include files. *)

let error n =
module String = struct
include String

(* TODO: more efficient version *)
let contains_substring l s =
let n = String.length s in
try
for i = 0 to String.length l - n do
if String.sub l i n = s then raise Exit
done;
false
with
| Exit -> true
end

let error fname n =
Printf.ksprintf
(fun s ->
output_string stderr (s ^ "\n");
Printf.eprintf "pandoc-include error in file `%s`: %s\n%!" fname s;
exit n)

let () =
Expand All @@ -18,45 +33,85 @@ let () =
``` *)
| CodeBlock ((ident, classes, keyvals), _) when List.mem_assoc "include" keyvals ->
let fname = List.assoc "include" keyvals in
let error n = error fname n in
let from =
match List.assoc_opt "from" keyvals with
| None -> `Int 0
| Some from ->
match int_of_string_opt from with
| Some from -> `Int from
| None -> `String from
in
let last =
match List.assoc_opt "to" keyvals with
| None -> `Last
| Some last ->
match int_of_string_opt last with
| Some last -> `Int last
| None -> `String last
in
let contents =
if not (Sys.file_exists fname) then
error 1 "pandoc-include: could not find file `%s`." fname
error 1 "Could not find file."
else
let nb_lines () =
let ans = ref 0 in
let from = ref from in
let last = ref last in
let lines = ref 0 in
(
let ic = open_in fname in
try
while true do
ignore (input_line ic);
incr ans
done;
0
let l = input_line ic in
(
match !from with
| `String s ->
if String.contains_substring l s then from := `Int (!lines + 1)
| _ -> ()
);
(
match !last with
| `String s ->
if String.contains_substring l s then last := `Int (!lines - 1)
| _ -> ()
);
incr lines
done
with
| End_of_file -> !ans
| End_of_file -> close_in ic
);
let lines = !lines in
let from =
match !from with
| `Int n -> n
| `String s -> error 2 "Could not find string `%s` for first line." s
in
let from = try int_of_string (List.assoc "from" keyvals) with Not_found -> 0 in
let last = try int_of_string (List.assoc "to" keyvals) with Not_found -> max_int in
let from = if from < 0 then nb_lines () + from else from in
let last = if last < 0 then nb_lines () - 1 + last else last in

let last =
match !last with
| `Int n -> n
| `Last -> lines - 1
| `String s -> error 2 "Could not find string `%s` for last line." s
in
let from = if from < 0 then lines + from else from in
let last = if last < 0 then lines - 1 + last else last in
if from < 0 || from >= lines then error 3 "First line (%d) out of range." from;
if last < 0 || last >= lines then error 3 "Last line (%d) out of range." last;
try
let ic = open_in fname in
let ans = ref "" in
let line = ref 0 in
try
while true do
let l = input_line ic in
if !line >= from && !line <= last then ans := !ans ^ l ^ "\n";
if !line > last then raise Exit;
if !line >= from then ans := !ans ^ l ^ "\n";
incr line
done;
""
with
| End_of_file -> !ans
| End_of_file | Exit -> !ans
with
| Sys_error _ ->
let err = "ERROR: file \""^fname^"\" not found!" in
prerr_endline err;
err
| Sys_error _ as err ->
error 1 "System error: %s." (Printexc.to_string err);
in
Some [Pandoc.CodeBlock ((ident, classes, keyvals), contents)]
| _ -> None
Expand Down
3 changes: 3 additions & 0 deletions examples/include.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ B
C
D
E
F
G
H
3 changes: 3 additions & 0 deletions examples/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ Table: Demonstration of __simple table__ syntax.

```{include="include.txt" from=2 to=-1}
```

```{include="include.txt" from="B" to="F"}
```

0 comments on commit ebc19bc

Please sign in to comment.