gfngfn / SATySFi

A statically-typed, functional typesetting system
GNU Lesser General Public License v3.0
1.16k stars 82 forks source link

Add make-deps command #275

Open yasuo-ozu opened 3 years ago

yasuo-ozu commented 3 years ago

Add deps-make command like gcc's -MM flag.

Satyrographos has such a command, but it enumerates only @require: or @import:-ed files (recursively). So, there is no way to list used image files.

@import: local
let _ = load-pdf-image `in.pdf` 1
$ SATYROGRAPHOS_EXPERIMENTAL=1 satyrographos  util deps-make a.saty --satysfi-version 0.0.5
a.pdf: a.saty local.satyh

Is it reasonable to implement deps-make command in satysfi?

na4zagin3 commented 3 years ago

I’m for adding such a feature to SATySFi with adding optionally-open file APIs.

The main purpose of the -MM option is to let a build tool know the dependencies.

Unlike programming languages, It’s normal for typesetting languages to process a document that depends on an intermediate file that is generated from other sources. For example, consider a case where a SATySFi document requires a sheetmusic PDF file that is generated from a Lilypond source file.

This causes a cyclic dependency during a fulll build.

We need to break the cyclic dependency; the simplest way is to add APIs that try to read a file, record it as a dependency anyway, and return the result in option.

yasuo-ozu commented 3 years ago

Thanks for reply.

We need to break the cyclic dependency

I think this API-redesign is complex. Is there any problem in load-image API which just returns stub image object with arbitrary geometry when the file not exists? Of course, the stub image occurs error when processing page-break, except when SATySFi is running with -MM mode.

yasuo-ozu commented 3 years ago

Note: I am using this script to generate dependency file. It works in many cases, but not always.

%.d:    %.saty
    @eval `opam env` && SATYROGRAPHOS_EXPERIMENTAL=1 satyrographos util deps-make "$<" --target "" --satysfi-version 0.0.5 2>/dev/null | tr ' :' '\n' | sed -e '/^$$/d' | while read LINE; do \
        cat "$$LINE" | sed -e 's/\(^\|[^\\]\)%.*$$/\1/' | sed -ne '/`/p' | sed -e 's/^.*`\([^`]*\)`.*$$/\1/' | sed -ne '/[a-zA-Z0-9]\+\.\(pdf\|jpg\)$$/p' | sed -e '/^http/d' | xargs -I{} echo '$(patsubst %.d,%.pdf,$@):  '`dirname "$$LINE"`'/{}' ; \
    done > "$@"
na4zagin3 commented 3 years ago

API with null objects could be simpler than that with option (or either) if every primitive that reads a file returned a image.

In fact, we already have read-file, which read a file, returning a list of lines. In future we may have more and more.

Let me elaborate my proposal:

File API returning a Option

We can have a new primitive, namely load-pdf-image-opt,

primitive load-pdf-image-opt : string -> int -> image option

We then can define load-pdf-image that has the semantics you suggested with stub:

primitive stub : image

let load-pdf-image file-name page-number =
  Option.from stub (load-pdf-image-opt file-name page-number)

This API allows more sophisticated handling of failures. For example, we can show a crossed box with the given size like draftfigure.

let crossed-box width height = ...

let load-pdf-image-or-draft width height file-name page-number =
  Option.from (crossed-box width height) (load-pdf-image-opt file-name page-number)
yasuo-ozu commented 3 years ago

Thank you for detailed design on your API. I agree with it.

Or more short-circuited way, simply make those API as statically analyzable like this:

@load-pdf-image: `in.pdf` 1 as mypic
@read-file: `in.txt` 1 as mytext
% mypic : image, mytext : string

Of course, this API design is too restricted, and na4zagin3's API is flexible,