aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/.command_entry.lua7
-rw-r--r--core/.find.lua58
-rw-r--r--core/.pm.lua38
-rw-r--r--core/events.lua75
-rw-r--r--core/ext/command_entry.lua69
-rw-r--r--core/ext/find.lua58
-rw-r--r--core/ext/pm.lua53
-rw-r--r--core/ext/pm/modules_browser.lua6
-rw-r--r--src/Makefile4
-rw-r--r--src/lua_interface.c524
-rw-r--r--src/textadept.c138
-rw-r--r--src/textadept.h19
12 files changed, 478 insertions, 571 deletions
diff --git a/core/.command_entry.lua b/core/.command_entry.lua
index 3d5e24fd..c1a06f45 100644
--- a/core/.command_entry.lua
+++ b/core/.command_entry.lua
@@ -16,10 +16,3 @@ command_entry = { entry_text = nil }
--- Focuses the command entry.
function focus() end
-
----
--- Gets completions for the current command_entry text.
--- This function is called internally and shouldn't be called by script.
--- @param command The command to complete.
--- @return sorted table of completions
-function get_completions_for(command) end
diff --git a/core/.find.lua b/core/.find.lua
index bea87c36..40829cb1 100644
--- a/core/.find.lua
+++ b/core/.find.lua
@@ -33,7 +33,7 @@ module('textadept.find')
---
-- Textadept's find table.
-- @class table
--- @name textadept.find
+-- @name find
-- @field find_entry_text The text in the find entry.
-- @field replace_entry_text The text in the replace entry.
-- @field match_case Flag indicating whether or not case-sensitive search is
@@ -53,68 +53,20 @@ find = {
function focus() end
---
--- [Local table] Text escape sequences with their associated characters.
--- @class table
--- @name escapes
-local escapes = {}
-
----
--- Finds and selects text in the current buffer.
--- This is used by the find dialog. It is recommended to use the
--- buffer:search_in_target() or buffer:search_next() and buffer:search_prev()
--- functions for scripting.
--- @param text The text to find.
--- @param next Flag indicating whether or not the search direction is forward.
--- @param flags Search flags. This is a number mask of 4 flags: match case (2),
--- whole word (4), Lua pattern (8), and in files (16) joined with binary OR.
--- If nil, this is determined based on the checkboxes in the find box.
--- @param nowrap Flag indicating whether or not the search won't wrap.
--- @param wrapped Utility flag indicating whether or not the search has wrapped
--- for displaying useful statusbar information. This flag is used and set
--- internally, and should not be set otherwise.
--- @return position of the found text or -1
-function find.find(text, next, flags, nowrap, wrapped) end
-
----
--- Replaces found text.
--- This function is used by the find dialog. It is not recommended to call it
--- via scripts.
--- textadept.find.find is called first, to select any found text. The selected
--- text is then replaced by the specified replacement text.
--- This function ignores 'Find in Files'.
--- @param rtext The text to replace found text with. It can contain both Lua
--- capture items (%n where 1 <= n <= 9) for Lua pattern searches and %()
--- sequences for embedding Lua code for any search.
--- @see find.find
-function find.replace(rtext) end
-
----
--- Replaces all found text.
--- This function is used by the find dialog. It is not recommended to call it
--- via scripts.
--- If any text is selected, all found text in that selection is replaced.
--- This function ignores 'Find in Files'.
--- @param ftext The text to find.
--- @param rtext The text to replace found text with.
--- @param flags The number mask identical to the one in 'find'.
--- @see find.find
-function find.replace_all(ftext, rtext, flags) end
-
----
-- Mimicks a press of the 'Find Next' button in the Find box.
-function find.call_find_next() end
+function find_next() end
---
-- Mimicks a press of the 'Find Prev' button in the Find box.
-function find.call_find_prev() end
+function find_prev() end
---
-- Mimicks a press of the 'Replace' button in the Find box.
-function find.call_replace() end
+function replace() end
---
-- Mimicks a press of the 'Replace All' button in the Find box.
-function find.call_replace_all() end
+function replace_all() end
---
-- Goes to the next or previous file found relative to the file
diff --git a/core/.pm.lua b/core/.pm.lua
index 3b1ffbd8..5371d286 100644
--- a/core/.pm.lua
+++ b/core/.pm.lua
@@ -61,12 +61,6 @@ module('textadept.pm')
-- current GtkTreePath).
pm = { entry_text = nil, width = nil, cursor = nil }
---- Focuses the project manager entry.
-function focus() end
-
---- Clears the project manager contents.
-function clear() end
-
--- Requests the project manager to get its contents based on its entry text.
function activate() end
@@ -75,3 +69,35 @@ function activate() end
-- manager entry combo box.
-- @param prefix The text to add.
function add_browser(prefix) end
+
+--- Clears the project manager contents.
+function clear() end
+
+---
+-- Adds contents to the Project Manager view.
+-- @param contents Table of tables to for display in the treeview (single
+-- level). Each key in the return table is the treeview item's ID. The table
+-- value has the following recognized fields:
+-- * parent - boolean value indicating if this entry can contain children.
+-- If true, an expanding arrow is displayed next to the entry.
+-- * pixbuf - a string representing a GTK stock-id whose icon is displayed
+-- next to an entry.
+-- * text - the entry's Pango marked-up display text.
+-- Note that only a SINGLE level of data needs to be returned. When parents
+-- are expanded, this function is called again to get that level of data.
+-- @param parent String representation of parent GtkTreePath to add the child
+-- contents to.
+function fill(contents, parent)
+
+--- Focuses the project manager entry.
+function focus() end
+
+---
+-- Shows a context menu.
+-- @param menu Table of menu items. It consists of an ordered list of strings
+-- to be used to construct a context menu. The strings are handled as follows:
+-- * 'gtk-*' - a stock menu item is created based on the GTK stock-id.
+-- * 'separator' - a menu separator item is created.
+-- * Otherwise a regular menu item with a mnemonic is created.
+-- @param event The GDK event associated with the context menu request.
+function show_context_menu(menu, event) end
diff --git a/core/events.lua b/core/events.lua
index 3d0cadee..28e446c9 100644
--- a/core/events.lua
+++ b/core/events.lua
@@ -71,7 +71,35 @@ module('textadept.events', package.seeall)
-- alt: flag indicating whether or not alt is pressed.
-- menu_clicked(menu_id)
-- menu_id: the numeric ID of the menu item.
--- pm_view_filled()
+-- pm_contents_request(full_path, expanding)
+-- full_path: a numerically indexed table of treeview item parents. The
+-- first index contains the text of pm_entry. Subsequent indexes contain
+-- the ID's of parents of the child requested for expanding (if any).
+-- expanding: indicates if the contents of a parent are being requested.
+-- pm_item_selected(selected_item, gdkevent)
+-- selected_item: identical to 'full_path' for 'pm_contents_request' event.
+-- gdkevent: the GDK event associated with the request. It must be passed to
+-- pm.show_context_menu()
+-- pm_context_menu_request(selected_item)
+-- selected_item: identical to 'full_path' for 'pm_contents_request' event.
+-- pm_menu_clicked(menu_id, selected_item)
+-- menu_id: the numeric ID for the menu item.
+-- selected_item: identical to 'full_path' for 'pm_contents_request' event.
+-- find(text, next)
+-- text: the text to find.
+-- next: flag indicating whether or not the search direction is forward.
+-- replace(text)
+-- text: the text to replace the current selection with. It can contain both
+-- Lua capture items (%n where 1 <= n <= 9) for Lua pattern searches and %()
+-- sequences for embedding Lua code for any search.
+-- replace_all(find_text, repl_text)
+-- find_text: the text to find.
+-- repl_text: the text to replace found text with.
+-- find_keypress(code)
+-- code: the key code.
+-- command_entry_completions_request()
+-- command_entry_keypress(code)
+-- code: the key code.
local events = textadept.events
@@ -163,41 +191,6 @@ function notification(n)
if f then f(n) end
end
--- Textadept events.
-function buffer_new()
- return handle('buffer_new')
-end
-function buffer_deleted()
- return handle('buffer_deleted')
-end
-function buffer_before_switch()
- return handle('buffer_before_switch')
-end
-function buffer_after_switch()
- return handle('buffer_after_switch')
-end
-function view_new()
- return handle('view_new')
-end
-function view_before_switch()
- return handle('view_before_switch')
-end
-function view_after_switch()
- return handle('view_after_switch')
-end
-function quit()
- return handle('quit')
-end
-function keypress(code, shift, control, alt)
- return handle('keypress', code, shift, control, alt)
-end
-function menu_clicked(menu_id_str)
- return handle('menu_clicked', tonumber(menu_id_str))
-end
-function pm_view_filled()
- return handle('pm_view_filled')
-end
-
-- Default handlers to follow.
add_handler('view_new',
@@ -478,11 +471,9 @@ add_handler('quit',
end)
if MAC then
- function appleevent_odoc(uri) return handle('uri_dropped', 'file://'..uri) end
+ add_handler('appleevent_odoc',
+ function(uri) return handle('uri_dropped', 'file://'..uri) end)
end
----
--- Default error handler.
--- Prints the errors to an error buffer.
--- @param ... Error strings.
-function error(...) textadept._print(locale.ERROR_BUFFER, ...) end
+add_handler('error',
+ function(...) textadept._print(locale.ERROR_BUFFER, ...) end)
diff --git a/core/ext/command_entry.lua b/core/ext/command_entry.lua
index d2a64243..0170f21c 100644
--- a/core/ext/command_entry.lua
+++ b/core/ext/command_entry.lua
@@ -2,32 +2,51 @@
local textadept = _G.textadept
local locale = _G.locale
-local ce = textadept.command_entry
--- LuaDoc is in core/.command_entry.lua
-function ce.get_completions_for(command)
- local substring = command:match('[%w_.:]+$') or ''
- local path, o, prefix = substring:match('^([%w_.:]-)([.:]?)([%w_]*)$')
- local ret, tbl = pcall(loadstring('return ('..path..')'))
- if not ret then tbl = getfenv(0) end
- if type(tbl) ~= 'table' then return end
- local cmpls = {}
- 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(textadept.buffer_functions) do
- if f:find('^'..prefix) then cmpls[#cmpls + 1] = f end
+textadept.events.add_handler('command_entry_completions_request',
+ function(command) -- get a Lua completion list for the command being entered
+ local substring = command:match('[%w_.:]+$') or ''
+ local path, o, prefix = substring:match('^([%w_.:]-)([.:]?)([%w_]*)$')
+ local ret, tbl = pcall(loadstring('return ('..path..')'))
+ if not ret then tbl = getfenv(0) end
+ if type(tbl) ~= 'table' then return end
+ local cmpls = {}
+ for k in pairs(tbl) do
+ if type(k) == 'string' and k:find('^'..prefix) then
+ cmpls[#cmpls + 1] = k
end
- else
- for p in pairs(textadept.buffer_properties) do
- if p:find('^'..prefix) then cmpls[#cmpls + 1] = p end
+ end
+ if path == 'buffer' then
+ if o == ':' then
+ for f in pairs(textadept.buffer_functions) do
+ if f:find('^'..prefix) then cmpls[#cmpls + 1] = f end
+ end
+ else
+ for p in pairs(textadept.buffer_properties) do
+ if p:find('^'..prefix) then cmpls[#cmpls + 1] = p end
+ end
end
end
- end
- table.sort(cmpls)
- return cmpls
-end
+ table.sort(cmpls)
+ textadept.command_entry.show_completions(cmpls)
+ end)
+
+textadept.events.add_handler('command_entry_command',
+ function(command) -- execute a Lua command
+ local f, err = loadstring(command)
+ if err then error(err) end
+ f()
+ end)
+
+textadept.events.add_handler('command_entry_keypress',
+ function(code)
+ local ce = textadept.command_entry
+ if code == 65307 then -- escape
+ ce.focus() -- toggle focus to hide
+ return true
+ elseif code == 65289 then -- tab
+ textadept.events.handle('command_entry_completions_request',
+ ce.entry_text)
+ return true
+ end
+ end)
diff --git a/core/ext/find.lua b/core/ext/find.lua
index b4f4efee..c97cefd3 100644
--- a/core/ext/find.lua
+++ b/core/ext/find.lua
@@ -10,14 +10,28 @@ local MARK_FIND = 0
local MARK_FIND_COLOR = 0x4D9999
local previous_view
--- LuaDoc is in core/.find.lua.
+---
+-- [Local table] Text escape sequences with their associated characters.
+-- @class table
+-- @name escapes
local escapes = {
['\\a'] = '\a', ['\\b'] = '\b', ['\\f'] = '\f', ['\\n'] = '\n',
['\\r'] = '\r', ['\\t'] = '\t', ['\\v'] = '\v', ['\\\\'] = '\\'
}
--- LuaDoc is in core/.find.lua.
-function find.find(text, next, flags, nowrap, wrapped)
+---
+-- [Local function] Finds and selects text in the current buffer.
+-- @param text The text to find.
+-- @param next Flag indicating whether or not the search direction is forward.
+-- @param flags Search flags. This is a number mask of 4 flags: match case (2),
+-- whole word (4), Lua pattern (8), and in files (16) joined with binary OR.
+-- If nil, this is determined based on the checkboxes in the find box.
+-- @param nowrap Flag indicating whether or not the search won't wrap.
+-- @param wrapped Utility flag indicating whether or not the search has wrapped
+-- for displaying useful statusbar information. This flag is used and set
+-- internally, and should not be set otherwise.
+-- @return position of the found text or -1
+local function find_(text, next, flags, nowrap, wrapped)
if #text == 0 then return end
local buffer = buffer
local first_visible_line = buffer.first_visible_line -- for 'no results found'
@@ -128,7 +142,7 @@ function find.find(text, next, flags, nowrap, wrapped)
buffer:goto_pos(buffer.length)
end
textadept.statusbar_text = locale.FIND_SEARCH_WRAPPED
- result = find.find(text, next, flags, true, true)
+ result = find_(text, next, flags, true, true)
if result == -1 then
textadept.statusbar_text = locale.FIND_NO_RESULTS
buffer:line_scroll(0, first_visible_line)
@@ -141,9 +155,18 @@ function find.find(text, next, flags, nowrap, wrapped)
return result
end
+textadept.events.add_handler('find', find_)
--- LuaDoc is in core/.find.lua.
-function find.replace(rtext)
+---
+-- [Local function] Replaces found text.
+-- 'find_' is called first, to select any found text. The selected text is then
+-- replaced by the specified replacement text.
+-- This function ignores 'Find in Files'.
+-- @param rtext The text to replace found text with. It can contain both Lua
+-- capture items (%n where 1 <= n <= 9) for Lua pattern searches and %()
+-- sequences for embedding Lua code for any search.
+-- @see find
+local function replace(rtext)
if #buffer:get_sel_text() == 0 then return end
if find.in_files then find.in_files = false end
local buffer = buffer
@@ -179,9 +202,17 @@ function find.replace(rtext)
buffer:goto_pos(buffer.current_pos)
end
end
+textadept.events.add_handler('replace', replace)
--- LuaDoc is in core/.find.lua.
-function find.replace_all(ftext, rtext, flags)
+---
+-- [Local function] Replaces all found text.
+-- If any text is selected, all found text in that selection is replaced.
+-- This function ignores 'Find in Files'.
+-- @param ftext The text to find.
+-- @param rtext The text to replace found text with.
+-- @param flags The number mask identical to the one in 'find'.
+-- @see find
+local function replace_all(ftext, rtext, flags)
if #ftext == 0 then return end
if find.in_files then find.in_files = false end
local buffer = buffer
@@ -189,8 +220,8 @@ function find.replace_all(ftext, rtext, flags)
local count = 0
if #buffer:get_sel_text() == 0 then
buffer:goto_pos(0)
- while(find.find(ftext, true, flags, true) ~= -1) do
- find.replace(rtext)
+ while(find_(ftext, true, flags, true) ~= -1) do
+ replace(rtext)
count = count + 1
end
else
@@ -201,13 +232,13 @@ function find.replace_all(ftext, rtext, flags)
local end_marker =
buffer:marker_add(buffer:line_from_position(e + 1), MARK_FIND)
buffer:goto_pos(s)
- local pos = find.find(ftext, true, flags, true)
+ local pos = find_(ftext, true, flags, true)
while pos ~= -1 and
pos < buffer:position_from_line(
buffer:marker_line_from_handle(end_marker)) do
- find.replace(rtext)
+ replace(rtext)
count = count + 1
- pos = find.find(ftext, true, flags, true)
+ pos = find_(ftext, true, flags, true)
end
e = buffer:position_from_line(buffer:marker_line_from_handle(end_marker))
buffer:goto_pos(e)
@@ -220,6 +251,7 @@ function find.replace_all(ftext, rtext, flags)
string.format(locale.FIND_REPLACEMENTS_MADE, tostring(count))
buffer:end_undo_action()
end
+textadept.events.add_handler('replace_all', replace_all)
---
-- [Local function] When the user double-clicks a found file, go to the line in
diff --git a/core/ext/pm.lua b/core/ext/pm.lua
index 67cbbbfb..8838582c 100644
--- a/core/ext/pm.lua
+++ b/core/ext/pm.lua
@@ -8,37 +8,36 @@ local current_browser = nil
local last_browser_text = nil
local browser_cursors = {}
--- LuaDoc is in core/.browser.lua.
-function pm.get_contents_for(full_path, expanding)
- for _, browser in pairs(pm.browsers) do
- if browser.matches(full_path[1]) then
- current_browser = browser
- if last_browser_text and last_browser_text ~= pm.entry_text then
- -- Switching browsers, save the current one's cursor.
- -- Don't reset last_browser_text here though, we still need to detect
- -- the switch when the 'pm_view_filled' event is called so as to restore
- -- the cursor to the new browser.
- browser_cursors[last_browser_text] = pm.cursor
+textadept.events.add_handler('pm_contents_request',
+ function(full_path, expanding)
+ for _, browser in pairs(pm.browsers) do
+ if browser.matches(full_path[1]) then
+ current_browser = browser
+ if last_browser_text and last_browser_text ~= pm.entry_text then
+ -- Switching browsers, save the current one's cursor.
+ -- Don't reset last_browser_text here though, we still need to detect
+ -- the switch when the 'pm_view_filled' event is called so as to restore
+ -- the cursor to the new browser.
+ browser_cursors[last_browser_text] = pm.cursor
+ end
+ pm.fill(browser.get_contents_for(full_path, expanding), expanding)
+ textadept.events.handle('pm_view_filled')
end
- return browser.get_contents_for(full_path, expanding)
end
- end
-end
+ end)
--- LuaDoc is in core/.browser.lua.
-function pm.perform_action(selected_item)
- current_browser.perform_action(selected_item)
-end
+textadept.events.add_handler('pm_item_selected',
+ function(selected_item) current_browser.perform_action(selected_item) end)
--- LuaDoc is in core/.browser.lua.
-function pm.get_context_menu(selected_item)
- return current_browser.get_context_menu(selected_item)
-end
+textadept.events.add_handler('pm_context_menu_request',
+ function(selected_item, event)
+ pm.show_context_menu(current_browser.get_context_menu(selected_item), event)
+ end)
--- LuaDoc is in core/.browser.lua.
-function pm.perform_menu_action(menu_id, selected_item)
- current_browser.perform_menu_action(menu_id, selected_item)
-end
+textadept.events.add_handler('pm_menu_clicked',
+ function(menu_id, selected_item)
+ current_browser.perform_menu_action(menu_id, selected_item)
+ end)
-- LuaDoc is in core/.browser.lua.
function pm.toggle_visible()
@@ -51,7 +50,7 @@ function pm.toggle_visible()
end
textadept.events.add_handler('pm_view_filled',
- function() -- tries to restore the cursor for a previous browser
+ function() -- try to restore previous browser cursor
if last_browser_text ~= pm.entry_text then
last_browser_text = pm.entry_text
local previous_cursor = browser_cursors[pm.entry_text]
diff --git a/core/ext/pm/modules_browser.lua b/core/ext/pm/modules_browser.lua
index 4cbe715c..8472ee0d 100644
--- a/core/ext/pm/modules_browser.lua
+++ b/core/ext/pm/modules_browser.lua
@@ -84,8 +84,10 @@ function matches(entry_text)
end
local function modify_path(path)
- path[1] = textadept.iconv(_HOME..'/modules', 'UTF-8', _CHARSET)
- return path
+ local new_path = {}
+ for _, v in ipairs(path) do new_path[#new_path + 1] = v end
+ new_path[1] = textadept.iconv(_HOME..'/modules', 'UTF-8', _CHARSET)
+ return new_path
end
function get_contents_for(full_path)
diff --git a/src/Makefile b/src/Makefile
index 06857307..52fb26fe 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,9 +4,9 @@
INCLUDEDIRS=-Iscintilla-st/include -Ilua/include
ifdef DEBUG
-CXXFLAGS=-DDEBUG -g -DGTK -DSCI_LEXER -W -Wall
+CXXFLAGS=-DDEBUG -g -DGTK -DSCI_LEXER -W -Wall -Wno-sign-compare
else
-CXXFLAGS=-DNDEBUG -O -DGTK -DSCI_LEXER -W -Wall
+CXXFLAGS=-DNDEBUG -O -DGTK -DSCI_LEXER -W -Wall -Wno-sign-compare
endif
GTKFLAGS=$(shell pkg-config --cflags gtk+-2.0)
GTKLIBS=$(shell pkg-config --libs gtk+-2.0 gthread-2.0)
diff --git a/src/lua_interface.c b/src/lua_interface.c
index 9a126cbf..b8101e20 100644
--- a/src/lua_interface.c
+++ b/src/lua_interface.c
@@ -58,12 +58,12 @@ static int l_buffer_mt_index(lua_State *lua),
l_ce_mt_index(lua_State *lua),
l_ce_mt_newindex(lua_State *lua);
-static int l_cf_ta_buffer_new(lua_State *lua),
- l_cf_buffer_delete(lua_State *lua),
+static int l_cf_buffer_delete(lua_State *lua),
l_cf_buffer_text_range(lua_State *lua),
l_cf_view_focus(lua_State *lua),
l_cf_view_split(lua_State *lua),
l_cf_view_unsplit(lua_State *lua),
+ l_cf_ta_buffer_new(lua_State *lua),
l_cf_ta_get_split_table(lua_State *lua),
l_cf_ta_goto_window(lua_State *lua),
l_cf_view_goto_buffer(lua_State *lua),
@@ -71,16 +71,19 @@ static int l_cf_ta_buffer_new(lua_State *lua),
l_cf_ta_iconv(lua_State *lua),
l_cf_ta_reset(lua_State *lua),
l_cf_ta_quit(lua_State *lua),
- l_cf_pm_focus(lua_State *lua),
- l_cf_pm_clear(lua_State *lua),
l_cf_pm_activate(lua_State *lua),
l_cf_pm_add_browser(lua_State *lua),
+ l_cf_pm_clear(lua_State *lua),
+ l_cf_pm_fill(lua_State *lua),
+ l_cf_pm_focus(lua_State *lua),
+ l_cf_pm_show_context_menu(lua_State *lua),
l_cf_find_focus(lua_State *lua),
- l_cf_call_find_next(lua_State *lua),
- l_cf_call_find_prev(lua_State *lua),
- l_cf_call_replace(lua_State *lua),
- l_cf_call_replace_all(lua_State *lua),
- l_cf_ce_focus(lua_State *lua);
+ l_cf_find_next(lua_State *lua),
+ l_cf_find_prev(lua_State *lua),
+ l_cf_find_replace(lua_State *lua),
+ l_cf_find_replace_all(lua_State *lua),
+ l_cf_ce_focus(lua_State *lua),
+ l_cf_ce_show_completions(lua_State *lua);
/**
* Inits or re-inits the Lua State.
@@ -114,31 +117,34 @@ bool l_init(int argc, char **argv, bool reinit) {
lua_newtable(lua);
lua_newtable(lua);
- l_cfunc(lua, l_cf_pm_focus, "focus");
- l_cfunc(lua, l_cf_pm_clear, "clear");
l_cfunc(lua, l_cf_pm_activate, "activate");
l_cfunc(lua, l_cf_pm_add_browser, "add_browser");
+ l_cfunc(lua, l_cf_pm_clear, "clear");
+ l_cfunc(lua, l_cf_pm_fill, "fill");
+ l_cfunc(lua, l_cf_pm_focus, "focus");
+ l_cfunc(lua, l_cf_pm_show_context_menu, "show_context_menu");
l_mt(lua, "_pm_mt", l_pm_mt_index, l_pm_mt_newindex);
lua_setfield(lua, -2, "pm");
lua_newtable(lua);
+ l_cfunc(lua, l_cf_find_next, "find_next");
+ l_cfunc(lua, l_cf_find_prev, "find_prev");
l_cfunc(lua, l_cf_find_focus, "focus");
- l_cfunc(lua, l_cf_call_find_next, "call_find_next");
- l_cfunc(lua, l_cf_call_find_prev, "call_find_prev");
- l_cfunc(lua, l_cf_call_replace, "call_replace");
- l_cfunc(lua, l_cf_call_replace_all, "call_replace_all");
+ l_cfunc(lua, l_cf_find_replace, "replace");
+ l_cfunc(lua, l_cf_find_replace_all, "replace_all");
l_mt(lua, "_find_mt", l_find_mt_index, l_find_mt_newindex);
lua_setfield(lua, -2, "find");
lua_newtable(lua);
l_cfunc(lua, l_cf_ce_focus, "focus");
+ l_cfunc(lua, l_cf_ce_show_completions, "show_completions");
l_mt(lua, "_ce_mt", l_ce_mt_index, l_ce_mt_newindex);
lua_setfield(lua, -2, "command_entry");
- l_cfunc(lua, l_cf_ta_buffer_new, "new_buffer");
- l_cfunc(lua, l_cf_ta_goto_window, "goto_view");
l_cfunc(lua, l_cf_ta_get_split_table, "get_split_table");
+ l_cfunc(lua, l_cf_ta_goto_window, "goto_view");
l_cfunc(lua, l_cf_ta_gtkmenu, "gtkmenu");
l_cfunc(lua, l_cf_ta_iconv, "iconv");
- l_cfunc(lua, l_cf_ta_reset, "reset");
+ l_cfunc(lua, l_cf_ta_buffer_new, "new_buffer");
l_cfunc(lua, l_cf_ta_quit, "quit");
+ l_cfunc(lua, l_cf_ta_reset, "reset");
l_mt(lua, "_textadept_mt", l_ta_mt_index, l_ta_mt_newindex);
lua_setglobal(lua, "textadept");
@@ -272,9 +278,9 @@ void l_goto_scintilla_window(GtkWidget *editor, int n, bool absolute) {
lua_rawgeti(lua, -1, n);
}
editor = l_checkview(lua, -1);
- if (!closing) l_handle_event("view_before_switch");
+ if (!closing) l_handle_event("view_before_switch", -1);
gtk_widget_grab_focus(editor);
- if (!closing) l_handle_event("view_after_switch");
+ if (!closing) l_handle_event("view_after_switch", -1);
lua_pop(lua, 2); // view table and views
}
@@ -374,16 +380,6 @@ unsigned int l_get_docpointer_index(sptr_t doc) {
return idx;
}
-#define l_set_bufferp(k, v) { \
- lua_pushstring(lua, k); \
- lua_pushinteger(lua, v); \
- lua_rawset(lua, -3); \
-}
-#define l_get_bufferp(k, i) { \
- lua_pushstring(lua, k); \
- lua_rawget(lua, (i < 0) ? i - 1 : i); \
-}
-
/**
* Changes a Scintilla window's document to one in the global 'buffers' table.
* Before doing so, it saves the scroll and caret positions in the current
@@ -414,10 +410,10 @@ void l_goto_scintilla_buffer(GtkWidget *editor, int n, bool absolute) {
lua_rawgeti(lua, -1, n);
}
sptr_t doc = l_checkdocpointer(lua, -1);
- if (!closing) l_handle_event("buffer_before_switch");
+ if (!closing) l_handle_event("buffer_before_switch", -1);
SS(sci, SCI_SETDOCPOINTER, 0, doc);
l_set_buffer_global(sci);
- if (!closing) l_handle_event("buffer_after_switch");
+ if (!closing) l_handle_event("buffer_after_switch", -1);
lua_pop(lua, 2); // buffer table and buffers
}
@@ -509,13 +505,19 @@ bool l_ista2function(const char *table, const char *key) {
* values at the top of the stack. If false, discards the return values.
* Defaults to false.
*/
-bool l_call_function(int nargs, int retn=0, bool keep_return=false) {
+static bool l_call_function(int nargs, int retn=0, bool keep_return=false) {
int ret = lua_pcall(lua, nargs, retn, 0);
if (ret == 0) {
bool result = (retn > 0) ? lua_toboolean(lua, -1) == 1 : true;
if (retn > 0 && !keep_return) lua_pop(lua, retn); // retn
return result;
- } else l_handle_error(NULL);
+ } else {
+ if (focused_editor)
+ l_handle_event("error", LUA_TSTRING, lua_tostring(lua, -1), -1);
+ else
+ printf("Lua Error: %s\n", lua_tostring(lua, -1));
+ lua_settop(lua, 0);
+ }
return false;
}
@@ -637,47 +639,48 @@ static void l_check_focused_buffer(lua_State *lua, int narg) {
// Notification/event handlers
/**
- * Handles a Lua error.
- * The main error message is at the top of the Lua stack.
- * @param extramsg An additional error message to display.
- */
-void l_handle_error(const char *extramsg) {
- if (focused_editor && l_ista2function("events", "error")) {
- l_insert(lua, -1); // shift error message down
- if (extramsg) lua_pushstring(lua, extramsg);
- l_call_function(extramsg ? 2 : 1);
- } else {
- printf("Lua Error: %s\n", lua_tostring(lua, -1));
- if (extramsg) printf("%s\n", extramsg);
- }
- lua_settop(lua, 0);
-}
-
-/**
* Handles a Textadept event.
* @param s String event name.
- * @param arg Optional string argument.
- */
-bool l_handle_event(const char *s, const char *arg) {
- if (!l_ista2function("events", s)) return false;
- if (arg) lua_pushstring(lua, arg);
- return l_call_function(arg ? 1 : 0, 1);
-}
-
-/**
- * Handles a Textadept keypress.
- * @param keyval The key value of the key pressed.
- * @param shift Flag indicating whether or not the shift modifier was held.
- * @param control Flag indicating whether or not the control modifier was held.
- * @param alt Flag indicating whether or not the alt modifier was held.
+ * @param ... Optional arguments to pass to the handler. The variable argument
+ * list should contain Lua types followed by the data of that type to pass.
+ * The list is terminated by a -1.
*/
-bool l_handle_keypress(int keyval, bool shift, bool control, bool alt) {
- if (!l_ista2function("events", "keypress")) return false;
- lua_pushinteger(lua, keyval);
- lua_pushboolean(lua, shift);
- lua_pushboolean(lua, control);
- lua_pushboolean(lua, alt);
- return l_call_function(4, 1);
+bool l_handle_event(const char *s, ...) {
+ if (!l_ista2function("events", "handle")) return false;
+ lua_pushstring(lua, s);
+ int n = 1;
+ va_list ap;
+ va_start(ap, s);
+ int type = va_arg(ap, int);
+ while (type != -1) {
+ void *arg = va_arg(ap, void*);
+ switch(type) {
+ case LUA_TNIL:
+ lua_pushnil(lua);
+ break;
+ case LUA_TBOOLEAN:
+ lua_pushboolean(lua, reinterpret_cast<long>(arg));
+ break;
+ case LUA_TNUMBER:
+ lua_pushinteger(lua, reinterpret_cast<long>(arg));
+ break;
+ case LUA_TSTRING:
+ lua_pushstring(lua, reinterpret_cast<char*>(arg));
+ break;
+ case LUA_TLIGHTUSERDATA:
+ case LUA_TTABLE: {
+ long ref = reinterpret_cast<long>(arg);
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, ref);
+ luaL_unref(lua, LUA_REGISTRYINDEX, ref);
+ break;
+ } default:
+ warn("events.handle: ignored invalid argument type");
+ }
+ n++;
+ type = va_arg(ap, int);
+ }
+ va_end(ap);
+ return l_call_function(n, 1);
}
#define l_pushscninteger(i, n) { \
@@ -740,206 +743,52 @@ void l_ta_popup_context_menu(GdkEventButton *event) {
// Project Manager
/**
- * Creates and pushes a Lua table of parent nodes for the given Project Manager
- * treeview path.
+ * Creates a Lua table of parent nodes for the given Project Manager treeview
+ * path and returns a reference to it.
* The first table item is the PM Entry text, the next items are parents of the
* given node in descending order, and the last item is the given node itself.
+ * The reference can be retrieved using lua_rawgeti.
* @param store The GtkTreeStore of the PM view.
* @param path The GtkTreePath of the node. If NULL, only the PM Entry text is
* contained in the resulting table.
+ * @return int reference to the created table in LUA_REGISTRYINDEX.
*/
-void l_pushpathtable(GtkTreeStore *store, GtkTreePath *path) {
+int l_pm_pathtableref(GtkTreeStore *store, GtkTreePath *path) {
lua_newtable(lua);
lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(pm_entry)));
lua_rawseti(lua, -2, 1);
- if (!path) return;
- GtkTreeIter iter;
- while (gtk_tree_path_get_depth(path) > 0) {
- char *item = 0;
- gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
- gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 1, &item, -1);
- lua_pushstring(lua, item);
- lua_rawseti(lua, -2, gtk_tree_path_get_depth(path) + 1);
- g_free(item);
- gtk_tree_path_up(path);
- }
-}
-
-/**
- * Requests and adds contents to the Project Manager view.
- * @param store The GtkTreeStore of the PM view.
- * @param initial_iter An initial GtkTreeIter. If NULL, contents will be added
- * to the treeview root. Otherwise they will be added to this parent node.
- */
-void l_pm_view_fill(GtkTreeStore *store, GtkTreeIter *initial_iter) {
- if (!l_ista2function("pm", "get_contents_for")) return;
- if (initial_iter) {
- GtkTreePath *path =
- gtk_tree_model_get_path(GTK_TREE_MODEL(store), initial_iter);
- l_pushpathtable(store, path);
- gtk_tree_path_free(path);
- } else l_pushpathtable(store, NULL);
- lua_pushboolean(lua, initial_iter != NULL);
- l_call_function(2, 1, true);
- if (!lua_istable(lua, -1)) {
- if (!lua_isnil(lua, -1)) warn("pm.get_contents_for: table expected");
- lua_pop(lua, 1); // non-table return
- return;
- }
-
- if (!initial_iter) gtk_tree_store_clear(store);
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- if (lua_istable(lua, -1) && lua_type(lua, -2) == LUA_TSTRING) {
- GtkTreeIter iter, child;
- gtk_tree_store_append(store, &iter, initial_iter);
- gtk_tree_store_set(store, &iter, 1, lua_tostring(lua, -2), -1);
- lua_getfield(lua, -1, "parent");
- if (lua_toboolean(lua, -1)) {
- gtk_tree_store_append(store, &child, &iter);
- gtk_tree_store_set(store, &child, 1, "\0dummy", -1);
- }
- lua_pop(lua, 1); // parent
- lua_getfield(lua, -1, "pixbuf");
- if (lua_isstring(lua, -1))
- gtk_tree_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
- else if (!lua_isnil(lua, -1))
- warn("pm.fill: non-string pixbuf key ignored");
- lua_pop(lua, 1); // pixbuf
- lua_getfield(lua, -1, "text");
- gtk_tree_store_set(store, &iter, 2, lua_isstring(lua, -1) ?
- lua_tostring(lua, -1) : lua_tostring(lua, -3), -1);
- lua_pop(lua, 1); // display text
- } else warn("pm.fill: string id key must have table value");
- lua_pop(lua, 1); // value
+ if (path) {
+ GtkTreeIter iter;
+ while (gtk_tree_path_get_depth(path) > 0) {
+ char *item = 0;
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 1, &item, -1);
+ lua_pushstring(lua, item);
+ lua_rawseti(lua, -2, gtk_tree_path_get_depth(path) + 1);
+ g_free(item);
+ gtk_tree_path_up(path);
+ }
}
- lua_pop(lua, 1); // returned table
-
- l_handle_event("pm_view_filled");
+ return luaL_ref(lua, LUA_REGISTRYINDEX);
}
/**
- * Requests and pops up a context menu for a selected Project Manager item.
- * @param store The GtkTreeStore of the PM view.
- * @param path The GtkTreePath of the item.
+ * Requests a popup context menu for a selected Project Manager item.
* @param event The mouse button event.
- * @param callback The GCallback associated with each menu item.
- */
-void l_pm_popup_context_menu(GtkTreeStore *store, GtkTreePath *path,
- GdkEventButton *event, GCallback callback) {
- if (!l_ista2function("pm", "get_context_menu")) return;
- l_pushpathtable(store, path);
- l_call_function(1, 1, true);
- if (lua_istable(lua, -1)) {
- GtkWidget *menu = l_create_gtkmenu(lua, callback, false);
- gtk_widget_show_all(menu);
- gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
- event ? event->button : 0,
- gdk_event_get_time(reinterpret_cast<GdkEvent*>(event)));
- } else warn("pm.get_context_menu: table expected");
- lua_pop(lua, 1); // returned value
-}
-
-/**
- * Performs an action for the selected Project Manager item.
- * @param store The GtkTreeStore of the PM view.
- * @param path The GtkTreePath of the item.
- */
-void l_pm_perform_action(GtkTreeStore *store, GtkTreePath *path) {
- if (!l_ista2function("pm", "perform_action")) return;
- l_pushpathtable(store, path);
- l_call_function(1);
-}
-
-/**
- * Performs a selected menu action from a Project Manager item's context menu.
- * @param store The GtkTreeStore of the PM view.
- * @param path The GtkTreePath of the item.
- * @param id The numeric ID for the menu item.
- */
-void l_pm_perform_menu_action(GtkTreeStore *store, GtkTreePath *path, int id) {
- if (!l_ista2function("pm", "perform_menu_action")) return;
- lua_pushnumber(lua, id);
- l_pushpathtable(store, path);
- l_call_function(2);
-}
-
-// Find/Replace
-
-/**
- * Finds text in the current document.
- * @param ftext The text to find.
- * @param next Flag indicating whether or not to find next. If false, finds
- * previous matches.
- */
-void l_find(const char *ftext, bool next) {
- if (!l_ista2function("find", "find")) return;
- lua_pushstring(lua, ftext);
- lua_pushboolean(lua, next);
- l_call_function(2);
-}
-
-/**
- * Replaces text in the current document.
- * @param rtext The text to replace the found text with.
- */
-void l_find_replace(const char *rtext) {
- if (!l_ista2function("find", "replace")) return;
- lua_pushstring(lua, rtext);
- l_call_function(1);
-}
-
-/**
- * Replaces all found text in the current document.
- * @param ftext The text to find.
- * @param rtext The text to replace the found text with.
- */
-void l_find_replace_all(const char *ftext, const char *rtext) {
- if (!l_ista2function("find", "replace_all")) return;
- lua_pushstring(lua, ftext);
- lua_pushstring(lua, rtext);
- l_call_function(2);
-}
-
-// Command Entry
-
-/**
- * Executes a given command string as Lua code.
- * @param command Lua code to execute.
- */
-void l_ce_command(const char *command) {
- int top = lua_gettop(lua);
- if (luaL_dostring(lua, command) == 0) {
- l_handle_event("update_ui");
- lua_settop(lua, top);
- } else l_handle_error("Error executing command");
-}
-
-/**
- * Requests and adds completions for the Command Entry Completion.
- * @param store The GtkListStore to populate.
*/
-void l_cec_fill(GtkListStore *store) {
- if (!l_ista2function("command_entry", "get_completions_for")) return;
- lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(command_entry)));
- l_call_function(1, 1, true);
- if (!lua_istable(lua, -1)) {
- if (!lua_isnil(lua, -1)) warn("ce.get_completions_for: table expected");
- lua_pop(lua, 1); // non-table return
- return;
- }
-
- gtk_list_store_clear(store);
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- if (lua_type(lua, -1) == LUA_TSTRING) {
- GtkTreeIter iter;
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
- } else warn("ce.get_completions_for: non-string value ignored");
- lua_pop(lua, 1); // value
- }
- lua_pop(lua, 1); // returned table
+void l_pm_popup_context_menu(GdkEventButton *event) {
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view));
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view));
+ if (gtk_tree_selection_get_selected(sel, NULL, &iter))
+ path = gtk_tree_model_get_path(model, &iter);
+ lua_pushlightuserdata(lua, const_cast<GdkEventButton*>(event));
+ int ref = luaL_ref(lua, LUA_REGISTRYINDEX);
+ l_handle_event("pm_context_menu_request", LUA_TTABLE,
+ l_pm_pathtableref(GTK_TREE_STORE(model), path),
+ LUA_TLIGHTUSERDATA, ref, -1);
+ if (path) gtk_tree_path_free(path);
}
// Lua functions (stack maintenence is unnecessary)
@@ -1308,13 +1157,6 @@ static int l_ce_mt_newindex(lua_State *lua) {
// Lua CFunctions. For documentation, consult the LuaDoc.
-static int l_cf_ta_buffer_new(lua_State *lua) {
- new_scintilla_buffer(SCINTILLA(focused_editor), true, true);
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_rawgeti(lua, -1, lua_objlen(lua, -1));
- return 1;
-}
-
static int l_cf_buffer_delete(lua_State *lua) {
l_check_focused_buffer(lua, 1);
sptr_t doc = l_checkdocpointer(lua, 1);
@@ -1324,10 +1166,17 @@ static int l_cf_buffer_delete(lua_State *lua) {
else
new_scintilla_buffer(SCINTILLA(focused_editor), true, true);
remove_scintilla_buffer(doc);
- l_handle_event("buffer_deleted");
+ l_handle_event("buffer_deleted", -1);
return 0;
}
+static int l_cf_ta_buffer_new(lua_State *lua) {
+ new_scintilla_buffer(SCINTILLA(focused_editor), true, true);
+ lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
+ lua_rawgeti(lua, -1, lua_objlen(lua, -1));
+ return 1;
+}
+
static int l_cf_buffer_text_range(lua_State *lua) {
l_check_focused_buffer(lua, 1);
#ifndef MAC
@@ -1414,10 +1263,6 @@ static int l_cf_ta_goto_(lua_State *lua, GtkWidget *editor, bool buffer) {
return 0;
}
-static int l_cf_ta_goto_window(lua_State *lua) {
- return l_cf_ta_goto_(lua, focused_editor, false);
-}
-
// If the indexed view is not currently focused, temporarily focus it so calls
// to handlers will not throw 'indexed buffer is not the focused one' error.
static int l_cf_view_goto_buffer(lua_State *lua) {
@@ -1434,12 +1279,12 @@ static int l_cf_view_goto_buffer(lua_State *lua) {
return 0;
}
+static int l_cf_ta_goto_window(lua_State *lua) {
+ return l_cf_ta_goto_(lua, focused_editor, false);
+}
+
static void t_menu_activate(GtkWidget *, gpointer id) {
- int menu_id = GPOINTER_TO_INT(id);
- char *menu_id_str = static_cast<char*>(malloc(sizeof(char) * 12));
- sprintf(menu_id_str, "%i", menu_id);
- l_handle_event("menu_clicked", menu_id_str);
- g_free(menu_id_str);
+ l_handle_event("menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id), -1);
}
static int l_cf_ta_gtkmenu(lua_State *lua) {
@@ -1462,8 +1307,17 @@ static int l_cf_ta_iconv(lua_State *lua) {
return 1;
}
+static int l_cf_ta_quit(lua_State *) {
+ GdkEventAny event;
+ event.type = GDK_DELETE;
+ event.window = window->window;
+ event.send_event = TRUE;
+ gdk_event_put(reinterpret_cast<GdkEvent*>(&event));
+ return 0;
+}
+
static int l_cf_ta_reset(lua_State *lua) {
- l_handle_event("resetting");
+ l_handle_event("resetting", -1);
l_init(0, NULL, true);
lua_pushboolean(lua, true);
lua_setglobal(lua, "RESETTING");
@@ -1475,17 +1329,14 @@ static int l_cf_ta_reset(lua_State *lua) {
return 0;
}
-static int l_cf_ta_quit(lua_State *) {
- GdkEventAny event;
- event.type = GDK_DELETE;
- event.window = window->window;
- event.send_event = TRUE;
- gdk_event_put(reinterpret_cast<GdkEvent*>(&event));
+static int l_cf_pm_activate(lua_State *) {
+ g_signal_emit_by_name(G_OBJECT(pm_entry), "activate");
return 0;
}
-static int l_cf_pm_focus(lua_State *) {
- pm_toggle_focus();
+static int l_cf_pm_add_browser(lua_State *lua) {
+ GtkWidget *pm_combo = gtk_widget_get_parent(pm_entry);
+ gtk_combo_box_append_text(GTK_COMBO_BOX(pm_combo), lua_tostring(lua, -1));
return 0;
}
@@ -1495,14 +1346,83 @@ static int l_cf_pm_clear(lua_State *) {
return 0;
}
-static int l_cf_pm_activate(lua_State *) {
- g_signal_emit_by_name(G_OBJECT(pm_entry), "activate");
+static int l_cf_pm_fill(lua_State *lua) {
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view));
+ GtkTreeStore *store = GTK_TREE_STORE(model);
+ GtkTreeIter initial_iter, *initial_iter_p = NULL;
+ if (lua_gettop(lua) > 1 && lua_type(lua, 2) == LUA_TSTRING &&
+ gtk_tree_model_get_iter_from_string(model, &initial_iter,
+ lua_tostring(lua, 2)))
+ initial_iter_p = &initial_iter;
+ if (!initial_iter_p) gtk_tree_store_clear(store);
+ GtkTreeIter iter, child;
+ lua_pushnil(lua);
+ while (lua_next(lua, 1)) {
+ if (lua_istable(lua, -1) && lua_type(lua, -2) == LUA_TSTRING) {
+ gtk_tree_store_append(store, &iter, initial_iter_p);
+ gtk_tree_store_set(store, &iter, 1, lua_tostring(lua, -2), -1);
+ lua_getfield(lua, -1, "parent");
+ if (lua_toboolean(lua, -1)) {
+ gtk_tree_store_append(store, &child, &iter);
+ gtk_tree_store_set(store, &child, 1, "\0dummy", -1);
+ }
+ lua_pop(lua, 1); // parent
+ lua_getfield(lua, -1, "pixbuf");
+ if (lua_isstring(lua, -1))
+ gtk_tree_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
+ else if (!lua_isnil(lua, -1))
+ warn("pm.fill: non-string pixbuf key ignored");
+ lua_pop(lua, 1); // pixbuf
+ lua_getfield(lua, -1, "text");
+ gtk_tree_store_set(store, &iter, 2, lua_isstring(lua, -1) ?
+ lua_tostring(lua, -1) : lua_tostring(lua, -3), -1);
+ lua_pop(lua, 1); // display text
+ } else warn("pm.fill: string id key must have table value");
+ lua_pop(lua, 1); // value
+ }
+ if (initial_iter_p) {
+ char *item;
+ gtk_tree_model_iter_nth_child(model, &child, initial_iter_p, 0);
+ gtk_tree_model_get(model, &child, 1, &item, -1);
+ if (strcmp(reinterpret_cast<const char*>(item), "\0dummy") == 0)
+ gtk_tree_store_remove(store, &child);
+ g_free(item);
+ }
return 0;
}
-static int l_cf_pm_add_browser(lua_State *lua) {
- GtkWidget *pm_combo = gtk_widget_get_parent(pm_entry);
- gtk_combo_box_append_text(GTK_COMBO_BOX(pm_combo), lua_tostring(lua, -1));
+static void pm_menu_activate(GtkWidget *, gpointer id) {
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view));
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view));
+ if (gtk_tree_selection_get_selected(sel, NULL, &iter))
+ path = gtk_tree_model_get_path(model, &iter);
+ l_handle_event("pm_menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id),
+ LUA_TTABLE, l_pm_pathtableref(GTK_TREE_STORE(model), path),
+ -1);
+ if (path) gtk_tree_path_free(path);
+}
+
+static int l_cf_pm_show_context_menu(lua_State *lua) {
+ GdkEventButton *event = NULL;
+ if (lua_gettop(lua) > 1) {
+ if (lua_isuserdata(lua, 2))
+ event = reinterpret_cast<GdkEventButton*>(lua_touserdata(lua, 2));
+ lua_pop(lua, 1); // userdata
+ }
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ GtkWidget *menu = l_create_gtkmenu(lua, G_CALLBACK(pm_menu_activate), false);
+ gtk_widget_show_all(menu);
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+ event ? event->button : 0,
+ gdk_event_get_time(reinterpret_cast<GdkEvent*>(event)));
+ return 0;
+}
+
+static int l_cf_pm_focus(lua_State *) {
+ pm_toggle_focus();
return 0;
}
@@ -1511,22 +1431,22 @@ static int l_cf_find_focus(lua_State *) {
return 0;
}
-static int l_cf_call_find_next(lua_State *) {
+static int l_cf_find_next(lua_State *) {
g_signal_emit_by_name(G_OBJECT(fnext_button), "clicked");
return 0;
}
-static int l_cf_call_find_prev(lua_State *) {
+static int l_cf_find_prev(lua_State *) {
g_signal_emit_by_name(G_OBJECT(fprev_button), "clicked");
return 0;
}
-static int l_cf_call_replace(lua_State *) {
+static int l_cf_find_replace(lua_State *) {
g_signal_emit_by_name(G_OBJECT(r_button), "clicked");
return 0;
}
-static int l_cf_call_replace_all(lua_State *) {
+static int l_cf_find_replace_all(lua_State *) {
g_signal_emit_by_name(G_OBJECT(ra_button), "clicked");
return 0;
}
@@ -1535,3 +1455,23 @@ static int l_cf_ce_focus(lua_State *) {
ce_toggle_focus();
return 0;
}
+
+static int l_cf_ce_show_completions(lua_State *lua) {
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ 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);
+ lua_pushnil(lua);
+ while (lua_next(lua, 1)) {
+ if (lua_type(lua, -1) == LUA_TSTRING) {
+ GtkTreeIter iter;
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
+ } else warn("command_entry.show_completions: non-string value ignored");
+ lua_pop(lua, 1); // value
+ }
+ gtk_entry_completion_complete(completion);
+ return 0;
+}
diff --git a/src/textadept.c b/src/textadept.c
index c0615351..cec9cb3c 100644
--- a/src/textadept.c
+++ b/src/textadept.c
@@ -42,7 +42,7 @@ static int pm_sort_iter_compare_func(GtkTreeModel *model, GtkTreeIter *a,
static void pm_entry_activated(GtkWidget *, gpointer);
static void pm_entry_changed(GtkComboBoxEntry *, gpointer);
static gbool pm_keypress(GtkWidget *, GdkEventKey *event, gpointer);
-static void pm_row_expanded(GtkTreeView *, GtkTreeIter *iter, GtkTreePath *,
+static void pm_row_expanded(GtkTreeView *, GtkTreeIter *, GtkTreePath *path,
gpointer);
static void pm_row_collapsed(GtkTreeView *, GtkTreeIter *iter, GtkTreePath *,
gpointer);
@@ -50,7 +50,6 @@ static void pm_row_activated(GtkTreeView *view, GtkTreePath *path,
GtkTreeViewColumn *, gpointer);
static gbool pm_buttonpress(GtkTreeView *, GdkEventButton *event, gpointer);
static gbool pm_popup_menu(GtkWidget *, gpointer);
-static void pm_menu_activate(GtkWidget *, gpointer id);
// Find/Replace
GtkWidget *findbox, *find_entry, *replace_entry, *fnext_button, *fprev_button,
@@ -60,6 +59,7 @@ GtkWidget *find_create_ui();
GtkListStore *find_store, *repl_store;
static void find_button_clicked(GtkWidget *button, gpointer);
+static gbool find_entry_keypress(GtkWidget *, GdkEventKey *event, gpointer);
// Command Entry
GtkWidget *command_entry;
@@ -245,7 +245,7 @@ GtkWidget *new_scintilla_window(sptr_t buffer_id) {
new_scintilla_buffer(SCINTILLA(editor), false, false);
} else new_scintilla_buffer(SCINTILLA(editor), false, true);
l_set_view_global(editor);
- l_handle_event("view_new");
+ l_handle_event("view_new", -1);
return editor;
}
@@ -287,8 +287,8 @@ void new_scintilla_buffer(ScintillaObject *sci, bool create, bool addref) {
SS(sci, SCI_ADDREFDOCUMENT, 0, doc);
}
l_set_buffer_global(sci);
- l_handle_event("buffer_new");
- l_handle_event("update_ui"); // update document status
+ l_handle_event("buffer_new", -1);
+ l_handle_event("update_ui", -1); // update document status
}
/**
@@ -422,11 +422,11 @@ void set_statusbar_text(const char *text, bool docbar) {
* @see s_command
*/
static void switch_to_view(GtkWidget *editor) {
- l_handle_event("view_before_switch");
+ l_handle_event("view_before_switch", -1);
focused_editor = editor;
l_set_view_global(editor);
l_set_buffer_global(SCINTILLA(editor));
- l_handle_event("view_after_switch");
+ l_handle_event("view_after_switch", -1);
}
/**
@@ -451,17 +451,18 @@ static void s_command(GtkWidget *editor, gint wParam, gpointer, gpointer) {
/**
* Signal for a Scintilla keypress.
* Collects the modifier states as flags and calls Lua to handle the keypress.
- * @see l_handle_keypress
*/
static gbool s_keypress(GtkWidget *, GdkEventKey *event, gpointer) {
- bool shift = event->state & GDK_SHIFT_MASK;
- bool control = event->state & GDK_CONTROL_MASK;
+ return l_handle_event("keypress",
+ LUA_TNUMBER, event->keyval,
+ LUA_TBOOLEAN, event->state & GDK_SHIFT_MASK,
+ LUA_TBOOLEAN, event->state & GDK_CONTROL_MASK,
#ifndef MAC
- bool alt = event->state & GDK_MOD1_MASK;
+ LUA_TBOOLEAN, event->state & GDK_MOD1_MASK,
#else
- bool alt = event->state & GDK_META_MASK;
+ LUA_TBOOLEAN, event->state & GDK_META_MASK,
#endif
- return l_handle_keypress(event->keyval, shift, control, alt) ? TRUE : FALSE;
+ -1) ? TRUE : FALSE;
}
/**
@@ -505,7 +506,7 @@ static gbool w_keypress(GtkWidget *, GdkEventKey *event, gpointer) {
* @see l_close
*/
static gbool w_exit(GtkWidget *, GdkEventAny *, gpointer) {
- if (!l_handle_event("quit")) return TRUE;
+ if (!l_handle_event("quit", -1)) return TRUE;
l_close();
scintilla_release_resources();
gtk_main_quit();
@@ -516,7 +517,6 @@ static gbool w_exit(GtkWidget *, GdkEventAny *, gpointer) {
/**
* Signal for an Open Document AppleEvent.
* Generates a 'appleevent_odoc' event for each document sent.
- * @see l_handle_event
*/
static OSErr w_ae_open(const AppleEvent *event, AppleEvent *, long) {
AEDescList file_list;
@@ -529,7 +529,7 @@ static OSErr w_ae_open(const AppleEvent *event, AppleEvent *, long) {
NULL);
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsref);
if (url) {
- l_handle_event("appleevent_odoc", CFURL_TO_STR(url));
+ l_handle_event("appleevent_odoc", LUA_TSTRING, CFURL_TO_STR(url), -1);
CFRelease(url);
}
}
@@ -657,19 +657,19 @@ static int pm_sort_iter_compare_func(GtkTreeModel *model, GtkTreeIter *a,
/**
* Signal for the activation of the Project Manager entry.
* Requests contents for the Project Manager.
- * @see l_pm_view_fill
*/
static void pm_entry_activated(GtkWidget *, gpointer) {
- l_pm_view_fill(pm_store, NULL);
+ l_handle_event("pm_contents_request", LUA_TTABLE,
+ l_pm_pathtableref(pm_store, NULL), LUA_TNIL, 0, -1);
}
/**
* Signal for a change of the text in the Project Manager entry.
* Requests contents for the Project Manager.
- * @see l_pm_view_fill
*/
static void pm_entry_changed(GtkComboBoxEntry *, gpointer) {
- l_pm_view_fill(pm_store, NULL);
+ l_handle_event("pm_contents_request", LUA_TTABLE,
+ l_pm_pathtableref(pm_store, NULL), LUA_TNIL, 0, -1);
}
/**
@@ -689,18 +689,13 @@ static gbool pm_keypress(GtkWidget *, GdkEventKey *event, gpointer) {
* Requests contents for a Project Manager parent node being opened.
* Since a parent is given a dummy child by default in order to indicate that
* it is a parent, that dummy child is removed.
- * @see l_pm_view_fill
*/
-static void pm_row_expanded(GtkTreeView *, GtkTreeIter *iter, GtkTreePath *,
+static void pm_row_expanded(GtkTreeView *, GtkTreeIter *, GtkTreePath *path,
gpointer) {
- l_pm_view_fill(pm_store, iter);
- GtkTreeIter child;
- char *item;
- gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(pm_store), &child, iter, 0);
- gtk_tree_model_get(GTK_TREE_MODEL(pm_store), &child, 1, &item, -1);
- if (strcmp(reinterpret_cast<const char*>(item), "\0dummy") == 0)
- gtk_tree_store_remove(pm_store, &child);
- g_free(item);
+ char *path_str = gtk_tree_path_to_string(path);
+ l_handle_event("pm_contents_request", LUA_TTABLE,
+ l_pm_pathtableref(pm_store, path), LUA_TSTRING, path_str, -1);
+ g_free(path_str);
}
/**
@@ -724,27 +719,13 @@ static void pm_row_collapsed(GtkTreeView *, GtkTreeIter *iter, GtkTreePath *,
* Performs the appropriate action on a selected Project Manager node.
* If the node is a collapsed parent, it is expanded; otherwise the parent is
* collapsed. If the node is not a parent at all, a Lua action is performed.
- * @see l_pm_perform_action
*/
static void pm_row_activated(GtkTreeView *view, GtkTreePath *path,
GtkTreeViewColumn *, gpointer) {
if (!gtk_tree_view_expand_row(view, path, FALSE))
if (!gtk_tree_view_collapse_row(view, path))
- l_pm_perform_action(pm_store, path);
-}
-
-/**
- * Helper function to return the path of the selected Project Manager view item
- * (if any).
- * The returned GtkTreePath must be freed if it is not NULL.
- */
-static GtkTreePath *pm_view_get_selection_path() {
- GtkTreeIter iter;
- GtkTreePath *path = 0;
- GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view));
- if (gtk_tree_selection_get_selected(sel, NULL, &iter))
- path = gtk_tree_model_get_path(GTK_TREE_MODEL(pm_store), &iter);
- return path;
+ l_handle_event("pm_item_selected", LUA_TTABLE,
+ l_pm_pathtableref(pm_store, path), -1);
}
/**
@@ -754,9 +735,7 @@ static GtkTreePath *pm_view_get_selection_path() {
*/
static gbool pm_buttonpress(GtkTreeView *, GdkEventButton *event, gpointer) {
if (event->type != GDK_BUTTON_PRESS || event->button != 3) return FALSE;
- GtkTreePath *path = pm_view_get_selection_path();
- l_pm_popup_context_menu(pm_store, path, event, G_CALLBACK(pm_menu_activate));
- if (path) gtk_tree_path_free(path);
+ l_pm_popup_context_menu(event);
return TRUE;
}
@@ -766,24 +745,10 @@ static gbool pm_buttonpress(GtkTreeView *, GdkEventButton *event, gpointer) {
* @see l_pm_popup_context_menu
*/
static gbool pm_popup_menu(GtkWidget *, gpointer) {
- GtkTreePath *path = pm_view_get_selection_path();
- l_pm_popup_context_menu(pm_store, path, NULL, G_CALLBACK(pm_menu_activate));
- if (path) gtk_tree_path_free(path);
+ l_pm_popup_context_menu(NULL);
return TRUE;
}
-/**
- * Signal for a selected Project Manager menu item.
- * Performs a Lua action for a selected menu item.
- * @param id The numeric ID for the menu item.
- * @see l_pm_perform_menu_action
- */
-static void pm_menu_activate(GtkWidget *, gpointer id) {
- GtkTreePath *path = pm_view_get_selection_path();
- l_pm_perform_menu_action(pm_store, path, GPOINTER_TO_INT(id));
- if (path) gtk_tree_path_free(path);
-}
-
// Find/Replace
#define attach(w, x1, x2, y1, y2, xo, yo, xp, yp) \
@@ -840,6 +805,7 @@ GtkWidget *find_create_ui() {
attach(lua_opt, 5, 6, 0, 1, ao_normal, ao_normal, 5, 0);
attach(in_files_opt, 5, 6, 1, 2, ao_normal, ao_normal, 5, 0);
+ signal(find_entry, "key-press-event", find_entry_keypress);
signal(fnext_button, "clicked", find_button_clicked);
signal(fprev_button, "clicked", find_button_clicked);
signal(r_button, "clicked", find_button_clicked);
@@ -906,20 +872,30 @@ static void find_button_clicked(GtkWidget *button, gpointer) {
if (strlen(find_text) == 0) return;
if (button == fnext_button || button == fprev_button) {
find_add_to_history(find_text, find_store);
- l_find(find_text, button == fnext_button);
+ l_handle_event("find", LUA_TSTRING, find_text, LUA_TBOOLEAN,
+ button == fnext_button, -1);
} else {
find_add_to_history(repl_text, repl_store);
if (button == r_button) {
- l_find_replace(repl_text);
- l_find(find_text, true);
- } else l_find_replace_all(find_text, repl_text);
+ l_handle_event("replace", LUA_TSTRING, repl_text, -1);
+ l_handle_event("find", LUA_TSTRING, find_text, LUA_TBOOLEAN, 1, -1);
+ } else
+ l_handle_event("replace_all", LUA_TSTRING, find_text, LUA_TSTRING,
+ repl_text, -1);
}
}
+/**
+ * Signal for a Find entry keypress.
+ */
+static gbool find_entry_keypress(GtkWidget *, GdkEventKey *event, gpointer) {
+ return l_handle_event("find_keypress", LUA_TNUMBER, event->keyval, -1);
+}
+
// Command Entry
/**
- * Toggles focus between a Scintilla window and the Lua command entry.
+ * Toggles focus between a Scintilla window and the Command Entry.
* When the entry is visible, the statusbars are temporarily hidden.
*/
void ce_toggle_focus() {
@@ -977,30 +953,18 @@ static gbool cec_match_selected(GtkEntryCompletion *, GtkTreeModel *model,
// Signals
/**
- * Signal for the 'enter' key being pressed in the Lua command entry.
- * Evaluates the input text as Lua code.
+ * Signal for the 'enter' key being pressed in the Command Entry.
*/
static void c_activated(GtkWidget *widget, gpointer) {
- l_ce_command(gtk_entry_get_text(GTK_ENTRY(widget)));
+ l_handle_event("command_entry_command", LUA_TSTRING,
+ gtk_entry_get_text(GTK_ENTRY(widget)), -1);
ce_toggle_focus();
}
/**
- * Signal for a keypress inside the Lua command entry.
- * Currently handled keypresses:
- * - Escape - Hide the completion buffer if it is open.
- * - Tab - Display possible completions.
+ * Signal for a keypress inside the Command Entry.
*/
static gbool c_keypress(GtkWidget *, GdkEventKey *event, gpointer) {
- if (event->state == 0)
- switch(event->keyval) {
- case 0xff1b:
- ce_toggle_focus();
- return TRUE;
- case 0xff09:
- l_cec_fill(cec_store);
- gtk_entry_completion_complete(command_entry_completion);
- return TRUE;
- }
- return FALSE;
+ return l_handle_event("command_entry_keypress", LUA_TNUMBER, event->keyval,
+ -1);
}
diff --git a/src/textadept.h b/src/textadept.h
index 666c361d..73064fdf 100644
--- a/src/textadept.h
+++ b/src/textadept.h
@@ -3,6 +3,7 @@
#ifndef TEXTADEPT_H
#define TEXTADEPT_H
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -62,23 +63,11 @@ void l_remove_scintilla_buffer(sptr_t doc);
void l_goto_scintilla_buffer(GtkWidget *editor, int n, bool absolute);
void l_set_buffer_global(ScintillaObject *sci);
-void l_handle_error(const char *errmsg);
-bool l_handle_event(const char *e, const char *arg=NULL);
-bool l_handle_keypress(int keyval, bool shift, bool control, bool alt);
+bool l_handle_event(const char *e, ...);
void l_handle_scnnotification(SCNotification *n);
void l_ta_popup_context_menu(GdkEventButton *event);
-void l_pm_view_fill(GtkTreeStore *store, GtkTreeIter *initial_iter);
-void l_pm_perform_action(GtkTreeStore *store, GtkTreePath *path);
-void l_pm_popup_context_menu(GtkTreeStore *store, GtkTreePath *path,
- GdkEventButton *event, GCallback callback);
-void l_pm_perform_menu_action(GtkTreeStore *store, GtkTreePath *path, int id);
-
-void l_find(const char *ftext, bool next);
-void l_find_replace(const char *rtext);
-void l_find_replace_all(const char *ftext, const char *rtext);
-
-void l_ce_command(const char *command);
-void l_cec_fill(GtkListStore *store);
+int l_pm_pathtableref(GtkTreeStore *store, GtkTreePath *path);
+void l_pm_popup_context_menu(GdkEventButton *event);
#endif