aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/.buffer.luadoc4
-rw-r--r--core/keys.lua11
-rw-r--r--modules/textadept/command_entry.lua52
-rw-r--r--modules/textadept/file_types.lua5
-rw-r--r--modules/textadept/find.lua2
-rw-r--r--modules/textadept/keys.lua10
-rw-r--r--src/textadept.c334
7 files changed, 147 insertions, 271 deletions
diff --git a/core/.buffer.luadoc b/core/.buffer.luadoc
index 871d32f0..c5e5e2fd 100644
--- a/core/.buffer.luadoc
+++ b/core/.buffer.luadoc
@@ -512,8 +512,8 @@
-- * `buffer.MARGIN_RTEXT`
-- A right-justified text margin.
--
--- The default values are `true`, `false`, `false`, `false`, and `false`, for
--- a line number margin and symbol margins.
+-- The default value for the first margin is `buffer.MARGIN_NUMBER`, followed
+-- by `buffer.MARGIN_SYMBOL` for the rest.
-- @field margin_width_n (table)
-- Table of pixel margin widths for margin numbers from zero to four.
-- @field marker_alpha (table, Write-only)
diff --git a/core/keys.lua b/core/keys.lua
index 0761cfa1..ce19c1fe 100644
--- a/core/keys.lua
+++ b/core/keys.lua
@@ -167,9 +167,8 @@ M.keychain = setmetatable({}, {
})
-- Clears the current key sequence.
--- This is also used by *modules/textadept/command_entry.lua*.
-M.clear_key_sequence = function()
- -- Clearing a table is faster than re-creating one.
+local function clear_key_sequence()
+ -- Clearing a table is sometimes faster than re-creating one.
if #keychain == 1 then keychain[1] = nil else keychain = {} end
end
@@ -187,7 +186,7 @@ M.run_command = function(command, command_type)
-- If the argument is a view or buffer, use the current one instead.
if type(args[2]) == 'table' then
local mt, buffer, view = getmetatable(args[2]), buffer, view
- if mt == getmetatable(buffer) then
+ if mt == getmetatable(buffer) and args[2] ~= ui.command_entry then
args[2] = buffer
elseif mt == getmetatable(view) then
args[2] = view
@@ -242,7 +241,7 @@ local function keypress(code, shift, control, alt, meta)
--if CURSES then ui.statusbar_text = '"'..key_seq..'"' end
local keychain_size = #keychain
if keychain_size > 0 and key_seq == M.CLEAR then
- M.clear_key_sequence()
+ clear_key_sequence()
return true
end
keychain[keychain_size + 1] = key_seq
@@ -254,7 +253,7 @@ local function keypress(code, shift, control, alt, meta)
else
status = key_command(M.MODE)
end
- if status ~= CHAIN then M.clear_key_sequence() end
+ if status ~= CHAIN then clear_key_sequence() end
if status > PROPAGATE then return true end -- CHAIN or HALT
if status == INVALID and keychain_size > 0 then
ui.statusbar_text = _L['Invalid sequence']
diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua
index b75405ca..8dca8c6a 100644
--- a/modules/textadept/command_entry.lua
+++ b/modules/textadept/command_entry.lua
@@ -30,8 +30,8 @@ local M = ui.command_entry
-- `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.
--- @field entry_text (string)
--- The text in the command entry.
+-- @field height (number)
+-- The height in pixels of the command entry.
module('ui.command_entry')]]
---
@@ -47,9 +47,7 @@ module('ui.command_entry')]]
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:select_all()
M.focus()
end
@@ -63,9 +61,9 @@ end
-- @usage keys['\n'] = {ui.command_entry.finish_mode, ui.print}
-- @name finish_mode
function M.finish_mode(f)
+ if M:auto_c_active() then return false end -- allow Enter to autocomplete
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
+ if f then f(M:get_text()) end
end
-- Environment for abbreviated commands.
@@ -103,13 +101,12 @@ local function execute_lua(code)
end
args.register('-e', '--execute', 1, execute_lua, 'Execute Lua code')
--- Shows a set of Lua code completions for string *code* or `entry_text`.
+-- Shows a set of Lua code completions for string *code* or the entry's 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`.
+-- @param code The Lua code to complete. The default value is the entry's text.
local function complete_lua(code)
- if not code then code = M.entry_text end
+ if not code then code = M:get_text() end
local symbol, op, part = code:match('([%w_.]-)([%.:]?)([%w_]*)$')
local ok, result = pcall((load('return ('..symbol..')', nil, 'bt', env)))
local cmpls = {}
@@ -139,19 +136,28 @@ local function complete_lua(code)
end
end
table.sort(cmpls)
- M.show_completions(cmpls)
+ M:auto_c_show(#part - 1, table.concat(cmpls, ' '))
end
-- Define key mode for entering Lua commands.
keys.lua_command = {
- ['\t'] = complete_lua, ['\n'] = {M.finish_mode, execute_lua}
+ ['\t'] = complete_lua, ['\n'] = {M.finish_mode, execute_lua},
+ [not OSX and 'cx' or 'mx'] = {buffer.cut, M},
+ [not OSX and 'cc' or 'mc'] = {buffer.copy, M},
+ [not OSX and 'cv' or 'mv'] = {buffer.paste, M},
+ [not OSX and not CURSES and 'ca' or 'ma'] = {buffer.select_all, M},
+ [not OSX and 'cz' or 'mz'] = {buffer.undo, M},
+ [not OSX and 'cy' or 'mZ'] = {buffer.redo, M},
+ [not OSX and 'cZ' or 'mZ'] = {buffer.redo, M},
}
--- 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
+-- Configure the command entry's default properties.
+events.connect(events.INITIALIZED, function()
+ if not arg then return end -- no need to reconfigure on reset
+ M.h_scroll_bar, M.v_scroll_bar = false, false
+ M.margin_width_n[0], M.margin_width_n[1], M.margin_width_n[2] = 0, 0, 0
+ if not CURSES then M.height = M:text_height(1) end
+ M:set_lexer('lua')
end)
--[[ The function below is a Lua C function.
@@ -161,14 +167,4 @@ end)
-- @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
]]
diff --git a/modules/textadept/file_types.lua b/modules/textadept/file_types.lua
index cb5c34da..48c3414e 100644
--- a/modules/textadept/file_types.lua
+++ b/modules/textadept/file_types.lua
@@ -94,7 +94,7 @@ local function set_lexer(buffer, lang)
end
-- Gives new buffers lexer-specific functions.
-local function set_lexer_functions()
+events.connect(events.BUFFER_NEW, function()
buffer.get_lexer, buffer.set_lexer = get_lexer, set_lexer
buffer.style_name = setmetatable({}, {
__index = function(t, style_num) -- LuaDoc is in core/.buffer.luadoc
@@ -103,8 +103,7 @@ local function set_lexer_functions()
end,
__newindex = function() error('read-only property') end
})
-end
-events.connect(events.BUFFER_NEW, set_lexer_functions, 1)
+end, 1)
-- Auto-detect lexer on file open or save as.
events.connect(events.FILE_OPENED, function() buffer:set_lexer() end)
diff --git a/modules/textadept/find.lua b/modules/textadept/find.lua
index 8f5dde69..bde8dfa5 100644
--- a/modules/textadept/find.lua
+++ b/modules/textadept/find.lua
@@ -207,7 +207,7 @@ end
function M.find_incremental(text, next, anchor)
if text then find_incremental(text, next, anchor) return end
M.incremental_start = buffer.current_pos
- ui.command_entry.entry_text = ''
+ ui.command_entry:set_text('')
ui.command_entry.enter_mode('find_incremental')
end
diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua
index 8904fc15..36161672 100644
--- a/modules/textadept/keys.lua
+++ b/modules/textadept/keys.lua
@@ -612,21 +612,21 @@ keys.filter_through = {
}
keys.find_incremental = {
['\n'] = function()
- ui.find.find_entry_text = ui.command_entry.entry_text -- save
- ui.find.find_incremental(ui.command_entry.entry_text, true, true)
+ ui.find.find_entry_text = ui.command_entry:get_text() -- save
+ ui.find.find_incremental(ui.command_entry:get_text(), true, true)
end,
['cr'] = function()
- ui.find.find_incremental(ui.command_entry.entry_text, false, true)
+ ui.find.find_incremental(ui.command_entry:get_text(), false, true)
end,
['\b'] = function()
- ui.find.find_incremental(ui.command_entry.entry_text:sub(1, -2), true)
+ ui.find.find_incremental(ui.command_entry:get_text():sub(1, -2), true)
return false -- propagate
end
}
-- Add the character for any key pressed without modifiers to incremental find.
setmetatable(keys.find_incremental, {__index = function(t, k)
if #k > 1 and k:find('^[cams]*.+$') then return end
- ui.find.find_incremental(ui.command_entry.entry_text..k, true)
+ ui.find.find_incremental(ui.command_entry:get_text()..k, true)
end})
return M
diff --git a/src/textadept.c b/src/textadept.c
index cbe37689..7bb6cd95 100644
--- a/src/textadept.c
+++ b/src/textadept.c
@@ -103,7 +103,7 @@ typedef GtkWidget Scintilla;
static char *textadept_home;
// User interface objects and related macros.
-static Scintilla *focused_view, *dummy_view;
+static Scintilla *focused_view, *dummy_view, *command_entry;
#if GTK
// GTK window.
static GtkWidget *window, *menubar, *tabbar, *statusbar[2];
@@ -142,14 +142,11 @@ static ListStore *find_store, *repl_store;
#define attach(w, x1, _, y1, __, ...) \
gtk_grid_attach(GTK_GRID(findbox), w, x1, y1, 1, 1)
#endif
-// GTK command entry.
-static GtkWidget *command_entry;
-#define command_text gtk_entry_get_text(GTK_ENTRY(command_entry))
-static GtkListStore *cc_store;
-static GtkEntryCompletion *command_entry_completion;
+#define command_entry_focused gtk_widget_has_focus(command_entry)
#elif CURSES
// curses window.
static struct WindowManager *wm;
+static int command_entry_focused;
#if !_WIN32
TermKey *ta_tk; // global for CDK use
#endif
@@ -159,7 +156,11 @@ TermKey *ta_tk; // global for CDK use
SS(view, SCI_SETFOCUS, 1, 0))
/** Callback for refreshing a single Scintilla view. */
static void r_cb(void *view, void*_) {scintilla_refresh((Scintilla *)view);}
-#define refresh_all() (wman_walk(wm, r_cb, NULL), wman_refresh(wm), refresh())
+#define refresh_all() { \
+ wman_walk(wm, r_cb, NULL), wman_refresh(wm); \
+ if (command_entry_focused) scintilla_refresh(command_entry); \
+ refresh(); \
+}
#define flushch() (timeout(0), getch(), timeout(-1))
// curses find & replace pane.
static CDKSCREEN *findbox;
@@ -190,9 +191,6 @@ static ListStore find_store[10], repl_store[10];
fcopy(&option_labels[i], lua_tostring(L, -1)); \
if (!*option) option_labels[i] += 4; \
}
-// curses command entry.
-static CDKENTRY *command_entry;
-static char *command_text;
#endif
#define set_clipboard(s) SS(focused_view, SCI_COPYTEXT, strlen(s), (sptr_t)s)
@@ -551,142 +549,21 @@ static int lfind__newindex(lua_State *L) {
return 0;
}
-#if CURSES
-/**
- * Signal for a keypress inside the Command Entry.
- * As a BINDFN, returns `TRUE` to stop key propagation.
- * As a PROCESSFN, returns `TRUE` to continue key propagation.
- */
-static int c_keypress(EObjectType _, void *object, void *data, chtype key) {
- if (!data && key == KEY_TAB) return TRUE; // do not exit on Tab
- int ctrl = key < 0x20 && key != 9 && key != 27;
- if (ctrl) key = tolower(key ^ 0x40);
- if (key == 27) key = SCK_ESCAPE;
- int halt = lL_event(lua, "command_entry_keypress", LUA_TNUMBER, key,
- LUA_TBOOLEAN, FALSE, LUA_TBOOLEAN, ctrl, -1);
- refresh_all(), drawCDKEntry((CDKENTRY *)object, FALSE);
- return !halt || key == SCK_ESCAPE;
-}
-#endif
-
/** `command_entry.focus()` Lua function. */
static int lce_focus(lua_State *L) {
+ //if (closing) return 0;
#if GTK
if (!gtk_widget_get_visible(command_entry))
gtk_widget_show(command_entry), gtk_widget_grab_focus(command_entry);
else
gtk_widget_hide(command_entry), gtk_widget_grab_focus(focused_view);
#elif CURSES
- if (command_entry) return 0; // already active
- CDKSCREEN *screen = initCDKScreen(newwin(1, 0, LINES - 2, 0));
- command_entry = newCDKEntry(screen, LEFT, TOP, NULL, NULL, A_NORMAL, '_',
- vMIXED, 0, 0, 256, FALSE, FALSE);
- bindCDKObject(vENTRY, command_entry, KEY_TAB, c_keypress, NULL);
- setCDKEntryPreProcess(command_entry, c_keypress, "");
- setCDKEntryValue(command_entry, command_text);
- char *clipboard = get_clipboard();
- GPasteBuffer = copyChar(clipboard); // set the CDK paste buffer
- curs_set(1), activateCDKEntry(command_entry, NULL), curs_set(0);
- // Set Scintilla clipboard with new CDK paste buffer if necessary.
- if (strcmp(clipboard, GPasteBuffer)) set_clipboard(GPasteBuffer);
- free(clipboard), free(GPasteBuffer), GPasteBuffer = NULL;
- destroyCDKEntry(command_entry), command_entry = NULL;
- delwin(screen->window), destroyCDKScreen(screen), flushch();
-#if _WIN32
- redrawwin(scintilla_get_window(focused_view)); // needed for pdcurses
-#endif
+ command_entry_focused = !command_entry_focused;
+ focus_view(command_entry_focused ? command_entry : focused_view);
#endif
return 0;
}
-/** `command_entry.show_completions()` Lua function. */
-static int lce_show_completions(lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- int len = lua_rawlen(L, 1);
-#if GTK
- if (!gtk_widget_get_visible(command_entry))
- luaL_error(L, "command entry inactive");
- GtkEntryCompletion *completion = gtk_entry_get_completion(
- GTK_ENTRY(command_entry));
- GtkListStore *store = GTK_LIST_STORE(
- gtk_entry_completion_get_model(completion));
- gtk_list_store_clear(store);
-#elif CURSES
- if (!command_entry) luaL_error(L, "command entry inactive");
- const char **items = malloc(len * sizeof(const char *));
- int width = 0;
-#endif
- for (int i = 1; i <= len; i++) {
- lua_rawgeti(L, 1, i);
- if (lua_type(L, -1) == LUA_TSTRING) {
-#if GTK
- GtkTreeIter iter;
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, lua_tostring(L, -1), -1);
-#elif CURSES
- items[i - 1] = lua_tostring(L, -1);
- if (width < strlen(items[i - 1])) width = strlen(items[i - 1]);
-#endif
- }
- lua_pop(L, 1); // value
- }
-#if GTK
- gtk_entry_completion_complete(completion);
-#elif CURSES
- // Screen needs to take into account border width and scroll bar width.
- int height = (len < LINES - 3) ? len : LINES - 5;
- CDKSCREEN *screen = initCDKScreen(newwin(height + 2, width + 4,
- LINES - 4 - height, 0));
- CDKSCROLL *scrolled = newCDKScroll(screen, LEFT, TOP, RIGHT, 0, 0, NULL,
- (char **)items, len, FALSE, A_REVERSE,
- TRUE, FALSE);
- curs_set(0);
- if (len > 0 && activateCDKScroll(scrolled, NULL) >= 0) {
- char *text = getCDKEntryValue(command_entry), *p = text + strlen(text);
- while (p > text && (isalnum(*(p - 1)) || *(p - 1) == '_')) p--;
- lua_pushlstring(L, text, p - text);
- lua_pushstring(L, items[getCDKScrollCurrentItem(scrolled)]);
- lua_concat(L, 2);
- setCDKEntryValue(command_entry, (char *)lua_tostring(L, -1));
- }
- curs_set(1);
- destroyCDKScroll(scrolled);
- delwin(screen->window), destroyCDKScreen(screen), flushch();
- free(items);
-#if _WIN32
- redrawwin(scintilla_get_window(focused_view)); // needed for pdcurses
-#endif
- drawCDKEntry(command_entry, FALSE);
-#endif
- return 0;
-}
-
-/** `command_entry.__index` Lua metatable. */
-static int lce__index(lua_State *L) {
- const char *key = lua_tostring(L, 2);
- if (strcmp(key, "entry_text") == 0) {
- lua_pushstring(L, command_text);
-#if CURSES
- if (command_entry) lua_pushstring(L, getCDKEntryValue(command_entry));
-#endif
- } else lua_rawget(L, 1);
- return 1;
-}
-
-/** `command_entry.__newindex` Lua metatable. */
-static int lce__newindex(lua_State *L) {
- const char *key = lua_tostring(L, 2);
- if (strcmp(key, "entry_text") == 0) {
-#if GTK
- gtk_entry_set_text(GTK_ENTRY(command_entry), lua_tostring(L, 3));
-#elif CURSES
- if (command_entry) setCDKEntryValue(command_entry, lua_tostring(L, 3));
- fcopy(&command_text, lua_tostring(L, 3));
-#endif
- } else lua_rawset(L, 1);
- return 0;
-}
-
/** `ui.dialog()` Lua function. */
static int lui_dialog(lua_State *L) {
GTDialogType type = gtdialog_type(luaL_checkstring(L, 1));
@@ -1042,45 +919,46 @@ static int lui__newindex(lua_State *L) {
}
/**
+ * Returns the buffer at the given acceptable index as a Scintilla document.
+ * @param L The Lua state.
+ * @param index Stack index of the buffer.
+ * @return Scintilla document
+ */
+static sptr_t l_todoc(lua_State *L, int index) {
+ lua_getfield(L, index, "doc_pointer");
+ sptr_t doc = (sptr_t)lua_touserdata(L, -1);
+ lua_pop(L, 1); // doc_pointer
+ return doc;
+}
+
+/**
* Compares the Scintilla document at the given index with the global one and
- * returns 0 if they are equivalent, non-zero otherwise.
- * If non-equivalent, loads the document in `dummy_view` for non-global document
+ * returns 0 if they are equivalent, less than zero if that document belongs to
+ * the command entry, and greater than zero otherwise.
+ * In the last case, loads the document in `dummy_view` for non-global document
* use. Raises and error if the value is not a Scintilla document or if the
* document no longer exists.
* @param L The Lua state.
* @param index The stack index of the Scintilla document.
- * @return 0 or the Scintilla document's pointer
+ * @return 0, -1, or the Scintilla document's pointer
*/
static sptr_t l_globaldoccompare(lua_State *L, int index) {
luaL_getmetatable(L, "ta_buffer");
lua_getmetatable(L, (index > 0) ? index : index - 1);
luaL_argcheck(L, lua_rawequal(L, -1, -2), index, "Buffer expected");
- lua_getfield(L, (index > 0) ? index : index - 2, "doc_pointer");
- sptr_t doc = (sptr_t)lua_touserdata(L, -1);
- lua_pop(L, 3); // doc_pointer, metatable, metatable
+ sptr_t doc = l_todoc(L, (index > 0) ? index : index - 2);
+ lua_pop(L, 2); // metatable, metatable
if (doc != SS(focused_view, SCI_GETDOCPOINTER, 0, 0)) {
lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
l_pushdoc(L, doc), lua_gettable(L, -2);
luaL_argcheck(L, !lua_isnil(L, -1), index, "this Buffer does not exist");
lua_pop(L, 2); // buffer, ta_buffers
+ if (doc == SS(command_entry, SCI_GETDOCPOINTER, 0, 0)) return -1;
return (SS(dummy_view, SCI_SETDOCPOINTER, 0, doc), doc);
} else return 0;
}
/**
- * Returns the buffer at the given acceptable index as a Scintilla document.
- * @param L The Lua state.
- * @param index Stack index of the buffer.
- * @return Scintilla document
- */
-static sptr_t l_todoc(lua_State *L, int index) {
- lua_getfield(L, index, "doc_pointer");
- sptr_t doc = (sptr_t)lua_touserdata(L, -1);
- lua_pop(L, 1); // doc_pointer
- return doc;
-}
-
-/**
* Switches to a document in the given view.
* @param L The Lua state.
* @param view The Scintilla view.
@@ -1112,6 +990,25 @@ static void lL_gotodoc(lua_State *L, Scintilla *view, int n, int relative) {
}
/**
+ * Adds the command entry's buffer to the 'buffers' registry table at a constant
+ * index (0).
+ */
+static void register_command_entry_doc() {
+ sptr_t doc = SS(command_entry, SCI_GETDOCPOINTER, 0, 0);
+ lua_getfield(lua, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_getglobal(lua, "ui");
+ lua_getfield(lua, -1, "command_entry"), lua_replace(lua, -2);
+ lua_pushstring(lua, "doc_pointer");
+ lua_pushlightuserdata(lua, (sptr_t *)doc), lua_rawset(lua, -3);
+ // t[doc_pointer] = ce, t[0] = ce, t[ce] = 0
+ lua_pushlightuserdata(lua, (sptr_t *)doc);
+ lua_pushvalue(lua, -2), lua_settable(lua, -4);
+ lua_pushvalue(lua, -1), lua_rawseti(lua, -3, 0);
+ lua_pushinteger(lua, 0), lua_settable(lua, -3);
+ lua_pop(lua, 1); // buffers
+}
+
+/**
* Removes the Scintilla document from the 'buffers' registry table.
* The document must have been previously added with lL_adddoc.
* It is removed from any other views showing it first. Therefore, ensure the
@@ -1135,7 +1032,7 @@ static void lL_removedoc(lua_State *L, sptr_t doc) {
lua_rawgeti(L, -1, i);
if (doc != l_todoc(L, -1)) {
lua_getfield(L, -1, "doc_pointer");
- // bs[userdata] = b, bs[#bs + 1] = b, bs[b] = #bs
+ // t[doc_pointer] = buffer, t[#t + 1] = buffer, t[buffer] = #t
lua_pushvalue(L, -2), lua_rawseti(L, -5, lua_rawlen(L, -5) + 1);
lua_pushvalue(L, -2), lua_settable(L, -5);
lua_pushinteger(L, lua_rawlen(L, -3)), lua_settable(L, -4);
@@ -1152,6 +1049,7 @@ static void lL_removedoc(lua_State *L, sptr_t doc) {
}
lua_pop(L, 1); // buffers
lua_pushvalue(L, -1), lua_setfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ register_command_entry_doc();
lua_setglobal(L, "_BUFFERS");
}
@@ -1186,7 +1084,9 @@ static int lbuffer_new(lua_State *L) {
/** `buffer.text_range()` Lua function. */
static int lbuffer_text_range(lua_State *L) {
- Scintilla *view = l_globaldoccompare(L, 1) == 0 ? focused_view : dummy_view;
+ Scintilla *view = focused_view;
+ int result = l_globaldoccompare(L, 1);
+ if (result != 0) view = (result > 0) ? dummy_view : command_entry;
long min = luaL_checklong(L, 2), max = luaL_checklong(L, 3);
luaL_argcheck(L, min <= max, 3, "start > end");
struct Sci_TextRange tr = {{min, max}, malloc(max - min + 1)};
@@ -1284,7 +1184,10 @@ static int l_callscintilla(lua_State *L, Scintilla *view, int msg, int wtype,
static int lbuf_closure(lua_State *L) {
Scintilla *view = focused_view;
// If optional buffer argument is given, check it.
- if (lua_istable(L, 1) && l_globaldoccompare(L, 1) != 0) view = dummy_view;
+ if (lua_istable(L, 1)) {
+ int result = l_globaldoccompare(L, 1);
+ if (result != 0) view = (result > 0) ? dummy_view : command_entry;
+ }
// Interface table is of the form { msg, rtype, wtype, ltype }.
return l_callscintilla(L, view, l_rawgetiint(L, lua_upvalueindex(1), 1),
l_rawgetiint(L, lua_upvalueindex(1), 3),
@@ -1321,7 +1224,8 @@ static int lbuf_property(lua_State *L) {
Scintilla *view = focused_view;
// Interface table is of the form {get_id, set_id, rtype, wtype}.
if (!is_buffer) lua_getfield(L, 1, "buffer");
- if (l_globaldoccompare(L, is_buffer ? 1 : -1) != 0) view = dummy_view;
+ int result = l_globaldoccompare(L, is_buffer ? 1 : -1);
+ if (result != 0) view = (result > 0) ? dummy_view : command_entry;
if (!is_buffer) lua_pop(L, 1);
if (is_buffer && l_rawgetiint(L, -1, 4) != SVOID) { // indexible property
lua_newtable(L);
@@ -1345,7 +1249,8 @@ static int lbuf_property(lua_State *L) {
(!is_buffer || !newindex) ? 2 : 3);
} else lua_pop(L, 2); // non-table, ta_properties
- if (strcmp(lua_tostring(L, 2), "tab_label") == 0) {
+ if (strcmp(lua_tostring(L, 2), "tab_label") == 0 &&
+ l_todoc(L, 1) != SS(command_entry, SCI_GETDOCPOINTER, 0, 0)) {
// Return or update the buffer's tab label.
lua_getfield(L, 1, "tab_pointer");
#if GTK
@@ -1358,6 +1263,26 @@ static int lbuf_property(lua_State *L) {
// TODO: tabs
#endif
return !newindex ? 1 : 0;
+ } else if (strcmp(lua_tostring(L, 2), "height") == 0 &&
+ l_todoc(L, 1) == SS(command_entry, SCI_GETDOCPOINTER, 0, 0)) {
+ // Return or set the command entry's pixel height.
+ int height = luaL_optint(L, 3, 0);
+#if GTK
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(command_entry, &allocation);
+ if (newindex) {
+ int min_height = SS(command_entry, SCI_TEXTHEIGHT, 0, 0);
+ if (height < min_height) height = min_height;
+ gtk_widget_set_size_request(command_entry, allocation.width, height);
+ } else lua_pushnumber(L, allocation.height);
+#elif CURSES
+ WINDOW *win = scintilla_get_window(command_entry);
+ if (newindex) {
+ if (height < 1) height = 1;
+ wresize(win, height, COLS), mvwin(win, LINES - 1 - height, 0);
+ } else lua_pushinteger(L, getmaxy(win));
+#endif
+ return !newindex ? 1 : 0;
} else if (!newindex) {
// If the key is a Scintilla constant, return its value.
lua_getfield(L, LUA_REGISTRYINDEX, "ta_constants");
@@ -1389,7 +1314,7 @@ static void lL_adddoc(lua_State *L, sptr_t doc) {
l_setcfunction(L, -2, "new", lbuffer_new);
l_setcfunction(L, -2, "text_range", lbuffer_text_range);
l_setmetatable(L, -2, "ta_buffer", lbuf_property, lbuf_property);
- // bs[userdata] = b, bs[#bs + 1] = b, bs[b] = #bs
+ // t[doc_pointer] = buffer, t[#t + 1] = buffer, t[buffer] = #t
lua_pushvalue(L, -2), lua_settable(L, -4);
lua_pushvalue(L, -1), lua_rawseti(L, -3, lua_rawlen(L, -3) + 1);
lua_pushinteger(L, lua_rawlen(L, -2)), lua_settable(L, -3);
@@ -1611,8 +1536,8 @@ static int lL_init(lua_State *L, int argc, char **argv, int reinit) {
lua_setfield(L, -2, "find");
lua_newtable(L);
l_setcfunction(L, -1, "focus", lce_focus);
- l_setcfunction(L, -1, "show_completions", lce_show_completions);
- l_setmetatable(L, -1, "ta_command_entry", lce__index, lce__newindex);
+ l_setcfunction(L, -1, "text_range", lbuffer_text_range);
+ l_setmetatable(L, -1, "ta_buffer", lbuf_property, lbuf_property);
lua_setfield(L, -2, "command_entry");
l_setcfunction(L, -1, "dialog", lui_dialog);
l_setcfunction(L, -1, "get_split_table", lui_get_split_table);
@@ -1793,7 +1718,8 @@ static void l_close(lua_State *L) {
for (int i = 1; i <= lua_rawlen(L, -1); i++)
lua_rawgeti(L, -1, i), delete_buffer(l_todoc(L, -1)), lua_pop(L, 1);
lua_pop(L, 1); // buffers
- scintilla_delete(focused_view);
+ scintilla_delete(focused_view), scintilla_delete(dummy_view);
+ scintilla_delete(command_entry);
lua_close(L);
}
@@ -2196,53 +2122,10 @@ static GtkWidget *new_findbox() {
return findbox;
}
-/** Signal for the "Enter" key being pressed in the Command Entry. */
-static void c_activate(GtkWidget*_, void*__) {
- lL_event(lua, "command_entry_keypress", LUA_TNUMBER, GDK_Return, -1);
-}
-
-/** Signal for a keypress inside the Command Entry. */
-static int c_keypress(GtkWidget*_, GdkEventKey *event, void*__) {
- // If "Enter" is pressed by itself, pass it to the entry completion.
- if (event->keyval == GDK_Return && event->state == 0) return FALSE;
- return lL_event(lua, "command_entry_keypress", LUA_TNUMBER, event->keyval,
- event_mod(SHIFT), event_mod(CONTROL), event_mod(MOD1),
- event_mod(META), -1);
-}
-
-/** Emit "Escape" key to the command entry on focus lost. */
+/** Emit "Escape" key for the command entry on focus lost. */
static int c_focusout(GtkWidget*_, GdkEvent *__, void*___) {
- lL_event(lua, "command_entry_keypress", LUA_TNUMBER, GDK_Escape, -1);
- return FALSE;
-}
-
-/**
- * Replaces the current word (consisting of alphanumeric and underscore
- * characters) with the match text.
- */
-static int cc_matchselected(GtkEntryCompletion*_, GtkTreeModel *model,
- GtkTreeIter *iter, void*__) {
- const char *text = gtk_entry_get_text(GTK_ENTRY(command_entry)), *p, *match;
- p = text + strlen(text) - 1;
- for (; p >= text && (g_ascii_isalnum(*p) || *p == '_'); p--)
- g_signal_emit_by_name(G_OBJECT(command_entry), "move-cursor",
- GTK_MOVEMENT_VISUAL_POSITIONS, -1, TRUE, 0);
- if (p < text + strlen(text) - 1)
- g_signal_emit_by_name(G_OBJECT(command_entry), "backspace", 0); // for undo
- gtk_tree_model_get(model, iter, 0, &match, -1);
- g_signal_emit_by_name(G_OBJECT(command_entry), "insert-at-cursor", match, 0);
- g_free((char *)match);
- gtk_list_store_clear(cc_store);
- return TRUE;
+ return (lL_event(lua, "keypress", LUA_TNUMBER, GDK_Escape, -1), FALSE);
}
-
-/**
- * The match function for the command entry.
- * Since the completion list is filled by Lua, every item is a "match".
- */
-static int cc_matchfunc(GtkEntryCompletion*_, const char *__, GtkTreeIter*___,
- void*____) {return 1;}
-
#endif // if GTK
/**
@@ -2302,24 +2185,12 @@ static void new_window() {
gtk_box_pack_start(GTK_BOX(vbox), new_findbox(), FALSE, FALSE, 5);
- command_entry = gtk_entry_new();
- signal(command_entry, "activate", c_activate);
- signal(command_entry, "key-press-event", c_keypress);
+ command_entry = scintilla_new();
+ gtk_widget_set_size_request(command_entry, 1, 20);
+ signal(command_entry, "key-press-event", s_keypress);
signal(command_entry, "focus-out-event", c_focusout);
gtk_box_pack_start(GTK_BOX(vbox), command_entry, FALSE, FALSE, 0);
- command_entry_completion = gtk_entry_completion_new();
- signal(command_entry_completion, "match-selected", cc_matchselected);
- gtk_entry_completion_set_match_func(command_entry_completion, cc_matchfunc,
- NULL, NULL);
- gtk_entry_completion_set_popup_set_width(command_entry_completion, FALSE);
- gtk_entry_completion_set_text_column(command_entry_completion, 0);
- cc_store = gtk_list_store_new(1, G_TYPE_STRING);
- gtk_entry_completion_set_model(command_entry_completion,
- GTK_TREE_MODEL(cc_store));
- gtk_entry_set_completion(GTK_ENTRY(command_entry), command_entry_completion);
- g_object_unref(cc_store);
-
GtkWidget *hboxs = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxs, FALSE, FALSE, 0);
@@ -2340,8 +2211,12 @@ static void new_window() {
Scintilla *view = new_view(0);
wm = wman_create(view, scintilla_get_window(view));
wman_resize(wm, LINES - 2, COLS, 1, 0);
+ command_entry = scintilla_new(NULL);
+ wresize(scintilla_get_window(command_entry), 1, COLS);
+ mvwin(scintilla_get_window(command_entry), LINES - 2, 0);
dummy_view = scintilla_new(NULL);
#endif
+ register_command_entry_doc();
}
#if (CURSES && !_WIN32)
@@ -2351,6 +2226,8 @@ static void resize(int signal) {
ioctl(0, TIOCGWINSZ, &win);
resizeterm(win.ws_row, win.ws_col);
wman_resize(wm, LINES - 2, COLS, 1, 0);
+ WINDOW *ce_win = scintilla_get_window(command_entry);
+ wresize(ce_win, 1, COLS), mvwin(ce_win, LINES - 1 - getmaxy(ce_win), 0);
lL_event(lua, "update_ui", -1);
refresh_all();
}
@@ -2446,11 +2323,14 @@ int main(int argc, char **argv) {
#endif
#endif
- setlocale(LC_COLLATE, "C"), setlocale(LC_NUMERIC, "C");
+ setlocale(LC_COLLATE, "C"), setlocale(LC_NUMERIC, "C"); // for Lua
if (lua = luaL_newstate(), !lL_init(lua, argc, argv, FALSE)) return 1;
initing = TRUE, new_window(), lL_dofile(lua, "init.lua"), initing = FALSE;
lL_event(lua, "buffer_new", -1), lL_event(lua, "view_new", -1); // first ones
- lL_event(lua, "initialized", -1);
+ l_setglobaldoc(lua, SS(command_entry, SCI_GETDOCPOINTER, 0, 0));
+ lL_event(lua, "buffer_new", -1), lL_event(lua, "view_new", -1); // cmd entry
+ l_setglobaldoc(lua, SS(focused_view, SCI_GETDOCPOINTER, 0, 0));
+ lL_event(lua, "initialized", -1); // ready
#if (__APPLE__ && !CURSES)
gtkosx_application_ready(osxapp);
#endif
@@ -2481,13 +2361,14 @@ int main(int argc, char **argv) {
PDC_save_key_modifiers(TRUE);
#endif
+ Scintilla *view = focused_view;
int c = 0;
#if _WIN32
int keysyms[] = {0,SCK_DOWN,SCK_UP,SCK_LEFT,SCK_RIGHT,SCK_HOME,SCK_BACK,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_DELETE,SCK_INSERT,0,0,0,0,0,0,SCK_NEXT,SCK_PRIOR,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_END};
int shift_keysyms[] = {SCK_TAB,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_DELETE,0,0,SCK_END,0,0,0,SCK_HOME,SCK_INSERT,0,SCK_LEFT,0,0,0,0,0,0,0,0,SCK_RIGHT,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_UP,SCK_DOWN};
int ctrl_keysyms[] = {SCK_LEFT,SCK_RIGHT,SCK_PRIOR,SCK_NEXT,SCK_HOME,SCK_END,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_INSERT,0,0,SCK_UP,SCK_DOWN,SCK_TAB,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_BACK,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,SCK_DELETE,0,SCK_RETURN};
int alt_keysyms[] = {SCK_DELETE,SCK_INSERT,0,0,0,SCK_TAB,'-','=',SCK_HOME,SCK_PRIOR,SCK_NEXT,SCK_END,SCK_UP,SCK_DOWN,SCK_RIGHT,SCK_LEFT,SCK_RETURN,SCK_ESCAPE,'`','[',']',';','\'',',','.','/',SCK_BACK,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'\\'}; // SCK_RETURN, '\\' do not work for me
- while ((c = wgetch(scintilla_get_window(focused_view))) != ERR) {
+ while ((c = wgetch(scintilla_get_window(view))) != ERR) {
if (c < 0x20 && c != 8 && c != 9 && c != 13 && c != 27)
c = tolower(c ^ 0x40);
else if (c == 27)
@@ -2525,7 +2406,7 @@ int main(int argc, char **argv) {
#endif
if (!lL_event(lua, "keypress", LUA_TNUMBER, c, LUA_TBOOLEAN, shift,
LUA_TBOOLEAN, ctrl, LUA_TBOOLEAN, alt, -1))
- scintilla_send_key(focused_view, c, shift, ctrl, alt);
+ scintilla_send_key(view, c, shift, ctrl, alt);
if (quit && lL_event(lua, "quit", -1)) {
l_close(lua);
// Free some memory.
@@ -2542,6 +2423,7 @@ int main(int argc, char **argv) {
break;
} else quit = FALSE;
refresh_all();
+ view = !command_entry_focused ? focused_view : command_entry;
}
endwin();
#if !_WIN32