aboutsummaryrefslogtreecommitdiff
path: root/modules/textadept/command_entry.lua
diff options
context:
space:
mode:
Diffstat (limited to 'modules/textadept/command_entry.lua')
-rw-r--r--modules/textadept/command_entry.lua172
1 files changed, 120 insertions, 52 deletions
diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua
index 7e52282b..005af837 100644
--- a/modules/textadept/command_entry.lua
+++ b/modules/textadept/command_entry.lua
@@ -1,13 +1,79 @@
-- Copyright 2007-2013 Mitchell mitchell.att.foicica.com. See LICENSE.
--- Modified by Jay Gould.
+-- Abbreviated environment and commands from Jay Gould.
+
+local M = gui.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 used for
+-- looking up key bindings. An example mode is "lua_command" mode for executing
+-- Lua commands:
+--
+-- local gui_ce = gui.command_entry
+-- keys['ce'] = {gui_ce.enter_mode, 'lua_command'}
+-- keys.lua_command = {
+-- ['\t'] = gui_ce.complete_lua,
+-- ['\n'] = {gui_ce.finish_mode, gui_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, `Esc` is pre-defined 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. All other keys are
+-- handled normally by the command entry.
+--
+-- It is important to note that while in any command entry key mode, all editor
+-- key bindings are ignored -- even if the editor, not the command entry, has
+-- focus. You must first exit the key mode by pressing `Esc` (or `Enter` in the
+-- case of the above "lua_command" key mode).
+--
+-- [modes]: keys.html#Modes
-- @field entry_text (string)
-- The text in the entry.
module('gui.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'] = {gui.command_entry.enter_mode, 'command_entry'}
+-- @see _G.keys.MODE
+-- @name enter_mode
+function M.enter_mode(mode)
+ keys.MODE = mode
+ if mode 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*
+-- 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 The function to call. It should accept the command entry text as an
+-- argument.
+-- @usage keys['\n'] = {gui.command_entry.finish_mode, gui.print}
+-- @name finish_mode
+function M.finish_mode(f)
+ M.enter_mode(nil)
+ f(M.entry_text)
+ if CURSES then return false end -- propagate to exit CDK entry on Enter
+end
+
-- Environment for abbreviated commands.
-- @class table
-- @name env
@@ -29,71 +95,73 @@ local env = setmetatable({}, {
end,
})
-local events = events
-
--- Execute a Lua command.
-events.connect(events.COMMAND_ENTRY_COMMAND, function(command)
- local f, err = load(command, nil, 'bt', env)
+---
+-- Executes string *code* as Lua code.
+-- Code is subject to an "abbreviated" environment where the `buffer`, `view`,
+-- and `gui` tables are also considered as globals.
+-- @param code The Lua code to execute.
+-- @name execute_lua
+function M.execute_lua(code)
+ local f, err = load(code, nil, 'bt', env)
if err then error(err) end
- if not CURSES then gui.command_entry.focus() end -- toggle focus to hide
f()
events.emit(events.UPDATE_UI)
-end)
+end
+args.register('-e', '--execute', 1, M.execute_lua, 'Execute Lua code')
-events.connect(events.COMMAND_ENTRY_KEYPRESS, function(code)
- if keys.KEYSYMS[code] == 'esc' then
- gui.command_entry.focus() -- toggle focus to hide
- elseif keys.KEYSYMS[code] == '\t' then
- local substring = gui.command_entry.entry_text:match('[%w_.:]+$') or ''
- local path, o, prefix = substring:match('^([%w_.:]-)([.:]?)([%w_]*)$')
- local f, err = load('return ('..path..')', nil, 'bt', env)
- local ok, tbl = pcall(f)
- local cmpls = {}
- prefix = '^'..prefix
- if not ok then -- shorthand notation
- for _, t in ipairs{buffer, view, gui, _G} do
- for k in pairs(t) do
- if type(k) == 'string' and k:find(prefix) then
- cmpls[#cmpls + 1] = k
- end
- end
+---
+-- 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 `gui` 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, tbl = pcall(f)
+ local cmpls = {}
+ prefix = '^'..prefix
+ if not ok then -- shorthand notation
+ for _, t in ipairs{buffer, view, gui, _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(tbl) ~= 'table' then return end
+ for k in pairs(tbl) 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
- else
- if type(tbl) ~= 'table' then return end
- for k in pairs(tbl) do
- if type(k) == 'string' and k:find(prefix) then cmpls[#cmpls + 1] = k end
- end
- if path == 'buffer' then
- if o == ':' then
- for f in pairs(_SCINTILLA.functions) do
- if f:find(prefix) then cmpls[#cmpls + 1] = f end
- end
- else
- for p in pairs(_SCINTILLA.properties) do
- if p:find(prefix) then cmpls[#cmpls + 1] = p end
- end
- end
- end
end
- table.sort(cmpls)
- gui.command_entry.show_completions(cmpls)
- return true
end
-end)
-
--- Executes Lua code on startup.
-local function execute(command)
- local f, err = load(command, nil, 'bt', env)
- if err then error(err) end
- f()
+ table.sort(cmpls)
+ M.show_completions(cmpls)
+ return true
end
-args.register('-e', '--execute', 1, execute, 'Execute Lua code')
+
+local events = events
+-- 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.