jgm / djot

A light markup language
https://djot.net
MIT License
1.67k stars 43 forks source link

Create a C library that wraps lua and the djot code #79

Closed jgm closed 1 year ago

jgm commented 1 year ago

If we had a C library, it would be easy to use from other languages via ffi. The easiest route to this would be simply building in liblua.a + the djot sources. I don't think this would be too complicated, because we don't have any external Lua dependencies.

jgm commented 1 year ago

The following produces a single C file, djot.luastatic.c, that embeds all the djot modules as bytestrings and includes code to load them.

CC="" luastatic djot.lua djot/*.lua

This should be a good starting point; one only needs to add bridge code and a header to make a library.

One could add the lua sources to make the build completely self-contained.

jgm commented 1 year ago

In terms of an API, one would probably want a function that initializes the module (loading and interpreting the djot code and returning a Lua state), a function that cleans up, and functions that wrap the Lua library functions.

jgm commented 1 year ago

Another approach is to create a one-file version of the djot code, and then load it using Lua's C API.

jgm commented 1 year ago

This short lua script, run from djot's source directory, will produce a single-file version of djot (about 131K):

-- combine modules into one file

local modules = {"djot", "djot.ast", "djot.attributes", "djot.block",
                 "djot.emoji", "djot.html", "djot.inline", "djot.json",
                 "djot.match"}

for _,module in ipairs(modules) do
  print(string.format('package.preload["%s"] = function()', module))
  local path = module:gsub("%.","/") .. ".lua"
  local f = assert(io.open(path, "r"))
  local content = f:read("*all")
  print(content)
  print('end\n')
end

print('local djot = require("djot")')
print('return djot')
jgm commented 1 year ago

I added a simple example of embedding the lua code in a C program under the clib directory. Next steps: make a proper C library.

jgm commented 1 year ago

Updated to add compilation to wasm/js and a demo of the library running in the browser. We can use this to replace the live playground.

jgm commented 1 year ago

Next step would be to expose functions that allow manipulation of the AST before rendering. This is more complex.

The easiest approach would be to add something like pandoc's Lua filters: the user can pass in a small Lua script that manipulates the AST, and this is run between parsing and rendering. We can do that because we're compiling in the Lua interpreter anyway!