diff --git a/.cirrus.yml b/.cirrus.yml index 378771fe8..fe2e5dbc7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -15,13 +15,13 @@ task: fingerprint_script: cat Makefile-fonts luarocks_cache: folder: /usr/local/lib/luarocks - fingerprint_script: cat sile-dev-1.rockspec + fingerprint_script: cat sile.rockspec.in luarocks_lua_cache: folder: /usr/local/share/lua - fingerprint_script: cat sile-dev-1.rockspec + fingerprint_script: cat sile.rockspec.in luarocks_lib_cache: folder: /usr/local/lib/lua - fingerprint_script: cat sile-dev-1.rockspec + fingerprint_script: cat sile.rockspec.in dependencies_script: - pkg install -y autoconf automake fontconfig GentiumPlus git gmake harfbuzz libtool pkgconf png - pkg install -y lua54 lua54-lpeg lua54-luafilesystem lua54-luarocks lua54-luasec lua54-luasocket @@ -46,7 +46,7 @@ task: - ./bootstrap.sh configure_script: | ./configure MAKE=gmake \ - --enable-developer LUAROCKS=false LUACHECK=false BUSTED=false \ + --enable-developer LUAROCKS=false LUACHECK=false BUSTED=false NIX=false \ --disable-font-variations \ --with-system-luarocks \ --without-manual diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f9f35e4d9..034b41eb1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: with: path: | lua_modules - key: luarocks-${{ hashFiles('Makefile-luarocks', 'sile-dev-1.rockspec') }} + key: luarocks-${{ hashFiles('Makefile-luarocks', 'sile.rockspec.in') }} - name: Fetch tags run: | git fetch --prune --tags ||: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 1b4ac17d4..0f95c5d61 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -31,7 +31,7 @@ jobs: with: path: | lua_modules - key: luarocks-luajit-${{ hashFiles('Makefile-luarocks', 'sile-dev-1.rockspec') }} + key: luarocks-luajit-${{ hashFiles('Makefile-luarocks', 'sile.rockspec.in') }} - name: Fetch tags run: | git fetch --prune --tags ||: @@ -63,7 +63,7 @@ jobs: run: | ./bootstrap.sh ./configure \ - --enable-developer LUACHECK=false \ + --enable-developer LUACHECK=false NIX=false \ --disable-font-variations \ --without-system-luarocks \ --with-luajit \ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5c4eda17c..4ae336891 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,7 @@ jobs: with: path: | lua_modules - key: luarocks-${{ matrix.luaVersion[0] }}-${{ hashFiles('Makefile-luarocks', 'sile-dev-1.rockspec') }} + key: luarocks-${{ matrix.luaVersion[0] }}-${{ hashFiles('Makefile-luarocks', 'sile.rockspec.in') }} - name: Fetch tags run: | git fetch --prune --tags ||: @@ -69,7 +69,7 @@ jobs: run: | ./bootstrap.sh ./configure \ - --enable-developer LUACHECK=false \ + --enable-developer LUACHECK=false NIX=false \ --disable-font-variations \ --without-system-luarocks \ --with${{ startsWith(matrix.luaVersion[0], '5') && 'out' || '' }}-luajit \ diff --git a/.gitignore b/.gitignore index 5afcaef87..76a9c3b23 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ tags Makefile-distfiles documentation/*.pdf gource.webm +*.rockspec .fonts/* .sources/* /sile @@ -87,6 +88,7 @@ sile.1 *.so core/version.lua core/features.lua +core/pathsetup.lua # Nix symlink to builds /result diff --git a/.luacheckrc b/.luacheckrc index 55574cc41..bb102010f 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -26,6 +26,8 @@ globals = { "luautf8", "pl", "fluent", + "extendSilePath", + "executablePath", "SYSTEM_SILE_PATH", "SHARED_LIB_EXT" } diff --git a/.luarc.json b/.luarc.json index 3b7cf8fcd..16515bea9 100644 --- a/.luarc.json +++ b/.luarc.json @@ -7,6 +7,8 @@ "luautf8", "pl", "fluent", + "extendSilePath", + "executablePath", "SYSTEM_SILE_PATH", "SHARED_LIB_EXT" ], diff --git a/Makefile.am b/Makefile.am index 5ffe5aac6..269b51806 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,7 @@ _MANUAL = $(MANUAL) endif nobase_dist_pkgdata_DATA = $(SILEDATA) $(LUALIBRARIES) -nobase_nodist_pkgdata_DATA = core/features.lua core/version.lua $(LUAMODULES) +nobase_nodist_pkgdata_DATA = core/features.lua core/pathsetup.lua core/version.lua $(LUAMODULES) dist_man_MANS = sile.1 dist_doc_DATA = README.md CHANGELOG.md dist_pdf_DATA = $(_MANUAL) @@ -60,11 +60,11 @@ EXTRA_DIST = spec tests documentation sile-dev-1.rockspec fontconfig.conf EXTRA_DIST += Makefile-distfiles EXTRA_DIST += build-aux/action-updater.js build-aux/decore-automake.sh build-aux/git-version-gen build-aux/list-dist-files.sh EXTRA_DIST += Dockerfile build-aux/docker-bootstrap.sh build-aux/docker-fontconfig.conf hooks/build -EXTRA_DIST += default.nix flake.nix flake.lock libtexpdf.git-rev shell.nix +EXTRA_DIST += default.nix flake.nix flake.lock shell.nix EXTRA_DIST += package.json # imported by both Nix and Docker EXTRA_DIST += $(MANUAL) -BUILT_SOURCES = .version core/features.lua core/version.lua Makefile-distfiles +BUILT_SOURCES = .version core/features.lua core/pathsetup.lua core/version.lua Makefile-distfiles CLEANFILES = $(bin_SCRIPTS) $(dist_man_MANS) $(BUILT_SOURCES) $(DEPFILES) $(ACTUALS) $(TESTPDFS) $(MANUAL) $(_BUILT_SUBDIRS) .version-prev @@ -85,9 +85,6 @@ _BRANCH_REF != $(AWK) '{print ".git/" $$2}' .git/HEAD 2>/dev/null ||: cmp -s "$@" "$@-prev" || ( autoreconf configure.ac --force && build-aux/decore-automake.sh ); \ fi -libtexpdf.git-rev: $(_BRANCH_REF) - $(GIT) submodule status -- libtexpdf | $(AWK) '{ print $$1 }' > $@ - dist-hook: $(MANUAL) cd $(distdir) printf "$(VERSION)" > .tarball-version @@ -130,8 +127,8 @@ sile-%.md: CHANGELOG.md update_libtexpdf: $(GIT) diff-index --quiet --cached HEAD || exit 1 # die if anything already staged $(GIT) submodule update --init --remote -- libtexpdf - $(GIT) submodule status -- libtexpdf | $(AWK) '{ print $$1 }' > libtexpdf.git-rev - $(GIT) add -- libtexpdf libtexpdf.git-rev + $(NIX) flake lock --override-input libtexpdf-src github:sile-typesetter/libtexpdf/$(shell $(GIT) submodule status -- libtexpdf | awk '{print $$1}') + $(GIT) add -- libtexpdf flake.lock $(GIT) diff-index --quiet --cached HEAD || $(GIT) commit -m "chore(build): Pin latest libtexpdf library submodule" DEPDIR := .deps diff --git a/build-aux/list-dist-files.sh.in b/build-aux/list-dist-files.sh.in index 3c0ae546a..c007dcb00 100755 --- a/build-aux/list-dist-files.sh.in +++ b/build-aux/list-dist-files.sh.in @@ -7,7 +7,7 @@ finder () { } printf '%s' "SILEDATA =" -finder core -name '*.lua' -not -name '*_spec.lua' -not -name 'version.lua' +finder core -name '*.lua' -not -name '*_spec.lua' -not -name 'version.lua' -not -name 'features.lua' -not -name 'pathsetup.lua' finder classes inputters languages outputters packages shapers typesetters pagebuilders -name '*.lua' -not -name '*_spec.lua' finder classes i18n packages -name '*.ftl' finder packages -name '*.svg' diff --git a/configure.ac b/configure.ac index 4981a75bc..ad1ebe932 100644 --- a/configure.ac +++ b/configure.ac @@ -200,6 +200,7 @@ AM_COND_IF([DEPENDENCY_CHECKS], [ AX_PROGVAR([busted]) AX_PROGVAR([luacheck]) AX_PROGVAR([luarocks]) + AX_PROGVAR([nix]) AX_PROGVAR([perl]) ]) @@ -245,11 +246,15 @@ adl_RECURSIVE_EVAL(["${libdir}/${TRANSFORMED_PACKAGE_NAME}"], [SILE_LIB_PATH]) AC_DEFINE_UNQUOTED([SILE_LIB_PATH],["${SILE_LIB_PATH}"],[Path for SILE libraries]) AC_SUBST([SILE_LIB_PATH]) +AC_SUBST([ROCKSPECWARNING], ["DO NOT EDIT! Modify template sile.rockspec.in"]) +AC_SUBST([ROCKREV], [1]) + AX_SUBST_MAN_DATE AC_CONFIG_FILES([build-aux/list-dist-files.sh], [chmod +x build-aux/list-dist-files.sh]) -AC_CONFIG_FILES([Makefile src/Makefile sile.1 core/features.lua core/version.lua]) +AC_CONFIG_FILES([Makefile src/Makefile sile.1 core/features.lua core/pathsetup.lua core/version.lua]) AC_CONFIG_FILES([sile tests/regressions.pl], [chmod +x sile tests/regressions.pl]) +AC_CONFIG_FILES([sile-dev-1.rockspec:sile.rockspec.in]) AC_ARG_PROGRAM diff --git a/core/cli.lua b/core/cli.lua index 2fc777046..fcc3fae12 100644 --- a/core/cli.lua +++ b/core/cli.lua @@ -15,7 +15,7 @@ cli.parseArguments = function () changed to .pdf. Additional input or output formats can be handled by requiring a module that adds support for them first. ]]) - cliargs:splat("INPUT", "input document, by default in SIL or XML format") + cliargs:splat("INPUTS", "input document(s), by default in SIL or XML format", nil, 999) cliargs:option("-b, --backend=VALUE", "choose an alternative output backend") cliargs:option("-c, --class=VALUE", "override default document class") cliargs:option("-d, --debug=VALUE", "show debug information for tagged aspects of SILE’s operation", {}) @@ -42,16 +42,20 @@ cli.parseArguments = function () local code = parse_err:match("^Usage:") and 0 or 1 os.exit(code) end - if opts.INPUT then - if opts.INPUT == "STDIO" then - opts.INPUT = "-" + if opts.INPUTS then + local has_input_filename = false + pl.tablex.foreachi(opts.INPUTS, function (v, k) + if v == "STDIO" then + opts.INPUTS[k] = "-" + elseif not has_input_filename then + has_input_filename = true + end + end) + if not has_input_filename and not opts.output then + SU.error("Unable to derive an output filename (perhaps because input is a STDIO stream).\n".. + " Please use --output to set one explicitly.") end - SILE.input.filename = opts.INPUT - -- Turn slashes around in the event we get passed a path from a Windows shell - local filename = opts.INPUT:gsub("\\", "/") - -- Strip extension - SILE.masterFilename = string.match(filename, "(.+)%..-$") or filename - SILE.masterDir = SILE.masterFilename:match("(.-)[^%/]+$") + SILE.input.filenames = opts.INPUTS end if opts.backend then SILE.backend = opts.backend diff --git a/core/pathsetup.lua.in b/core/pathsetup.lua.in new file mode 100644 index 000000000..ea9ad466f --- /dev/null +++ b/core/pathsetup.lua.in @@ -0,0 +1,72 @@ +local executable = debug.getinfo(3, "S").source +local luaversion = _VERSION:match("%d+%.%d+") + +-- Normalize possibly dirty Lua path formatting shortcut: /./ → / +-- Even leafo/gh-actions-luarocks takes this shortcut which inhibits duplicate cleanup +package.path = package.path:gsub("/%./", "/") +package.cpath = package.cpath:gsub("/%./", "/") + +local function prepend_and_dedup (segment, path) + local escaped = segment:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1') -- copied from pl.utils.escape() which we can't load yet + local striped = path:gsub(("^%s"):format(escaped), ""):gsub((";%s"):format(escaped), "") + return ("%s;%s"):format(segment, striped) +end + +local function prependPath (path) + package.path = prepend_and_dedup(path .. "/?/init.lua", package.path) + package.path = prepend_and_dedup(path .. "/?.lua", package.path) +end + +local function prependCPath (path) + package.cpath = prepend_and_dedup(path .. "/?.@SHARED_LIB_EXT@", package.cpath) +end + +local function extendPaths (path, ours) + prependCPath(path) + prependPath(path) + if ours then + prependPath(path .. "/lua-libraries") + if "@SYSTEM_LUAROCKS_FALSE@" == "" then -- see ./configure --with[out]-system-luarocks + prependCPath(path .. "/lua_modules/lib/lua/" .. luaversion) + prependPath(path .. "/lua_modules/share/lua/" .. luaversion) + end + else + prependCPath(path .. "/sile") + prependPath(path .. "/sile") + end +end + +-- Facilitate loading SILE classes & packages from system LuaRocks +-- Also weed out CWD relative paths, we add them in a different order later +local luapath = {} +local extpath = {} +for path in package.path:gmatch("[^;]+") do + table.insert(extpath, tostring(path:gsub("%?", "sile/?"))) + table.insert(luapath, path) +end +package.path = table.concat(luapath, ";") + +extendPaths("@SILE_PATH@", true) +extendPaths("@SILE_LIB_PATH@", true) + +package.path = table.concat(extpath, ";") .. ";" .. package.path + +local pathvar = os.getenv("SILE_PATH") +if pathvar then + for path in string.gmatch(pathvar, "[^;]+") do + if not path:match("^./") and path:len() >= 1 then + extendPaths(path) + end + end +end + +local cwd = executable:gsub("(.*)(/.*)", "%1") +if cwd:match("^@") then -- Consider "ours" for the sake of Nix Flake + extendPaths(".", true) +else + if cwd ~= "./" then extendPaths(cwd) end + extendPaths(".") +end + +_G.extendSilePath = extendPaths +_G.executablePath = executable diff --git a/core/sile.lua b/core/sile.lua index d19f5cdf8..eb9471610 100644 --- a/core/sile.lua +++ b/core/sile.lua @@ -29,6 +29,9 @@ fluent = require("fluent")() -- Includes for _this_ scope local lfs = require("lfs") +-- Developer tooling profiler +local ProFi + SILE.utilities = require("core.utilities") SU = SILE.utilities -- regrettable global alias @@ -59,7 +62,7 @@ SILE.rawHandlers = {} -- needed for a user to use a SILE-as-a-library verion to produce documents -- programatically. SILE.input = { - filename = "", + filenames = {}, evaluates = {}, evaluateAfters = {}, includes = {}, @@ -131,6 +134,14 @@ SILE.init = function () SILE.outputter = SILE.outputters.dummy() end SILE.pagebuilder = SILE.pagebuilders.base() + io.stdout:setvbuf("no") + if SU.debugging("profile") then + ProFi = require("ProFi") + ProFi:start() + end + if SILE.makeDeps then + SILE.makeDeps:add(_G.executablePath) + end runEvals(SILE.input.evaluates, "evaluate") end @@ -280,7 +291,7 @@ function SILE.processString (doc, format, filename, options) -- a specific inputter to use, use it at the exclusion of all content type -- detection local inputter - if filename and filename:gsub("STDIN", "-") == SILE.input.filename and SILE.inputter then + if filename and pl.path.splitext(pl.path.normcase(filename)) == SILE.masterFilename and SILE.inputter then inputter = SILE.inputter else format = format or detectFormat(doc, filename) @@ -290,7 +301,7 @@ function SILE.processString (doc, format, filename, options) inputter = SILE.inputters[format](options) -- If we did content detection *and* this is the master file, save the -- inputter for posterity and postambles - if filename and filename:gsub("STDIN", "-") == SILE.input.filename then + if filename and pl.path.splitext(pl.path.normcase(filename)) == SILE.masterFilename then SILE.inputter = inputter end end @@ -304,8 +315,21 @@ function SILE.processFile (filename, format, options) local doc if filename == "-" then filename = "STDIN" + SILE.masterFilename = "STDIN" doc = io.stdin:read("*a") else + -- Turn slashes around in the event we get passed a path from a Windows shell + filename = filename:gsub("\\", "/") + if not SILE.masterFilename then + -- Strip extension + SILE.masterFilename = string.match(filename, "(.+)%..-$") or filename + end + if SILE.masterFilename and not SILE.masterDir then + SILE.masterDir = SILE.masterFilename:match("(.-)[^%/]+$") + end + if SILE.masterDir and SILE.masterDir:len() >= 1 then + _G.extendSilePath(SILE.masterDir) + end filename = SILE.resolveFile(filename) if not filename then SU.error("Could not find file") @@ -356,7 +380,7 @@ function SILE.resolveFile (filename, pathprefix) candidates[#candidates+1] = "?" -- Iterate through the directory of the master file, the SILE_PATH variable, and the current directory -- Check for prefixed paths first, then the plain path in that fails - if SILE.masterFilename then + if SILE.masterDir then for path in SU.gtoke(SILE.masterDir..";"..tostring(os.getenv("SILE_PATH")), ";") do if path.string and path.string ~= "nil" then if pathprefix then candidates[#candidates+1] = pl.path.join(path.string, pathprefix, "?") end @@ -437,6 +461,13 @@ function SILE.finish () if not SILE.quiet then io.stderr:write("\n") end + if SU.debugging("profile") then + ProFi:stop() + ProFi:writeReport(SILE.masterFilename..'.profile.txt') + end + if SU.debugging("versions") then + SILE.shaper:debugVersions() + end end -- Internal libraries that run core SILE functions on load diff --git a/documentation/c01-whatis.sil b/documentation/c01-whatis.sil index f892b9536..baf0bfa9e 100644 --- a/documentation/c01-whatis.sil +++ b/documentation/c01-whatis.sil @@ -19,7 +19,7 @@ There are several important differences. The job of a word processor is to produce a document that looks exactly like what you type on the screen. By contrast, the job of a typesetting system is to take raw content and produce a document that looks as good as possible. The input for SILE is a text document that includes instructions about how the content should be laid out on a page. -In order to obtain the typeset result, the input file must be \em{processed} to render the desired output. +In order to obtain the typeset result, the input file(s) must be \em{processed} to render the desired output. Word processors often describe themselves as WYSIWYG: What You See Is What You Get. SILE is cheerfully \em{not} WYSIWYG. diff --git a/documentation/c02-gettingstarted.sil b/documentation/c02-gettingstarted.sil index 7d63eef33..bdef6415e 100644 --- a/documentation/c02-gettingstarted.sil +++ b/documentation/c02-gettingstarted.sil @@ -298,7 +298,7 @@ All the available CLI options are documented both in the help output (\code{sile This manual will only mention a few in passing as they come up in other other topics. \begin{autodoc:note} -SILE output filenames are generated by replacing the extension from the master input filename with the proper extension for the outputter. +SILE generates output filenames by replacing the extension from the first input filename with the default extension for the outputter. For most outputters this will be \code{.pdf} but, for example, the text backend will append \code{.txt} instead. If you want to write to a different filename altogether, use the \code{--output file.pdf} command line option. You can use \code{--output -} to write the output directly to the system IO stream—useful if you wish to use SILE as part of a pipeline. diff --git a/documentation/c10-classdesign.sil b/documentation/c10-classdesign.sil index b7f9c31e5..8f3800ce6 100644 --- a/documentation/c10-classdesign.sil +++ b/documentation/c10-classdesign.sil @@ -15,7 +15,7 @@ Their use below is straightforward and is expected to be covered by examples, bu \section{Designing a package} -Packages live somewhere in the \code{packages/} subdirectory of either where your input file is located, your current working directory, or your SILE path. +Packages live somewhere in the \code{packages/} subdirectory of either where your first input file is located, your current working directory, or your SILE path. \subsection{Implementing a bare package} diff --git a/documentation/c12-tricks.sil b/documentation/c12-tricks.sil index 16f3f777d..9383f254a 100644 --- a/documentation/c12-tricks.sil +++ b/documentation/c12-tricks.sil @@ -444,7 +444,7 @@ stack traceback: Sometimes it’s useful for you to try out Lua code within the SILE environment; SILE contains a REPL (read-evaluate-print loop) for you to enter Lua code and print the results back to you. -If you call SILE with no input file name, it enters the REPL: +If you call SILE with no input file names, it enters the REPL: \begin{autodoc:codeblock} \sileversion diff --git a/flake.lock b/flake.lock index d5602393a..17ea5fc9f 100644 --- a/flake.lock +++ b/flake.lock @@ -17,12 +17,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -51,13 +54,29 @@ "type": "github" } }, + "libtexpdf-src": { + "flake": false, + "locked": { + "lastModified": 1662109873, + "narHash": "sha256-yThIb+D/m1xeJZESojRd3u4OugbWl7f2s8oJohspwZs=", + "owner": "sile-typesetter", + "repo": "libtexpdf", + "rev": "736a5e7530c13582ea704a061a358d0caa774916", + "type": "github" + }, + "original": { + "owner": "sile-typesetter", + "repo": "libtexpdf", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1674487464, - "narHash": "sha256-Jgq50e4S4JVCYpWLqrabBzDp/1mfaxHCh8/OOorHTy0=", + "lastModified": 1682109806, + "narHash": "sha256-d9g7RKNShMLboTWwukM+RObDWWpHKaqTYXB48clBWXI=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3954218cf613eba8e0dcefa9abe337d26bc48fd0", + "rev": "2362848adf8def2866fabbffc50462e929d7fffb", "type": "github" }, "original": { @@ -72,8 +91,24 @@ "flake-compat": "flake-compat", "flake-utils": "flake-utils", "gitignore": "gitignore", + "libtexpdf-src": "libtexpdf-src", "nixpkgs": "nixpkgs" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 2fe4eacb5..ea0adc2ca 100644 --- a/flake.nix +++ b/flake.nix @@ -8,6 +8,13 @@ url = "github:hercules-ci/gitignore.nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + # TODO: Should this be replaced with libtexpdf package from nixpkgs? or + # should we keep it that way, so that it'd be easy to test new versions + # of libtexpdf when developing? + inputs.libtexpdf-src = { + url = "github:sile-typesetter/libtexpdf"; + flake = false; + }; # https://nixos.wiki/wiki/Flakes#Using_flakes_project_from_a_legacy_Nix inputs.flake-compat = { @@ -20,19 +27,13 @@ , flake-utils , flake-compat , gitignore + , libtexpdf-src }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; - # TODO: Should this be replaced with libtexpdf package from nixpkgs? or - # should we keep it that way, so that it'd be easy to test new versions - # of libtexpdf when developing? - libtexpdf-src = builtins.fetchGit { - url = "https://github.com/sile-typesetter/libtexpdf"; - rev = "${(pkgs.lib.fileContents "${self}/libtexpdf.git-rev")}"; - }; inherit (gitignore.lib) gitignoreSource; # https://discourse.nixos.org/t/passing-git-commit-hash-and-tag-to-build-with-flakes/11355/2 version_rev = if (self ? rev) then (builtins.substring 0 7 self.rev) else "dirty"; diff --git a/libtexpdf.git-rev b/libtexpdf.git-rev deleted file mode 100644 index 81e684cec..000000000 --- a/libtexpdf.git-rev +++ /dev/null @@ -1 +0,0 @@ -d1030b48014adcb09d41dae20cc8fccd4a77a04e diff --git a/packages/converters/init.lua b/packages/converters/init.lua index cdcbcbafc..7cbb0c511 100644 --- a/packages/converters/init.lua +++ b/packages/converters/init.lua @@ -59,11 +59,12 @@ function package.register (_, sourceExt, targetExt, command) end function package.checkConverters (_, source) + local resolvedSrc = SILE.resolveFile(source) or SU.error("Couldn't find file " .. source) for _, converter in ipairs(SILE.scratch.converters) do local extLen = string.len(converter.sourceExt) - if ((string.len(source) > extLen) and - (string.sub(source, -extLen) == converter.sourceExt)) then - return applyConverter(source, converter) + if ((string.len(resolvedSrc) > extLen) and + (string.sub(resolvedSrc, -extLen) == converter.sourceExt)) then + return applyConverter(resolvedSrc, converter) end end return source -- No conversion needed. @@ -75,17 +76,23 @@ function package:_init () SILE.scratch.converters = {} end extendCommand("include", function (options, content, original) - local result = self:checkConverters(options.src) - if not result then + local source = SU.required(options, "src", "include (converters)") + local result = self:checkConverters(source) + if result then options["src"] = result original(options, content) + else + SU.error("Conversion failure for include '" .. source ..'"') end end) extendCommand("img", function (options, content, original) - local result = self:checkConverters(options.src) - if not result then + local source = SU.required(options, "src", "img (converters)") + local result = self:checkConverters(source) + if result then options["src"] = result original(options, content) + else + SU.error("Conversion failure for image '" .. source ..'"') end end) self:deprecatedExport("register", self.register) diff --git a/sile-dev-1.rockspec b/sile-dev-1.rockspec deleted file mode 100644 index bd9ba0058..000000000 --- a/sile-dev-1.rockspec +++ /dev/null @@ -1,36 +0,0 @@ -package = "sile" -description = { - summary = "Simon’s Improved Layout Engine", - license = "MIT" -} -version = "dev-1" -source = { - url = "..." -} -dependencies = { - "lua >= 5.1", - "bit32", -- only required on Lua < 5.2, versions vary between Rock and VM provided - "cassowary == 2.3.2-1", - "cldr == 0.3.0-0", - "compat53 == 0.8-1", -- only required on Lua < 5.3 - "cosmo == 16.06.04-1", - "fluent == 0.2.0-0", - "linenoise == 0.9-1", - "loadkit == 1.1.0-1", - "lpeg == 1.0.2-1", - "lua-zlib == 1.2-2", - "lua_cliargs == 3.0-2", - "luaepnf == 0.3-2", - "luaexpat == 1.5.1-1", - "luafilesystem == 1.8.0-1", - "luarepl == 0.10-1", - "luasec == 1.3.1-1", - "luasocket == 3.1.0-1", - "luautf8 == 0.1.5-1", - "penlight == 1.13.1-1", - "vstruct == 2.1.1-1" -} -build = { - type = "builtin", - modules = {} -} diff --git a/sile.in b/sile.in index 94695fef6..b0bd02964 100755 --- a/sile.in +++ b/sile.in @@ -4,108 +4,32 @@ SYSTEM_SILE_PATH = "@SILE_PATH@" SHARED_LIB_EXT = "@SHARED_LIB_EXT@" -local executable = debug.getinfo(1, "S").source -local luaversion = _VERSION:match("%d+%.%d+") - --- Normalize possibly dirty Lua path formatting shortcut: /./ → / --- Even leafo/gh-actions-luarocks takes this shortcut which inhibits duplicate cleanup -package.path = package.path:gsub("/%./", "/") -package.cpath = package.cpath:gsub("/%./", "/") - -local function prepend_and_dedup (segment, path) - local escaped = segment:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1') -- copied from pl.utils.escape() which we can't load yet - local striped = path:gsub(("^%s"):format(escaped), ""):gsub((";%s"):format(escaped), "") - return ("%s;%s"):format(segment, striped) -end - -local function prependPath (path) - package.path = prepend_and_dedup(path .. "/?/init.lua", package.path) - package.path = prepend_and_dedup(path .. "/?.lua", package.path) -end - -local function prependCPath (path) - package.cpath = prepend_and_dedup(path .. "/?.@SHARED_LIB_EXT@", package.cpath) -end - -local function extendPaths (path, ours) - prependCPath(path) - prependPath(path) - if ours then - prependPath(path .. "/lua-libraries") - if "@SYSTEM_LUAROCKS_FALSE@" == "" then -- see ./configure --with[out]-system-luarocks - prependCPath(path .. "/lua_modules/lib/lua/" .. luaversion) - prependPath(path .. "/lua_modules/share/lua/" .. luaversion) - end - else - prependCPath(path .. "/sile") - prependPath(path .. "/sile") - end -end - --- Facilitate loading SILE classes & packages from system LuaRocks --- Also weed out CWD relative paths, we add them in a different order later -local luapath = {} -local extpath = {} -for path in package.path:gmatch("[^;]+") do - table.insert(extpath, tostring(path:gsub("%?", "sile/?"))) - table.insert(luapath, path) -end -package.path = table.concat(luapath, ";") - -extendPaths("@SILE_PATH@", true) -extendPaths("@SILE_LIB_PATH@", true) - -package.path = table.concat(extpath, ";") .. ";" .. package.path - -local pathvar = os.getenv("SILE_PATH") -if pathvar then - for path in string.gmatch(pathvar, "[^;]+") do - if not path:match("^./") and path:len() >= 1 then - extendPaths(path) - end - end +-- At this point at run time we may or may not have anything useful in package.path, +-- so require() isn't something we can rely on. +local status = pcall(dofile, "@SILE_PATH@/core/pathsetup.lua") +if not status then + dofile("./core/pathsetup.lua") end -local cwd = executable:gsub("(.*)(/.*)", "%1") -if cwd:match("^@") then -- Consider "ours" for the sake of Nix Flake - extendPaths(".", true) -else - if cwd ~= "./" then extendPaths(cwd) end - extendPaths(".") +-- On FreeBSD, Lua's debug module doesn't give us info above the top of the stack. +-- Since our detection is currently burried in a module it doesn't tell us the executable. +if _G.executablePath == "=[C]" then + _G.executablePath = debug.getinfo(1, "S").source end -- This global is set here and *also* in the core library, since this -- effectively passes the same table they are interchangeable (for now). SILE = require("core.sile") -io.stdout:setvbuf 'no' - SILE.cli:parseArguments() if not os.getenv 'LUA_REPL_RLWRAP' and not SILE.quiet then io.stderr:write(SILE.full_version .. '\n') end -local ProFi -if SU.debugging("profile") then - ProFi = require("ProFi") -end - -if SILE.makeDeps then - SILE.makeDeps:add(executable) -end - SILE.init() -if SILE.masterFilename then - - if SILE.masterDir:len() >= 1 then - extendPaths(SILE.masterDir) - end - - if SU.debugging("profile") then - ProFi:start() - end +if SILE.input.filenames and #SILE.input.filenames >= 1 then -- Deprecated, notice given in core.cli when argument used for _, path in ipairs(SILE.input.includes) do @@ -125,7 +49,7 @@ if SILE.masterFilename then end local main, err = xpcall(function() - return SILE.processFile(SILE.input.filename) + pl.tablex.imap(SILE.processFile, SILE.input.filenames) end, SILE.errorHandler) if not main then @@ -139,15 +63,6 @@ if SILE.masterFilename then SILE.finish() - if SU.debugging("profile") then - ProFi:stop() - ProFi:writeReport(SILE.masterFilename..'.profile.txt') - end - - if SU.debugging("versions") then - SILE.shaper:debugVersions() - end - else SILE.repl:enter() end diff --git a/sile.rockspec.in b/sile.rockspec.in new file mode 100644 index 000000000..24f2baf4d --- /dev/null +++ b/sile.rockspec.in @@ -0,0 +1,53 @@ +-- @ROCKSPECWARNING@ +rockspec_format = "3.0" +package = "@TRANSFORMED_PACKAGE_NAME@" +version = "dev-@ROCKREV@" + +source = { + url = "git+https://github.com/sile-typesetter/sile.git", + branch = "master" +} + +description = { + summary = "Simon’s Improved Layout Engine", + detailed = [[SILE is a typesetting system; its job is to produce beautiful printed documents. + Conceptually, SILE is similar to TeX—from which it borrows some concepts and even + syntax and algorithms—but the similarities end there. Rather than being a + derivative of the TeX family SILE is a new typesetting and layout engine written + from the ground up using modern technologies and borrowing some ideas from + graphical systems such as InDesign.]], + license = "MIT", + homepage = "https://github.com/sile-typesetter/fontproof", + issues_url = "https://github.com/sile-typesetter/fontproof/issues", + maintainer = "Caleb Maclennan ", + labels = { "typesetting" } +} + +dependencies = { + "lua >= 5.1", + "bit32", -- only required on Lua < 5.2, versions vary between Rock and VM provided + "cassowary == 2.3.2-1", + "cldr == 0.3.0-0", + "compat53 == 0.8-1", -- only required on Lua < 5.3 + "cosmo == 16.06.04-1", + "fluent == 0.2.0-0", + "linenoise == 0.9-1", + "loadkit == 1.1.0-1", + "lpeg == 1.0.2-1", + "lua-zlib == 1.2-2", + "lua_cliargs == 3.0-2", + "luaepnf == 0.3-2", + "luaexpat == 1.5.1-1", + "luafilesystem == 1.8.0-1", + "luarepl == 0.10-1", + "luasec == 1.3.1-1", + "luasocket == 3.1.0-1", + "luautf8 == 0.1.5-1", + "penlight == 1.13.1-1", + "vstruct == 2.1.1-1" +} + +build = { + type = "builtin", + modules = {} +} diff --git a/src/justenoughharfbuzz.c b/src/justenoughharfbuzz.c index edc2de790..f8d9ba340 100644 --- a/src/justenoughharfbuzz.c +++ b/src/justenoughharfbuzz.c @@ -185,7 +185,7 @@ int shape (lua_State *L) { } glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); - lua_checkstack(L, glyph_count); + lua_checkstack(L, glyph_count*10); for (j = 0; j < glyph_count; ++j) { char namebuf[255]; hb_glyph_extents_t extents = {0,0,0,0};