aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/textadept.c2344
1 files changed, 1072 insertions, 1272 deletions
diff --git a/src/textadept.c b/src/textadept.c
index cd3611cc..a1fdfc9e 100644
--- a/src/textadept.c
+++ b/src/textadept.c
@@ -7,14 +7,14 @@
#include <gtk/gtk.h>
#define PLAT_GTK 1
-#include <Scintilla.h>
-#include <SciLexer.h>
-#include <ScintillaWidget.h>
+#include "Scintilla.h"
+#include "SciLexer.h"
+#include "ScintillaWidget.h"
-#include <gcocoadialog.h>
-#include <lua.h>
-#include <lualib.h>
-#include <lauxlib.h>
+#include "gcocoadialog.h"
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
#if __WIN32__
#include <windows.h>
@@ -29,38 +29,15 @@
#include <sys/sysctl.h>
#endif
-#define gbool gboolean
#define SS(view, m, w, l) scintilla_send_message(SCINTILLA(view), m, w, l)
#define signal(o, s, c) g_signal_connect(G_OBJECT(o), s, G_CALLBACK(c), 0)
-#define streq(s1, s2) strcmp(s1, s2) == 0
-#define l_append(l, i) lua_rawseti(l, i, lua_objlen(l, i) + 1)
-#define l_cfunc(l, f, k) { \
- lua_pushcfunction(l, f); \
- lua_setfield(l, -2, k); \
-}
-#define l_emit_event_key(name, event) \
- l_emit_event(name, LUA_TNUMBER, event->keyval, LUA_TBOOLEAN, \
- event->state & GDK_SHIFT_MASK, LUA_TBOOLEAN, \
- event->state & GDK_CONTROL_MASK, LUA_TBOOLEAN, \
- event->state & GDK_MOD1_MASK, LUA_TBOOLEAN, \
- event->state & GDK_MOD5_MASK, -1)
-#define l_mt(l, k, i, ni) { \
- if (luaL_newmetatable(l, k)) { \
- l_cfunc(l, i, "__index"); \
- l_cfunc(l, ni, "__newindex"); \
- } \
- lua_setmetatable(l, -2); \
-}
-#define l_togtkwidget(l, i) (GtkWidget *)lua_touserdata(l, i)
// Defines for different GTK versions.
#if !(GTK_CHECK_VERSION(2,18,0) || GTK_CHECK_VERSION(3,0,0))
#define gtk_widget_set_can_default(w,_) GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT)
#define gtk_widget_set_can_focus(w,_) GTK_WIDGET_UNSET_FLAGS(w, GTK_CAN_FOCUS)
-#define gtk_widget_get_allocation(e, a) { \
- (a)->width = e->allocation.width; \
- (a)->height = e->allocation.height; \
-}
+#define gtk_widget_get_allocation(e, a) \
+ ((a)->width = e->allocation.width, (a)->height = e->allocation.height)
#define gtk_widget_has_focus GTK_WIDGET_HAS_FOCUS
#define gtk_widget_get_visible GTK_WIDGET_VISIBLE
#define gtk_widget_get_window(w) w->window
@@ -79,20 +56,18 @@
// Window
GtkWidget *window, *focused_view, *menubar, *statusbar[2];
-GtkAccelGroup *accel = 0;
+GtkAccelGroup *accel;
char *textadept_home;
-
-void create_ui();
-GtkWidget *new_view(sptr_t);
-void new_buffer(GtkWidget *, int, int);
-
-static void s_notification(GtkWidget *, gint, gpointer, gpointer);
+static void new_window();
+static GtkWidget *new_view(sptr_t);
+static void new_buffer(sptr_t);
+static void s_notify(GtkWidget *, gint, gpointer, gpointer);
static void s_command(GtkWidget *, gint, gpointer, gpointer);
-static gbool s_keypress(GtkWidget *, GdkEventKey *, gpointer);
-static gbool s_buttonpress(GtkWidget *, GdkEventButton *, gpointer);
-static gbool w_focus(GtkWidget *, GdkEventFocus *, gpointer);
-static gbool w_keypress(GtkWidget *, GdkEventKey *, gpointer);
-static gbool w_exit(GtkWidget *, GdkEventAny *, gpointer);
+static gboolean s_keypress(GtkWidget *, GdkEventKey *, gpointer);
+static gboolean s_buttonpress(GtkWidget *, GdkEventButton *, gpointer);
+static gboolean w_focus(GtkWidget *, GdkEventFocus *, gpointer);
+static gboolean w_keypress(GtkWidget *, GdkEventKey *, gpointer);
+static gboolean w_exit(GtkWidget *, GdkEventAny *, gpointer);
#if __OSX__
static OSErr w_ae_open(const AppleEvent *, AppleEvent *, long);
static OSErr w_ae_quit(const AppleEvent *, AppleEvent *, long);
@@ -102,22 +77,20 @@ static OSErr w_ae_quit(const AppleEvent *, AppleEvent *, long);
GtkWidget *findbox, *find_entry, *replace_entry, *fnext_button, *fprev_button,
*r_button, *ra_button, *match_case_opt, *whole_word_opt, *lua_opt,
*in_files_opt, *flabel, *rlabel;
-GtkWidget *find_create_ui();
GtkListStore *find_store, *repl_store;
-
-static void find_button_clicked(GtkWidget *, gpointer);
+static GtkWidget *new_findbox();
+static void f_clicked(GtkWidget *, gpointer);
// Command Entry
GtkWidget *command_entry;
GtkListStore *cc_store;
GtkEntryCompletion *command_entry_completion;
-
-static int cc_match_func(GtkEntryCompletion *, const char *, GtkTreeIter *,
- gpointer);
-static gbool cc_match_selected(GtkEntryCompletion *, GtkTreeModel *,
- GtkTreeIter *, gpointer);
-static void c_activated(GtkWidget *, gpointer);
-static gbool c_keypress(GtkWidget *, GdkEventKey *, gpointer);
+static int cc_matchfunc(GtkEntryCompletion *, const char *, GtkTreeIter *,
+ gpointer);
+static gboolean cc_matchselected(GtkEntryCompletion *, GtkTreeModel *,
+ GtkTreeIter *, gpointer);
+static void c_activate(GtkWidget *, gpointer);
+static gboolean c_keypress(GtkWidget *, GdkEventKey *, gpointer);
// Lua
lua_State *lua;
@@ -125,42 +98,40 @@ int closing = FALSE;
char *statusbar_text = 0;
static int tVOID = 0, tINT = 1, tLENGTH = 2, /*tPOSITION = 3, tCOLOUR = 4,*/
tBOOL = 5, tKEYMOD = 6, tSTRING = 7, tSTRINGRESULT = 8;
-
-int l_init(int, char **, int);
-void l_close();
-int l_load_script(const char *);
-void l_add_view(GtkWidget *);
-void l_remove_view(GtkWidget *);
-void l_set_view_global(GtkWidget *);
-int l_add_buffer(sptr_t);
-void l_remove_buffer(sptr_t);
-void l_goto_buffer(GtkWidget *, int, int);
-void l_set_buffer_global(GtkWidget *);
-int l_emit_event(const char *, ...);
-void l_emit_scnotification(struct SCNotification *);
-void l_gui_popup_context_menu(GdkEventButton *);
-// Extra Lua libraries.
-LUALIB_API int (luaopen_lpeg) (lua_State *L);
-LUALIB_API int (luaopen_lfs) (lua_State *L);
-
-static void clear_table(lua_State *, int);
-static int l_buffer_mt_index(lua_State *), l_buffer_mt_newindex(lua_State *),
- l_bufferp_mt_index(lua_State *), l_bufferp_mt_newindex(lua_State *),
- l_view_mt_index(lua_State *), l_view_mt_newindex(lua_State *),
- l_gui_mt_index(lua_State *), l_gui_mt_newindex(lua_State *),
- l_find_mt_index(lua_State *), l_find_mt_newindex(lua_State *),
- l_ce_mt_index(lua_State *), l_ce_mt_newindex(lua_State *);
-static int l_cf_buffer_delete(lua_State *), l_cf_buffer_text_range(lua_State *),
- l_cf_view_focus(lua_State *), l_cf_view_split(lua_State *),
- l_cf_view_unsplit(lua_State *), l_cf_buffer_new(lua_State *),
- l_cf_gui_dialog(lua_State *), l_cf_gui_get_split_table(lua_State *),
- l_cf_gui_goto_view(lua_State *), l_cf_view_goto_buffer(lua_State *),
- l_cf_gui_gtkmenu(lua_State *), l_cf_string_iconv(lua_State *),
- l_cf_reset(lua_State *), l_cf_quit(lua_State *),
- l_cf_find_focus(lua_State *), l_cf_find_next(lua_State *),
- l_cf_find_prev(lua_State *), l_cf_find_replace(lua_State *),
- l_cf_find_replace_all(lua_State *), l_cf_ce_focus(lua_State *),
- l_cf_ce_show_completions(lua_State *), l_cf_timeout(lua_State *);
+static int lL_init(lua_State *, int, char **, int);
+static void l_close(lua_State *);
+static int lL_dofile(lua_State *, const char *);
+static void lL_addview(lua_State *, GtkWidget *);
+static void lL_removeview(lua_State *, GtkWidget *);
+static void lL_adddoc(lua_State *, sptr_t);
+static void lL_removedoc(lua_State *, sptr_t);
+static void lL_gotodoc(lua_State *, GtkWidget *, int, int);
+static int lL_event(lua_State *, const char *, ...);
+static void lL_notify(lua_State *, struct SCNotification *);
+static void lL_showcontextmenu(lua_State *, GdkEventButton *);
+static void lL_cleartable(lua_State *, int);
+static void l_pushview(lua_State *, GtkWidget *);
+static void l_pushdoc(lua_State *, sptr_t);
+#define l_setglobalview(l, v) (l_pushview(l, v), lua_setglobal(l, "view"))
+#define l_setglobaldoc(l, d) (l_pushdoc(l, d), lua_setglobal(l, "buffer"))
+LUALIB_API int (luaopen_lpeg) (lua_State *);
+LUALIB_API int (luaopen_lfs) (lua_State *);
+static int lbuf_property(lua_State *),
+ lview__index(lua_State *), lview__newindex(lua_State *),
+ lgui__index(lua_State *), lgui__newindex(lua_State *),
+ lfind__index(lua_State *), lfind__newindex(lua_State *),
+ lce__index(lua_State *), lce__newindex(lua_State *),
+ lbuffer_check_global(lua_State *), lbuffer_delete(lua_State *),
+ lbuffer_new(lua_State *), lbuffer_text_range(lua_State *),
+ lview_split(lua_State *), lview_unsplit(lua_State *),
+ lgui_dialog(lua_State *), lgui_get_split_table(lua_State *),
+ lgui_goto_view(lua_State *), lview_goto_buffer(lua_State *),
+ lgui_gtkmenu(lua_State *), lstring_iconv(lua_State *),
+ lquit(lua_State *), lreset(lua_State *), ltimeout(lua_State *),
+ lfind_focus(lua_State *), lfind_next(lua_State *),
+ lfind_prev(lua_State *), lfind_replace(lua_State *),
+ lfind_replace_all(lua_State *),
+ lce_focus(lua_State *), lce_show_completions(lua_State *);
/******************************************************************************/
/******************************* GUI Interface ********************************/
@@ -168,8 +139,8 @@ static int l_cf_buffer_delete(lua_State *), l_cf_buffer_text_range(lua_State *),
/**
* Runs Textadept in Linux or Mac.
- * Inits the Lua State, creates the user interface, loads the core/init.lua
- * script, and also loads init.lua.
+ * Inits the Lua state, creates the user interface, and then runs core/init.lua
+ * followed by init.lua.
* @param argc The number of command line params.
* @param argv The array of command line params.
*/
@@ -182,8 +153,7 @@ int main(int argc, char **argv) {
CFStringRef path = CFURLCopyFileSystemPath(bundle, kCFURLPOSIXPathStyle);
const char *p = CFStringGetCStringPtr(path, kCFStringEncodingMacRoman);
textadept_home = g_strconcat(p, "/Contents/Resources/", NULL);
- CFRelease(path);
- CFRelease(bundle);
+ CFRelease(path), CFRelease(bundle);
} else textadept_home = calloc(1, 1);
#elif __BSD__
textadept_home = malloc(FILENAME_MAX);
@@ -194,9 +164,9 @@ int main(int argc, char **argv) {
char *last_slash = strrchr(textadept_home, G_DIR_SEPARATOR);
if (last_slash) *last_slash = '\0';
gtk_init(&argc, &argv);
- if (!l_init(argc, argv, FALSE)) return 1;
- create_ui();
- l_load_script("init.lua");
+ if (lua = lua_open(), !lL_init(lua, argc, argv, FALSE)) return 1;
+ new_window();
+ lL_dofile(lua, "init.lua");
gtk_main();
free(textadept_home);
return 0;
@@ -207,8 +177,7 @@ int main(int argc, char **argv) {
* Runs Textadept in Windows.
* @see main
*/
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow) {
+int WINAPI WinMain(HINSTANCE _, HINSTANCE __, LPSTR lpCmdLine, int ___) {
textadept_home = malloc(FILENAME_MAX);
GetModuleFileName(0, textadept_home, FILENAME_MAX);
return main(1, &lpCmdLine);
@@ -216,17 +185,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
#endif
/**
- * Creates the user interface.
- * The UI consists of:
- * - A menubar initially hidden and empty. It should be populated by script
- * and then shown.
- * - A frame for Scintilla views.
- * - A find text frame initially hidden.
- * - A command entry initially hidden. This entry accepts and runs Lua code
- * in the current Lua state.
- * - Two status bars: one for notifications, the other for document status.
+ * Creates the Textadept window.
+ * The window contains a menubar, frame for Scintilla views, hidden find box,
+ * hidden command entry, and two status bars: one for notifications and the
+ * other for buffer status.
*/
-void create_ui() {
+static void new_window() {
GList *icon_list = NULL;
const char *icons[] = { "16x16", "32x32", "48x48", "64x64", "128x128" };
for (int i = 0; i < 5; i++) {
@@ -266,18 +230,18 @@ void create_ui() {
GtkWidget *view = new_view(0);
gtk_box_pack_start(GTK_BOX(hbox), view, TRUE, TRUE, 0);
- GtkWidget *find = find_create_ui();
+ GtkWidget *find = new_findbox();
gtk_box_pack_start(GTK_BOX(vbox), find, FALSE, FALSE, 5);
command_entry = gtk_entry_new();
gtk_widget_set_name(command_entry, "textadept-command-entry");
- signal(command_entry, "activate", c_activated);
+ signal(command_entry, "activate", c_activate);
signal(command_entry, "key-press-event", c_keypress);
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_match_selected);
- gtk_entry_completion_set_match_func(command_entry_completion, cc_match_func,
+ 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);
@@ -306,96 +270,86 @@ void create_ui() {
gtk_widget_hide(menubar); // hide initially
gtk_widget_hide(findbox); // hide initially
gtk_widget_hide(command_entry); // hide initially
- gtk_widget_grab_focus(view);
}
/**
* Creates a new Scintilla view.
- * The Scintilla view is the GTK widget that displays a Scintilla buffer.
* Generates a 'view_new' event.
- * @param buffer_id A Scintilla buffer ID to load into the new window. If NULL,
- * creates a new Scintilla buffer and loads it into the new window.
- * @return the Scintilla view.
- * @see l_add_view
+ * @param doc The document to load in the new view. Almost never zero, except
+ * for the first Scintilla view created, in which there is no doc pointer.
+ * @return Scintilla view
+ * @see lL_addview
*/
-GtkWidget *new_view(sptr_t buffer_id) {
+static GtkWidget *new_view(sptr_t doc) {
GtkWidget *view = scintilla_new();
gtk_widget_set_size_request(view, 1, 1); // minimum size
SS(view, SCI_USEPOPUP, 0, 0);
- signal(view, SCINTILLA_NOTIFY, s_notification);
+ signal(view, SCINTILLA_NOTIFY, s_notify);
signal(view, "command", s_command);
signal(view, "key-press-event", s_keypress);
signal(view, "button-press-event", s_buttonpress);
- l_add_view(view);
+ lL_addview(lua, view);
gtk_widget_grab_focus(view);
focused_view = view;
- if (buffer_id) {
- SS(view, SCI_SETDOCPOINTER, 0, buffer_id);
- l_set_buffer_global(view);
- } else new_buffer(view, FALSE, TRUE);
- l_set_view_global(view);
- l_emit_event("view_new", -1);
+ if (doc) {
+ SS(view, SCI_SETDOCPOINTER, 0, doc);
+ l_setglobaldoc(lua, doc);
+ } else new_buffer(SS(view, SCI_GETDOCPOINTER, 0, 0));
+ l_setglobalview(lua, view);
+ lL_event(lua, "view_new", -1);
return view;
}
/**
* Removes a Scintilla view.
* @param view The Scintilla view to remove.
- * @see l_remove_view
+ * @see lL_removeview
*/
-void remove_view(GtkWidget *view) {
- l_remove_view(view);
+static void delete_view(GtkWidget *view) {
+ lL_removeview(lua, view);
gtk_widget_destroy(view);
}
/**
- * Creates a new Scintilla buffer for a newly created Scintilla view.
- * Generates a 'buffer_new' event.
- * @param view The Scintilla view to associate the buffer with.
- * @param create Flag indicating whether or not to create a buffer. If FALSE,
- * the Scintilla view already has a buffer associated with it (typically
- * because new_view was passed a non-NULL buffer_id).
- * @param addref Flag indicating whether or not to add a reference to the buffer
- * in the Scintilla view when create is FALSE. This is necessary for creating
- * Scintilla views in split views. If a buffer appears in two separate
- * Scintilla views, that buffer should have multiple references so when one
- * Scintilla view closes, the buffer is not deleted because its reference
- * count is not zero.
- * @see l_add_buffer
+ * Creates a new Scintilla document and adds it to the Lua state.
+ * Generates 'buffer_before_switch' and 'buffer_new' events.
+ * @param doc Almost always zero, except for the first Scintilla view created,
+ * in which its doc pointer would be given here.
+ * @see lL_adddoc
*/
-void new_buffer(GtkWidget *view, int create, int addref) {
- sptr_t doc;
- doc = SS(view, SCI_GETDOCPOINTER, 0, 0);
- if (create) { // create the new document
- doc = SS(view, SCI_CREATEDOCUMENT, 0, 0);
- l_emit_event("buffer_before_switch", -1);
- l_goto_buffer(focused_view, l_add_buffer(doc), TRUE);
- } else if (addref) {
- l_add_buffer(doc);
- SS(view, SCI_ADDREFDOCUMENT, 0, doc);
+static void new_buffer(sptr_t doc) {
+ if (!doc) { // create the new document
+ doc = SS(focused_view, SCI_CREATEDOCUMENT, 0, 0);
+ lL_event(lua, "buffer_before_switch", -1);
+ lL_adddoc(lua, doc);
+ lL_gotodoc(lua, focused_view, -1, FALSE);
+ } else {
+ // The first Scintilla window already has a pre-created buffer.
+ lL_adddoc(lua, doc);
+ SS(focused_view, SCI_ADDREFDOCUMENT, 0, doc);
}
- l_set_buffer_global(view);
- l_emit_event("buffer_new", -1);
+ l_setglobaldoc(lua, doc);
+ lL_event(lua, "buffer_new", -1);
}
/**
* Removes the Scintilla buffer from the current Scintilla view.
- * @param doc The Scintilla buffer ID to remove.
- * @see l_remove_buffer
+ * @param doc The Scintilla document.
+ * @see lL_removedoc
*/
-void remove_buffer(sptr_t doc) {
- l_remove_buffer(doc);
+static void delete_buffer(sptr_t doc) {
+ lL_removedoc(lua, doc);
SS(focused_view, SCI_RELEASEDOCUMENT, 0, doc);
}
/**
- * Splits a Scintilla view into two windows separated by a GTK pane.
- * The buffer in the original pane is also shown in the new pane.
+ * Splits the given Scintilla view into two views.
+ * The new view shows the same document as the original one.
* @param view The Scintilla view to split.
- * @param vertical Flag indicating whether to split the window vertically or
+ * @param vertical Flag indicating whether to split the view vertically or
* horozontally.
*/
-void split_view(GtkWidget *view, int vertical) {
+static void split_view(GtkWidget *view, int vertical) {
g_object_ref(view);
int first_line = SS(view, SCI_GETFIRSTVISIBLELINE, 0, 0);
int current_pos = SS(view, SCI_GETCURRENTPOS, 0, 0);
@@ -405,53 +359,50 @@ void split_view(GtkWidget *view, int vertical) {
int middle = (vertical ? allocation.width : allocation.height) / 2;
sptr_t curdoc = SS(view, SCI_GETDOCPOINTER, 0, 0);
- GtkWidget *newview = new_view(curdoc);
+ GtkWidget *view2 = new_view(curdoc);
GtkWidget *parent = gtk_widget_get_parent(view);
gtk_container_remove(GTK_CONTAINER(parent), view);
GtkWidget *pane = vertical ? gtk_hpaned_new() : gtk_vpaned_new();
- gtk_paned_add1(GTK_PANED(pane), view);
- gtk_paned_add2(GTK_PANED(pane), newview);
+ gtk_paned_add1(GTK_PANED(pane), view), gtk_paned_add2(GTK_PANED(pane), view2);
gtk_container_add(GTK_CONTAINER(parent), pane);
gtk_paned_set_position(GTK_PANED(pane), middle);
gtk_widget_show_all(pane);
- gtk_widget_grab_focus(newview);
+ gtk_widget_grab_focus(view2);
- SS(newview, SCI_SETSEL, anchor, current_pos);
- int new_first_line = SS(newview, SCI_GETFIRSTVISIBLELINE, 0, 0);
- SS(newview, SCI_LINESCROLL, first_line - new_first_line, 0);
+ SS(view2, SCI_SETSEL, anchor, current_pos);
+ int new_first_line = SS(view2, SCI_GETFIRSTVISIBLELINE, 0, 0);
+ SS(view2, SCI_LINESCROLL, first_line - new_first_line, 0);
g_object_unref(view);
}
/**
- * For a given GTK pane, remove the Scintilla views inside it recursively.
+ * Remove all Scintilla views from the given pane and delete them.
* @param pane The GTK pane to remove Scintilla views from.
- * @see remove_view
+ * @see delete_view
*/
-void remove_views_in_pane(GtkWidget *pane) {
+static void remove_views_from_pane(GtkWidget *pane) {
GtkWidget *child1 = gtk_paned_get_child1(GTK_PANED(pane));
GtkWidget *child2 = gtk_paned_get_child2(GTK_PANED(pane));
- GTK_IS_PANED(child1) ? remove_views_in_pane(child1) : remove_view(child1);
- GTK_IS_PANED(child2) ? remove_views_in_pane(child2) : remove_view(child2);
+ GTK_IS_PANED(child1) ? remove_views_from_pane(child1) : delete_view(child1);
+ GTK_IS_PANED(child2) ? remove_views_from_pane(child2) : delete_view(child2);
}
/**
- * Unsplits the pane a given Scintilla view is in and keeps that window.
- * If the pane to discard contains other Scintilla views, they are removed
- * recursively.
+ * Unsplits the pane a given Scintilla view is in and keeps the view.
+ * All views in the other pane are deleted.
* @param view The Scintilla view to keep when unsplitting.
- * @see remove_views_in_pane
- * @see remove_view
+ * @see remove_views_from_pane
+ * @see delete_view
*/
-int unsplit_view(GtkWidget *view) {
+static int unsplit_view(GtkWidget *view) {
GtkWidget *pane = gtk_widget_get_parent(view);
if (!GTK_IS_PANED(pane)) return FALSE;
GtkWidget *other = gtk_paned_get_child1(GTK_PANED(pane));
if (other == view) other = gtk_paned_get_child2(GTK_PANED(pane));
- g_object_ref(view);
- g_object_ref(other);
+ g_object_ref(view), g_object_ref(other);
gtk_container_remove(GTK_CONTAINER(pane), view);
gtk_container_remove(GTK_CONTAINER(pane), other);
- GTK_IS_PANED(other) ? remove_views_in_pane(other) : remove_view(other);
+ GTK_IS_PANED(other) ? remove_views_from_pane(other) : delete_view(other);
GtkWidget *parent = gtk_widget_get_parent(pane);
gtk_container_remove(GTK_CONTAINER(parent), pane);
if (GTK_IS_PANED(parent)) {
@@ -462,73 +413,40 @@ int unsplit_view(GtkWidget *view) {
} else gtk_container_add(GTK_CONTAINER(parent), view);
gtk_widget_show_all(parent);
gtk_widget_grab_focus(GTK_WIDGET(view));
- g_object_unref(view);
- g_object_unref(other);
+ g_object_unref(view), g_object_unref(other);
return TRUE;
}
-/**
- * Sets a user-defined GTK menubar and displays it.
- * @param new_menubar The GTK menubar.
- * @see l_gui_mt_newindex
- */
-void set_menubar(GtkWidget *new_menubar) {
- GtkWidget *vbox = gtk_widget_get_parent(menubar);
- gtk_container_remove(GTK_CONTAINER(vbox), menubar);
- menubar = new_menubar;
- gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
- gtk_box_reorder_child(GTK_BOX(vbox), menubar, 0);
- gtk_widget_show_all(menubar);
-#if __OSX__
- ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(menubar));
- gtk_widget_hide(menubar);
-#endif
-}
-
-/**
- * Sets the notification statusbar text.
- * @param text The text to display.
- * @param bar Statusbar. 0 for statusbar, 1 for docstatusbar.
- */
-void set_statusbar_text(const char *text, int bar) {
- if (!statusbar[0] || !statusbar[1]) return; // unavailable on startup
- gtk_statusbar_pop(GTK_STATUSBAR(statusbar[bar]), 0);
- gtk_statusbar_push(GTK_STATUSBAR(statusbar[bar]), 0, text);
-}
-
/******************************************************************************/
/************************* GUI Notifications/Signals **************************/
/******************************************************************************/
/**
- * Helper function for switching the focused view to the given one.
+ * Change focus to the given Scintilla view.
+ * Generates 'view_before_switch' and 'view_after_switch' events.
* @param view The Scintilla view to focus.
- * @see s_notification
- * @see s_command
- * @see l_goto_view
*/
-static void switch_to_view(GtkWidget *view) {
- if (!closing) l_emit_event("view_before_switch", -1);
+static void goto_view(GtkWidget *view) {
+ if (!closing) lL_event(lua, "view_before_switch", -1);
focused_view = view;
- l_set_view_global(view);
- l_set_buffer_global(view);
- if (!closing) l_emit_event("view_after_switch", -1);
+ l_setglobalview(lua, view);
+ l_setglobaldoc(lua, SS(view, SCI_GETDOCPOINTER, 0, 0));
+ if (!closing) lL_event(lua, "view_after_switch", -1);
}
/**
* Signal for a Scintilla notification.
*/
-static void s_notification(GtkWidget *view, gint wParam, gpointer lParam,
- gpointer udata) {
+static void s_notify(GtkWidget *view, gint _, gpointer lParam, gpointer __) {
struct SCNotification *n = (struct SCNotification *)lParam;
if (focused_view == view || n->nmhdr.code == SCN_URIDROPPED) {
- if (focused_view != view) switch_to_view(view);
- l_emit_scnotification(n);
+ if (focused_view != view) goto_view(view);
+ lL_notify(lua, n);
} else if (n->nmhdr.code == SCN_SAVEPOINTLEFT) {
GtkWidget *prev = focused_view;
- switch_to_view(view);
- l_emit_scnotification(n);
- switch_to_view(prev); // do not let a split view steal focus
+ goto_view(view);
+ lL_notify(lua, n);
+ goto_view(prev); // do not let a split view steal focus
}
}
@@ -536,35 +454,34 @@ static void s_notification(GtkWidget *view, gint wParam, gpointer lParam,
* Signal for a Scintilla command.
* Currently handles SCEN_SETFOCUS.
*/
-static void s_command(GtkWidget *view, gint wParam, gpointer lParam,
- gpointer udata) {
- if (wParam >> 16 == SCEN_SETFOCUS) switch_to_view(view);
+static void s_command(GtkWidget *view, gint wParam, gpointer _, gpointer __) {
+ if (wParam >> 16 == SCEN_SETFOCUS) goto_view(view);
}
/**
* Signal for a Scintilla keypress.
- * Collects the modifier states as flags and calls Lua to handle the keypress.
*/
-static gbool s_keypress(GtkWidget *view, GdkEventKey *event, gpointer udata) {
- return l_emit_event_key("keypress", event) ? TRUE : FALSE;
+static gboolean s_keypress(GtkWidget *view, GdkEventKey *event, gpointer _) {
+ return lL_event(lua, "keypress", LUA_TNUMBER, event->keyval, LUA_TBOOLEAN,
+ event->state & GDK_SHIFT_MASK, LUA_TBOOLEAN,
+ event->state & GDK_CONTROL_MASK, LUA_TBOOLEAN,
+ event->state & GDK_MOD1_MASK, LUA_TBOOLEAN,
+ event->state & GDK_MOD5_MASK, -1);
}
/**
* Signal for a Scintilla mouse click.
- * If it is a right-click, popup a context menu.
- * @see l_gui_popup_context_menu
*/
-static gbool s_buttonpress(GtkWidget *view, GdkEventButton *event,
- gpointer udata) {
- if (event->type != GDK_BUTTON_PRESS || event->button != 3) return FALSE;
- l_gui_popup_context_menu(event);
- return TRUE;
+static gboolean s_buttonpress(GtkWidget*_, GdkEventButton *event, gpointer __) {
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+ return (lL_showcontextmenu(lua, event), TRUE);
+ return FALSE;
}
/**
* Signal for a Textadept window focus change.
*/
-static gbool w_focus(GtkWidget *window, GdkEventFocus *event, gpointer udata) {
+static gboolean w_focus(GtkWidget*_, GdkEventFocus *event, gpointer __) {
if (focused_view && !gtk_widget_has_focus(focused_view))
gtk_widget_grab_focus(focused_view);
return FALSE;
@@ -573,9 +490,9 @@ static gbool w_focus(GtkWidget *window, GdkEventFocus *event, gpointer udata) {
/**
* Signal for a Textadept keypress.
* Currently handled keypresses:
- * - Escape - hides the search frame if it's open.
+ * - Escape: hides the find box if it is open.
*/
-static gbool w_keypress(GtkWidget *window, GdkEventKey *event, gpointer udata) {
+static gboolean w_keypress(GtkWidget*_, GdkEventKey *event, gpointer __) {
if (event->keyval == 0xff1b && gtk_widget_get_visible(findbox) &&
!gtk_widget_has_focus(command_entry)) {
gtk_widget_hide(findbox);
@@ -586,13 +503,13 @@ static gbool w_keypress(GtkWidget *window, GdkEventKey *event, gpointer udata) {
/**
* Signal for exiting Textadept.
- * Closes the Lua State and releases resources.
* Generates a 'quit' event.
+ * Closes the Lua state and releases resources.
* @see l_close
*/
-static gbool w_exit(GtkWidget *window, GdkEventAny *event, gpointer udata) {
- if (!l_emit_event("quit", -1)) return TRUE;
- l_close();
+static gboolean w_exit(GtkWidget*_, GdkEventAny*__, gpointer ___) {
+ if (!lL_event(lua, "quit", -1)) return TRUE;
+ l_close(lua);
scintilla_release_resources();
gtk_main_quit();
return FALSE;
@@ -601,9 +518,9 @@ static gbool w_exit(GtkWidget *window, GdkEventAny *event, gpointer udata) {
#if __OSX__
/**
* Signal for an Open Document AppleEvent.
- * Generates a 'appleevent_odoc' event for each document sent.
+ * Generates an 'appleevent_odoc' event for each document sent.
*/
-static OSErr w_ae_open(const AppleEvent *event, AppleEvent *reply, long ref) {
+static OSErr w_ae_open(const AppleEvent *event, AppleEvent*_, long __) {
AEDescList file_list;
if (AEGetParamDesc(event, keyDirectObject, typeAEList, &file_list) == noErr) {
long count = 0;
@@ -616,9 +533,8 @@ static OSErr w_ae_open(const AppleEvent *event, AppleEvent *reply, long ref) {
if (url) {
CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
const char *p = CFStringGetCStringPtr(path, kCFStringEncodingMacRoman);
- l_emit_event("appleevent_odoc", LUA_TSTRING, p, -1);
- CFRelease(path);
- CFRelease(url);
+ lL_event(lua, "appleevent_odoc", LUA_TSTRING, p, -1);
+ CFRelease(path), CFRelease(url);
}
}
AEDisposeDesc(&file_list);
@@ -628,10 +544,8 @@ static OSErr w_ae_open(const AppleEvent *event, AppleEvent *reply, long ref) {
/**
* Signal for a Quit Application AppleEvent.
- * Calls the signal for exiting Textadept.
- * @see w_exit
*/
-static OSErr w_ae_quit(const AppleEvent *event, AppleEvent *reply, long ref) {
+static OSErr w_ae_quit(const AppleEvent*_, AppleEvent*__, long ___) {
return w_exit(NULL, NULL, NULL) ? (OSErr) noErr : errAEEventNotHandled;
}
#endif
@@ -644,11 +558,10 @@ static OSErr w_ae_quit(const AppleEvent *event, AppleEvent *reply, long ref) {
gtk_table_attach(GTK_TABLE(findbox), w, x1, x2, y1, y2, xo, yo, xp, yp)
#define ao_expand (GtkAttachOptions)(GTK_EXPAND | GTK_FILL)
#define ao_normal (GtkAttachOptions)(GTK_SHRINK | GTK_FILL)
-
/**
- * Creates the Find/Replace text frame.
+ * Creates the Find box.
*/
-GtkWidget *find_create_ui() {
+static GtkWidget *new_findbox() {
findbox = gtk_table_new(2, 6, FALSE);
find_store = gtk_list_store_new(1, G_TYPE_STRING);
repl_store = gtk_list_store_new(1, G_TYPE_STRING);
@@ -696,10 +609,10 @@ 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(fnext_button, "clicked", find_button_clicked);
- signal(fprev_button, "clicked", find_button_clicked);
- signal(r_button, "clicked", find_button_clicked);
- signal(ra_button, "clicked", find_button_clicked);
+ signal(fnext_button, "clicked", f_clicked);
+ signal(fprev_button, "clicked", f_clicked);
+ signal(r_button, "clicked", f_clicked);
+ signal(ra_button, "clicked", f_clicked);
gtk_widget_set_can_default(fnext_button, TRUE);
gtk_widget_set_can_focus(fnext_button, FALSE);
@@ -714,24 +627,12 @@ GtkWidget *find_create_ui() {
return findbox;
}
-/**
- * Toggles the focus between the Find/Replace frame and the current Scintilla
- * window.
- */
-void find_toggle_focus() {
- if (!gtk_widget_has_focus(findbox)) {
- gtk_widget_show(findbox);
- gtk_widget_grab_focus(find_entry);
- gtk_widget_grab_default(fnext_button);
- } else {
- gtk_widget_grab_focus(focused_view);
- gtk_widget_hide(findbox);
- }
-}
+/******************************************************************************/
+/**************************** Find/Replace Signals ****************************/
+/******************************************************************************/
/**
- * Adds the given text to the Find/Replace history list if it's not the first
- * item.
+ * Adds the given text to the find/replace history list if it is not at the top.
* @param text The text to add.
* @param store The GtkListStore to add the text to.
*/
@@ -750,30 +651,25 @@ static void find_add_to_history(const char *text, GtkListStore *store) {
}
}
-/******************************************************************************/
-/**************************** Find/Replace Signals ****************************/
-/******************************************************************************/
-
/**
- * Signal for a Find frame button click.
- * Performs the appropriate action depending on the button clicked.
+ * Signal for a find box button click.
*/
-static void find_button_clicked(GtkWidget *button, gpointer udata) {
+static void f_clicked(GtkWidget *button, gpointer _) {
const char *find_text = gtk_entry_get_text(GTK_ENTRY(find_entry));
const char *repl_text = gtk_entry_get_text(GTK_ENTRY(replace_entry));
if (strlen(find_text) == 0) return;
if (button == fnext_button || button == fprev_button) {
find_add_to_history(find_text, find_store);
- l_emit_event("find", LUA_TSTRING, find_text, LUA_TBOOLEAN,
- button == fnext_button, -1);
+ lL_event(lua, "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_emit_event("replace", LUA_TSTRING, repl_text, -1);
- l_emit_event("find", LUA_TSTRING, find_text, LUA_TBOOLEAN, 1, -1);
+ lL_event(lua, "replace", LUA_TSTRING, repl_text, -1);
+ lL_event(lua, "find", LUA_TSTRING, find_text, LUA_TBOOLEAN, 1, -1);
} else
- l_emit_event("replace_all", LUA_TSTRING, find_text, LUA_TSTRING,
- repl_text, -1);
+ lL_event(lua, "replace_all", LUA_TSTRING, find_text, LUA_TSTRING,
+ repl_text, -1);
}
}
@@ -782,49 +678,29 @@ static void find_button_clicked(GtkWidget *button, gpointer udata) {
/******************************************************************************/
/**
- * Toggles focus between a Scintilla view and the Command Entry.
- * When the entry is visible, the statusbars are temporarily hidden.
- */
-void ce_toggle_focus() {
- if (!gtk_widget_has_focus(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);
- }
-}
-
-/**
- * Sets every item in the Command Entry Model to be a match.
- * For each attempted completion, the Command Entry Model is filled with the
- * results from a call to Lua to make a list of possible completions. Therefore,
- * every item in the list is valid.
+ * The match function for the command entry.
+ * Since the completion list is filled by Lua, every item is a "match".
*/
-static int cc_match_func(GtkEntryCompletion *entry, const char *key,
- GtkTreeIter *iter, gpointer udata) { return 1; }
+static int cc_matchfunc(GtkEntryCompletion*_, const char *__, GtkTreeIter*___,
+ gpointer ____) { return 1; }
/**
- * Enters the requested completion text into the Command Entry.
- * The last word at the cursor is replaced with the completion. A word consists
- * of any alphanumeric character or underscore.
+ * Replaces the current word (consisting of alphanumeric and underscore
+ * characters) with the match text.
*/
-static gbool cc_match_selected(GtkEntryCompletion *entry, GtkTreeModel *model,
- GtkTreeIter *iter, gpointer udata) {
- const char *entry_text = gtk_entry_get_text(GTK_ENTRY(command_entry));
- const char *p = entry_text + strlen(entry_text) - 1;
- while (g_ascii_isalnum(*p) || *p == '_') {
+static gboolean cc_matchselected(GtkEntryCompletion*_, GtkTreeModel *model,
+ GtkTreeIter *iter, gpointer __) {
+ const char *text = gtk_entry_get_text(GTK_ENTRY(command_entry)), *p;
+ for (p = text + strlen(text) - 1; g_ascii_isalnum(*p) || *p == '_'; p--)
g_signal_emit_by_name(G_OBJECT(command_entry), "move-cursor",
GTK_MOVEMENT_VISUAL_POSITIONS, -1, TRUE, 0);
- p--;
- }
- if (p < entry_text + strlen(entry_text) - 1)
+ if (p < text + strlen(text) - 1)
g_signal_emit_by_name(G_OBJECT(command_entry), "backspace", 0);
- char *text;
- gtk_tree_model_get(model, iter, 0, &text, -1);
- g_signal_emit_by_name(G_OBJECT(command_entry), "insert-at-cursor", text, 0);
- g_free(text);
+ char *match;
+ 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(match);
gtk_list_store_clear(cc_store);
return TRUE;
@@ -837,411 +713,328 @@ static gbool cc_match_selected(GtkEntryCompletion *entry, GtkTreeModel *model,
/**
* Signal for the 'enter' key being pressed in the Command Entry.
*/
-static void c_activated(GtkWidget *entry, gpointer udata) {
- l_emit_event("command_entry_command", LUA_TSTRING,
- gtk_entry_get_text(GTK_ENTRY(entry)), -1);
+static void c_activate(GtkWidget *entry, gpointer _) {
+ lL_event(lua, "command_entry_command", LUA_TSTRING,
+ gtk_entry_get_text(GTK_ENTRY(entry)), -1);
}
/**
* Signal for a keypress inside the Command Entry.
*/
-static gbool c_keypress(GtkWidget *entry, GdkEventKey *event, gpointer udata) {
- return l_emit_event_key("command_entry_keypress", event);
+static gboolean c_keypress(GtkWidget*_, GdkEventKey *event, gpointer __) {
+ return lL_event(lua, "command_entry_keypress", LUA_TNUMBER, event->keyval,
+ LUA_TBOOLEAN, event->state & GDK_SHIFT_MASK, LUA_TBOOLEAN,
+ event->state & GDK_CONTROL_MASK, LUA_TBOOLEAN,
+ event->state & GDK_MOD1_MASK, LUA_TBOOLEAN,
+ event->state & GDK_MOD5_MASK, -1);
}
/******************************************************************************/
/******************************** Lua Interface *******************************/
/******************************************************************************/
-#define l_openlib(l, n, f) { \
- lua_pushcfunction(l, f); \
- lua_pushstring(l, n); \
- lua_call(l, 1, 0); \
-}
-#define l_archive(l, k) { \
- lua_pushstring(l, k); \
- lua_rawget(l, -2); \
- lua_setfield(l, LUA_REGISTRYINDEX, k); \
+#define lL_openlib(l, n, f) \
+ (lua_pushcfunction(l, f), lua_pushstring(l, n), lua_call(l, 1, 0))
+#define l_setcfunction(l, n, k, f) \
+ (lua_pushcfunction(l, f), lua_setfield(l, (n > 0) ? n : n - 1, k))
+#define l_setmetatable(l, n, k, i, ni) { \
+ if (luaL_newmetatable(l, k)) { \
+ l_setcfunction(l, -1, "__index", i); \
+ l_setcfunction(l, -1, "__newindex", ni); \
+ } \
+ lua_setmetatable(l, (n > 0) ? n : n - 1); \
}
/**
- * Inits or re-inits the Lua State.
+ * Initializes or re-initializes the Lua state.
* Populates the state with global variables and functions, then runs the
* 'core/init.lua' script.
* @param argc The number of command line parameters.
* @param argv The array of command line parameters.
- * @param reinit Flag indicating whether or not to reinitialize the Lua State.
- * @return TRUE on success, FALSE on failure.
+ * @param reinit Flag indicating whether or not to reinitialize the Lua state.
+ * @return TRUE on success, FALSE otherwise.
*/
-int l_init(int argc, char **argv, int reinit) {
+static int lL_init(lua_State *L, int argc, char **argv, int reinit) {
if (!reinit) {
- lua = lua_open();
- lua_newtable(lua);
- for (int i = 0; i < argc; i++) {
- lua_pushstring(lua, argv[i]);
- lua_rawseti(lua, -2, i);
- }
- lua_setfield(lua, LUA_REGISTRYINDEX, "arg");
- lua_newtable(lua);
- lua_setfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_newtable(lua);
- lua_setfield(lua, LUA_REGISTRYINDEX, "views");
+ lua_newtable(L);
+ for (int i = 0; i < argc; i++)
+ lua_pushstring(L, argv[i]), lua_rawseti(L, -2, i);
+ lua_setfield(L, LUA_REGISTRYINDEX, "ta_arg");
+ lua_newtable(L), lua_setfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_newtable(L), lua_setfield(L, LUA_REGISTRYINDEX, "ta_views");
} else { // clear package.loaded and _G
- lua_getglobal(lua, "package");
- lua_getfield(lua, -1, "loaded");
- clear_table(lua, lua_gettop(lua));
- lua_pop(lua, 2); // package and package.loaded
- clear_table(lua, LUA_GLOBALSINDEX);
+ lua_getglobal(L, "package"), lua_getfield(L, -1, "loaded");
+ lL_cleartable(L, lua_gettop(L));
+ lua_pop(L, 2); // package and package.loaded
+ lL_cleartable(L, LUA_GLOBALSINDEX);
}
- luaL_openlibs(lua);
- l_openlib(lua, "lpeg", luaopen_lpeg);
- l_openlib(lua, "lfs", luaopen_lfs);
-
- lua_newtable(lua);
- 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_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_gui_dialog, "dialog");
- l_cfunc(lua, l_cf_gui_get_split_table, "get_split_table");
- l_cfunc(lua, l_cf_gui_goto_view, "goto_view");
- l_cfunc(lua, l_cf_gui_gtkmenu, "gtkmenu");
- l_mt(lua, "_gui_mt", l_gui_mt_index, l_gui_mt_newindex);
- lua_setglobal(lua, "gui");
-
- lua_getglobal(lua, "_G");
- l_cfunc(lua, l_cf_buffer_new, "new_buffer");
- l_cfunc(lua, l_cf_quit, "quit");
- l_cfunc(lua, l_cf_reset, "reset");
- l_cfunc(lua, l_cf_timeout, "timeout");
- lua_pop(lua, 1); // _G
-
- lua_getglobal(lua, "string");
- l_cfunc(lua, l_cf_string_iconv, "iconv");
- lua_pop(lua, 1); // string
-
- lua_getfield(lua, LUA_REGISTRYINDEX, "arg");
- lua_setglobal(lua, "arg");
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_setglobal(lua, "_BUFFERS");
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- lua_setglobal(lua, "_VIEWS");
- lua_pushstring(lua, textadept_home);
- lua_setglobal(lua, "_HOME");
+ luaL_openlibs(L);
+ lL_openlib(L, "lpeg", luaopen_lpeg);
+ lL_openlib(L, "lfs", luaopen_lfs);
+
+ lua_newtable(L);
+ lua_newtable(L);
+ l_setcfunction(L, -1, "find_next", lfind_next);
+ l_setcfunction(L, -1, "find_prev", lfind_prev);
+ l_setcfunction(L, -1, "focus", lfind_focus);
+ l_setcfunction(L, -1, "replace", lfind_replace);
+ l_setcfunction(L, -1, "replace_all", lfind_replace_all);
+ l_setmetatable(L, -1, "ta_find", lfind__index, lfind__newindex);
+ 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);
+ lua_setfield(L, -2, "command_entry");
+ l_setcfunction(L, -1, "dialog", lgui_dialog);
+ l_setcfunction(L, -1, "get_split_table", lgui_get_split_table);
+ l_setcfunction(L, -1, "goto_view", lgui_goto_view);
+ l_setcfunction(L, -1, "gtkmenu", lgui_gtkmenu);
+ l_setmetatable(L, -1, "ta_gui", lgui__index, lgui__newindex);
+ lua_setglobal(L, "gui");
+
+ lua_getglobal(L, "_G");
+ l_setcfunction(L, -1, "new_buffer", lbuffer_new);
+ l_setcfunction(L, -1, "quit", lquit);
+ l_setcfunction(L, -1, "reset", lreset);
+ l_setcfunction(L, -1, "timeout", ltimeout);
+ lua_pop(L, 1); // _G
+
+ lua_getglobal(L, "string");
+ l_setcfunction(L, -1, "iconv", lstring_iconv);
+ lua_pop(L, 1); // string
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_arg"), lua_setglobal(L, "arg");
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_setglobal(L, "_BUFFERS");
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_views"), lua_setglobal(L, "_VIEWS");
+ lua_pushstring(L, textadept_home), lua_setglobal(L, "_HOME");
#if __WIN32__
- lua_pushboolean(lua, 1);
- lua_setglobal(lua, "WIN32");
+ lua_pushboolean(L, 1), lua_setglobal(L, "WIN32");
#elif __OSX__
- lua_pushboolean(lua, 1);
- lua_setglobal(lua, "OSX");
+ lua_pushboolean(L, 1), lua_setglobal(L, "OSX");
#endif
const char *charset = 0;
g_get_charset(&charset);
- lua_pushstring(lua, charset);
- lua_setglobal(lua, "_CHARSET");
-
- if (l_load_script("core/init.lua")) {
- lua_getglobal(lua, "_SCINTILLA");
- l_archive(lua, "constants");
- l_archive(lua, "functions");
- l_archive(lua, "properties");
- lua_pop(lua, 1); // _SCINTILLA
+ lua_pushstring(L, charset), lua_setglobal(L, "_CHARSET");
+
+ if (lL_dofile(L, "core/init.lua")) {
+ lua_getglobal(L, "_SCINTILLA");
+ lua_getfield(L, -1, "constants");
+ lua_setfield(L, LUA_REGISTRYINDEX, "ta_constants");
+ lua_getfield(L, -1, "functions");
+ lua_setfield(L, LUA_REGISTRYINDEX, "ta_functions");
+ lua_getfield(L, -1, "properties");
+ lua_setfield(L, LUA_REGISTRYINDEX, "ta_properties");
+ lua_pop(L, 1); // _SCINTILLA
return TRUE;
}
- lua_close(lua);
+ lua_close(L);
return FALSE;
}
/**
- * Loads and runs a given Lua script.
- * @param script_file The path of the Lua script relative to textadept_home.
- * @return TRUE on success, FALSE otherwise.
+ * Loads and runs the given file.
+ * @param L The Lua state.
+ * @param filename The file name relative to textadept_home.
+ * @return 1 if there are no errors or 0 in case of errors.
*/
-int l_load_script(const char *script_file) {
- char *script = g_strconcat(textadept_home, "/", script_file, NULL);
- int retval = luaL_dofile(lua, script) == 0;
- if (!retval) {
- const char *errmsg = lua_tostring(lua, -1);
- lua_settop(lua, 0);
+static int lL_dofile(lua_State *L, const char *filename) {
+ char *file = g_strconcat(textadept_home, "/", filename, NULL);
+ int ok = (luaL_dofile(L, file) == 0);
+ if (!ok) {
GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK, "%s\n", errmsg);
+ GTK_BUTTONS_OK, "%s\n",
+ lua_tostring(L, -1));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
+ lua_settop(L, 0);
}
- g_free(script);
- return retval;
+ g_free(file);
+ return ok;
}
/**
- * Checks a specified stack element to see if it is a Scintilla view and returns
- * it as a GtkWidget.
- * Throws an error if the check is not satisfied.
- * @param lua The Lua State.
- * @param narg Relative stack index to check for a Scintilla view.
- * @return GtkWidget Scintilla view.
+ * Returns the view at the given acceptable index as a Scintilla view.
+ * @param L The Lua state.
+ * @param index Stack index of the view.
+ * @return Scintilla view
*/
-static GtkWidget *l_checkview(lua_State *lua, int narg) {
- luaL_argcheck(lua, lua_istable(lua, narg), narg, "View expected");
- lua_pushstring(lua, "widget_pointer");
- lua_rawget(lua, (narg > 0) ? narg : narg - 1);
- luaL_argcheck(lua, lua_islightuserdata(lua, -1), narg, "View expected");
- GtkWidget *view = l_togtkwidget(lua, -1);
- lua_pop(lua, 1); // widget_pointer
+static GtkWidget *l_toview(lua_State *L, int index) {
+ lua_getfield(L, index, "widget_pointer");
+ GtkWidget *view = (GtkWidget *)lua_touserdata(L, -1);
+ lua_pop(L, 1); // widget pointer
return view;
}
/**
- * Adds a Scintilla view to the global '_VIEWS' table with a metatable.
+ * Adds the Scintilla view with a metatable to the 'views' registry table.
+ * @param L The Lua state.
* @param view The Scintilla view to add.
*/
-void l_add_view(GtkWidget *view) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- lua_newtable(lua);
- lua_pushlightuserdata(lua, (GtkWidget *)view);
- lua_setfield(lua, -2, "widget_pointer");
- l_cfunc(lua, l_cf_view_focus, "focus");
- l_cfunc(lua, l_cf_view_goto_buffer, "goto_buffer");
- l_cfunc(lua, l_cf_view_split, "split");
- l_cfunc(lua, l_cf_view_unsplit, "unsplit");
- l_mt(lua, "_view_mt", l_view_mt_index, l_view_mt_newindex);
- l_append(lua, -2); // pops table
- lua_pop(lua, 1); // views
+static void lL_addview(lua_State *L, GtkWidget *view) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_views");
+ lua_newtable(L);
+ lua_pushlightuserdata(L, view);
+ lua_pushvalue(L, -1), lua_setfield(L, -3, "widget_pointer");
+ l_setcfunction(L, -2, "goto_buffer", lview_goto_buffer);
+ l_setcfunction(L, -2, "split", lview_split);
+ l_setcfunction(L, -2, "unsplit", lview_unsplit);
+ l_setmetatable(L, -2, "ta_view", lview__index, lview__newindex);
+ // vs[userdata] = v, vs[#vs + 1] = v, vs[v] = #vs
+ lua_pushvalue(L, -2), lua_settable(L, -4);
+ lua_pushvalue(L, -1), lua_rawseti(L, -3, lua_objlen(L, -3) + 1);
+ lua_pushinteger(L, lua_objlen(L, -2)), lua_settable(L, -3);
+ lua_pop(L, 1); // views
}
/**
- * Removes a Scintilla view from the global '_VIEWS' table.
+ * Removes the Scintilla view from the 'views' registry table.
+ * The view must have been previously added with lL_addview.
+ * @param L The Lua state.
* @param view The Scintilla view to remove.
+ * @see lL_addview
*/
-void l_remove_view(GtkWidget *view) {
- lua_newtable(lua);
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- lua_pushnil(lua);
- while (lua_next(lua, -2))
- (view != l_checkview(lua, -1)) ? l_append(lua, -4) : lua_pop(lua, 1);
- lua_pop(lua, 1); // views
- lua_pushvalue(lua, -1);
- lua_setfield(lua, LUA_REGISTRYINDEX, "views");
- lua_setglobal(lua, "_VIEWS");
-}
-
-/**
- * Changes focus a Scintilla view in the global '_VIEWS' table.
- * @param view The currently focused Scintilla view.
- * @param n The index of the window in the '_VIEWS' table to focus.
- * @param absolute Flag indicating whether or not the index specified in
- * '_VIEWS' is absolute. If FALSE, focuses the window relative to the
- * currently focused window for the given index.
- * Throws an error if the view does not exist.
- */
-void l_goto_view(GtkWidget *view, int n, int absolute) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- if (!absolute) {
- unsigned int idx = 1;
- lua_pushnil(lua);
- while (lua_next(lua, -2))
- if (view == l_checkview(lua, -1)) {
- idx = lua_tointeger(lua, -2);
- lua_pop(lua, 2); // key and value
- break;
- } else lua_pop(lua, 1); // value
- idx += n;
- if (idx > lua_objlen(lua, -1))
- idx = 1;
- else if (idx < 1)
- idx = lua_objlen(lua, -1);
- lua_rawgeti(lua, -1, idx);
- } else {
- luaL_argcheck(lua, n >= 0 && n <= lua_objlen(lua, -1), 1,
- "no View exists at that index");
- lua_rawgeti(lua, -1, n);
+static void lL_removeview(lua_State *L, GtkWidget *view) {
+ lua_newtable(L);
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_views");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_isnumber(L, -2) && view != l_toview(L, -1)) {
+ lua_getfield(L, -1, "widget_pointer");
+ // vs[userdata] = v, vs[#vs + 1] = v, vs[v] = #vs
+ lua_pushvalue(L, -2), lua_rawseti(L, -6, lua_objlen(L, -6) + 1);
+ lua_pushvalue(L, -2), lua_settable(L, -6);
+ lua_pushinteger(L, lua_objlen(L, -4)), lua_settable(L, -5);
+ } else lua_pop(L, 1); // value
}
- view = l_checkview(lua, -1);
- gtk_widget_grab_focus(view);
- // gui.dialog() interferes with focus so gtk_widget_grab_focus() does not
- // always work. If this is the case, ensure switch_to_view() is called.
- if (!gtk_widget_has_focus(view)) switch_to_view(view);
- lua_pop(lua, 2); // view table and views
-}
-
-/**
- * Sets the global 'view' variable to be the specified Scintilla view.
- * @param view The Scintilla view to set 'view' to.
- */
-void l_set_view_global(GtkWidget *view) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- lua_pushnil(lua);
- while (lua_next(lua, -2))
- if (view == l_checkview(lua, -1)) {
- lua_setglobal(lua, "view"); // value (view table)
- lua_pop(lua, 1); // key
- break;
- } else lua_pop(lua, 1); // value
- lua_pop(lua, 1); // views
+ lua_pop(L, 1); // views
+ lua_pushvalue(L, -1), lua_setfield(L, LUA_REGISTRYINDEX, "ta_views");
+ lua_setglobal(L, "_VIEWS");
}
/**
- * Checks a specified element to see if it is a buffer table and returns the
- * Scintilla document pointer associated with it.
- * Throws an error if the check is not satisfied.
- * @param lua The Lua State.
- * @param narg Relative stack index to check for a buffer table.
+ * 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_checkdocpointer(lua_State *lua, int narg) {
- luaL_argcheck(lua, lua_istable(lua, narg), narg, "Buffer expected");
- lua_pushstring(lua, "doc_pointer");
- lua_rawget(lua, (narg > 0) ? narg : narg - 1);
- luaL_argcheck(lua, lua_isnumber(lua, -1), narg, "Buffer expected");
- sptr_t doc = lua_tointeger(lua, -1);
- lua_pop(lua, 1); // doc_pointer
+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;
}
/**
- * Adds a Scintilla document to the global '_BUFFERS' table with a metatable.
+ * Adds a Scintilla document with a metatable to the 'buffers' registry table.
+ * @param L The Lua state.
* @param doc The Scintilla document to add.
- * @return integer index of the new buffer in _BUFFERS.
*/
-int l_add_buffer(sptr_t doc) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_newtable(lua);
- lua_pushinteger(lua, doc);
- lua_setfield(lua, -2, "doc_pointer");
- l_cfunc(lua, l_cf_buffer_delete, "delete");
- l_cfunc(lua, l_cf_buffer_text_range, "text_range");
- l_mt(lua, "_buffer_mt", l_buffer_mt_index, l_buffer_mt_newindex);
- l_append(lua, -2); // pops table
- int index = lua_objlen(lua, -1);
- lua_pop(lua, 1); // buffers
- return index;
+static void lL_adddoc(lua_State *L, sptr_t doc) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_newtable(L);
+ lua_pushlightuserdata(L, (sptr_t *)doc); // TODO: can this fail?
+ lua_pushvalue(L, -1), lua_setfield(L, -3, "doc_pointer");
+ l_setcfunction(L, -2, "check_global", lbuffer_check_global);
+ l_setcfunction(L, -2, "delete", lbuffer_delete);
+ 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
+ lua_pushvalue(L, -2), lua_settable(L, -4);
+ lua_pushvalue(L, -1), lua_rawseti(L, -3, lua_objlen(L, -3) + 1);
+ lua_pushinteger(L, lua_objlen(L, -2)), lua_settable(L, -3);
+ lua_pop(L, 1); // buffers
}
/**
- * Removes a Scintilla document from the global '_BUFFERS' table.
- * If any views currently show the document to be removed, change the documents
- * they show first.
- * @param doc The Scintilla buffer to remove.
+ * 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
+ * length of 'buffers' is more than one unless quitting the application.
+ * @param L The Lua state.
+ * @param doc The Scintilla document to remove.
+ * @see lL_adddoc
*/
-void l_remove_buffer(sptr_t doc) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- GtkWidget *view = l_checkview(lua, -1);
- sptr_t that_doc = SS(view, SCI_GETDOCPOINTER, 0, 0);
- if (that_doc == doc) l_goto_buffer(view, -1, FALSE);
- lua_pop(lua, 1); // value
+static void lL_removedoc(lua_State *L, sptr_t doc) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_views");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_isnumber(L, -2)) {
+ GtkWidget *view = l_toview(L, -1);
+ if (doc == SS(view, SCI_GETDOCPOINTER, 0, 0))
+ lL_gotodoc(L, view, -1, TRUE);
+ }
+ lua_pop(L, 1); // value
}
- lua_pop(lua, 1); // views
- lua_newtable(lua);
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_pushnil(lua);
- while (lua_next(lua, -2))
- (doc != l_checkdocpointer(lua, -1)) ? l_append(lua, -4) : lua_pop(lua, 1);
- lua_pop(lua, 1); // buffers
- lua_pushvalue(lua, -1);
- lua_setfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_setglobal(lua, "_BUFFERS");
-}
-
-/**
- * Retrieves the index in the global '_BUFFERS' table for a given Scintilla
- * document.
- * @param doc The Scintilla document to get the index of.
- * @return int buffer index.
- */
-unsigned int l_get_docpointer_index(sptr_t doc) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- unsigned int idx = 1;
- lua_pushnil(lua);
- while (lua_next(lua, -2))
- if (doc == l_checkdocpointer(lua, -1)) {
- idx = lua_tointeger(lua, -2);
- lua_pop(lua, 2); // key and value
- break;
- } else lua_pop(lua, 1); // value
- lua_pop(lua, 1); // buffers
- return idx;
+ lua_pop(L, 1); // views
+ lua_newtable(L);
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_isnumber(L, -2) && doc != l_todoc(L, -1)) {
+ lua_getfield(L, -1, "doc_pointer");
+ // bs[userdata] = b, bs[#bs + 1] = b, bs[b] = #bs
+ lua_pushvalue(L, -2), lua_rawseti(L, -6, lua_objlen(L, -6) + 1);
+ lua_pushvalue(L, -2), lua_settable(L, -6);
+ lua_pushinteger(L, lua_objlen(L, -4)), lua_settable(L, -5);
+ } else lua_pop(L, 1); // value
+ }
+ lua_pop(L, 1); // buffers
+ lua_pushvalue(L, -1), lua_setfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_setglobal(L, "_BUFFERS");
}
/**
- * Changes a Scintilla view's document to one in the global '_BUFFERS' table.
- * Before doing so, it saves the scroll and caret positions in the current
- * Scintilla document. Then when the new document is shown, its scroll and caret
- * positions are restored.
- * @param view The Scintilla view to change the document of.
- * @param n The index of the document in '_BUFFERS' to focus.
- * @param absolute Flag indicating whether or not the index specified in
- * '_BUFFERS' is absolute. If FALSE, focuses the document relative to the
- * currently focused document for the given index.
- * Throws an error if the buffer does not exist.
+ * Switches to a document in the given view.
+ * @param L The Lua state.
+ * @param view The Scintilla view.
+ * @param n Relative or absolute index of the document to switch to. An absolute
+ * n of -1 represents the last document.
+ * @param relative Flag indicating whether or not n is relative.
*/
-void l_goto_buffer(GtkWidget *view, int n, int absolute) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- if (!absolute) {
- sptr_t doc = SS(view, SCI_GETDOCPOINTER, 0, 0);
- unsigned int idx = l_get_docpointer_index(doc);
- idx += n;
- if (idx > lua_objlen(lua, -1))
- idx = 1;
- else if (idx < 1)
- idx = lua_objlen(lua, -1);
- lua_rawgeti(lua, -1, idx);
+static void lL_gotodoc(lua_State *L, GtkWidget *view, int n, int relative) {
+ if (relative && n == 0) return;
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ if (relative) {
+ l_pushdoc(L, SS(view, SCI_GETDOCPOINTER, 0, 0)), lua_gettable(L, -2);
+ n = lua_tointeger(L, -1) + n;
+ lua_pop(L, 1); // index
+ if (n > lua_objlen(L, -1))
+ n = 1;
+ else if (n < 1)
+ n = lua_objlen(L, -1);
+ lua_rawgeti(L, -1, n);
} else {
- luaL_argcheck(lua, n >= 0 && n <= lua_objlen(lua, -1), 2,
+ luaL_argcheck(L, (n > 0 && n <= lua_objlen(L, -1)) || n == -1, 2,
"no Buffer exists at that index");
- lua_rawgeti(lua, -1, n);
+ lua_rawgeti(L, -1, (n > 0) ? n : lua_objlen(L, -1));
}
- sptr_t doc = l_checkdocpointer(lua, -1);
+ sptr_t doc = l_todoc(L, -1);
SS(view, SCI_SETDOCPOINTER, 0, doc);
- l_set_buffer_global(view);
- lua_pop(lua, 2); // buffer table and buffers
+ l_setglobaldoc(L, doc);
+ lua_pop(L, 2); // buffer table and buffers
}
/**
- * Sets the global 'buffer' variable to be the document in the specified
- * Scintilla object.
- * @param view The Scintilla widget housing the buffer to be 'buffer'.
+ * Closes the Lua state.
+ * Unsplits and destroys all Scintilla views and removes all Scintilla
+ * documents, before closing the state.
+ * @param L The Lua state.
*/
-void l_set_buffer_global(GtkWidget *view) {
- sptr_t doc = SS(view, SCI_GETDOCPOINTER, 0, 0);
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_pushnil(lua);
- while (lua_next(lua, -2))
- if (doc == l_checkdocpointer(lua, -1)) {
- lua_setglobal(lua, "buffer"); // value (buffer table)
- lua_pop(lua, 1); // key
- break;
- } else lua_pop(lua, 1); // value
- lua_pop(lua, 1); // buffers
-}
-
-/**
- * Closes the Lua State.
- * Unsplits all Scintilla views recursively, removes all Scintilla documents,
- * and deletes the last Scintilla view before closing the state.
- */
-void l_close() {
+static void l_close(lua_State *L) {
closing = TRUE;
while (unsplit_view(focused_view)) ; // need space to fix compiler warning
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- sptr_t doc = l_checkdocpointer(lua, -1);
- remove_buffer(doc);
- lua_pop(lua, 1); // value
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_isnumber(L, -2)) delete_buffer(l_todoc(L, -1));
+ lua_pop(L, 1); // value
}
- lua_pop(lua, 1); // buffers
+ lua_pop(L, 1); // buffers
gtk_widget_destroy(focused_view);
- lua_close(lua);
+ lua_close(L);
}
/******************************************************************************/
@@ -1249,179 +1042,201 @@ void l_close() {
/******************************************************************************/
/**
- * Recurses through a Lua table, setting each of its keys and values to nil,
- * effectively clearing the table.
- * @param lua The Lua State.
- * @param abs_index The absolute stack index of the table to clear.
+ * Clears a table at the given valid index by setting all of its keys to nil.
+ * Cannot be called with a pseudo-index.
+ * @param L The Lua state.
+ * @param index The stack index of the table.
*/
-static void clear_table(lua_State *lua, int abs_index) {
- lua_pushnil(lua);
- while (lua_next(lua, abs_index)) {
- lua_pop(lua, 1); // value
- lua_pushnil(lua);
- lua_rawset(lua, abs_index);
- lua_pushnil(lua); // get 'new' first key
+static void lL_cleartable(lua_State *L, int index) {
+ lua_pushnil(L);
+ while (lua_next(L, index)) {
+ lua_pop(L, 1); // value
+ lua_pushnil(L), lua_rawset(L, index);
+ lua_pushnil(L); // get 'new' first key
}
}
/**
- * Prints a warning.
- * @param s The warning to print.
+ * Pushes the Scintilla view onto the stack.
+ * The view must have previously been added with lL_addview.
+ * @param L The Lua state.
+ * @param view The Scintilla view to push.
+ * @see lL_addview
*/
-static void warn(const char *s) { printf("Warning: %s\n", s); }
+static void l_pushview(lua_State *L, GtkWidget *view) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_views");
+ lua_pushlightuserdata(L, view), lua_gettable(L, -2);
+ lua_remove(L, -2); // views
+}
/**
- * Calls a Lua function with a number of arguments and expected return values.
- * The last argument is at the stack top, and each argument in reverse order is
- * one element lower on the stack with the Lua function being under the first
- * argument.
- * @param nargs The number of arguments to pass to the Lua function to call.
- * @param retn Optional number of expected return values. Defaults to 0.
- * @param keep_return Optional flag indicating whether or not to keep the return
- * values at the top of the stack. If FALSE, discards the return values.
- * Defaults to FALSE.
- * @return FALSE if an error occured or the function returns false explicitly;
- * TRUE otherwise.
+ * Pushes the Scintilla document onto the stack.
+ * The document must have previously been added with lL_adddoc.
+ * @param L The Lua state.
+ * @param doc The document to push.
+ * @see lL_adddoc
*/
-static int l_call_function(int nargs, int retn, int keep_return) {
- int ret = lua_pcall(lua, nargs, retn, 0);
- if (ret == 0) {
- int result = (retn > 0) ? lua_toboolean(lua, -1) == 1 : TRUE;
- if (retn > 0 && !keep_return) lua_pop(lua, retn); // retn
- return result;
- } else {
- if (focused_view)
- l_emit_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;
+static void l_pushdoc(lua_State *L, sptr_t doc) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_pushlightuserdata(L, (sptr_t *)doc), lua_gettable(L, -2);
+ lua_remove(L, -2); // buffers
}
/**
- * Performs a Lua rawget on a table at a given stack index and returns an int.
- * @param lua The Lua State.
- * @param index The relative index of the table to rawget from.
- * @param n The index in the table to rawget.
- * @return int result of lua_rawgeti().
+ * Prints a warning.
+ * @param s The warning to print.
*/
-static int l_rawgeti_int(lua_State *lua, int index, int n) {
- lua_rawgeti(lua, index, n);
- int ret = lua_tointeger(lua, -1);
- lua_pop(lua, 1); // integer
- return ret;
-}
+static void warn(const char *s) { printf("Warning: %s\n", s); }
/**
- * Performs a Lua rawget on a table at a given stack index and returns a string.
- * @param lua The Lua State.
- * @param index The relative index of the table to rawget from.
- * @param k String key in the table to rawget.
- * @return string result of lua_rawget().
+ * Returns the value t[n] as an integer where t is the value at the given valid
+ * index.
+ * The access is raw; that is, it does not invoke metamethods.
+ * @param L The Lua state.
+ * @param index The stack index of the table.
+ * @param n The index in the table to get.
+ * @return integer
*/
-static const char *l_rawget_str(lua_State *lua, int index, const char *k) {
- lua_pushstring(lua, k);
- lua_rawget(lua, index);
- const char *str = lua_tostring(lua, -1);
- lua_pop(lua, 1); // string
- return str;
+static int l_rawgetiint(lua_State *L, int index, int n) {
+ lua_rawgeti(L, index, n);
+ int ret = lua_tointeger(L, -1);
+ lua_pop(L, 1); // integer
+ return ret;
}
/**
- * Creates a GtkMenu from a table at the top of the Lua stack.
- * The table has a key 'title' and a numeric list of subitems.
- * @param lua The Lua State.
- * @param callback A GCallback associated with each menu item.
- * @param submenu Flag indicating whether or not this menu is a submenu.
- * @return GtkWidget menu.
+ * Returns the value t[k] as a string where t is the value at the given valid
+ * index.
+ * The access is raw; that is, it does not invoke metamethods.
+ * @param L The Lua state.
+ * @param index The stack index of the table.
+ * @param k String key in the table to get.
+ * @return string
*/
-GtkWidget *l_create_gtkmenu(lua_State *lua, GCallback callback, int submenu) {
- GtkWidget *menu = gtk_menu_new(), *menu_item = 0, *submenu_root = 0;
- const char *label;
- lua_getfield(lua, -1, "title");
- if (!lua_isnil(lua, -1) || submenu) { // title required for submenu
- label = !lua_isnil(lua, -1) ? lua_tostring(lua, -1) : "notitle";
- submenu_root = gtk_menu_item_new_with_mnemonic(label);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu_root), menu);
- }
- lua_pop(lua, 1); // title
- lua_pushnil(lua);
- while (lua_next(lua, -2)) {
- if (lua_istable(lua, -1)) {
- lua_getfield(lua, -1, "title");
- int is_submenu = !lua_isnil(lua, -1);
- lua_pop(lua, 1); // title
- if (is_submenu)
- gtk_menu_shell_append(GTK_MENU_SHELL(menu),
- l_create_gtkmenu(lua, callback, TRUE));
- else
- if (lua_objlen(lua, -1) == 2 || lua_objlen(lua, -1) == 4) {
- lua_rawgeti(lua, -1, 1);
- lua_rawgeti(lua, -2, 2);
- label = lua_tostring(lua, -2);
- int menu_id = lua_tointeger(lua, -1);
- lua_rawgeti(lua, -3, 3);
- lua_rawgeti(lua, -4, 4);
- int key = !lua_isnil(lua, -2) ? lua_tointeger(lua, -2) : 0;
- int modifiers = !lua_isnil(lua, -1) ? lua_tointeger(lua, -1) : 0;
- lua_pop(lua, 4); // label, id, key, and modifiers
- if (label) {
- if (g_str_has_prefix(label, "gtk-"))
- menu_item = gtk_image_menu_item_new_from_stock(label, NULL);
- else if (streq(label, "separator"))
- menu_item = gtk_separator_menu_item_new();
- else
- menu_item = gtk_menu_item_new_with_mnemonic(label);
- if (key || modifiers)
- gtk_widget_add_accelerator(menu_item, "activate", accel, key,
- modifiers, GTK_ACCEL_VISIBLE);
- g_signal_connect(menu_item, "activate", callback,
- GINT_TO_POINTER(menu_id));
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
- }
- } else warn("gtkmenu: { 'label', id_num [, keycode, mods] } expected");
- }
- lua_pop(lua, 1); // value
- }
- return !submenu_root ? menu : submenu_root;
+static const char *l_rawgetstr(lua_State *L, int index, const char *k) {
+ lua_pushstring(L, k);
+ lua_rawget(L, index);
+ const char *str = lua_tostring(L, -1);
+ lua_pop(L, 1); // string
+ return str;
}
/**
- * Convert the stack element at a specified index to a Scintilla w and/or l long
- * parameter based on type.
- * @param lua The Lua State.
- * @param type The Lua type the top stack element is.
- * @param arg_idx The initial stack index to start converting at. It is
- * incremented as parameters are read from the stack.
- * @return long for Scintilla.
+ * Checks whether the function argument narg is the given Scintilla parameter
+ * type and returns it cast to the proper type.
+ * @param L The Lua state.
+ * @param index The stack index of the Scintilla parameter.
+ * @param type The Scintilla type to convert to.
+ * @return Scintilla param
*/
-static long l_toscintillaparam(lua_State *lua, int type, int *arg_idx) {
+static long lL_checkscintillaparam(lua_State *L, int *narg, int type) {
if (type == tSTRING)
- return (long)luaL_checkstring(lua, (*arg_idx)++);
+ return (long)luaL_checkstring(L, (*narg)++);
else if (type == tBOOL)
- return lua_toboolean(lua, (*arg_idx)++);
+ return lua_toboolean(L, (*narg)++);
else if (type == tKEYMOD) {
- int key = luaL_checkinteger(lua, (*arg_idx)++) & 0xFFFF;
- return key | ((luaL_checkinteger(lua, (*arg_idx)++) &
+ int key = luaL_checkinteger(L, (*narg)++) & 0xFFFF;
+ return key | ((luaL_checkinteger(L, (*narg)++) &
(SCMOD_SHIFT | SCMOD_CTRL | SCMOD_ALT)) << 16);
} else if (type > tVOID && type < tBOOL)
- return luaL_checklong(lua, (*arg_idx)++);
+ return luaL_checklong(L, (*narg)++);
else
return 0;
}
/**
- * Checks if the Scintilla document of the buffer table at the index specified
- * is the document of the focused Scintilla view.
- * Throws an error if the check is not satisfied.
- * @param lua The Lua State.
- * @param narg The relative stack position of the buffer table.
+ * Checks whether the function argument narg is a Scintilla view and returns
+ * this view cast to a GtkWidget.
+ * @param L The Lua state.
+ * @param narg The stack index of the Scintilla view.
+ * @return Scintilla view
+ */
+static GtkWidget *lL_checkview(lua_State *L, int narg) {
+ luaL_getmetatable(L, "ta_view");
+ lua_getmetatable(L, narg);
+ luaL_argcheck(L, lua_equal(L, -1, -2), narg, "View expected");
+ lua_getfield(L, (narg > 0) ? narg : narg - 2, "widget_pointer");
+ GtkWidget *view = (GtkWidget *)lua_touserdata(L, -1);
+ lua_pop(L, 3); // widget_pointer, metatable, metatable
+ return view;
+}
+
+/**
+ * Checks whether the function argument narg is a Scintilla document. If not,
+ * raises an error.
+ * @param L The Lua state.
+ * @param narg The stack index of the Scintilla document.
+ * @return Scintilla document
*/
-static void l_check_focused_buffer(lua_State *lua, int narg) {
- sptr_t cur_doc = SS(focused_view, SCI_GETDOCPOINTER, 0, 0);
- luaL_argcheck(lua, cur_doc == l_checkdocpointer(lua, narg), 1,
+static void lL_globaldoccheck(lua_State *L, int narg) {
+ luaL_getmetatable(L, "ta_buffer");
+ lua_getmetatable(L, (narg > 0) ? narg : narg - 1);
+ luaL_argcheck(L, lua_equal(L, -1, -2), narg, "Buffer expected");
+ lua_getfield(L, (narg > 0) ? narg : narg - 2, "doc_pointer");
+ sptr_t doc = (sptr_t)lua_touserdata(L, -1);
+ luaL_argcheck(L, doc == SS(focused_view, SCI_GETDOCPOINTER, 0, 0), narg,
"this buffer is not the current one");
+ lua_pop(L, 3); // doc_pointer, metatable, metatable
+}
+
+/**
+ * Pushes a GTK menu created from the table at the given valid index onto the
+ * stack.
+ * Consult the LuaDoc for the table format.
+ * @param L The Lua state.
+ * @param callback A GCallback associated with each menu item.
+ * @param submenu Flag indicating whether or not this menu is a submenu.
+ */
+static void l_pushgtkmenu(lua_State *L, int index, GCallback callback,
+ int submenu) {
+ GtkWidget *menu = gtk_menu_new(), *menu_item = 0, *submenu_root = 0;
+ const char *label;
+ lua_pushvalue(L, index); // copy to stack top so pseudo-indices can be used
+ lua_getfield(L, -1, "title");
+ if (!lua_isnil(L, -1) || submenu) { // title required for submenu
+ label = !lua_isnil(L, -1) ? lua_tostring(L, -1) : "notitle";
+ submenu_root = gtk_menu_item_new_with_mnemonic(label);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu_root), menu);
+ }
+ lua_pop(L, 1); // title
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "title");
+ int is_submenu = !lua_isnil(L, -1);
+ lua_pop(L, 1); // title
+ if (is_submenu) {
+ l_pushgtkmenu(L, -1, callback, TRUE);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu),
+ (GtkWidget *)lua_touserdata(L, -1));
+ lua_pop(L, 1); // gtkmenu
+ } else if (lua_objlen(L, -1) == 2 || lua_objlen(L, -1) == 4) {
+ lua_rawgeti(L, -1, 1);
+ label = lua_tostring(L, -1);
+ lua_pop(L, 1); // label
+ int menu_id = l_rawgetiint(L, -1, 2);
+ int key = l_rawgetiint(L, -1, 3);
+ int modifiers = l_rawgetiint(L, -1, 4);
+ if (label) {
+ if (g_str_has_prefix(label, "gtk-"))
+ menu_item = gtk_image_menu_item_new_from_stock(label, NULL);
+ else if (strcmp(label, "separator") == 0)
+ menu_item = gtk_separator_menu_item_new();
+ else
+ menu_item = gtk_menu_item_new_with_mnemonic(label);
+ if (key || modifiers)
+ gtk_widget_add_accelerator(menu_item, "activate", accel, key,
+ modifiers, GTK_ACCEL_VISIBLE);
+ g_signal_connect(menu_item, "activate", callback,
+ GINT_TO_POINTER(menu_id));
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
+ }
+ } else warn("gtkmenu: { 'label', id_num [, keycode, mods] } expected");
+ }
+ lua_pop(L, 1); // value
+ }
+ lua_pop(L, 1); // table copy
+ lua_pushlightuserdata(L, !submenu_root ? menu : submenu_root);
}
/******************************************************************************/
@@ -1429,99 +1244,107 @@ static void l_check_focused_buffer(lua_State *lua, int narg) {
/******************************************************************************/
/**
- * Handles a Textadept event.
- * @param s String event name.
- * @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.
- * @return FALSE on error or if event returns false explicitly; TRUE otherwise.
+ * Emits an event.
+ * @param L The Lua state.
+ * @param name The event name.
+ * @param ... Arguments to pass with the event. Each pair of arguments should be
+ * a Lua type followed by the data value itself. For LUA_TLIGHTUSERDATA and
+ * LUA_TTABLE types, push the data values to the stack and give the value
+ * returned by luaL_ref(); luaL_unref() will be called appropriately. The list
+ * must be terminated with a -1.
+ * @return TRUE or FALSE depending on the boolean value returned by the event
+ * handler, if any.
*/
-int l_emit_event(const char *s, ...) {
- lua_getglobal(lua, "events");
- if (lua_istable(lua, -1)) {
- lua_getfield(lua, -1, "emit");
- lua_remove(lua, -2); // events table
- if (lua_isfunction(lua, -1)) {
- lua_pushstring(lua, s);
+static int lL_event(lua_State *L, const char *name, ...) {
+ int ret = FALSE;
+ lua_getglobal(L, "events");
+ if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "emit");
+ lua_remove(L, -2); // events table
+ if (lua_isfunction(L, -1)) {
+ lua_pushstring(L, name);
int n = 1;
va_list ap;
- va_start(ap, s);
+ va_start(ap, name);
int type = va_arg(ap, int);
while (type != -1) {
void *arg = va_arg(ap, void*);
if (type == LUA_TNIL)
- lua_pushnil(lua);
+ lua_pushnil(L);
else if (type == LUA_TBOOLEAN)
- lua_pushboolean(lua, (long)arg);
+ lua_pushboolean(L, (long)arg);
else if (type == LUA_TNUMBER)
- lua_pushinteger(lua, (long)arg);
+ lua_pushinteger(L, (long)arg);
else if (type == LUA_TSTRING)
- lua_pushstring(lua, (char *)arg);
+ lua_pushstring(L, (char *)arg);
else if (type == LUA_TLIGHTUSERDATA || type == LUA_TTABLE) {
long ref = (long)arg;
- lua_rawgeti(lua, LUA_REGISTRYINDEX, ref);
- luaL_unref(lua, LUA_REGISTRYINDEX, ref);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+ luaL_unref(L, LUA_REGISTRYINDEX, ref);
} else warn("events.emit: ignored invalid argument type");
n++;
type = va_arg(ap, int);
}
va_end(ap);
- return l_call_function(n, 1, FALSE);
- } else lua_pop(lua, 1); // non-function
- } else lua_pop(lua, 1); // non-table
- return FALSE;
-}
-
-#define l_pushscninteger(i, n) { \
- lua_pushinteger(lua, i); \
- lua_setfield(lua, -2, n); \
+ if (lua_pcall(L, n, 1, 0) == 0)
+ ret = lua_toboolean(L, -1);
+ else
+ lL_event(L, "error", LUA_TSTRING, lua_tostring(L, -1), -1);
+ lua_pop(L, 1); // result
+ } else lua_pop(L, 1); // non-function
+ } else lua_pop(L, 1); // non-table
+ return ret;
}
/**
- * Handles a Scintilla notification.
+ * Emits a Scintilla notification event.
+ * @param L The Lua state.
* @param n The Scintilla notification struct.
+ * @see lL_event
*/
-void l_emit_scnotification(struct SCNotification *n) {
- lua_newtable(lua);
- l_pushscninteger(n->nmhdr.code, "code");
- l_pushscninteger(n->position, "position");
- l_pushscninteger(n->ch, "ch");
- l_pushscninteger(n->modifiers, "modifiers");
- //l_pushscninteger(n->modificationType, "modification_type");
- lua_pushstring(lua, n->text);
- lua_setfield(lua, -2, "text");
- //l_pushscninteger(n->length, "length");
- //l_pushscninteger(n->linesAdded, "lines_added");
- //l_pushscninteger(n->message, "message");
- l_pushscninteger(n->wParam, "wParam");
- l_pushscninteger(n->lParam, "lParam");
- l_pushscninteger(n->line, "line");
- //l_pushscninteger(n->foldLevelNow, "fold_level_now");
- //l_pushscninteger(n->foldLevelPrev, "fold_level_prev");
- l_pushscninteger(n->margin, "margin");
- l_pushscninteger(n->x, "x");
- l_pushscninteger(n->y, "y");
- l_emit_event("SCN", LUA_TTABLE, luaL_ref(lua, LUA_REGISTRYINDEX), -1);
+static void lL_notify(lua_State *L, struct SCNotification *n) {
+ lua_newtable(L);
+ lua_pushinteger(L, n->nmhdr.code), lua_setfield(L, -2, "code");
+ lua_pushinteger(L, n->position), lua_setfield(L, -2, "position");
+ lua_pushinteger(L, n->ch), lua_setfield(L, -2, "ch");
+ lua_pushinteger(L, n->modifiers), lua_setfield(L, -2, "modifiers");
+ //lua_pushinteger(L, n->modificationType);
+ //lua_setfield(L, -2, "modification_type");
+ lua_pushstring(L, n->text), lua_setfield(L, -2, "text");
+ //lua_pushinteger(L, n->length), lua_setfield(L, -2, "length");
+ //lua_pushinteger(L, n->linesAdded), lua_setfield(L, -2, "lines_added");
+ //lua_pushinteger(L, n->message), lua_setfield(L, -2, "message");
+ lua_pushinteger(L, n->wParam), lua_setfield(L, -2, "wParam");
+ lua_pushinteger(L, n->lParam), lua_setfield(L, -2, "lParam");
+ lua_pushinteger(L, n->line), lua_setfield(L, -2, "line");
+ //lua_pushinteger(L, n->foldLevelNow), lua_setfield(L, -2, "fold_level_now");
+ //lua_pushinteger(L, n->foldLevelPrev);
+ //lua_setfield(L, -2, "fold_level_prev");
+ lua_pushinteger(L, n->margin), lua_setfield(L, -2, "margin");
+ lua_pushinteger(L, n->x), lua_setfield(L, -2, "x");
+ lua_pushinteger(L, n->y), lua_setfield(L, -2, "y");
+ lL_event(L, "SCN", LUA_TTABLE, luaL_ref(L, LUA_REGISTRYINDEX), -1);
}
/**
- * Requests and pops up a context menu for the Scintilla view.
+ * Shows the context menu for a Scintilla view based on a mouse event.
+ * @param L The Lua state.
* @param event The mouse button event.
*/
-void l_gui_popup_context_menu(GdkEventButton *event) {
- lua_getglobal(lua, "gui");
- if (lua_istable(lua, -1)) {
- lua_getfield(lua, -1, "context_menu");
- if (lua_isuserdata(lua, -1)) {
- GtkWidget *menu = l_togtkwidget(lua, -1);
+static void lL_showcontextmenu(lua_State *L, GdkEventButton *event) {
+ lua_getglobal(L, "gui");
+ if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "context_menu");
+ if (lua_isuserdata(L, -1)) {
+ GtkWidget *menu = (GtkWidget *)lua_touserdata(L, -1);
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
event ? event->button : 0,
gdk_event_get_time((GdkEvent *)event));
- } else if (!lua_isnil(lua, -1))
+ } else if (!lua_isnil(L, -1))
warn("gui.context_menu: gtkmenu expected");
- lua_pop(lua, 1); // gui.context_menu
- } else lua_pop(lua, 1);
+ lua_pop(L, 1); // gui.context_menu
+ } else lua_pop(L, 1); // non-table
}
/******************************************************************************/
@@ -1530,518 +1353,476 @@ void l_gui_popup_context_menu(GdkEventButton *event) {
/******************************************************************************/
/**
- * Calls Scintilla with appropriate parameters and returs appropriate values.
- * @param lua The Lua State.
- * @param view The Scintilla view to call.
- * @param msg The integer message index to call Scintilla with.
- * @param p1_type The Lua type of p1, the Scintilla w parameter.
- * @param p2_type The Lua type of p2, the Scintilla l parameter.
- * @param rt_type The Lua type of the Scintilla return parameter.
- * @param arg The index on the Lua stack where arguments to Scintilla begin.
+ * Calls a function as a Scintilla function.
+ * Does not remove any arguments from the stack, but does push results.
+ * @param L The Lua state.
+ * @param msg The Scintilla message.
+ * @param wtype The type of Scintilla wParam.
+ * @param ltype The type of Scintilla lParam.
+ * @param rtype The type of the Scintilla return.
+ * @param arg The stack index of the first Scintilla parameter. Subsequent
+ * elements will also be passed to Scintilla as needed.
+ * @return number of results pushed onto the stack.
+ * @see lL_checkscintillaparam
*/
-static int l_call_scintilla(lua_State *lua, GtkWidget *view, int msg,
- int p1_type, int p2_type, int rt_type, int arg) {
- long params[2] = {0, 0};
- int params_needed = 2, len = 0, string_return = FALSE;
+static int l_callscintilla(lua_State *L, int msg, int wtype, int ltype,
+ int rtype, int arg) {
+ uptr_t wparam = 0;
+ sptr_t lparam = 0, len = 0;
+ int params_needed = 2, string_return = FALSE;
char *return_string = 0;
- // SCI_PRIVATELEXERCALL iface has p1_type int, p2_type int. Change p2_type
- // appropriately. See LPeg lexer API for more info.
+ // Even though the SCI_PRIVATELEXERCALL interface has ltype int, the LPeg
+ // lexer API uses different types depending on wparam. Modify ltype
+ // appropriately. See the LPeg lexer API for more information.
if (msg == SCI_PRIVATELEXERCALL) {
- p2_type = tSTRINGRESULT;
- int c = luaL_checklong(lua, arg);
+ ltype = tSTRINGRESULT;
+ int c = luaL_checklong(L, arg);
if (c == SCI_GETDIRECTFUNCTION || c == SCI_SETDOCPOINTER)
- p2_type = tINT;
+ ltype = tINT;
else if (c == SCI_SETLEXERLANGUAGE)
- p2_type = tSTRING;
+ ltype = tSTRING;
}
- // Set the w and l parameters appropriately for Scintilla.
- if (p1_type == tLENGTH && p2_type == tSTRING) {
- params[0] = (long)lua_strlen(lua, arg);
- params[1] = (long)luaL_checkstring(lua, arg);
+ // Set wParam and lParam appropriately for Scintilla based on wtype and ltype.
+ if (wtype == tLENGTH && ltype == tSTRING) {
+ wparam = (uptr_t)lua_strlen(L, arg);
+ lparam = (sptr_t)luaL_checkstring(L, arg);
params_needed = 0;
- } else if (p2_type == tSTRINGRESULT) {
+ } else if (ltype == tSTRINGRESULT) {
string_return = TRUE;
- params_needed = (p1_type == tLENGTH) ? 0 : 1;
+ params_needed = (wtype == tLENGTH) ? 0 : 1;
}
- if (params_needed > 0) params[0] = l_toscintillaparam(lua, p1_type, &arg);
- if (params_needed > 1) params[1] = l_toscintillaparam(lua, p2_type, &arg);
- if (string_return) { // if a string return, create a buffer for it
- len = SS(view, msg, params[0], 0);
- if (p1_type == tLENGTH) params[0] = len;
- return_string = malloc(len + 1);
- return_string[len] = '\0';
+ if (params_needed > 0) wparam = lL_checkscintillaparam(L, &arg, wtype);
+ if (params_needed > 1) lparam = lL_checkscintillaparam(L, &arg, ltype);
+ if (string_return) { // create a buffer for the return string
+ len = SS(focused_view, msg, wparam, 0);
+ if (wtype == tLENGTH) wparam = len;
+ return_string = malloc(len + 1), return_string[len] = '\0';
if (msg == SCI_GETTEXT || msg == SCI_GETSELTEXT || msg == SCI_GETCURLINE)
len--; // Scintilla appends '\0' for these messages; compensate
- params[1] = (long)return_string;
+ lparam = (sptr_t)return_string;
}
// Send the message to Scintilla and return the appropriate values.
- sptr_t result = SS(view, msg, params[0], params[1]);
- arg = lua_gettop(lua);
- if (string_return) lua_pushlstring(lua, return_string, len);
- if (rt_type == tBOOL) lua_pushboolean(lua, result);
- if (rt_type > tVOID && rt_type < tBOOL) lua_pushinteger(lua, result);
+ sptr_t result = SS(focused_view, msg, wparam, lparam);
+ arg = lua_gettop(L);
+ if (string_return) lua_pushlstring(L, return_string, len);
+ if (rtype == tBOOL) lua_pushboolean(L, result);
+ if (rtype > tVOID && rtype < tBOOL) lua_pushinteger(L, result);
g_free(return_string);
- return lua_gettop(lua) - arg;
-}
-
-/**
- * Calls a Scintilla buffer function with upvalues from a closure.
- * @param lua The Lua State.
- * @see l_buffer_mt_index
- */
-static int l_call_buffer_function(lua_State *lua) {
- GtkWidget *view = focused_view;
- int buffer_func_table_idx = lua_upvalueindex(1);
- int msg = l_rawgeti_int(lua, buffer_func_table_idx, 1);
- int rt_type = l_rawgeti_int(lua, buffer_func_table_idx, 2);
- int p1_type = l_rawgeti_int(lua, buffer_func_table_idx, 3);
- int p2_type = l_rawgeti_int(lua, buffer_func_table_idx, 4);
- int arg = 1;
- if (lua_type(lua, 1) == LUA_TTABLE) {
- l_check_focused_buffer(lua, 1);
- arg = 2;
+ return lua_gettop(L) - arg;
+}
+
+static int lbuf_closure(lua_State *L) {
+ // If optional buffer argument is given, check it.
+ if (lua_istable(L, 1)) lL_globaldoccheck(L, 1);
+ // Interface table is of the form { msg, rtype, wtype, ltype }.
+ return l_callscintilla(L, l_rawgetiint(L, lua_upvalueindex(1), 1),
+ l_rawgetiint(L, lua_upvalueindex(1), 3),
+ l_rawgetiint(L, lua_upvalueindex(1), 4),
+ l_rawgetiint(L, lua_upvalueindex(1), 2),
+ lua_istable(L, 1) ? 2 : 1);
+}
+
+static int lbuf_property(lua_State *L) {
+ int newindex = (lua_gettop(L) == 3);
+ luaL_getmetatable(L, "ta_buffer");
+ lua_getmetatable(L, 1); // metatable can be either ta_buffer or ta_bufferp
+ int is_buffer = lua_equal(L, -1, -2);
+ lua_pop(L, 2); // metatable, metatable
+
+ // If the key is a Scintilla function, return a callable closure.
+ if (is_buffer && !newindex) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_functions");
+ lua_pushvalue(L, 2), lua_gettable(L, -2);
+ if (lua_istable(L, -1)) return (lua_pushcclosure(L, lbuf_closure, 1), 1);
+ lua_pop(L, 2); // non-table, ta_functions
}
- return l_call_scintilla(lua, view, msg, p1_type, p2_type, rt_type, arg);
-}
-/**
- * Metatable index for a buffer table.
- * If the key is a Scintilla buffer function, push a closure so it can be called
- * as a function. If the key is a non-indexable buffer property, call Scintilla
- * to get it. If the key is an indexible buffer property, push a table with a
- * metatable to access buffer property indices.
- * @param lua The Lua State.
- */
-static int l_buffer_mt_index(lua_State *lua) {
- const char *key = luaL_checkstring(lua, 2);
-
- lua_getfield(lua, LUA_REGISTRYINDEX, "functions");
- lua_getfield(lua, -1, key);
- lua_remove(lua, -2); // buffer functions
- if (lua_istable(lua, -1)) {
- // Of the form { msg, rt_type, p1_type, p2_type }
- lua_pushcclosure(lua, l_call_buffer_function, 1);
- return 1;
- } else lua_pop(lua, 1); // non-table
-
- lua_getfield(lua, LUA_REGISTRYINDEX, "properties");
- lua_getfield(lua, -1, key);
- lua_remove(lua, -2); // buffer properties
- if (lua_istable(lua, -1)) {
- l_check_focused_buffer(lua, 1);
- // Of the form { get_id, set_id, rt_type, p1_type }
- int msg = l_rawgeti_int(lua, -1, 1); // getter
- int rt_type = l_rawgeti_int(lua, -1, 3);
- int p1_type = l_rawgeti_int(lua, -1, 4);
- if (p1_type != tVOID) { // indexible property
- sptr_t doc = SS(focused_view, SCI_GETDOCPOINTER, 0, 0);
- lua_newtable(lua);
- lua_pushstring(lua, key);
- lua_setfield(lua, -2, "property");
- lua_pushinteger(lua, doc);
- lua_setfield(lua, -2, "doc_pointer");
- l_mt(lua, "_bufferp_mt", l_bufferp_mt_index, l_bufferp_mt_newindex);
+ // If the key is a Scintilla property, determine if it is an indexible one or
+ // not. If so, return a table with the appropriate metatable; otherwise call
+ // Scintilla to get or set the property's value.
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_properties");
+ if (is_buffer)
+ lua_pushvalue(L, 2); // key is given
+ else
+ lua_getfield(L, 1, "property"); // indexible property
+ lua_gettable(L, -2);
+ if (lua_istable(L, -1)) {
+ // Interface table is of the form { get_id, set_id, rtype, wtype }.
+ if (!is_buffer)
+ lua_getfield(L, 1, "buffer"), lL_globaldoccheck(L, -1), lua_pop(L, 1);
+ else
+ lL_globaldoccheck(L, 1);
+ if (is_buffer && l_rawgetiint(L, -1, 4) != tVOID) { // indexible property
+ lua_newtable(L);
+ lua_pushvalue(L, 2), lua_setfield(L, -2, "property");
+ lua_pushvalue(L, 1), lua_setfield(L, -2, "buffer");
+ l_setmetatable(L, -1, "ta_bufferp", lbuf_property, lbuf_property);
return 1;
- } else return l_call_scintilla(lua, focused_view, msg, p1_type, tVOID,
- rt_type, 2);
- } else lua_pop(lua, 1); // non-table
-
- lua_rawget(lua, 1);
- return 1;
-}
-
-/**
- * Helper function for the buffer property metatable.
- * Throws an error when trying to write to a read-only property or when trying
- * to read a write-only property.
- * @param lua The Lua State.
- * @param n 1 for getter property, 2 for setter.
- * @param prop String property name.
- * @param arg The index on the Lua stack where arguments to Scintilla begin.
- * For setter properties, it is 3 because the index is not an argument. For
- * getter and setter properties, it is 2 because the index is an argument.
- */
-static int l_bufferp_mt_(lua_State *lua, int n, const char *prop, int arg) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "properties");
- lua_getfield(lua, -1, prop);
- lua_remove(lua, -2); // buffer properties
- if (lua_istable(lua, -1)) {
- l_check_focused_buffer(lua, 1);
- int msg = l_rawgeti_int(lua, -1, n); // getter (1) or setter (2)
- int rt_type = (n == 1) ? l_rawgeti_int(lua, -1, 3) : tVOID;
- int p1_type = l_rawgeti_int(lua, -1, (n == 1) ? 4 : 3);
- int p2_type = (n == 2) ? l_rawgeti_int(lua, -1, 4) : tVOID;
- if (n == 2 &&
- (p2_type != tVOID || (p2_type == tVOID && p1_type == tSTRING))) {
- int temp = p1_type;
- p1_type = p2_type;
- p2_type = temp;
}
- luaL_argcheck(lua, msg != 0, arg,
- (n == 1) ? "write-only property" : "read-only property");
- return l_call_scintilla(lua, focused_view, msg, p1_type, p2_type, rt_type,
- arg);
- } else lua_pop(lua, 1); // non-table
-
- (lua_gettop(lua) > 2) ? lua_rawset(lua, 1) : lua_rawget(lua, 1);
- return 0;
-}
-
-static int l_buffer_mt_newindex(lua_State *lua) {
- return l_bufferp_mt_(lua, 2, lua_tostring(lua, 2), 3);
-}
-
-static int l_bufferp_mt_index(lua_State *lua) {
- return l_bufferp_mt_(lua, 1, l_rawget_str(lua, 1, "property"), 2);
-}
+ int msg = l_rawgetiint(L, -1, !newindex ? 1 : 2);
+ int wtype = l_rawgetiint(L, -1, !newindex ? 4 : 3);
+ int ltype = !newindex ? tVOID : l_rawgetiint(L, -1, 4);
+ int rtype = !newindex ? l_rawgetiint(L, -1, 3) : tVOID;
+ if (newindex && (ltype != tVOID || wtype == tSTRING)) {
+ int temp = wtype;
+ wtype = ltype, ltype = temp;
+ }
+ luaL_argcheck(L, msg != 0, !newindex ? 2 : 3,
+ !newindex ? "write-only property" : "read-only property");
+ return l_callscintilla(L, msg, wtype, ltype, rtype,
+ (!is_buffer || !newindex) ? 2 : 3);
+ } else lua_pop(L, 2); // non-table, ta_properties
-static int l_bufferp_mt_newindex(lua_State *lua) {
- return l_bufferp_mt_(lua, 2, l_rawget_str(lua, 1, "property"), 2);
+ !newindex ? lua_rawget(L, 1) : lua_rawset(L, 1);
+ return 1;
}
-static int l_view_mt_index(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "doc_pointer"))
- lua_pushinteger(lua, SS(l_checkview(lua, 1), SCI_GETDOCPOINTER, 0, 0));
- else if (streq(key, "size")) {
- GtkWidget *view = l_checkview(lua, 1);
+static int lview__index(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "buffer") == 0)
+ l_pushdoc(L, SS(lL_checkview(L, 1), SCI_GETDOCPOINTER, 0, 0));
+ else if (strcmp(key, "size") == 0) {
+ GtkWidget *view = lL_checkview(L, 1);
if (GTK_IS_PANED(gtk_widget_get_parent(view))) {
int pos = gtk_paned_get_position(GTK_PANED(gtk_widget_get_parent(view)));
- lua_pushinteger(lua, pos);
- } else lua_pushnil(lua);
- } else lua_rawget(lua, 1);
+ lua_pushinteger(L, pos);
+ } else lua_pushnil(L);
+ } else lua_rawget(L, 1);
return 1;
}
-static int l_view_mt_newindex(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "size")) {
- GtkWidget *pane = gtk_widget_get_parent(l_checkview(lua, 1));
- int size = luaL_checkinteger(lua, 3);
+static int lview__newindex(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "buffer") == 0)
+ luaL_argerror(L, 3, "read-only property");
+ else if (strcmp(key, "size") == 0) {
+ GtkWidget *pane = gtk_widget_get_parent(lL_checkview(L, 1));
+ int size = luaL_checkinteger(L, 3);
if (size < 0) size = 0;
if (GTK_IS_PANED(pane)) gtk_paned_set_position(GTK_PANED(pane), size);
- } else lua_rawset(lua, 1);
+ } else lua_rawset(L, 1);
return 0;
}
-static int l_gui_mt_index(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "title"))
- lua_pushstring(lua, gtk_window_get_title(GTK_WINDOW(window)));
- else if (streq(key, "focused_doc_pointer"))
- lua_pushinteger(lua, SS(focused_view, SCI_GETDOCPOINTER, 0, 0));
- else if (streq(key, "statusbar_text"))
- lua_pushstring(lua, statusbar_text);
- else if (streq(key, "clipboard_text")) {
+static int lgui__index(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "title") == 0)
+ lua_pushstring(L, gtk_window_get_title(GTK_WINDOW(window)));
+ else if (strcmp(key, "statusbar_text") == 0)
+ lua_pushstring(L, statusbar_text);
+ else if (strcmp(key, "clipboard_text") == 0) {
char *text = gtk_clipboard_wait_for_text(
gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
- if (text) {
- lua_pushstring(lua, text);
- g_free(text);
- } else lua_pushstring(lua, "");
- } else if (streq(key, "size")) {
- lua_newtable(lua);
+ lua_pushstring(L, text ? text : "");
+ if (text) g_free(text);
+ } else if (strcmp(key, "size") == 0) {
int width, height;
gtk_window_get_size(GTK_WINDOW(window), &width, &height);
- lua_pushinteger(lua, width);
- lua_rawseti(lua, -2, 1);
- lua_pushinteger(lua, height);
- lua_rawseti(lua, -2, 2);
- } else lua_rawget(lua, 1);
+ lua_newtable(L);
+ lua_pushinteger(L, width), lua_rawseti(L, -2, 1);
+ lua_pushinteger(L, height), lua_rawseti(L, -2, 2);
+ } else lua_rawget(L, 1);
return 1;
}
-static int l_gui_mt_newindex(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "title"))
- gtk_window_set_title(GTK_WINDOW(window), lua_tostring(lua, 3));
- else if (streq(key, "focused_doc_pointer") || streq(key, "clipboard_text"))
- luaL_argerror(lua, 3, "read-only property");
- else if (streq(key, "docstatusbar_text"))
- set_statusbar_text(lua_tostring(lua, 3), 1);
- else if (streq(key, "statusbar_text")) {
+static void set_statusbar_text(const char *text, int bar) {
+ if (!statusbar[0] || !statusbar[1]) return; // unavailable on startup
+ gtk_statusbar_pop(GTK_STATUSBAR(statusbar[bar]), 0);
+ gtk_statusbar_push(GTK_STATUSBAR(statusbar[bar]), 0, text);
+}
+
+static int lgui__newindex(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "title") == 0)
+ gtk_window_set_title(GTK_WINDOW(window), lua_tostring(L, 3));
+ else if (strcmp(key, "clipboard_text") == 0)
+ luaL_argerror(L, 3, "read-only property");
+ else if (strcmp(key, "docstatusbar_text") == 0)
+ set_statusbar_text(lua_tostring(L, 3), 1);
+ else if (strcmp(key, "statusbar_text") == 0) {
g_free(statusbar_text);
- statusbar_text = g_strdup(!lua_isnil(lua, 3) ? lua_tostring(lua, 3) : "");
+ statusbar_text = g_strdup(luaL_optstring(L, 3, ""));
set_statusbar_text(statusbar_text, 0);
- } else if (streq(key, "menubar")) {
- luaL_argcheck(lua, lua_istable(lua, 3), 3, "table of menus expected");
- GtkWidget *menubar = gtk_menu_bar_new();
- lua_pushnil(lua);
- while (lua_next(lua, 3)) {
- luaL_argcheck(lua, lua_isuserdata(lua, -1), 3, "table of menus expected");
- GtkWidget *menu_item = l_togtkwidget(lua, -1);
- gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_item);
- lua_pop(lua, 1); // value
+ } else if (strcmp(key, "menubar") == 0) {
+ luaL_argcheck(L, lua_istable(L, 3), 3, "table of menus expected");
+ GtkWidget *new_menubar = gtk_menu_bar_new();
+ lua_pushnil(L);
+ while (lua_next(L, 3)) {
+ luaL_argcheck(L, lua_isuserdata(L, -1), 3, "table of menus expected");
+ GtkWidget *menu_item = (GtkWidget *)lua_touserdata(L, -1);
+ gtk_menu_shell_append(GTK_MENU_SHELL(new_menubar), menu_item);
+ lua_pop(L, 1); // value
}
- set_menubar(menubar);
- } else if (streq(key, "size")) {
- luaL_argcheck(lua, lua_istable(lua, 3) && lua_objlen(lua, 3) == 2, 3,
+ GtkWidget *vbox = gtk_widget_get_parent(menubar);
+ gtk_container_remove(GTK_CONTAINER(vbox), menubar);
+ menubar = new_menubar;
+ gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
+ gtk_box_reorder_child(GTK_BOX(vbox), menubar, 0);
+ gtk_widget_show_all(menubar);
+#if __OSX__
+ ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(menubar));
+ gtk_widget_hide(menubar);
+#endif
+ } else if (strcmp(key, "size") == 0) {
+ luaL_argcheck(L, lua_istable(L, 3) && lua_objlen(L, 3) == 2, 3,
"{ width, height } table expected");
- int width = l_rawgeti_int(lua, 3, 1);
- int height = l_rawgeti_int(lua, 3, 2);
- if (width > 0 && height > 0)
- gtk_window_resize(GTK_WINDOW(window), width, height);
- } else lua_rawset(lua, 1);
+ int w = l_rawgetiint(L, 3, 1), h = l_rawgetiint(L, 3, 2);
+ if (w > 0 && h > 0) gtk_window_resize(GTK_WINDOW(window), w, h);
+ } else lua_rawset(L, 1);
return 0;
}
#define toggled(w) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))
-static int l_find_mt_index(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "find_entry_text"))
- lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(find_entry)));
- else if (streq(key, "replace_entry_text"))
- lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(replace_entry)));
- else if (streq(key, "match_case"))
- lua_pushboolean(lua, toggled(match_case_opt));
- else if (streq(key, "whole_word"))
- lua_pushboolean(lua, toggled(whole_word_opt));
- else if (streq(key, "lua"))
- lua_pushboolean(lua, toggled(lua_opt));
- else if (streq(key, "in_files"))
- lua_pushboolean(lua, toggled(in_files_opt));
+static int lfind__index(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "find_entry_text") == 0)
+ lua_pushstring(L, gtk_entry_get_text(GTK_ENTRY(find_entry)));
+ else if (strcmp(key, "replace_entry_text") == 0)
+ lua_pushstring(L, gtk_entry_get_text(GTK_ENTRY(replace_entry)));
+ else if (strcmp(key, "match_case") == 0)
+ lua_pushboolean(L, toggled(match_case_opt));
+ else if (strcmp(key, "whole_word") == 0)
+ lua_pushboolean(L, toggled(whole_word_opt));
+ else if (strcmp(key, "lua") == 0)
+ lua_pushboolean(L, toggled(lua_opt));
+ else if (strcmp(key, "in_files") == 0)
+ lua_pushboolean(L, toggled(in_files_opt));
else
- lua_rawget(lua, 1);
+ lua_rawget(L, 1);
return 1;
}
#define toggle(w, b) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), b)
-static int l_find_mt_newindex(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "find_entry_text"))
- gtk_entry_set_text(GTK_ENTRY(find_entry), lua_tostring(lua, 3));
- else if (streq(key, "replace_entry_text"))
- gtk_entry_set_text(GTK_ENTRY(replace_entry), lua_tostring(lua, 3));
- else if (streq(key, "match_case"))
- toggle(match_case_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
- else if (streq(key, "whole_word"))
- toggle(whole_word_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
- else if (streq(key, "lua"))
- toggle(lua_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
- else if (streq(key, "in_files"))
- toggle(in_files_opt, lua_toboolean(lua, -1) ? TRUE : FALSE);
- else if (streq(key, "find_label_text"))
- gtk_label_set_text_with_mnemonic(GTK_LABEL(flabel), lua_tostring(lua, 3));
- else if (streq(key, "replace_label_text"))
- gtk_label_set_text_with_mnemonic(GTK_LABEL(rlabel), lua_tostring(lua, 3));
- else if (streq(key, "find_next_button_text"))
- gtk_button_set_label(GTK_BUTTON(fnext_button), lua_tostring(lua, 3));
- else if (streq(key, "find_prev_button_text"))
- gtk_button_set_label(GTK_BUTTON(fprev_button), lua_tostring(lua, 3));
- else if (streq(key, "replace_button_text"))
- gtk_button_set_label(GTK_BUTTON(r_button), lua_tostring(lua, 3));
- else if (streq(key, "replace_all_button_text"))
- gtk_button_set_label(GTK_BUTTON(ra_button), lua_tostring(lua, 3));
- else if (streq(key, "match_case_label_text"))
- gtk_button_set_label(GTK_BUTTON(match_case_opt), lua_tostring(lua, 3));
- else if (streq(key, "whole_word_label_text"))
- gtk_button_set_label(GTK_BUTTON(whole_word_opt), lua_tostring(lua, 3));
- else if (streq(key, "lua_pattern_label_text"))
- gtk_button_set_label(GTK_BUTTON(lua_opt), lua_tostring(lua, 3));
- else if (streq(key, "in_files_label_text"))
- gtk_button_set_label(GTK_BUTTON(in_files_opt), lua_tostring(lua, 3));
+static int lfind__newindex(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "find_entry_text") == 0)
+ gtk_entry_set_text(GTK_ENTRY(find_entry), lua_tostring(L, 3));
+ else if (strcmp(key, "replace_entry_text") == 0)
+ gtk_entry_set_text(GTK_ENTRY(replace_entry), lua_tostring(L, 3));
+ else if (strcmp(key, "match_case") == 0)
+ toggle(match_case_opt, lua_toboolean(L, -1));
+ else if (strcmp(key, "whole_word") == 0)
+ toggle(whole_word_opt, lua_toboolean(L, -1));
+ else if (strcmp(key, "lua") == 0)
+ toggle(lua_opt, lua_toboolean(L, -1));
+ else if (strcmp(key, "in_files") == 0)
+ toggle(in_files_opt, lua_toboolean(L, -1));
+ else if (strcmp(key, "find_label_text") == 0)
+ gtk_label_set_text_with_mnemonic(GTK_LABEL(flabel), lua_tostring(L, 3));
+ else if (strcmp(key, "replace_label_text") == 0)
+ gtk_label_set_text_with_mnemonic(GTK_LABEL(rlabel), lua_tostring(L, 3));
+ else if (strcmp(key, "find_next_button_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(fnext_button), lua_tostring(L, 3));
+ else if (strcmp(key, "find_prev_button_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(fprev_button), lua_tostring(L, 3));
+ else if (strcmp(key, "replace_button_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(r_button), lua_tostring(L, 3));
+ else if (strcmp(key, "replace_all_button_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(ra_button), lua_tostring(L, 3));
+ else if (strcmp(key, "match_case_label_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(match_case_opt), lua_tostring(L, 3));
+ else if (strcmp(key, "whole_word_label_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(whole_word_opt), lua_tostring(L, 3));
+ else if (strcmp(key, "lua_pattern_label_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(lua_opt), lua_tostring(L, 3));
+ else if (strcmp(key, "in_files_label_text") == 0)
+ gtk_button_set_label(GTK_BUTTON(in_files_opt), lua_tostring(L, 3));
else
- lua_rawset(lua, 1);
+ lua_rawset(L, 1);
return 0;
}
-static int l_ce_mt_index(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "entry_text"))
- lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(command_entry)));
+static int lce__index(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "entry_text") == 0)
+ lua_pushstring(L, gtk_entry_get_text(GTK_ENTRY(command_entry)));
else
- lua_rawget(lua, 1);
+ lua_rawget(L, 1);
return 1;
}
-static int l_ce_mt_newindex(lua_State *lua) {
- const char *key = lua_tostring(lua, 2);
- if (streq(key, "entry_text"))
- gtk_entry_set_text(GTK_ENTRY(command_entry), lua_tostring(lua, 3));
+static int lce__newindex(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "entry_text") == 0)
+ gtk_entry_set_text(GTK_ENTRY(command_entry), lua_tostring(L, 3));
else
- lua_rawset(lua, 1);
+ lua_rawset(L, 1);
return 0;
}
/******************************************************************************/
-/****************** Lua CFunctions *******************/
+/****************** Lua CFunctions *******************/
/****************** (For documentation, consult the LuaDoc) *******************/
/******************************************************************************/
-static int l_cf_buffer_delete(lua_State *lua) {
- l_check_focused_buffer(lua, 1);
- sptr_t doc = l_checkdocpointer(lua, 1);
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- if (lua_objlen(lua, -1) > 1)
- l_goto_buffer(focused_view, -1, FALSE);
- else
- new_buffer(focused_view, TRUE, TRUE);
- remove_buffer(doc);
- l_emit_event("buffer_deleted", -1);
- l_emit_event("buffer_after_switch", -1);
+static int lbuffer_check_global(lua_State *L) {
+ lL_globaldoccheck(L, 1);
return 0;
}
-static int l_cf_buffer_new(lua_State *lua) {
- new_buffer(focused_view, TRUE, TRUE);
- lua_getfield(lua, LUA_REGISTRYINDEX, "buffers");
- lua_rawgeti(lua, -1, lua_objlen(lua, -1));
+static int lbuffer_delete(lua_State *L) {
+ lL_globaldoccheck(L, 1);
+ sptr_t doc = SS(focused_view, SCI_GETDOCPOINTER, 0, 0);
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ if (lua_objlen(L, -1) == 1) new_buffer(0);
+ lL_gotodoc(L, focused_view, -1, TRUE);
+ delete_buffer(doc);
+ lL_event(L, "buffer_deleted", -1),
+ lL_event(L, "buffer_after_switch", -1);
+ return 0;
+}
+
+static int lbuffer_new(lua_State *L) {
+ new_buffer(0);
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers");
+ lua_rawgeti(L, -1, lua_objlen(L, -1));
return 1;
}
-static int l_cf_buffer_text_range(lua_State *lua) {
- l_check_focused_buffer(lua, 1);
+static int lbuffer_text_range(lua_State *L) {
+ lL_globaldoccheck(L, 1);
struct Sci_TextRange tr;
- tr.chrg.cpMin = luaL_checkinteger(lua, 2);
- tr.chrg.cpMax = luaL_checkinteger(lua, 3);
- luaL_argcheck(lua, tr.chrg.cpMin <= tr.chrg.cpMax, 3, "start > end");
- int length = tr.chrg.cpMax - tr.chrg.cpMin;
- char *text = malloc(length + 1);
- tr.lpstrText = text;
+ tr.chrg.cpMin = luaL_checkinteger(L, 2);
+ tr.chrg.cpMax = luaL_checkinteger(L, 3);
+ luaL_argcheck(L, tr.chrg.cpMin <= tr.chrg.cpMax, 3, "start > end");
+ tr.lpstrText = malloc(tr.chrg.cpMax - tr.chrg.cpMin + 1);
SS(focused_view, SCI_GETTEXTRANGE, 0, (long)(&tr));
- lua_pushlstring(lua, text, length);
- g_free(text);
+ lua_pushlstring(L, tr.lpstrText, tr.chrg.cpMax - tr.chrg.cpMin);
+ g_free(tr.lpstrText);
return 1;
}
-static int l_cf_view_focus(lua_State *lua) {
- GtkWidget *view = l_checkview(lua, 1);
- // view might be an old reference; GTK_IS_WIDGET checks for a valid widget
- if (GTK_IS_WIDGET(view)) gtk_widget_grab_focus(view);
- return 0;
-}
-
-static int l_cf_view_split(lua_State *lua) {
- GtkWidget *view = l_checkview(lua, 1);
- int vertical = TRUE;
- if (lua_gettop(lua) > 1) vertical = lua_toboolean(lua, 2) == 1;
- split_view(view, vertical);
- lua_pushvalue(lua, 1); // old view
- lua_getglobal(lua, "view"); // new view
+static int lview_split(lua_State *L) {
+ split_view(lL_checkview(L, 1), lua_toboolean(L, 2));
+ lua_pushvalue(L, 1); // old view
+ lua_getglobal(L, "view"); // new view
return 2;
}
-static int l_cf_view_unsplit(lua_State *lua) {
- GtkWidget *view = l_checkview(lua, 1);
- lua_pushboolean(lua, unsplit_view(view));
+static int lview_unsplit(lua_State *L) {
+ lua_pushboolean(L, unsplit_view(lL_checkview(L, 1)));
return 1;
}
#define child1(p) gtk_paned_get_child1(GTK_PANED(p))
#define child2(p) gtk_paned_get_child2(GTK_PANED(p))
-#define view_dpi(view) l_get_docpointer_index(SS(view, SCI_GETDOCPOINTER, 0, 0))
-void l_create_entry(lua_State *lua, GtkWidget *c1, GtkWidget *c2,
- int vertical) {
- lua_newtable(lua);
+static void l_pushsplittable(lua_State *L, GtkWidget *c1, GtkWidget *c2) {
+ lua_newtable(L);
if (GTK_IS_PANED(c1))
- l_create_entry(lua, child1(c1), child2(c1), GTK_IS_HPANED(c1) == 1);
+ l_pushsplittable(L, child1(c1), child2(c1));
else
- lua_pushinteger(lua, view_dpi(c1));
- lua_rawseti(lua, -2, 1);
+ l_pushview(L, c1);
+ lua_rawseti(L, -2, 1);
if (GTK_IS_PANED(c2))
- l_create_entry(lua, child1(c2), child2(c2), GTK_IS_HPANED(c2) == 1);
+ l_pushsplittable(L, child1(c2), child2(c2));
else
- lua_pushinteger(lua, view_dpi(c2));
- lua_rawseti(lua, -2, 2);
- lua_pushboolean(lua, vertical);
- lua_setfield(lua, -2, "vertical");
+ l_pushview(L, c2);
+ lua_rawseti(L, -2, 2);
+ lua_pushboolean(L, GTK_IS_HPANED(gtk_widget_get_parent(c1)));
+ lua_setfield(L, -2, "vertical");
int size = gtk_paned_get_position(GTK_PANED(gtk_widget_get_parent(c1)));
- lua_pushinteger(lua, size);
- lua_setfield(lua, -2, "size");
+ lua_pushinteger(L, size), lua_setfield(L, -2, "size");
}
-static int l_cf_gui_get_split_table(lua_State *lua) {
- lua_getfield(lua, LUA_REGISTRYINDEX, "views");
- if (lua_objlen(lua, -1) > 1) {
- GtkWidget *pane = gtk_widget_get_parent(focused_view);
+static int lgui_get_split_table(lua_State *L) {
+ GtkWidget *pane = gtk_widget_get_parent(focused_view);
+ if (GTK_IS_PANED(pane)) {
while (GTK_IS_PANED(gtk_widget_get_parent(pane)))
pane = gtk_widget_get_parent(pane);
- l_create_entry(lua, child1(pane), child2(pane), GTK_IS_HPANED(pane) == 1);
- } else lua_pushinteger(lua, view_dpi(focused_view));
+ l_pushsplittable(L, child1(pane), child2(pane));
+ } else l_pushview(L, focused_view);
return 1;
}
-static int l_cf_gui_goto_(lua_State *lua, GtkWidget *view, int buffer) {
- int n = luaL_checkinteger(lua, 1);
- int abs = (lua_gettop(lua) > 1) ? lua_toboolean(lua, 2) == 1 : TRUE;
- buffer ? l_goto_buffer(view, n, abs) : l_goto_view(view, n, abs);
- return 0;
-}
-
// 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) {
- GtkWidget *view = l_checkview(lua, 1);
- int switch_focus = view != focused_view;
- GtkWidget *orig_focused_view = focused_view;
+static int lview_goto_buffer(lua_State *L) {
+ GtkWidget *view = lL_checkview(L, 1), *prev_view = focused_view;
+ int n = luaL_checkinteger(L, 2), relative = lua_toboolean(L, 3);
+ int switch_focus = (view != focused_view);
if (switch_focus) SS(view, SCI_SETFOCUS, TRUE, 0);
- lua_remove(lua, 1); // view table
- l_emit_event("buffer_before_switch", -1);
- l_cf_gui_goto_(lua, view, TRUE);
- l_emit_event("buffer_after_switch", -1);
- if (switch_focus) {
- SS(view, SCI_SETFOCUS, FALSE, 0);
- gtk_widget_grab_focus(orig_focused_view);
- }
+ lL_event(L, "buffer_before_switch", -1);
+ lL_gotodoc(L, view, n, relative);
+ lL_event(L, "buffer_after_switch", -1);
+ if (switch_focus)
+ SS(view, SCI_SETFOCUS, FALSE, 0), gtk_widget_grab_focus(prev_view);
return 0;
}
-static int l_cf_gui_dialog(lua_State *lua) {
- GCDialogType type = gcocoadialog_type(luaL_checkstring(lua, 1));
- int i, j, k, n = lua_gettop(lua) - 1, argc = n;
+static int lgui_dialog(lua_State *L) {
+ GCDialogType type = gcocoadialog_type(luaL_checkstring(L, 1));
+ int i, j, k, n = lua_gettop(L) - 1, argc = n;
for (i = 2; i < n + 2; i++)
- if (lua_type(lua, i) == LUA_TTABLE) argc += lua_objlen(lua, i) - 1;
+ if (lua_istable(L, i)) argc += lua_objlen(L, i) - 1;
const char **argv = malloc((argc + 1) * sizeof(const char *));
for (i = 0, j = 2; j < n + 2; j++)
- if (lua_type(lua, j) == LUA_TTABLE) {
- int len = lua_objlen(lua, j);
+ if (lua_istable(L, j)) {
+ int len = lua_objlen(L, j);
for (k = 1; k <= len; k++) {
- lua_rawgeti(lua, j, k);
- argv[i++] = luaL_checkstring(lua, -1);
- lua_pop(lua, 1);
+ lua_rawgeti(L, j, k);
+ argv[i++] = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
}
- } else argv[i++] = luaL_checkstring(lua, j);
+ } else argv[i++] = luaL_checkstring(L, j);
argv[argc] = 0;
char *out = gcocoadialog(type, argc, argv);
- lua_pushstring(lua, out);
- free(out);
- free(argv);
+ lua_pushstring(L, out);
+ free(out), free(argv);
return 1;
}
-static int l_cf_gui_goto_view(lua_State *lua) {
- return l_cf_gui_goto_(lua, focused_view, FALSE);
+static int lgui_goto_view(lua_State *L) {
+ int n = luaL_checkinteger(L, 1), relative = lua_toboolean(L, 2);
+ if (relative && n == 0) return 0;
+ lua_getfield(L, LUA_REGISTRYINDEX, "ta_views");
+ if (relative) {
+ l_pushview(L, focused_view), lua_gettable(L, -2);
+ n = lua_tointeger(L, -1) + n;
+ if (n > lua_objlen(L, -2))
+ n = 1;
+ else if (n < 1)
+ n = lua_objlen(L, -2);
+ lua_rawgeti(L, -2, n);
+ } else {
+ luaL_argcheck(L, n > 0 && n <= lua_objlen(L, -1), 1,
+ "no View exists at that index");
+ lua_rawgeti(L, -1, n);
+ }
+ GtkWidget *view = l_toview(L, -1);
+ gtk_widget_grab_focus(view);
+ // gui.dialog() interferes with focus so gtk_widget_grab_focus() does not
+ // always work. If this is the case, ensure goto_view() is called.
+ if (!gtk_widget_has_focus(view)) goto_view(view);
+ return 0;
}
-static void t_menu_activate(GtkWidget *menu, gpointer id) {
- l_emit_event("menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id), -1);
+static void m_clicked(GtkWidget *menu, gpointer id) {
+ lL_event(lua, "menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id), -1);
}
-static int l_cf_gui_gtkmenu(lua_State *lua) {
- luaL_checktype(lua, 1, LUA_TTABLE);
- GtkWidget *menu = l_create_gtkmenu(lua, G_CALLBACK(t_menu_activate), FALSE);
- lua_pushlightuserdata(lua, (GtkWidget *)menu);
+static int lgui_gtkmenu(lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ l_pushgtkmenu(L, -1, G_CALLBACK(m_clicked), FALSE);
return 1;
}
-static int l_cf_string_iconv(lua_State *lua) {
+static int lstring_iconv(lua_State *L) {
size_t text_len = 0, conv_len = 0;
- const char *text = luaL_checklstring(lua, 1, &text_len);
- const char *to = luaL_checkstring(lua, 2);
- const char *from = luaL_checkstring(lua, 3);
+ const char *text = luaL_checklstring(L, 1, &text_len);
+ const char *to = luaL_checkstring(L, 2);
+ const char *from = luaL_checkstring(L, 3);
char *converted = g_convert(text, text_len, to, from, NULL, &conv_len, NULL);
- if (converted) {
- lua_pushlstring(lua, converted, conv_len);
- g_free(converted);
- } else luaL_error(lua, "Conversion failed");
+ if (!converted) luaL_error(L, "Conversion failed");
+ lua_pushlstring(L, converted, conv_len);
+ g_free(converted);
return 1;
}
-static int l_cf_quit(lua_State *lua) {
+static int lquit(lua_State *L) {
GdkEventAny event;
event.type = GDK_DELETE;
event.window = gtk_widget_get_window(window);
@@ -2050,84 +1831,103 @@ static int l_cf_quit(lua_State *lua) {
return 0;
}
-static int l_cf_reset(lua_State *lua) {
- l_emit_event("reset_before", -1);
- l_init(0, NULL, TRUE);
- lua_pushboolean(lua, TRUE);
- lua_setglobal(lua, "RESETTING");
- l_set_view_global(focused_view);
- l_set_buffer_global(focused_view);
- l_load_script("init.lua");
- lua_pushnil(lua);
- lua_setglobal(lua, "RESETTING");
- l_emit_event("reset_after", -1);
+static int lreset(lua_State *L) {
+ lL_event(L, "reset_before", -1);
+ lL_init(L, 0, NULL, TRUE);
+ lua_pushboolean(L, TRUE), lua_setglobal(L, "RESETTING");
+ l_setglobalview(L, focused_view);
+ l_setglobaldoc(L, SS(focused_view, SCI_GETDOCPOINTER, 0, 0));
+ lL_dofile(L, "init.lua");
+ lua_pushnil(L), lua_setglobal(L, "RESETTING");
+ lL_event(L, "reset_after", -1);
return 0;
}
-static gbool emit_timeout(gpointer data) {
+static gboolean emit_timeout(gpointer data) {
int *refs = (int *)data;
lua_rawgeti(lua, LUA_REGISTRYINDEX, refs[0]); // function
int nargs = 0, repeat = TRUE;
while (refs[++nargs]) lua_rawgeti(lua, LUA_REGISTRYINDEX, refs[nargs]);
- l_call_function(nargs - 1, 1, TRUE);
- if (lua_toboolean(lua, -1) == 0 || lua_isnil(lua, -1)) {
+ int ok = (lua_pcall(lua, nargs - 1, 1, 0) == 0);
+ if (!ok || !lua_toboolean(lua, -1)) {
while (--nargs >= 0) luaL_unref(lua, LUA_REGISTRYINDEX, refs[nargs]);
repeat = FALSE;
+ if (!ok) lL_event(lua, "error", LUA_TSTRING, lua_tostring(lua, -1), -1);
}
- lua_pop(lua, 1); // boolean or nil
+ lua_pop(lua, 1); // result
return repeat;
}
-static int l_cf_timeout(lua_State *lua) {
- int timeout = luaL_checkinteger(lua, 1);
- luaL_argcheck(lua, timeout > 0, 1, "timeout must be > 0");
- luaL_argcheck(lua, lua_isfunction(lua, 2), 2, "function expected");
- int n = lua_gettop(lua);
+static int ltimeout(lua_State *L) {
+ int timeout = luaL_checkinteger(L, 1);
+ luaL_argcheck(L, timeout > 0, 1, "timeout must be > 0");
+ luaL_argcheck(L, lua_isfunction(L, 2), 2, "function expected");
+ int n = lua_gettop(L);
int *refs = (int *)calloc(n, sizeof(int));
- lua_pushvalue(lua, 2);
- refs[0] = luaL_ref(lua, LUA_REGISTRYINDEX);
+ lua_pushvalue(L, 2);
+ refs[0] = luaL_ref(L, LUA_REGISTRYINDEX);
for (int i = 3; i <= n; i++) {
- lua_pushvalue(lua, i);
- refs[i - 2] = luaL_ref(lua, LUA_REGISTRYINDEX);
+ lua_pushvalue(L, i);
+ refs[i - 2] = luaL_ref(L, LUA_REGISTRYINDEX);
}
g_timeout_add_seconds(timeout, emit_timeout, (gpointer)refs);
return 0;
}
-static int l_cf_find_focus(lua_State *lua) {
- find_toggle_focus();
+static int lfind_focus(lua_State *L) {
+ if (!gtk_widget_has_focus(findbox)) {
+ gtk_widget_show(findbox);
+ gtk_widget_grab_focus(find_entry);
+ gtk_widget_grab_default(fnext_button);
+ } else {
+ gtk_widget_grab_focus(focused_view);
+ gtk_widget_hide(findbox);
+ }
return 0;
}
-#define emit(o, s) { \
- g_signal_emit_by_name(G_OBJECT(o), s); \
- return 0; \
+static int lfind_next(lua_State *L) {
+ return (g_signal_emit_by_name(G_OBJECT(fnext_button), "clicked"), 0);
}
-static int l_cf_find_next(lua_State *lua) { emit(fnext_button, "clicked") }
-static int l_cf_find_prev(lua_State *lua) { emit(fprev_button, "clicked") }
-static int l_cf_find_replace(lua_State *lua) { emit(r_button, "clicked") }
-static int l_cf_find_replace_all(lua_State *lua) { emit(ra_button, "clicked") }
-static int l_cf_ce_focus(lua_State *lua) {
- ce_toggle_focus();
+static int lfind_prev(lua_State *L) {
+ return (g_signal_emit_by_name(G_OBJECT(fprev_button), "clicked"), 0);
+}
+
+static int lfind_replace(lua_State *L) {
+ return (g_signal_emit_by_name(G_OBJECT(r_button), "clicked"), 0);
+}
+
+static int lfind_replace_all(lua_State *L) {
+ return (g_signal_emit_by_name(G_OBJECT(ra_button), "clicked"), 0);
+}
+
+static int lce_focus(lua_State *L) {
+ if (!gtk_widget_has_focus(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);
+ }
return 0;
}
-static int l_cf_ce_show_completions(lua_State *lua) {
- luaL_checktype(lua, 1, LUA_TTABLE);
+static int lce_show_completions(lua_State *L) {
+ luaL_checktype(L, 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) {
+ lua_pushnil(L);
+ while (lua_next(L, 1)) {
+ if (lua_type(L, -1) == LUA_TSTRING) {
GtkTreeIter iter;
gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, lua_tostring(lua, -1), -1);
+ gtk_list_store_set(store, &iter, 0, lua_tostring(L, -1), -1);
} else warn("command_entry.show_completions: non-string value ignored");
- lua_pop(lua, 1); // value
+ lua_pop(L, 1); // value
}
gtk_entry_completion_complete(completion);
return 0;