I'm writing a tool to parse lua plugins created by other users. The only guarentee about the plugin is that it has a data.lua file in a known directory. Inside there users are free to do anything they wish. This particular plugin using require to load a file and that file loads another file. Both are relative paths but the second is relative to the location of the first file.
data.lua
foo/bar.lua
foo/baz.lua
data.lua:
require("foo.bar")
foo/bar.lua:
require("baz")
When I try to execute data.lua I get an error when foo/bar.lua tries to require "baz". None of the paths it tries are ./foo/.
Any idea how I can fix this? I could find any documentation specifically about this case, it seemed like I need to hard code /foo/ into the path but I don't know it ahead of time. This seems like something that should be automatic is there a setting I'm missing or am I running the wrong version of lua? I'm using NLua 4.0
Thanks
I tested this script using node-lua and it fixes the issue for me!
https://gist.github.com/hoelzro/1299679
Relavent code:
local oldrequire = require
function require(modname)
local regular_loader = package.loaders[2]
local loader = function(inner)
if string.match(modname, '(.*)%.') then
return regular_loader(string.match(modname, '(.*)%.') .. '.' .. inner)
end
end
table.insert(package.loaders, 1, loader)
local retval = oldrequire(modname)
table.remove(package.loaders, 1)
return retval
end
To get this to work with Lua 5.2 change all uses of package.loaders to package.searchers.
Also if you want to override the global require function you need this snippet as well:
_G.require = require
You can alter the search behavior of require by changing the package.path variable.
Resources on package.path:
https://www.lua.org/manual/5.3/manual.html#pdf-package.path
http://lua-users.org/wiki/PackagePath
Example adding foo folder to search locations:
package.path = package.path .. ';./foo/?.lua'
the ? character will be where the string passed to require is placed.
Alternatively you can add a default file to load, to the package.path:
package.path = package.path .. ';./nested_require.lua'
Then define the behavior you would like within this file. You can use the global variable _REQUIREDNAME to reference the value passed to the require function.
The documentation for this method can be found here at the bottom of the page: https://www.lua.org/pil/8.1.html
Related
I decided to spring-clean and update my nvim config files/plugins, and thought I’d make proper use of the after/plug folder.
While setting up LSP (with mason, mason-lspconfig, and lspconfig), I wanted to move all the lsp language server settings out from after/plugin/lsp/init.lua to their own files (now in after/plugin/lsp/settings).
The problem is I don’t seem to be able to require them into the init.lua file.
Things I’ve tried to no avail:
require(‘after/plugin/lsp/settings/sumneko_lua.lua’)
require(vim.fn.stdpath("config") .. "/after/plugin/lsp/settings/sumneko_lua”)
require(vim.fn.expand('%:h').. ‘/settings/sumneko_lua’)
The attempt using expand works when I resource the file in nvim; but causes an error when starting nvim.
I understand that all the files in after/plugin are automagically sourced at startup. So if I had a file shared.lua:
local M = {}
function M.greet()
vim.notify("Hello!”)
end
return M
in the same folder as after/plugin/lsp/init.lua, how can I get access to the greet() function from init.lua?
Any pointers would be greatly appreciated.
It turned out to be quite a simple solution in the end: I simply updated the paths to be searched in init.lua
-- nvim/init.lua
-- Allow require to look in after/plugin folder
local home_dir = os.getenv("HOME”)
package.path = home_dir .. "/.config/nvim/after/plugin/?.lua;" .. package.path
And then I can require any file inside the after/plugin folder
e.g - require(‘lsp/settings/sumneko’) or require(‘lsp/shared’).greet()
I know this is possible because I have changed it before. I changed it to a custom directory that Lua checks for modules/libraries.
If you don't know what I'm saying, here's what I'm saying: I want to be able to change the directories Lua checks to find the file I'm trying to require.
For some reason, whenever I run require it doesn't check the current directory for the file. I have tried googling how to do it and no answers. The time when I changed this was when I was talking to someone who programmed Love2D and he walked me through the steps, but that conversation is gone and I can't find it.
Any help is appreciated, just let me know! And if you have any questions don't forget to ask!
Thanks!
You refer to the Lua 5.4 Reference Manual:
require
...
First require queries package.preload[modname]. If it has a value,
this value (which must be a function) is the loader. Otherwise require
searches for a Lua loader using the path stored in package.path. If
that also fails, it searches for a C loader using the path stored in
package.cpath. If that also fails, it tries an all-in-one loader (see
package.searchers).
Let's click on package.path
A string with the path used by require to search for a Lua loader.
At start-up, Lua initializes this variable with the value of the
environment variable LUA_PATH_5_4 or the environment variable LUA_PATH
or with a default path defined in luaconf.h, if those environment
variables are not defined. A ";;" in the value of the environment
variable is replaced by the default path.
So either you that string at runtime as you would modify any other string.
Or you change the value of your system variable LUA_PATH_5_4 in case you want to change it system wide.
I think you can figure out the rest yourself.
Just print package.path and have a look at what's inside.
My recommendation is to write a loader for path dependent require.
Because a script that modifies package.path and then loads another script that modifies also package.path ends up with a messy package.path.
A loader function in package.preload['name_of_loader_function'] returns in package.loaded
This is showing by a simple example...
( Shown in console: lua -i )
> package.preload['new_require']=function() return {'New to Lua?'} end
> newtab=require('new_require')
> table.concat(newtab)
New to Lua?
> table.concat(package.loaded.new_require)
New to Lua?
After that you can construct your loader with loadfile() and full path to your lua code.
But this time without extra () than it returns to package.loaded.
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
> package.preload['tprint']=loadfile('/tmp/tprint.lua')
> tprint=require('tprint')
> tprint(os)
Using pairs() for table print out
execute = function: 0x565d8a90
clock = function: 0x565d8b90
time = function: 0x565d8dc0
date = function: 0x565d8f60
remove = function: 0x565d8970
exit = function: 0x565d8a00
rename = function: 0x565d8910
difftime = function: 0x565d8b40
getenv = function: 0x565d89c0
setlocale = function: 0x565d88b0
tmpname = function: 0x565d8bd0
What was happen?
require checks package.preload for a loader for 'tprint'
require found and execute 'tprint' field function in package.preload
package.preload.tprint returning its value to package.loaded.tprint
require returns package.loaded.tprint to global tprint function
tprint is ready for use and typed with table argument prints out table keys/values
This works only if no package.loaded.tprint exists.
Because require() looks first in package.loaded.tprint and if absent in package.preload.tprint.
Ex:
I'm on a folder called 'tuna' and want to require a file that is before 'tuna':
Ex: require "some-file.lua/tuna"
but I don't know how to do it.
You should learn how Lua searches for files when requiring.
package.path is a string that estabilishes where and how it should search for the file you required. It usually looks like this:
"/some/path/?.lua; /some/other/path/?.lua; ?.lua;"
When you call require("module"), Lua takes the first path contained in the string in package.path (the paths are separated by semicolons, so the first path would be /some/path/?.lua), and replaces the ? in the string with the string that was passed to require.
So Lua would first search your module at /some/path/module.lua.
If it finds that file, then it executes it, otherwise it moves on to the next path: it would search at /some/other/path/module.lua, and finally at module.lua.
Now if your directory looks like this:
Outer_dir = {
tuna = {
main.lua,
tuna.lua
},
module.lua
} --didn't know how to represent a tree lol
And, if from main.lua you usually access tuna.lua just typing require("tuna"), then your package.path must be like /Outer_dir/tuna/?.lua. To be sure you can require module.lua, which is "before" tuna.lua, you should either change your package.path string to /Outer_dir/?.lua (this mean you should use require("tuna/tuna") to access tuna.lua) or to/Outer_dir/tuna/?.lua; /Outer_dir/?.luaso that eitherrequire("tuna")andrequire("module")` will work perfectly.
I need to call a LUA function, defined in another my .lua file; from another. So, what I want is the classic C/C++ include approach.
I tried with the following:
(file funcs.lua)
function myfunc(arg1, arg2)
..dosomething
end
and
(file main.lua)
package.path = package.path .. ";/path/to/libs/?.lua"
require "funcs"
myfunc(1, 2)
The require works good, but at execution I get this error:
attempt to call global 'myfunc' (a nil value)
How come?
Thanks in advance,
Thank you all for the comments; I'm running LUA under OpenResty/Nginx.
I solved by exporting directly the function(s), I don't know if this is the preferred method, but I noticed that is used by lots of newer LUA modules.
For example, I changed the code as follows:
file (funcs.lua)
local A = {}
function A.myfunc(arg1, arg2)
..dosomething
end
return A
(file main.lua)
package.path = package.path .. ";/path/to/libs/?.lua"
funcs = require "funcs"
funcs.myfunc(1, 2)
This works good and it's nice to have every function to be manually exported, in a sort of OOP-style.
If I have a file structure like this:
./main.lua
./mylib/mylib.lua
./mylib/mylib-utils.lua
./mylib/mylib-helpers.lua
./mylib/mylib-other-stuff.lua
From main.lua the file mylib.lua can be loaded with full path require('mylib.mylib'). But inside mylib.lua I would also like to load other necessary modules and I don't feel like always specifying the full path (e.g. mylib.mylib-utils). If I ever decide to move the folder I'm going to have a lot of search and replace. Is there a way to use just the relative part of the path?
UPD. I'm using Lua with Corona SDK, if that matters.
There is a way of deducing the "local path" of a file (more concretely, the string that was used to load the file).
If you are requiring a file inside lib.foo.bar, you might be doing something like this:
require 'lib.foo.bar'
Then you can get the path to the file as the first element (and only) ... variable, when you are outside all functions. In other words:
-- lib/foo/bar.lua
local pathOfThisFile = ... -- pathOfThisFile is now 'lib.foo.bar'
Now, to get the "folder" you need to remove the filename. Simplest way is using match:
local folderOfThisFile = (...):match("(.-)[^%.]+$") -- returns 'lib.foo.'
And there you have it. Now you can prepend that string to other file names and use that to require:
require(folderOfThisFile .. 'baz') -- require('lib.foo.baz')
require(folderOfThisFile .. 'bazinga') -- require('lib.foo.bazinga')
If you move bar.lua around, folderOfThisFile will get automatically updated.
You can do
package.path = './mylib/?.lua;' .. package.path
Or
local oldreq = require
local require = function(s) return oldreq('mylib.' .. s) end
Then
-- do all the requires
require('mylib-utils')
require('mylib-helpers')
require('mylib-other-stuff')
-- and optionally restore the old require, if you did it the second way
require = oldreq
I'm using the following snippet. It should work both for files loaded with require, and for files called via the command line. Then use requireRel instead of require for those you wish to be loaded with a relative path.
local requireRel
if arg and arg[0] then
package.path = arg[0]:match("(.-)[^\\/]+$") .. "?.lua;" .. package.path
requireRel = require
elseif ... then
local d = (...):match("(.-)[^%.]+$")
function requireRel(module) return require(d .. module) end
end
Under the Conky's Lua environment I've managed to include my common.lua (in the same directory) as require(".common"). Note the leading dot . character.
Try this:Here is my findings:
module1= require(".\\moduleName")
module2= dofile("..\\moduleName2.lua")
module3 =loadfile("..\\module3.lua")
To load from current directory. Append a double backslash with a prefix of a fullstop.
To specify a directory above use a prefix of two fullstops and repeat this pattern for any such directory.e.g
module4=require("..\\..\\module4")