Lua: Regex and Lua Patterns - lua

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.

Related

Sourcing nvim.init does not source required Lua files

I have neovim 0.7.0 running and my .vimrc is at ~/.config/nvim/init.vim
I also have the following file: ~/.config/nvim/lua/statusline.lua with one line of code:
print('message from statusline.lua')
Inside init.vim I have:
echo 'from init.vim'
lua require('statusline')
When I start nvim I get both messages printed out ('from init.vim' and 'message from statusline.lua') which is what I would expect.
When I run :source $MYVIMRC I only see 'from init.vim'. I would expect the other message ('message from statusline.lua') to appear as well.
I assume this means any changes I make in statusline.lua will not take effect when I run :source $MYVIMRC. How should I source my init.vim file plus any files it requires without closing and restarting neovim?
Either invalidate cache entry by appending return false to the end of a module.
Or don't use require at all, as you need neither cache nor path search anyway. E.g.
for k, v in ipairs(vim.fn.glob("~/.config/nvim/init.d/*.lua", false, true)) do
dofile(v)
end
P.S. Lua is not a "config tool". It is a full-featured programming language. If you don't like wasting your time by learning it properly (i.e. reading books and tutorials) you're highly suggested to use VimScript instead. It has some "dark corners" of its own but it is much better suited for writing config.
It depends on the design of your statusline.lua and knowledge about Lua' module loader system.
It looks, because i have to riddle about statusline.lua, that it nothing returns.
Because the return is going into package.loaded and same require in same session looks first there for statusline
So give following a try...
-- statusline.lua
print('message from statusline.lua')
return 'message from package.loaded.statusline'
I have tested above with...
$ lua -i
Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio
> require('statusline')
message from statusline.lua
message from package.loaded.statusline ./lua/statusline.lua
> require('statusline')
message from package.loaded.statusline
> require('statusline')
message from package.loaded.statusline
EDIT
Another design for doing something usefull...
-- ~.config/nvim/init.vim
lua print("init.vim")
lua dump = require("dump")
And...
-- ~/.config/nvim/lua/dump.lua
local dump = function(tab)
for key, value in pairs(tab) do
print(key, '=>', value)
end
end
return dump
Than you have a table viewer and you can see where the functions and tables come from with...
:lua dump(_G) -- The global environment table
:lua dump(vim) -- The nvim stuff (aka Module)
:lua dump(vim.api) -- The nvim API functions (aka Library)
:lua dump(jit) -- The Just In Time Compiler ;-)
:lua dump([Table Name]) -- Any table that looks interesting
:lua dump(package.loaded) -- The required or requireable stuff
Above function can be executed without defining dump first with: :lua require('dump')(_G)
So: First require loads dump.lua into package.loaded.dump and returning it and every further require returning: package.loaded.dump
If you have an sharp eye than take a look on _G.dump thats only a reference (pointer/link) to package.loaded.dump.
EDIT2
Preparing dump.lua for using it with vim.api.nvim_input()
-- ~/.config/nvim/lua/dump.lua
local dump = function(tab)
local tmp = ''
for key, value in pairs(tab) do
tmp = tmp .. ('%s %s %s\n'):format(key, '=>', value)
end
return tmp
end
return dump
Now the dump function returning a string and the output can be loaded into nvim with: :lua vim.api.nvim_input('i') vim.api.nvim_input(dump(vim.api))
Since many nvim API functions returning a table the dump function becomes handy with...

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.

How to include config file for variables in 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.

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