-- Copyright 2007-2013 Mitchell mitchell.att.foicica.com. See LICENSE. -- Abbreviated environment and commands from Jay Gould. local M = ui.command_entry --[[ This comment is for LuaDoc. --- -- Textadept's Command Entry. -- -- ## Modes -- -- The command entry supports multiple [modes][] that have their own sets of key -- bindings stored in a separate table in `_G.keys` under a mode prefix key. -- Mode names are arbitrary, but cannot conflict with lexer names or key -- sequence strings (e.g. `'lua'` or `'send'`) due to the method Textadept uses -- for looking up key bindings. An example mode is "lua_command" mode for -- executing Lua commands: -- -- local ui_ce = ui.command_entry -- keys['ce'] = {ui_ce.enter_mode, 'lua_command'} -- keys.lua_command = { -- ['\t'] = ui_ce.complete_lua, -- ['\n'] = {ui_ce.finish_mode, ui_ce.execute_lua} -- } -- -- In this case, `Ctrl+E` opens the command entry and enters "lua_command" key -- mode where the `Tab` and `Enter` keys have special, defined functionality. -- (By default, Textadept pre-defines `Esc` to exit any command entry mode.) -- `Tab` shows a list of Lua completions for the entry text and `Enter` exits -- "lua_command" key mode and executes the entered code. The command entry -- handles all other keys normally. -- -- [modes]: keys.html#Modes -- @field entry_text (string) -- The text in the entry. module('ui.command_entry')]] --- -- Opens the command entry in key mode *mode*. -- Key bindings will be looked up in `keys[mode]` instead of `keys`. The `Esc` -- (`⎋` on Mac OSX | `Esc` in curses) key exits the current mode, closes the -- command entry, and restores normal key lookup. -- This function is useful for binding keys to enter a command entry mode. -- @param mode The key mode to enter into, or `nil` to exit the current mode. -- @usage keys['ce'] = {ui.command_entry.enter_mode, 'command_entry'} -- @see _G.keys.MODE -- @name enter_mode function M.enter_mode(mode) keys.MODE = mode if mode and not keys[mode]['esc'] then keys[mode]['esc'] = M.enter_mode end -- In curses, M.focus() does not return immediately, so the key sequence that -- called M.focus() is still on the keychain. Clear it. if CURSES then keys.clear_key_sequence() end M.focus() end --- -- Exits the current key mode, closes the command entry, and calls function *f* -- (if given) with the command entry text as an argument. -- This is useful for binding keys to exit a command entry mode and perform an -- action with the entered text. -- @param f Optional function to call. It should accept the command entry text -- as an argument. -- @usage keys['\n'] = {ui.command_entry.finish_mode, ui.print} -- @name finish_mode function M.finish_mode(f) M.enter_mode(nil) if f then f(M.entry_text) end if CURSES then return false end -- propagate to exit CDK entry on Enter end -- Environment for abbreviated commands. -- @class table -- @name env local env = setmetatable({}, { __index = function(t, k) local f = buffer[k] if f and type(f) == 'function' then f = function(...) buffer[k](buffer, ...) end elseif f == nil then f = view[k] or ui[k] or _G[k] end return f end, __newindex = function(t, k, v) for _, t2 in ipairs{buffer, view, ui} do if t2[k] ~= nil then t2[k] = v return end end rawset(t, k, v) end, }) --- -- Executes string *code* as Lua code. -- Code is subject to an "abbreviated" environment where the `buffer`, `view`, -- and `ui` tables are also considered as globals. -- Prints the results of '=' expressions like in the Lua prompt. -- @param code The Lua code to execute. -- @name execute_lua function M.execute_lua(code) if code:sub(1, 1) == '=' then code = 'return '..code:sub(2) end local f, err = load(code, nil, 'bt', env) if err then error(err) end local result = f() if result ~= nil then ui.print(result) end events.emit(events.UPDATE_UI) end args.register('-e', '--execute', 1, M.execute_lua, 'Execute Lua code') --- -- Shows a set of Lua code completions for string *code* or `entry_text`. -- Completions are subject to an "abbreviated" environment where the `buffer`, -- `view`, and `ui` tables are also considered as globals. -- @param code The Lua code to complete. The default value is the value of -- `entry_text`. -- @name complete_lua function M.complete_lua(code) local substring = (code or M.entry_text):match('[%w_.:]+$') or '' local path, op, prefix = substring:match('^([%w_.:]-)([.:]?)([%w_]*)$') local f, err = load('return ('..path..')', nil, 'bt', env) local ok, result = pcall(f) local cmpls = {} prefix = '^'..prefix if not ok then -- shorthand notation for _, t in ipairs{buffer, view, ui, _G} do for k in pairs(t) do if type(k) == 'string' and k:find(prefix) then cmpls[#cmpls + 1] = k end end end for f in pairs(_SCINTILLA.functions) do if f:find(prefix) then cmpls[#cmpls + 1] = f end end for p in pairs(_SCINTILLA.properties) do if p:find(prefix) then cmpls[#cmpls + 1] = p end end else if type(result) ~= 'table' then return end for k in pairs(result) do if type(k) == 'string' and k:find(prefix) then cmpls[#cmpls + 1] = k end end if path == 'buffer' and op == ':' then for f in pairs(_SCINTILLA.functions) do if f:find(prefix) then cmpls[#cmpls + 1] = f end end elseif path == 'buffer' and op == '.' then for p in pairs(_SCINTILLA.properties) do if p:find(prefix) then cmpls[#cmpls + 1] = p end end end end table.sort(cmpls) M.show_completions(cmpls) end -- Pass command entry keys to the default keypress handler. -- Since the command entry is designed to be modal, command entry key bindings -- should stay separate from editor key bindings. events.connect(events.COMMAND_ENTRY_KEYPRESS, function(...) if keys.MODE then return events.emit(events.KEYPRESS, ...) end end) --[[ The function below is a Lua C function. --- -- Focuses the command entry. -- @class function -- @name focus local focus --- -- Shows the completion list *completions* for the current word prefix. -- Word prefix characters are alphanumerics and underscores. On selection, the -- word prefix is replaced with the completion. -- @param completions The table of completions to show. Non-string values are -- ignored. -- @class function -- @name show_completions local show_completions ]]