--- a/TODO Mon Mar 16 06:12:55 2009 +0200
+++ b/TODO Mon Mar 16 18:54:16 2009 +0200
@@ -2,7 +2,7 @@
print should allow other types to be printed
finish roster list information
non-setting settings?
-mcabber_config_file uses option to set dir? eliminate main.config_file, use modules_dir option instead in lua paths?
+mcabber_config_file use option to set dir?
do uninitialization of commands and features with objects?
help system accessors (needs major rewrite and planning)
object access to roster and buddies?
@@ -13,4 +13,7 @@
think about how tune notification should act on start/quit
clarify situation with disco, maybe it is due to this we are unable to receive pep events
lm debug should be more flexible
+common pubsub infrastructure, in particular, xmlns-based event handlers?
+forms abandoning hook to inform server
+eliminate main.parse_args?
--- a/examples/beep.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/beep.lua Mon Mar 16 18:54:16 2009 +0200
@@ -15,7 +15,7 @@
hooks_d['hook-message-in'].beep = nil
print ( "Beep on message is disabled" )
end
- end, 'yesno' )
+ end, false, 'yesno' )
commands_help['beep'] = "[enable|disable|on|off|yes|no|true|false]\n\nEnables or disables beeping on all messages.\nIf state is omitted, prints current state."
--- a/examples/jobs.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/jobs.lua Mon Mar 16 18:54:16 2009 +0200
@@ -27,7 +27,6 @@
main.command ( 'delay',
function ( args )
- args = main.parse_args ( args )
local who
if args.t then
who = args.t
@@ -38,11 +37,10 @@
local mess = args[2]
delayed_jobs[who] = { }
delayed_jobs[who][stat] = 'say_to -q ' .. who .. ' ' .. mess
- end )
+ end, true )
main.command ( 'job',
function ( args )
- args = main.parse_args ( args )
local action, jid, stat = args[1], args[2], args[3]
if action == 'del' then
delayed_jobs[jid][stat] = nil
@@ -59,7 +57,7 @@
print ( 'No jobs' )
end
end
- end, { "del" } )
+ end, true, { "del" } )
commands_help['delay'] = "[-t target_jid] status_letter message\n\nDelays sending a message to target jid (or current buddy) until it switches to specified status."
commands_help['job'] = "[del jid status_letter]\n\nLists available jobs or deletes specified one."
--- a/examples/marking.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/marking.lua Mon Mar 16 18:54:16 2009 +0200
@@ -44,11 +44,11 @@
main.command ( 'marked',
function ( args )
- local cmd = args:match ( "^%s*(%w+)" )
+ local cmd = args[1]
if cmd == 'clear' then
marked_clear ()
elseif cmd == 'do' then
- local command = args:match ( "^%s*%w+%s+(.+)" )
+ local command = args[2]
foreach_marked (
function ( jid )
main.run ( string.format ( command, jid ) )
@@ -60,17 +60,23 @@
print ( ' - ' .. jid )
end )
end
- end, { 'clear', 'do' } )
+ end, true, { 'clear', 'do' } )
commands_help['marked'] = "[clear | do mcabber_command]\n\nOperates on marked buddies. Without arguments prints list of marked jids.\nCommand should contain %s in place, where jid should be inserted."
+mark_ins_bound = false
+
-- Ins
--- TODO: check if ins already bound
-main.run ( 'bind 331 = lua mark_toggle ()' )
+if not main.binding ( '331' ) then
+ main.binding ( '331', 'lua mark_toggle ()' )
+ mark_ins_bound = true
+end
hooks_d['hook-quit'].mark =
function ( args )
- main.run ( 'bind 331 =' )
+ if mark_ins_bound then
+ main.binding ( '331', nil )
+ end
end
-- vim: se ts=4: --
--- a/examples/mcabberrc.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/mcabberrc.lua Mon Mar 16 18:54:16 2009 +0200
@@ -132,7 +132,7 @@
main.command ( 'post',
function ( args )
main.run ( 'say_to -f ' .. args .. ' .' )
- end, 'filename' )
+ end, false, 'filename' )
main.command ( 'cmd',
function ( args )
local to = main.current_buddy ()
@@ -146,7 +146,7 @@
return false
end
end )
- end, 'filename' )
+ end, false, 'filename' )
main.command ( 'exthelp',
function ( args )
if commands_help[args] then
@@ -160,7 +160,7 @@
print ( list:sub ( 1, -3 ) )
print ( "For built-in mcabber commands see /help" )
end
- end, 'cmd' )
+ end, false, 'cmd' )
main.command ( 'join!',
function ( args )
main.run ( 'room join ' .. main.current_buddy () )
--- a/examples/room_priv.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/room_priv.lua Mon Mar 16 18:54:16 2009 +0200
@@ -4,7 +4,7 @@
room_cid = main.command ( 'priv',
function ( args )
main.run ( 'room privmsg ' .. args )
- end, {} )
+ end, false, {} )
commands_help['priv'] = "nick message\n\nSends private message to room participant. Nick completion available! ;)"
@@ -29,13 +29,15 @@
end
end
-main.run ( 'bind 338 = lua main.run ( "roster down" ); register_nicks ()' )
-main.run ( 'bind 339 = lua main.run ( "roster up" ); register_nicks ()' )
+room_priv_pgup_action = main.binding ( '338' )
+room_priv_pgdn_action = main.binding ( '339' )
+main.binding ( '338', ('lua main.run ( %q ); register_nicks ()'):format ( room_priv_pgup_action ) )
+main.binding ( '339', ('lua main.run ( %q ); register_nicks ()'):format ( room_priv_pgdn_action ) )
hooks_d['hook-quit'].room_priv =
function ( args )
- main.run ( 'bind 338 = roster down' )
- main.run ( 'bind 339 = roster up' )
+ main.binding ( '338', room_priv_pgup_action )
+ main.binding ( '339', room_priv_pgdn_action )
end
-- vim: se ts=4: --
--- a/examples/xep0004.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0004.lua Mon Mar 16 18:54:16 2009 +0200
@@ -107,7 +107,6 @@
main.command ( 'form',
function ( args )
- args = main.parse_args ( args )
local action = args[1]
local id = tonumber (args[1])
if forms[id] then
@@ -154,7 +153,7 @@
print ( 'No forms' )
end
end
- end, form_cid )
+ end, true, form_cid )
commands_help['form'] = "[del form_id | send form_id | form_id [field_name {clear | [set] value}]\n\nWith bare form id prints info on that form.\nWith field name sets or clears field value. Set subcommand is optional, just to allow values, starting with 'clear'.\nWithout arguments prints form list."
--- a/examples/xep0030.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0030.lua Mon Mar 16 18:54:16 2009 +0200
@@ -55,7 +55,6 @@
main.command ( 'disco',
function ( args )
- args = main.parse_args ( args )
local who
if args.t then
who = args.t
@@ -108,7 +107,7 @@
end
end, who )
end
- end, 'jid' )
+ end, true, 'jid' )
commands_help['disco'] = "[-t target_jid] [info | items] [node]\n\nService discovery request.\nInfo is sent if omitted.\nIf info reveals, that buddy can do items, items request also will be sent."
--- a/examples/xep0047.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0047.lua Mon Mar 16 18:54:16 2009 +0200
@@ -167,7 +167,6 @@
main.command ( 'ibb',
function ( args )
- args = main.parse_args ( args )
local action = args[1]
if action == 'send' then
local who
@@ -201,7 +200,7 @@
print ( 'No streams' )
end
end
- end, { "send", "accept", "reject", "del" } )
+ end, true, { "send", "accept", "reject", "del" } )
commands_help['ibb'] = "[[-t target_jid] send filename | accept sid filename | reject sid filename | del sid]\n\nRequests, accepts or rejects sending file via in-band bytestream."
--- a/examples/xep0060.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0060.lua Mon Mar 16 18:54:16 2009 +0200
@@ -306,7 +306,6 @@
main.command ( 'node',
function ( args )
- args = main.parse_args ( args )
local who, action, node = args.t, args[1], args[2]
if not who then
who = main.current_buddy ()
@@ -335,7 +334,7 @@
else
print ( 'Error: unknown action' )
end
- end )
+ end, true )
-- FIXME
commands_help['node'] = "[-t jid] [-m max_items] action [node_name]\n\nAction can be subscribe, unsubscribe, retrieve (items, get), create (new), delete (del), purge (del_items), configure (conf*), subscriptions (subscribers), subscription (modify?)"
--- a/examples/xep0077.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0077.lua Mon Mar 16 18:54:16 2009 +0200
@@ -162,7 +162,7 @@
who = main.full_jid ()
end
register_to ( who )
- end, 'jid' )
+ end, false, 'jid' )
main.command ( 'cancel',
function ( args )
@@ -173,7 +173,7 @@
who = main.full_jid ()
end
unregister_from ( who )
- end, 'jid' )
+ end, false, 'jid' )
commands_help['register'] = "[jid]\n\nSends registration request to jid (or current buddy). You, probably, then will need to fill and send some form."
commands_help['cancel'] = "[jid]\n\nSends registration cancellation request to jid (or current buddy). May require a form filling."
--- a/examples/xep0146.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0146.lua Mon Mar 16 18:54:16 2009 +0200
@@ -41,7 +41,6 @@
main.command ( 'remote',
function ( args )
- args = main.parse_args ( args )
local who
if args.t then
who = args.t
@@ -69,7 +68,7 @@
elseif action then
remote_command ( who, action )
end
- end, 'jid' )
+ end, true, 'jid' )
commands_help['remote'] = "[-t target_jid] [remote_command]\n\nPrints list of available remote command or requests execution of specified command."
--- a/examples/xep0163.lua Mon Mar 16 06:12:55 2009 +0200
+++ b/examples/xep0163.lua Mon Mar 16 18:54:16 2009 +0200
@@ -266,10 +266,9 @@
else
enable_tune ( enable )
end
- end, 'yesno' )
+ end, false, 'yesno' )
main.command ( 'mood',
function ( args )
- args = main.parse_args ( args )
local data = { }
local mood, text = args[1], args[2]
if text then
@@ -279,10 +278,9 @@
data[mood] = { }
end
pep_publish ( 'mood', data )
- end )
+ end, true )
main.command ( 'activity',
function ( args )
- args = main.parse_args ( args )
local data = { }
local activity, text = args[1], args[2]
if text then
@@ -299,16 +297,15 @@
end
end
pep_publish ( 'activity', data )
- end )
+ end, true )
main.command ( 'location',
function ( args )
- args = main.parse_args ( args )
local data = { }
for key, val in pairs ( args ) do
data[key] = { val }
end
pep_publish ( 'geoloc', data )
- end )
+ end, true )
commands_help['tune'] = "[enable|disable|on|off|yes|no|true|false]\n\nEnables or disables publishing of notifications about playing music in your player (currently only mpd is supported)."
commands_help['mood'] = "[mood [message]]\n\nPublishes your mood.\nNote, that for now it does not checks for mood validity, so, see xep0107 for valid moods."
--- a/main.c Mon Mar 16 06:12:55 2009 +0200
+++ b/main.c Mon Mar 16 18:54:16 2009 +0200
@@ -559,6 +559,7 @@
typedef struct {
int reference;
+ int parse_args;
lua_State *L;
} lua_command_callback_t;
@@ -566,21 +567,8 @@
static GSList *lua_added_categories = NULL;
-/// command function
-/// Function to handle newly registered command.
-/// A: string (arguments)
-static void lua_main_command_handler (char *args, lua_command_callback_t *cb)
-{
- lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
- lua_pushstring (cb->L, args);
- if (lua_pcall (cb->L, 1, 0, 0)) {
- scr_LogPrint (LPRINT_LOGNORM, "lua: Command execution error: %s", lua_tostring (cb->L, -1));
- lua_pop (cb->L, 1);
- }
-}
-
-/// main.parse_args
-/// Function to parse command argument string.
+// returns true if string contains errors - unclosed quotes or unvalued option
+/// command arguments table
/// It can parse barewords (with escapes), double-quoted strings (with escapes), single-quoted strings (without escapes), options and arguments.
/// Arguments are separated only by whitespace, so, consequential quoted strings or barewords are one argument.
/// This strings are equal:
@@ -594,12 +582,9 @@
/// * All options should be before any arguments. First non-option argument disables options recognizing.
/// * EOL is a cutting edge, that can cut much earlier, than you expect. Non-closed quoted strings lose leading quote and option without value loses its leading minus.
/// * Escape character just before EOL is preserved.
-/// A: string
-/// R: table
-static int lua_main_parse_args (lua_State *L)
+static int luaL_pushargs (lua_State *L, const char *args)
{
- const char *args = luaL_checkstring (L, 1);
- const char *p = args;
+ const char *p = args;
luaL_Buffer buf;
int option = 0;
int options = 1;
@@ -629,6 +614,8 @@
luaL_addlstring (&buf, start, p - start); // XXX: eats quote on eol
if (*p)
++p;
+ else
+ return 1;
} else if (*p == '\'') { // no-escape quote
const char *start = ++p;
while (*p && *p != '\'')
@@ -636,6 +623,8 @@
luaL_addlstring (&buf, start, p - start); // XXX: eats quote on eol
if (*p)
++p;
+ else
+ return 1;
} else { // bareword
const char *start = p;
while (*p) {
@@ -679,9 +668,41 @@
luaL_buffinit (L, &buf);
}
}
- if (option)
+
+ if (option) {
luaL_ref (L, -2); // XXX: eats minus on eol
+ return 1;
+ }
+ return 0;
+}
+
+/// command function
+/// Function to handle newly registered command.
+/// Argument type passed depends on how command is registered.
+/// A: string (arguments) or command arguments table
+static void lua_main_command_handler (char *args, lua_command_callback_t *cb)
+{
+ lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
+
+ if (cb->parse_args)
+ luaL_pushargs (cb->L, args);
+ else
+ lua_pushstring (cb->L, args);
+
+ if (lua_pcall (cb->L, 1, 0, 0)) {
+ scr_LogPrint (LPRINT_LOGNORM, "lua: Command execution error: %s", lua_tostring (cb->L, -1));
+ lua_pop (cb->L, 1);
+ }
+}
+
+/// main.parse_args
+/// Function to parse command argument string to command arguments table.
+/// A: string
+/// R: table
+static int lua_main_parse_args (lua_State *L)
+{
+ luaL_pushargs (L, luaL_checkstring (L, 1));
return 1;
}
@@ -692,6 +713,7 @@
static int lua_main_add_category (lua_State *L)
{
guint cid;
+
if (lua_gettop (L) > 0) {
luaL_argcheck (L, lua_type (L, 1) == LUA_TTABLE, 1, "table expected");
cid = compl_new_category ();
@@ -708,11 +730,13 @@
}
} else
cid = compl_new_category ();
+
if (cid) {
lua_added_categories = g_slist_prepend (lua_added_categories, (gpointer) cid);
lua_pushinteger (L, cid);
} else
lua_pushnil (L);
+
return 1;
}
@@ -756,37 +780,44 @@
/// You can also specify a string name (see completion type) instead of table, for non-builtin, you can just pass integer id.
/// Note, that for now there are no way to unregister completion group, so, resources can be exausted easily.
/// Also note, that it ignores keys in a completion table.
-/// A: string (command name), command function (optional), table (completions, optional)/completion type (or integer comletion group id, optional)
+/// A: string (command name), command function (optional), boolean (parse args flag, optional), table (completions, optional)/completion type (or integer comletion group id, optional)
/// R: completion type (integer completion group id or string for builtin types, optional)
static int lua_main_command (lua_State *L)
-{
+{ // FIXME FIXME
const char *name = luaL_checkstring (L, 1); // XXX: to_utf8? looks like no :/
lua_command_callback_t *cb;
- if (lua_gettop (L) > 1) { // Register
+ int top = lua_gettop (L);
+ if (top > 1) { // Register
guint cid = 0;
+ int parse = 0;
luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
- if (lua_gettop (L) > 2) { // Completions provided
- if (lua_type (L, 3) == LUA_TTABLE) {
- cid = compl_new_category ();
- if (cid) {
- lua_added_categories = g_slist_prepend (lua_added_categories, (gpointer) cid);
- lua_pushnil (L);
- while (lua_next (L, 3)) {
- char *word = to_utf8 (luaL_checkstring (L, -1));
- compl_add_category_word (cid, word);
- lua_pop (L, 1);
- g_free (word);
+ if (top > 2) { // parse flag provided
+ parse = lua_toboolean (L, 3);
+
+ if (top > 3) { // Completions provided
+ if (lua_type (L, 4) == LUA_TTABLE) {
+ cid = compl_new_category ();
+ if (cid) {
+ lua_added_categories = g_slist_prepend (lua_added_categories, (gpointer) cid);
+ lua_pushnil (L);
+ while (lua_next (L, 4)) {
+ char *word = to_utf8 (luaL_checkstring (L, -1));
+ compl_add_category_word (cid, word);
+ lua_pop (L, 1);
+ g_free (word);
+ }
}
- }
- } else
- cid = luaL_checkenum (L, 3, lua_completion_type);
+ } else
+ cid = luaL_checkenum (L, 4, lua_completion_type);
+ }
}
cb = luaL_malloc (L, sizeof (lua_command_callback_t));
lua_pushvalue (L, 2);
- cb->reference = luaL_ref (L, LUA_REGISTRYINDEX);
- cb->L = L;
+ cb->reference = luaL_ref (L, LUA_REGISTRYINDEX);
+ cb->parse_args = parse;
+ cb->L = L;
cmd_add (name, "", cid, 0, (void (*) (char *p)) lua_main_command_handler, cb);
lua_added_commands = g_slist_prepend (lua_added_commands, g_strdup (name));