1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
-- 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 command 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 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
]]
|