NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lua.c File Reference

Integrated Lua scripting. More...

#include "config.h"
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "parse/lib.h"
#include "muttlib.h"
#include "version.h"
+ Include dependency graph for lua.c:

Go to the source code of this file.

Macros

#define LUA_COMPAT_ALL
 
#define LUA_COMPAT_5_1
 

Functions

static int lua_handle_panic (lua_State *l)
 Handle a panic in the Lua interpreter.
 
static int lua_handle_error (lua_State *l)
 Handle an error in the Lua interpreter.
 
static int lua_cb_global_call (lua_State *l)
 Call a NeoMutt command by name.
 
static int lua_cb_global_set (lua_State *l)
 Set a NeoMutt variable.
 
static int lua_cb_global_get (lua_State *l)
 Get a NeoMutt variable.
 
static int lua_cb_global_enter (lua_State *l)
 Execute NeoMutt config from Lua.
 
static int lua_cb_global_message (lua_State *l)
 Display a message in NeoMutt.
 
static int lua_cb_global_error (lua_State *l)
 Display an error in NeoMutt.
 
static void lua_expose_command (lua_State *l, const struct Command *cmd)
 Expose a NeoMutt command to the Lua interpreter.
 
static int lua_expose_commands (lua_State *l)
 Declare some NeoMutt types to the Lua interpreter.
 
static void lua_expose_mutt (lua_State *l)
 Expose a 'Mutt' object to the Lua interpreter.
 
bool lua_init_state (lua_State **l)
 Initialise a Lua State.
 

Variables

lua_State * LuaState = NULL
 Global Lua State.
 
static const luaL_Reg LuaMuttCommands []
 List of Lua commands to register.
 

Detailed Description

Integrated Lua scripting.

Authors
  • Bernard Pratz
  • Richard Russon
  • Victor Fernandes
  • Ian Zimmerman
  • Pietro Cerutti
  • Rayford Shireman

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file lua.c.

Macro Definition Documentation

◆ LUA_COMPAT_ALL

#define LUA_COMPAT_ALL

Definition at line 35 of file lua.c.

◆ LUA_COMPAT_5_1

#define LUA_COMPAT_5_1

Definition at line 38 of file lua.c.

Function Documentation

◆ lua_handle_panic()

static int lua_handle_panic ( lua_State * l)
static

Handle a panic in the Lua interpreter.

Parameters
lLua State
Return values
-1Always

Definition at line 63 of file lua.c.

64{
65 mutt_debug(LL_DEBUG1, "lua runtime panic: %s\n", lua_tostring(l, -1));
66 mutt_error("Lua runtime panic: %s", lua_tostring(l, -1));
67 lua_pop(l, 1);
68 return -1;
69}
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
+ Here is the caller graph for this function:

◆ lua_handle_error()

static int lua_handle_error ( lua_State * l)
static

Handle an error in the Lua interpreter.

Parameters
lLua State
Return values
-1Always

Definition at line 76 of file lua.c.

77{
78 mutt_debug(LL_DEBUG1, "lua runtime error: %s\n", lua_tostring(l, -1));
79 mutt_error("Lua runtime error: %s", lua_tostring(l, -1));
80 lua_pop(l, 1);
81 return -1;
82}
+ Here is the caller graph for this function:

◆ lua_cb_global_call()

static int lua_cb_global_call ( lua_State * l)
static

Call a NeoMutt command by name.

Parameters
lLua State
Return values
>=0Success
-1Error

Definition at line 90 of file lua.c.

91{
92 mutt_debug(LL_DEBUG2, "enter\n");
93 struct Buffer *buf = buf_pool_get();
94 struct ParseContext *pc = parse_context_new();
95 struct ParseError *pe = parse_error_new();
96 const struct Command *cmd = NULL;
97 int rc = 0;
98
99 if (lua_gettop(l) == 0)
100 {
101 buf_pool_release(&buf);
103 parse_error_free(&pe);
104 luaL_error(l, "Error command argument required");
105 return -1;
106 }
107
108 cmd = commands_get(&NeoMutt->commands, lua_tostring(l, 1));
109 if (!cmd)
110 {
111 buf_pool_release(&buf);
113 parse_error_free(&pe);
114 luaL_error(l, "Error command %s not found", lua_tostring(l, 1));
115 return -1;
116 }
117
118 for (int i = 2; i <= lua_gettop(l); i++)
119 {
120 buf_addstr(buf, lua_tostring(l, i));
121 buf_addch(buf, ' ');
122 }
123 buf_seek(buf, 0);
124
125 if (cmd->parse(cmd, buf, pc, pe))
126 {
127 luaL_error(l, "NeoMutt error: %s", buf_string(pe->message));
128 rc = -1;
129 }
130 else
131 {
132 if (!lua_pushstring(l, buf_string(pe->message)))
134 else
135 rc++;
136 }
137
138 buf_pool_release(&buf);
140 parse_error_free(&pe);
141 return rc;
142}
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition buffer.c:622
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const struct Command * commands_get(struct CommandArray *ca, const char *name)
Get a Command by its name.
Definition command.c:82
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
static int lua_handle_error(lua_State *l)
Handle an error in the Lua interpreter.
Definition lua.c:76
void parse_context_free(struct ParseContext **pptr)
Free a ParseContext.
Definition pcontext.c:48
struct ParseContext * parse_context_new(void)
Create a new ParseContext.
Definition pcontext.c:37
void parse_error_free(struct ParseError **pptr)
Free a ParseError.
Definition perror.c:50
struct ParseError * parse_error_new(void)
Create a new ParseError.
Definition perror.c:37
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
String manipulation buffer.
Definition buffer.h:36
enum CommandResult(* parse)(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Definition command.h:178
Container for Accounts, Notifications.
Definition neomutt.h:41
struct CommandArray commands
NeoMutt commands.
Definition neomutt.h:53
Context for config parsing (history/backtrace)
Definition pcontext.h:34
Detailed error information from config parsing.
Definition perror.h:34
struct Buffer * message
Error message.
Definition perror.h:35
+ Here is the call graph for this function:

◆ lua_cb_global_set()

static int lua_cb_global_set ( lua_State * l)
static

Set a NeoMutt variable.

Parameters
lLua State
Return values
0Success
-1Error

Definition at line 150 of file lua.c.

151{
152 const char *param = lua_tostring(l, -2);
153 mutt_debug(LL_DEBUG2, "%s\n", param);
154
155 struct Buffer *err = buf_pool_get();
156 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, param);
157 if (!he)
158 {
159 // In case it is a my_var, we have to create it
160 if (mutt_str_startswith(param, "my_"))
161 {
162 struct ConfigDef my_cdef = { 0 };
163 my_cdef.name = param;
164 my_cdef.type = DT_MYVAR;
165 he = cs_create_variable(NeoMutt->sub->cs, &my_cdef, err);
166 if (!he)
167 return -1;
168 }
169 else
170 {
171 luaL_error(l, "NeoMutt parameter not found %s", param);
172 return -1;
173 }
174 }
175
176 struct ConfigDef *cdef = he->data;
177
178 int rc = 0;
179
180 switch (CONFIG_TYPE(cdef->type))
181 {
182 case DT_ADDRESS:
183 case DT_ENUM:
184 case DT_EXPANDO:
185 case DT_MBTABLE:
186 case DT_MYVAR:
187 case DT_PATH:
188 case DT_REGEX:
189 case DT_SLIST:
190 case DT_SORT:
191 case DT_STRING:
192 {
193 const char *value = lua_tostring(l, -1);
194 size_t val_size = lua_rawlen(l, -1);
195 struct Buffer *value_buf = buf_pool_get();
196 buf_strcpy_n(value_buf, value, val_size);
197 if (CONFIG_TYPE(he->type) == DT_PATH)
198 expand_path(value_buf, false);
199
200 int rv = cs_subset_he_string_set(NeoMutt->sub, he, buf_string(value_buf), err);
201 buf_pool_release(&value_buf);
202 if (CSR_RESULT(rv) != CSR_SUCCESS)
203 rc = -1;
204 break;
205 }
206 case DT_LONG:
207 case DT_NUMBER:
208 case DT_QUAD:
209 {
210 const intptr_t value = lua_tointeger(l, -1);
211 int rv = cs_subset_he_native_set(NeoMutt->sub, he, value, err);
212 if (CSR_RESULT(rv) != CSR_SUCCESS)
213 rc = -1;
214 break;
215 }
216 case DT_BOOL:
217 {
218 const intptr_t value = lua_toboolean(l, -1);
219 int rv = cs_subset_he_native_set(NeoMutt->sub, he, value, err);
220 if (CSR_RESULT(rv) != CSR_SUCCESS)
221 rc = -1;
222 break;
223 }
224 default:
225 luaL_error(l, "Unsupported NeoMutt parameter type %d for %s",
226 CONFIG_TYPE(cdef->type), param);
227 rc = -1;
228 break;
229 }
230
231 buf_pool_release(&err);
232 return rc;
233}
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition buffer.c:416
struct HashElem * cs_create_variable(const struct ConfigSet *cs, struct ConfigDef *cdef, struct Buffer *err)
Create and register one config item.
Definition set.c:327
#define CSR_RESULT(x)
Extract the result code from CSR_* flags.
Definition set.h:53
#define CSR_SUCCESS
Action completed successfully.
Definition set.h:33
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
const char * name
User-visible name.
Definition set.h:66
uint32_t type
Variable type, e.g. DT_STRING.
Definition set.h:67
struct ConfigSet * cs
Parent ConfigSet.
Definition subset.h:50
The item stored in a Hash Table.
Definition hash.h:44
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition hash.h:45
void * data
User-supplied data.
Definition hash.h:47
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
int cs_subset_he_native_set(const struct ConfigSubset *sub, struct HashElem *he, intptr_t value, struct Buffer *err)
Natively set the value of a HashElem config item.
Definition subset.c:281
int cs_subset_he_string_set(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Set a config item by string.
Definition subset.c:370
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition subset.c:193
#define CONFIG_TYPE(t)
Extract the type from the flags.
Definition types.h:50
@ DT_NUMBER
a number
Definition types.h:38
@ DT_SLIST
a list of strings
Definition types.h:42
@ DT_BOOL
boolean option
Definition types.h:32
@ DT_QUAD
quad-option (no/yes/ask-no/ask-yes)
Definition types.h:40
@ DT_STRING
a string
Definition types.h:44
@ DT_SORT
sorting methods
Definition types.h:43
@ DT_MYVAR
a user-defined variable (my_foo)
Definition types.h:37
@ DT_MBTABLE
multibyte char table
Definition types.h:36
@ DT_ADDRESS
e-mail address
Definition types.h:31
@ DT_LONG
a number (long)
Definition types.h:35
@ DT_EXPANDO
an expando
Definition types.h:34
@ DT_ENUM
an enumeration
Definition types.h:33
@ DT_REGEX
regular expressions
Definition types.h:41
@ DT_PATH
a path to a file/directory
Definition types.h:39
+ Here is the call graph for this function:

◆ lua_cb_global_get()

static int lua_cb_global_get ( lua_State * l)
static

Get a NeoMutt variable.

Parameters
lLua State
Return values
1Success
-1Error

Definition at line 241 of file lua.c.

242{
243 const char *param = lua_tostring(l, -1);
244 mutt_debug(LL_DEBUG2, "%s\n", param);
245
246 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, param);
247 if (!he)
248 {
249 mutt_debug(LL_DEBUG2, "error\n");
250 luaL_error(l, "NeoMutt parameter not found %s", param);
251 return -1;
252 }
253
254 struct ConfigDef *cdef = he->data;
255
256 switch (CONFIG_TYPE(cdef->type))
257 {
258 case DT_ADDRESS:
259 case DT_ENUM:
260 case DT_EXPANDO:
261 case DT_MBTABLE:
262 case DT_MYVAR:
263 case DT_PATH:
264 case DT_REGEX:
265 case DT_SLIST:
266 case DT_SORT:
267 case DT_STRING:
268 {
269 struct Buffer *value = buf_pool_get();
270 int rc = cs_subset_he_string_get(NeoMutt->sub, he, value);
271 if (CSR_RESULT(rc) != CSR_SUCCESS)
272 {
273 buf_pool_release(&value);
274 return -1;
275 }
276
277 struct Buffer *escaped = buf_pool_get();
278 escape_string(escaped, buf_string(value));
279 lua_pushstring(l, buf_string(escaped));
280 buf_pool_release(&value);
281 buf_pool_release(&escaped);
282 return 1;
283 }
284 case DT_QUAD:
285 lua_pushinteger(l, (unsigned char) cdef->var);
286 return 1;
287 case DT_LONG:
288 lua_pushinteger(l, (signed long) cdef->var);
289 return 1;
290 case DT_NUMBER:
291 lua_pushinteger(l, (signed short) cdef->var);
292 return 1;
293 case DT_BOOL:
294 lua_pushboolean(l, (bool) cdef->var);
295 return 1;
296 default:
297 luaL_error(l, "NeoMutt parameter type %d unknown for %s", cdef->type, param);
298 return -1;
299 }
300}
size_t escape_string(struct Buffer *buf, const char *src)
Write a string to a buffer, escaping special characters.
Definition dump.c:47
intptr_t var
Storage for the variable.
Definition set.h:85
int cs_subset_he_string_get(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *result)
Get a config item as a string.
Definition subset.c:338
+ Here is the call graph for this function:

◆ lua_cb_global_enter()

static int lua_cb_global_enter ( lua_State * l)
static

Execute NeoMutt config from Lua.

Parameters
lLua State
Return values
>=0Success
-1Error

Definition at line 308 of file lua.c.

309{
310 mutt_debug(LL_DEBUG2, "enter\n");
311 struct Buffer *line = buf_pool_get();
312 struct ParseContext *pc = parse_context_new();
313 struct ParseError *pe = parse_error_new();
314
315 buf_strcpy(line, lua_tostring(l, -1));
316 int rc = 0;
317
318 if (parse_rc_line(line, pc, pe))
319 {
320 luaL_error(l, "NeoMutt error: %s", buf_string(pe->message));
321 rc = -1;
322 }
323 else
324 {
325 if (!lua_pushstring(l, buf_string(pe->message)))
327 else
328 rc++;
329 }
330
331 buf_pool_release(&line);
333 parse_error_free(&pe);
334
335 return rc;
336}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
enum CommandResult parse_rc_line(struct Buffer *line, struct ParseContext *pc, struct ParseError *pe)
Parse a line of user config.
Definition rc.c:45
+ Here is the call graph for this function:

◆ lua_cb_global_message()

static int lua_cb_global_message ( lua_State * l)
static

Display a message in NeoMutt.

Parameters
lLua State
Return values
0Always

Definition at line 343 of file lua.c.

344{
345 mutt_debug(LL_DEBUG2, "enter\n");
346 const char *msg = lua_tostring(l, -1);
347 if (msg)
348 mutt_message("%s", msg);
349 return 0;
350}
#define mutt_message(...)
Definition logging2.h:93

◆ lua_cb_global_error()

static int lua_cb_global_error ( lua_State * l)
static

Display an error in NeoMutt.

Parameters
lLua State
Return values
0Always

Definition at line 357 of file lua.c.

358{
359 mutt_debug(LL_DEBUG2, "enter\n");
360 const char *msg = lua_tostring(l, -1);
361 if (msg)
362 mutt_error("%s", msg);
363 return 0;
364}

◆ lua_expose_command()

static void lua_expose_command ( lua_State * l,
const struct Command * cmd )
static

Expose a NeoMutt command to the Lua interpreter.

Parameters
lLua state
cmdNeoMutt Command

Definition at line 371 of file lua.c.

372{
373 char buf[1024] = { 0 };
374 snprintf(buf, sizeof(buf), "mutt.command.%s = function (...); mutt.call('%s', ...); end",
375 cmd->name, cmd->name);
376 (void) luaL_dostring(l, buf);
377}
const char * name
Name of the Command.
Definition command.h:159
+ Here is the caller graph for this function:

◆ lua_expose_commands()

static int lua_expose_commands ( lua_State * l)
static

Declare some NeoMutt types to the Lua interpreter.

Parameters
lLua State
Return values
1Always

Definition at line 406 of file lua.c.

407{
408 mutt_debug(LL_DEBUG2, "enter\n");
409 luaL_newlib(l, LuaMuttCommands);
410 int lib_idx = lua_gettop(l);
411
412 // clang-format off
413 lua_pushstring(l, "VERSION"); lua_pushstring(l, mutt_make_version()); lua_settable(l, lib_idx);
414 lua_pushstring(l, "QUAD_YES"); lua_pushinteger(l, MUTT_YES); lua_settable(l, lib_idx);
415 lua_pushstring(l, "QUAD_NO"); lua_pushinteger(l, MUTT_NO); lua_settable(l, lib_idx);
416 lua_pushstring(l, "QUAD_ASKYES"); lua_pushinteger(l, MUTT_ASKYES); lua_settable(l, lib_idx);
417 lua_pushstring(l, "QUAD_ASKNO"); lua_pushinteger(l, MUTT_ASKNO); lua_settable(l, lib_idx);
418 // clang-format on
419
420 return 1;
421}
static const luaL_Reg LuaMuttCommands[]
List of Lua commands to register.
Definition lua.c:388
@ MUTT_ASKNO
Ask the user, defaulting to 'No'.
Definition quad.h:40
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_ASKYES
Ask the user, defaulting to 'Yes'.
Definition quad.h:41
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition version.c:293
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ lua_expose_mutt()

static void lua_expose_mutt ( lua_State * l)
static

Expose a 'Mutt' object to the Lua interpreter.

Parameters
lLua State

Definition at line 427 of file lua.c.

428{
429 luaL_requiref(l, "mutt", lua_expose_commands, 1);
430 (void) luaL_dostring(l, "mutt.command = {}");
431
432 const struct Command **cp = NULL;
434 {
435 const struct Command *cmd = *cp;
436
437 lua_expose_command(l, cmd);
438 }
439}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
static int lua_expose_commands(lua_State *l)
Declare some NeoMutt types to the Lua interpreter.
Definition lua.c:406
static void lua_expose_command(lua_State *l, const struct Command *cmd)
Expose a NeoMutt command to the Lua interpreter.
Definition lua.c:371
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ lua_init_state()

bool lua_init_state ( lua_State ** l)

Initialise a Lua State.

Parameters
[out]lLua State
Return values
trueSuccessful

Definition at line 446 of file lua.c.

447{
448 if (!l)
449 return false;
450 if (*l)
451 return true;
452
453 mutt_debug(LL_DEBUG2, "enter\n");
454 *l = luaL_newstate();
455
456 if (!*l)
457 {
458 mutt_error(_("Error: Couldn't load the lua interpreter"));
459 return false;
460 }
461
462 lua_atpanic(*l, lua_handle_panic);
463
464 /* load various Lua libraries */
465 luaL_openlibs(*l);
466 lua_expose_mutt(*l);
467
468 return true;
469}
static void lua_expose_mutt(lua_State *l)
Expose a 'Mutt' object to the Lua interpreter.
Definition lua.c:427
static int lua_handle_panic(lua_State *l)
Handle a panic in the Lua interpreter.
Definition lua.c:63
#define _(a)
Definition message.h:28
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ LuaState

lua_State* LuaState = NULL

Global Lua State.

Definition at line 56 of file lua.c.

◆ LuaMuttCommands

const luaL_Reg LuaMuttCommands[]
static
Initial value:
= {
{ "set", lua_cb_global_set },
{ "get", lua_cb_global_get },
{ "call", lua_cb_global_call },
{ "enter", lua_cb_global_enter },
{ "print", lua_cb_global_message },
{ "message", lua_cb_global_message },
{ "error", lua_cb_global_error },
{ NULL, NULL },
}
static int lua_cb_global_set(lua_State *l)
Set a NeoMutt variable.
Definition lua.c:150
static int lua_cb_global_message(lua_State *l)
Display a message in NeoMutt.
Definition lua.c:343
static int lua_cb_global_error(lua_State *l)
Display an error in NeoMutt.
Definition lua.c:357
static int lua_cb_global_enter(lua_State *l)
Execute NeoMutt config from Lua.
Definition lua.c:308
static int lua_cb_global_get(lua_State *l)
Get a NeoMutt variable.
Definition lua.c:241
static int lua_cb_global_call(lua_State *l)
Call a NeoMutt command by name.
Definition lua.c:90

List of Lua commands to register.

In NeoMutt, run:

‘:lua mutt.message('hello’)`

and it will call lua_cb_global_message()

Definition at line 388 of file lua.c.

388 {
389 // clang-format off
390 { "set", lua_cb_global_set },
391 { "get", lua_cb_global_get },
392 { "call", lua_cb_global_call },
393 { "enter", lua_cb_global_enter },
394 { "print", lua_cb_global_message },
395 { "message", lua_cb_global_message },
396 { "error", lua_cb_global_error },
397 { NULL, NULL },
398 // clang-format on
399};