How to include config file for variables in Lua - lua

In my lua script there are some variables I would like to put in a 'settings.conf' file so I can easily change variables without diving into the code.
In other languages they use 'include', but in Lua it seems different because it loads a module. I only need to load a config file for some parameters.
Which command should I use for this?

The simplest way to execute a Lua script from another script is to use dofile, which takes a path to a file:
dofile"myconfig.lua"
dofile "/usr/share/myapp/config.lua"
The problem with dofile is that it can raise an error and abort the calling script. If you want to handle errors, such as the file not existing, syntax or execution errors, then use pcall:
local ok,e = pcall(dofile,"myconfig.lua")
if not ok then
-- handle error; e has the error message
end
If you want finer control, then use loadfile followed by a function call:
local f,e = loadfile("myconfig.lua")
if f==nil then
-- handle error; e has the error message
end
local ok,e = pcall(f)
if not ok then
-- handle error; e has the error message
end

You can do something like this:
config.lua:
myconf = {
param1 = "qwe";
param2 = 7;
}
main program:
package.path = '*.lua;' .. package.path
require "config"
print("config param1 = " .. myconf.param1 .. "\n")
this works well in most cases.

Related

How can I reload my Neovim config written in lua with a shortcut?

I want to reload my neovim configuration files with just a couple of keystrokes instead of having to restart the app. I was able to do this when using an init.vim with the following command:
nnoremap <leader>sv <cmd>source $MYVIMRC<CR>
$MYVIMRC points correctly to my config entry point.
The problem is that I switched to using lua, and now I can't do the same. I have read the docs and tried variants of the following without success:
util.nnoremap("<leader>sv", "<cmd>luafile $MYVIMRC<CR>")
Finally, I found a solution doing this:
function load(name)
local path = vim.fn.stdpath('config') .. '/lua/' .. name .. '.lua'
dofile(path)
end
load('plugins')
load('config/mapping')
load('lsp/init')
Which is buggy and feels wrong.
Is there any way to do this? I read the example in vimpeccable, but I want to see the other available options since I would rather not install another plugin.
I know that plenary includes a function to reload modules, but I don't understand how to use it. A complete example of that would be good too since I already use plenary in my config.
I am a new Neovim user, so I guess my solution may not work for some edge cases.
This function flushes the module of current buffer:
local cfg = vim.fn.stdpath('config')
Flush = function()
local s = vim.api.nvim_buf_get_name(0)
if string.match(s, '^' .. cfg .. '*') == nil then
return
end
s = string.sub(s, 6 + string.len(cfg), -5)
local val = string.gsub(s, '%/', '.')
package.loaded[val] = nil
end
You can call it whenever you write to a buffer with this autocommand:
autocmd BufWrite *.lua,*vim call v:lua.Flush()
This way, after you execute :source $MYVIMRC it will also reload changed Lua modules.

Lua: Regex and Lua Patterns

local code = [[
client_script 'Bait.lua'
client_script 'Test.lua' --Test
]]
how am I gonna make a regex/pattern that takes everything that's between client_script ' and ' --Test
code seems to be Lua code and thus any pattern-based solution will fail if an equivalent but different piece of code is used instead (" instead of ', parentheses, line breaks, multi-line comments etc.). Why not parse it as Lua?
local code = [[
client_script 'Bait.lua'
client_script 'Test.lua' --Test
]]
local scripts = {}
local newenv = {
client_script = function(name)
table.insert(scripts, name)
end
}
load("local _ENV=...;"..code)(newenv)
for i, v in ipairs(scripts) do
print(v)
end
This parses and loads the code, but uses newenv as the environment with a different definition of client_script that stores the value. Note that FiveM also uses client_scripts and a couple of other functions that will have to be present (but most of them can be simply specified as function()end).
Also the code above works only for Lua 5.2 and higher. The difference for Lua 5.1 is the line with load, which has to be changed to this:
setfenv(loadstring(code), newenv)()
The reason is that load and loadstring got merged in 5.2, and accessing the environment is only defined in terms of accessing the _ENV variable, so there is no specific environment attached to a function anymore.

Lua one-liner to read entire file?

Is there a trick to slurp a file with just one line of code?
("to slup" = to read entire file into a string.)
Usually I do the following:
local f = io.open("/path/to/file")
local s = f:read("*a")
f:close()
But I wonder if there's a shorter way.
I know that we can do (in Lua 5.2) the following:
local s = io.lines("/path/to/file", "*a")()
But the file would stay open for a while until the garbage collector kicks in (and gets rid of the closure io.lines returns; I believe this closure knows to explicitly close the file, but this could happen only after the second invocation of it, when it knows EOF has been reached).
So, is there a one-line solution I'm missing?
There is no such function in the standard library, but you can just define it yourself:
local function slurp(path)
local f = io.open(path)
local s = f:read("*a")
f:close()
return s
end
Alternatively there is such a function in Penlight.

Cannot import module with Lua, results in attempt to index global 'test' (a nil value)

Without success I have attempted to import my own Lua files into other scripts using the require keyword but whenever I attempt to call any functions contained within the imported module (e.g. "test.lua") I reach the subsequent error:
require 'test'
test.method(args)
==> yields error:
==> Attempt to index global 'test' (a nil value)
I've added the file to the package.path in case this was the issue, but again there was no beginning error indicating that it cannot find the file in Lua's pathway.
package.path = package.path .. ";/path/to/test.lua"
require 'test'
test.method(args)
==> yields error:
==> Attempt to index global 'test' (a nil value)
I'm running an interactive Lua shell from the directory where the file is. When attempting to print the local variable name, e.g. local test = require "test" the value is nil.
package.path = package.path .. ";/path/to/test.lua"
local test = require 'test'
print(test)
==> nil
Thoughts? (Note: I also required the file in general without assigning it to a local variable and printed its values again with nil as the returned value.)
To expand on lhf's answer:
The Lua shell reads one statement at a time. It then loads the code string with the loadstring function (or more accurately, the C API equivalent), which compiles the Lua code and returns a function that executes it. Since each statement is loaded separately, and produces a different function, they don't share local variables.
Essentially, this console input:
local test = require "test"
print(test)
if test then
bar()
end
Is translated to this:
(function() local test = require "test" end)()
(function() print(test) end)()
(function()
if test then
bar()
end
end)()
(Note that this applies to files as well. Lua 'files' are actually just functions with an implicit function(...) signature. This means you can return from the top-level of a file, as well as perform any operations you can do on functions (sandboxing, etc) on files as well.)
If you're copying code from somewhere, you can surround the code in do ... end, like so:
do
local test = require "test"
print(test)
end
The do ... end block counts as one statement, and scopes local variables.
In the interactive Lua shell, each complete statement is executed as read. Local variables do not survive from one statement to the other.

Getting return status AND program output

I need to use Lua to run a binary program that may write something in its stdout and also returns a status code (also known as "exit status").
I searched the web and couldn't find something that does what I need. However I found out that in Lua:
os.execute() returns the status code
io.popen() returns a file handler that can be used to read process output
However I need both. Writing a wrapper function that runs both functions behind the scene is not an option because of process overhead and possibly changes in result on consecutive runs. I need to write a function like this:
function run(binpath)
...
return output,exitcode
end
Does anyone has an idea how this problem can be solved?
PS. the target system rung Linux.
With Lua 5.2 I can do the following and it works
-- This will open the file
local file = io.popen('dmesg')
-- This will read all of the output, as always
local output = file:read('*all')
-- This will get a table with some return stuff
-- rc[1] will be true, false or nil
-- rc[3] will be the signal
local rc = {file:close()}
I hope this helps!
I can't use Lua 5.2, I use this helper function.
function execute_command(command)
local tmpfile = '/tmp/lua_execute_tmp_file'
local exit = os.execute(command .. ' > ' .. tmpfile .. ' 2> ' .. tmpfile .. '.err')
local stdout_file = io.open(tmpfile)
local stdout = stdout_file:read("*all")
local stderr_file = io.open(tmpfile .. '.err')
local stderr = stderr_file:read("*all")
stdout_file:close()
stderr_file:close()
return exit, stdout, stderr
end
This is how I do it.
local process = io.popen('command; echo $?') -- echo return code of last run command
local lastline
for line in process:lines() do
lastline = line
end
print(lastline) -- the return code is the last line of output
If the last line has fixed length you can read it directly using file:seek("end", -offset), offset should be the length of the last line in bytes.
This functionality is provided in C by pclose.
Upon successful return, pclose() shall return the termination status
of the command language interpreter.
The interpreter returns the termination status of its child.
But Lua doesn't do this right (io.close always returns true). I haven't dug into these threads but some people are complaining about this brain damage.
http://lua-users.org/lists/lua-l/2004-05/msg00005.html
http://lua-users.org/lists/lua-l/2011-02/msg00387.html
If you're running this code on Win32 or in a POSIX environment, you could try this Lua extension: http://code.google.com/p/lua-ex-api/
Alternatively, you could write a small shell script (assuming bash or similar is available) that:
executes the correct executable, capturing the exit code into a shell variable,
prints a newline and terminal character/string onto standard out
prints the shell variables value (the exit code) onto standard out
Then, capture all the output of io.popen and parse backward.
Full disclosure: I'm not a Lua developer.
yes , your are right that os.execute() has returns and it's very simple if you understand how to run your command with and with out lua
you also may want to know how many variables it returns , and it might take a while , but i think you can try
local a, b, c, d, e=os.execute(-what ever your command is-)
for my example a is an first returned argument , b is the second returned argument , and etc.. i think i answered your question right, based off of what you are asking.

Resources