How to use Lua packages in an embedded Lua script

The Nixpkgs-endorsed way to write an executable Lua script is writers.buildLua; this accepts a libraries argument and gives the produced script a shebang to a Lua interpreter that has been wrapped to include the provided libraries in its search path.

This tip is for when you want to write a Lua script for an application that embeds Lua. In that case, wrapping the Lua interpreter is not possible. So how do you use packages from luaPackages in your script?

Here’s a solution I found. In this example, I wanted to add a script to Home Manager’s programs.mpv.scripts that would use luaPackages.ldbus. The Lua package system exposes two variables that it uses to search for packages: package.cpath and package.path. In the general case, both must be updated, and they can be updated from within the Lua script. I found two helper functions in luaPackages.luaLib for formatting the search strings. Here is what I use as the text of my script:

with pkgs.luaPackages; ''
  package.cpath = '${luaLib.genLuaCPathAbsStr ldbus};' .. package.cpath
  package.path = '${luaLib.genLuaPathAbsStr ldbus};' .. package.path

  -- My use case: use ldbus to send a D-Bus message when mpv is in
  -- fullscreen mode to a service I wrote that dims the lights in the
  -- room.
  local ldbus = require 'ldbus'
  local conn = ldbus.bus.get 'session'

  mp.observe_property('fullscreen', 'bool', function (prop, val)
    if val then
      cmd = 'Dim'
    else
      cmd = 'UnDim'
    end
    conn:send(ldbus.message.new_method_call('...', '...', '...', cmd))
  end)
''

(Post better solutions if you know them! I’m only a dabbler in Lua.)

3 Likes

Dabblers posting “here’s what worked for me :person_shrugging:” is awesome. Thank you.