diff options
-rw-r--r-- | core/ext/menu.lua | 10 | ||||
-rw-r--r-- | core/init.lua | 19 | ||||
-rw-r--r-- | modules/textadept/macros.lua | 70 | ||||
-rw-r--r-- | src/lua_interface.c | 21 |
4 files changed, 75 insertions, 45 deletions
diff --git a/core/ext/menu.lua b/core/ext/menu.lua index 2b3209e6..78d706bc 100644 --- a/core/ext/menu.lua +++ b/core/ext/menu.lua @@ -111,6 +111,11 @@ t.menubar = { '_Update Multiple Lines', '_Finished Editing', }, + { title = 'M_acros', + '_Start Recording', + 'S_top Recording', + '_Play Macro' + }, }, gtkmenu { title = '_Buffers', @@ -165,6 +170,7 @@ local b, v = 'buffer', 'view' local m_snippets = _m.textadept.lsnippets local m_editing = _m.textadept.editing local m_mlines = _m.textadept.mlines +local m_macros = _m.textadept.macros local function pm_activate(text) t.pm.entry_text = text t.pm.activate() end local function toggle_setting(setting) @@ -267,6 +273,10 @@ local actions = { ['Remove Multiple Lines'] = { m_mlines.remove_multiple }, ['Update Multiple Lines'] = { m_mlines.update }, ['Finished Editing'] = { m_mlines.clear }, + -- Tools -> Macros + ['Start Recording'] = { m_macros.start_recording }, + ['Stop Recording'] = { m_macros.stop_recording }, + ['Play Macro'] = { m_macros.play }, -- Buffers ['Next Buffer'] = { 'goto_buffer', v, 1, false }, ['Prev Buffer'] = { 'goto_buffer', v, -1, false }, diff --git a/core/init.lua b/core/init.lua index 84c0d4d6..7a25169b 100644 --- a/core/init.lua +++ b/core/init.lua @@ -38,21 +38,24 @@ end -- used. -- @return string CocoaDialog result. function cocoa_dialog(kind, opts) - local args = not MAC and { kind } or '' + local args = { kind } for k, v in pairs(opts) do - if not MAC then - args[#args + 1] = '--'..k - if type(v) == 'string' then args[#args + 1] = v end - else - args = args..' --'..k - if type(v) == 'string' then args = args..' "'..v..'"' end + args[#args + 1] = '--'..k + if k == 'items' and kind:match('dropdown') then + if not MAC then + for item in v:gmatch('"(.-)"%s+') do args[#args + 1] = item end + else + args[#args + 1] = v + end + elseif type(v) == 'string' then + args[#args + 1] = not MAC and v or '"'..v..'"' end end if not MAC then return lua_dialog.run(args) else local cocoa_dialog = '/CocoaDialog.app/Contents/MacOS/CocoaDialog ' - local p = io.popen(_HOME..cocoa_dialog..kind..args) + local p = io.popen( _HOME..cocoa_dialog..table.concat(args, ' ') ) local out = p:read('*all') p:close() return out diff --git a/modules/textadept/macros.lua b/modules/textadept/macros.lua index 67709a02..8b51fd13 100644 --- a/modules/textadept/macros.lua +++ b/modules/textadept/macros.lua @@ -14,9 +14,9 @@ local MACRO_FILE = _HOME..'/saved_macros' -- The list of available macros. -- Each key is the macro name, and the value is a numerically indexed table of -- commands. Each command is a table with a structure as follows: --- { command, wParam, lParam, type = 'function' or 'property' } --- where command is the buffer function or property name (depending on type) --- and wParam and lParam are the arguments for it. +-- { command, wParam, lParam } +-- where command is the buffer function and wParam and lParam are the arguments +-- for it. -- @class table -- @name list list = {} @@ -38,7 +38,7 @@ local recording = false -- @param msg The Scintilla message ID. local function macro_notification(msg, wParam, lParam) if recording then - current[#current + 1] = { msg, wParam or '', lParam or '' } + current[#current + 1] = { msg, wParam or 0, lParam or 0 } textadept.statusbar_text = 'Macro recording' end end @@ -57,36 +57,27 @@ end --- -- Stops recording a macro. -- Each command's msg in the recorded macro is changed to the name of the --- message and the type of the command is changed appropriately (function or --- property). Then the user is prompted for a macro name and the macro is saved --- to the current macro list and macro file. +-- message Then the user is prompted for a macro name and the macro is saved to +-- the current macro list and macro file. function stop_recording() if not recording then return end buffer:stop_record() recording = false local textadept = textadept - local bf, bp = textadept.buffer_functions, textadept.buffer_properties - local macro_name = cocoa_dialog( 'standard-inputbox', { - title = 'Save Macro', - text = 'Macro name:', + local ret, macro_name = cocoa_dialog( 'standard-inputbox', { + ['informative-text'] = 'Macro name?', + text = 'Macro name', ['no-newline'] = true - } ) + } ):match('^(%d)\n([^\n]+)$') - if #macro_name > 0 then + if ret == '1' and macro_name and #macro_name > 0 then for _, command in ipairs(current) do - command.type = 'function' local msg = command[1] - for f, t in pairs(bf) do + for f, t in pairs(textadept.buffer_functions) do if t[1] == msg then command[1] = f break end end - if type( command[1] ) ~= 'string' then - command.type = 'property' - for p, t in pairs(bp) do - if t[1] == msg or t[2] == msg then command[1] = p break end - end - end end - list[ macro_name:match('[^\n]+') ] = current + list[macro_name] = current save() textadept.statusbar_text = 'Macro saved' textadept.events.handle('macro_saved') @@ -109,22 +100,26 @@ function play(macro_name) if not macro_name then local macro_list = '' for name in pairs(list) do macro_list = macro_list..'"'..name..'"'..' ' end - macro_name = cocoa_dialog( 'standard-dropdown', { + local ret + ret, macro_name = cocoa_dialog( 'standard-dropdown', { title = 'Select a Macro', text = 'Macro name:', items = macro_list, + ['string-output'] = true, ['no-newline'] = true - } ) + } ):match('^([^\n]+)\n([^\n]+)$') + if ret == 'Cancel' then return end end local macro = list[macro_name] if not macro then return end - local buffer = buffer + local buffer, bf = buffer, textadept.buffer_functions for _, command in ipairs(macro) do local cmd, wParam, lParam = unpack(command) - if command.type == 'function' then - buffer[cmd](buffer, wParam, lParam) + local _, _, p1_type, p2_type = unpack( bf[cmd] ) + if p2_type == 7 and p1_type == 0 or p1_type == 2 then -- single string param + buffer[cmd](buffer, lParam) else - buffer[cmd] = #wParam > 0 and wParam or lParam + buffer[cmd](buffer, wParam, lParam) end end end @@ -149,7 +144,12 @@ function save(filename) for name, macro in pairs(list) do f:write(name, '\n') for _, command in ipairs(macro) do - f:write( ("%s\t%s\t%s\t%s\n"):format( command.type, unpack(command) ) ) + local msg, wParam, lParam = unpack(command) + if type(lParam) == 'string' then + lParam = lParam:gsub( '[\t\n\r\f]', + { ['\t'] = '\\t', ['\n'] = '\\n', ['\r'] = '\\r', ['\f'] = '\\f' } ) + end + f:write( ("%s\t%s\t%s\n"):format(msg, wParam, lParam) ) end f:write('\n') end @@ -173,11 +173,15 @@ function load(filename) list[name] = current_macro name = nil else - local type, cmd, wParam, lParam = - line:match('^([^\t]+)\t([^\t]+)\t?([^\t]*)\t?(.*)$') - if type and cmd then + local cmd, wParam, lParam = line:match('^([^\t]+)\t([^\t]+)\t(.*)$') + if cmd and wParam and lParam then + lParam = lParam:gsub( '\\[tnrf]', + { ['\\t'] = '\t', ['\\n'] = '\n', ['\\r'] = '\r', ['\\f'] = '\f' } ) + local num = wParam:match('^-?%d+$') + if num then wParam = tonumber(num) end + num = lParam:match('^-?%d+$') + if num then lParam = tonumber(num) end local command = { cmd, wParam, lParam } - command.type = type current_macro[#current_macro + 1] = command end end diff --git a/src/lua_interface.c b/src/lua_interface.c index 3baef912..179d963c 100644 --- a/src/lua_interface.c +++ b/src/lua_interface.c @@ -678,8 +678,8 @@ bool l_handle_keypress(int keyval, bool shift, bool control, bool alt) { return l_call_function(4, 1); } -#define l_scn_int(i, n) { lua_pushinteger(lua, i); lua_setfield(lua, -2, n); } -#define l_scn_str(s, n) { lua_pushstring(lua, s); lua_setfield(lua, -2, n); } +#define l_scn_int(i, n) { lua_pushinteger(lua, i); lua_setfield(lua, idx, n); } +#define l_scn_str(s, n) { lua_pushstring(lua, s); lua_setfield(lua, idx, n); } /** * Handles a Scintilla notification. @@ -688,6 +688,7 @@ bool l_handle_keypress(int keyval, bool shift, bool control, bool alt) { void l_handle_scnnotification(SCNotification *n) { if (!l_is_ta_table_function("events", "notification")) return; lua_newtable(lua); + int idx = lua_gettop(lua); l_scn_int(n->nmhdr.code, "code"); l_scn_int(n->position, "position"); l_scn_int(n->ch, "ch"); @@ -698,8 +699,20 @@ void l_handle_scnnotification(SCNotification *n) { l_scn_int(n->linesAdded, "lines_added"); l_scn_int(n->message, "message"); if (n->nmhdr.code == SCN_MACRORECORD) { - l_scn_str(reinterpret_cast<char*>(n->wParam), "wParam"); - l_scn_str(reinterpret_cast<char*>(n->lParam), "lParam"); + l_ta_get(lua, "buffer_functions"); + lua_pushnil(lua); + while (lua_next(lua, -2)) + if (l_rawgeti_int(lua, -1, 1) == n->message) { + if (l_rawgeti_int(lua, -1, 3) == tSTRING) { + l_scn_str(reinterpret_cast<char*>(n->wParam), "wParam"); + } else { l_scn_int(static_cast<int>(n->wParam), "wParam"); } + if (l_rawgeti_int(lua, -1, 4) == tSTRING) { + l_scn_str(reinterpret_cast<char*>(n->lParam), "lParam"); + } else { l_scn_int(static_cast<int>(n->lParam), "lParam"); } + lua_pop(lua, 2); // key and value + break; + } else lua_pop(lua, 1); // value + lua_pop(lua, 1); // textadept.buffer_functions } else { l_scn_int(static_cast<int>(n->wParam), "wParam"); l_scn_int(static_cast<int>(n->lParam), "lParam"); |