diff options
author | 2012-05-23 07:32:02 -0400 | |
---|---|---|
committer | 2012-05-23 07:32:02 -0400 | |
commit | 7872e44d71de9371f4eef162287c14d2e6b8dc29 (patch) | |
tree | 266576e5bc90e0f3b538c08ecab4df953bd3d8ba | |
parent | ec14d1f35de021ef6adfe3ee035bfe1e0dfea6e3 (diff) | |
download | textadept-7872e44d71de9371f4eef162287c14d2e6b8dc29.tar.gz textadept-7872e44d71de9371f4eef162287c14d2e6b8dc29.zip |
Initial support for ncurses.
-rw-r--r-- | core/gui.lua | 2 | ||||
-rw-r--r-- | src/Makefile | 67 | ||||
-rw-r--r-- | src/textadept.c | 615 |
3 files changed, 507 insertions, 177 deletions
diff --git a/core/gui.lua b/core/gui.lua index 6681388a..97cc481a 100644 --- a/core/gui.lua +++ b/core/gui.lua @@ -4,7 +4,7 @@ local gui = gui --[[ This comment is for LuaDoc. --- The core gui table. --- @field title (string) +-- @field title (string, Write-only) -- The title of the Textadept window. -- @field context_menu -- A GTK menu defining the editor's context menu. diff --git a/src/Makefile b/src/Makefile index a7110d60..955046b7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,10 +7,13 @@ CC = gcc CPP = g++ PKG_CONFIG = pkg-config PKG_CONFIG_PATH = $PKG_CONFIG_PATH -ifndef BSD +ifndef NCURSES PLAT_FLAGS = -DGTK else -PLAT_FLAGS = -DGTK -D__BSD__ +PLAT_FLAGS = -DNCURSES +endif +ifdef BSD +PLAT_FLAGS += -D__BSD__ endif SCI_THREAD_FLAG = LUAFLAGS = -DLUA_USE_LINUX @@ -30,7 +33,7 @@ CC = i486-mingw32-gcc -mms-bitfields CPP = i486-mingw32-g++ -mms-bitfields -mwindows -static-libgcc -static-libstdc++ PKG_CONFIG = pkg-config --define-variable=prefix=win32gtk PKG_CONFIG_PATH = $(shell pwd)/win32gtk/lib/pkgconfig -PLAT_FLAGS = -DGTK -D__WIN32__ +PLAT_FLAGS += -D__WIN32__ SCI_THREAD_FLAG = -DG_THREADS_IMPL_NONE LUAFLAGS = -D_WIN32 -DWIN32 TEXTADEPT = textadept.exe @@ -52,7 +55,7 @@ CPP = g++ -arch i386 -mdynamic-no-pic -mmacosx-version-min=10.5 \ -isysroot /Developer/SDKs/MacOSX10.5.sdk PKG_CONFIG = gtkosx/bin/pkg-config --define-variable=prefix=gtkosx PKG_CONFIG_PATH = $(shell pwd)/gtkosx/lib/pkgconfig -PLAT_FLAGS = -DGTK -D__OSX__ +PLAT_FLAGS += -D__OSX__ SCI_THREAD_FLAG = LUAFLAGS = -DLUA_USE_MACOSX TEXTADEPT = textadept.osx @@ -91,6 +94,9 @@ SI_FLAG = endif INCLUDEDIRS = -Iscintilla/include -I$(LUADIR)/src -Igcocoadialog +ifdef NCURSES +INCLUDEDIRS += -Iscintilla/term -Itermkey +endif ifdef GTK3 GTKVERSION = gtk+-3.0 @@ -104,6 +110,9 @@ CFLAGS = -std=c99 $(DEBUG_FLAG) $(LUAJIT_FLAG) $(SI_FLAG) -O $(PLAT_FLAGS) \ $(INCLUDEDIRS) -W -Wall -Wno-sign-compare -Wno-unused GTKFLAGS = $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) \ --cflags $(GTKVERSION)) +ifndef NCURSES +CFLAGS += $(GTKFLAGS) +endif GTKLIBS = $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) \ --libs $(GTKVERSION)) ifdef LIBPNG12 @@ -112,7 +121,15 @@ endif ifdef OSX GTKLIBS += -framework Cocoa -lgtkmacintegration endif -GCDFLAGS = -DNOHELP -DLIBRARY +GCDFLAGS = $(PLAT_FLAGS) -DNOHELP -DLIBRARY +ifndef NCURSES +GCDFLAGS += $(GTKFLAGS) +endif +ifndef NCURSES +LIBS = $(GTKLIBS) +else +LIBS = -lncursesw -lcdk +endif TEXTADEPT_OBJS = textadept.o LUA_OBJS = lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o \ @@ -124,13 +141,18 @@ LUA_OBJS = lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o \ LUA_SRCS = lua/src/*.c lua/src/lib/*.c LUAJIT_OBJS = GCOCOADIALOG = gcocoadialog.o +ifdef NCURSES +TERMKEY_OBJS = termkey.o driver-ti.o driver-csi.o +endif # Scintilla SCIFLAGS = $(DEBUG_FLAG) -pedantic -Os $(PLAT_FLAGS) -DSCI_LEXER \ - $(SCI_THREAD_FLAG) $(INCLUDEDIRS) -Iscintilla/src -Iscintilla/gtk \ - -Iscintilla/lexlib \ + $(SCI_THREAD_FLAG) $(INCLUDEDIRS) -Iscintilla/src -Iscintilla/lexlib \ -Wall -Wno-missing-braces -Wno-char-subscripts -Wno-long-long +ifndef NCURSES +SCIFLAGS += -Iscintilla/gtk +endif SCINTILLA_OBJS = AutoComplete.o CallTip.o Catalogue.o CellBuffer.o \ CharClassify.o ContractionState.o Decoration.o Document.o Editor.o \ @@ -138,9 +160,15 @@ SCINTILLA_OBJS = AutoComplete.o CallTip.o Catalogue.o CellBuffer.o \ PositionCache.o RESearch.o RunStyles.o ScintillaBase.o Selection.o \ Style.o UniConversion.o ViewStyle.o XPM.o \ Accessor.o CharacterSet.o LexerBase.o LexerModule.o LexerNoExceptions.o \ - LexerSimple.o PropSetSimple.o StyleContext.o WordList.o \ - PlatGTK.o ScintillaGTK.o + LexerSimple.o PropSetSimple.o StyleContext.o WordList.o +ifndef NCURSES +SCINTILLA_GTK_OBJS = PlatGTK.o ScintillaGTK.o SCINTILLA_MARSHALLER = scintilla-marshal.o +SCINTILLA_PLAT_OBJS = $(SCINTILLA_GTK_OBJS) $(SCINTILLA_MARSHALLER) +else +SCINTILLA_TERM_OBJS = ScintillaTerm.o +SCINTILLA_PLAT_OBJS = $(SCINTILLA_TERM_OBJS) +endif SCINTILLA_LEXER = LexLPeg.o # Build @@ -156,15 +184,18 @@ endif all: $(TEXTADEPT) -$(SCINTILLA_OBJS): scintilla/gtk/*.cxx scintilla/src/*.cxx \ - scintilla/lexlib/*.cxx +$(SCINTILLA_OBJS): scintilla/src/*.cxx scintilla/lexlib/*.cxx + $(CPP) $(SCIFLAGS) -c $^ +$(SCINTILLA_GTK_OBJS): scintilla/gtk/*.cxx $(CPP) $(SCIFLAGS) $(GTKFLAGS) -c $^ +$(SCINTILLA_TERM_OBJS): scintilla/term/*.cxx + $(CPP) $(SCIFLAGS) -c $^ $(SCINTILLA_MARSHALLER): scintilla/gtk/scintilla-marshal.c $(CC) $(SCIFLAGS) $(GTKFLAGS) -w -c $< $(SCINTILLA_LEXER): LexLPeg.cxx - $(CPP) $(SCIFLAGS) $(GTKFLAGS) $(LUAFLAGS) -DLPEG_LEXER -DNO_SCITE -c $< -o $@ + $(CPP) $(SCIFLAGS) $(LUAFLAGS) -DLPEG_LEXER -DNO_SCITE -c $< -o $@ $(TEXTADEPT_OBJS): textadept.c - $(CC) $(CFLAGS) $(GTKFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) -c $< -o $@ $(LUA_OBJS): $(LUA_SRCS) $(CC) $(LUAFLAGS) $(INCLUDEDIRS) -c $^ ifdef LUAJIT @@ -174,12 +205,14 @@ $(LUAJIT_OBJS): cd luajit && make $(LUAJIT_MAKE) cp luajit/src/$(LUAJIT_LIB) . $(GCOCOADIALOG): gcocoadialog/gcocoadialog.c - $(CC) $(GTKFLAGS) $(GCDFLAGS) $(INCLUDEDIRS) -c $< + $(CC) $(GCDFLAGS) $(INCLUDEDIRS) -c $< +$(TERMKEY_OBJS): termkey/*.c + $(CC) -std=c99 -c $^ $(TEXTADEPT):\ - $(SCINTILLA_OBJS) $(SCINTILLA_MARSHALLER) $(SCINTILLA_LEXER) \ + $(SCINTILLA_OBJS) $(SCINTILLA_PLAT_OBJS) $(SCINTILLA_LEXER) \ $(TEXTADEPT_OBJS) $(LUA_OBJS) $(LUAJIT_OBJS) $(GCOCOADIALOG) \ - $(TEXTADEPT_RC) - $(CPP) $(EXPORTLUASYMS) -o $@ $^ $(GTKLIBS) $(LDL) + $(TERMKEY_OBJS) $(TEXTADEPT_RC) + $(CPP) $(EXPORTLUASYMS) -o $@ $^ $(LIBS) $(LDL) mv $(TEXTADEPT) ../ $(TEXTADEPT_RC): textadept.rc $(WINDRES) $^ $@ diff --git a/src/textadept.c b/src/textadept.c index b59f169e..19ac73bc 100644 --- a/src/textadept.c +++ b/src/textadept.c @@ -1,22 +1,11 @@ // Copyright 2007-2012 Mitchell mitchell.att.foicica.com. See LICENSE. #include <locale.h> +#include <iconv.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <gtk/gtk.h> - -#define PLAT_GTK 1 -#include "Scintilla.h" -#include "SciLexer.h" -#include "ScintillaWidget.h" - -#include "gcocoadialog.h" -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" - #if __WIN32__ #include <windows.h> #define main main_ @@ -25,11 +14,36 @@ #elif __BSD__ #include <sys/types.h> #include <sys/sysctl.h> +#else +#include <unistd.h> +#endif +#if GTK +#include <gtk/gtk.h> +#define PLAT_GTK 1 +#elif NCURSES +#include <ncurses.h> +#define PLAT_TERM 1 #endif +#include "gcocoadialog.h" +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +#include "Scintilla.h" +#include "SciLexer.h" +#if GTK +#include "ScintillaWidget.h" +#elif NCURSES +#include "ScintillaTerm.h" +#include "termkey.h" +#endif + +#if GTK +typedef GtkWidget Scintilla; #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 focus_view(v) gtk_widget_grab_focus(v) +#define scintilla_delete(w) gtk_widget_destroy(w) #if GTK_CHECK_VERSION(3,0,0) #define gtk_statusbar_set_has_resize_grip(_,__) #define gtk_combo_box_entry_new_with_model(m,_) \ @@ -37,74 +51,114 @@ #define gtk_combo_box_entry_set_text_column gtk_combo_box_set_entry_text_column #define GTK_COMBO_BOX_ENTRY GTK_COMBO_BOX #endif +#elif NCURSES +#define SS(view, m, w, l) scintilla_send_message(view, m, w, l) +#define focus_view(v) \ + SS(focused_view, SCI_SETFOCUS, 0, 0), SS(v, SCI_SETFOCUS, 1, 0) +#endif +#define copy(s) strcpy(malloc(strlen(s) + 1), s) /******************************************************************************/ /***************************** Forward Declarations ***************************/ /******************************************************************************/ // Window +char *textadept_home = NULL; +#if GTK GtkWidget *window, *focused_view, *menubar, *statusbar[2]; GtkAccelGroup *accel; -char *textadept_home; 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 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); +static void s_notify(GtkWidget *, int, void *, void *); +static void s_command(GtkWidget *, int, void *, void *); +static int s_keypress(GtkWidget *, GdkEventKey *, void *); +static int s_buttonpress(GtkWidget *, GdkEventButton *, void *); +static int w_focus(GtkWidget *, GdkEventFocus *, void *); +static int w_keypress(GtkWidget *, GdkEventKey *, void *); +static int w_exit(GtkWidget *, GdkEventAny *, void *); #if GLIB_CHECK_VERSION(2,28,0) && SINGLE_INSTANCE -static int a_command_line(GApplication *, GApplicationCommandLine *, gpointer); +static int a_command_line(GApplication *, GApplicationCommandLine *, void *); #endif #if __OSX__ GtkOSXApplication *osxapp; #define app_signal(a, s, c) g_signal_connect(a, s, G_CALLBACK(c), 0) -static gboolean w_open_osx(GtkOSXApplication *, char *, gpointer); -static gboolean w_exit_osx(GtkOSXApplication *, gpointer); -static void w_quit_osx(GtkOSXApplication *, gpointer); +static int w_open_osx(GtkOSXApplication *, char *, void *); +static int w_exit_osx(GtkOSXApplication *, void *); +static void w_quit_osx(GtkOSXApplication *, void *); +#endif +#elif NCURSES +Scintilla *focused_view; +static void new_window(); +static Scintilla *new_view(sptr_t); +static void new_buffer(sptr_t); +static void s_notify(Scintilla *, int, void *, void *); #endif // Find/Replace +#if GTK 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; -GtkListStore *find_store, *repl_store; -static GtkWidget *new_findbox(); -static void f_clicked(GtkWidget *, gpointer); +typedef GtkListStore LIST_STORE; +LIST_STORE *find_store, *repl_store; +typedef GtkWidget FINDBOX; +typedef GtkWidget * FIND_BUTTON; +#elif NCURSES +WINDOW *findbox; +char *find_text = NULL, *repl_text = NULL; +enum { fnext_button, fprev_button, r_button, ra_button }; +int match_case_opt = FALSE, whole_word_opt = FALSE, lua_opt = FALSE, + in_files_opt = FALSE; +typedef char * LIST_STORE; +LIST_STORE find_store[10] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}, repl_store[10] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +typedef WINDOW FINDBOX; +typedef int FIND_BUTTON; +#endif +static FINDBOX *new_findbox(); +static void f_clicked(FIND_BUTTON, void *); // Command Entry +#if GTK GtkWidget *command_entry; GtkListStore *cc_store; GtkEntryCompletion *command_entry_completion; 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); + void *); +static int cc_matchselected(GtkEntryCompletion *, GtkTreeModel *, GtkTreeIter *, + void *); +static void c_activate(GtkWidget *, void *); +static int c_keypress(GtkWidget *, GdkEventKey *, void *); +#elif NCURSES +char *command_text = NULL; +#endif // Lua lua_State *lua; +#if NCURSES +int quit = FALSE; +#endif int closing = FALSE; -char *statusbar_text = 0; +char *statusbar_text = NULL; static int tVOID = 0, tINT = 1, tLENGTH = 2, /*tPOSITION = 3, tCOLOUR = 4,*/ tBOOL = 5, tKEYMOD = 6, tSTRING = 7, tSTRINGRESULT = 8; 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_addview(lua_State *, Scintilla *); +static void lL_removeview(lua_State *, Scintilla *); 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 void lL_gotodoc(lua_State *, Scintilla *, 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_showcontextmenu(lua_State *, void *); static void lL_cleartable(lua_State *, int); -static void l_pushview(lua_State *, GtkWidget *); +static void l_pushview(lua_State *, Scintilla *); 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")) @@ -120,7 +174,7 @@ static int lbuf_property(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 *), + lgui_menu(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 *), @@ -139,10 +193,16 @@ static int lbuf_property(lua_State *), * @param argv The array of command line params. */ int main(int argc, char **argv) { +#if GTK gtk_init(&argc, &argv); +#elif NCURSES + TermKey *tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + initscr(); // raw()/cbreak() and noecho() are taken care of in libtermkey +#endif #if !(__WIN32__ || __OSX__ || __BSD__) - textadept_home = g_file_read_link("/proc/self/exe", NULL); + textadept_home = malloc(FILENAME_MAX); + readlink("/proc/self/exe", textadept_home, FILENAME_MAX); #elif __WIN32__ textadept_home = malloc(FILENAME_MAX); GetModuleFileName(0, textadept_home, FILENAME_MAX); @@ -158,24 +218,28 @@ int main(int argc, char **argv) { size_t cb = FILENAME_MAX; sysctl(mib, 4, textadept_home, &cb, NULL, 0); #endif -#if !__OSX__ - char *last_slash = strrchr(textadept_home, G_DIR_SEPARATOR); - if (last_slash) *last_slash = '\0'; +#if !(__WIN32__ || __OSX__) + char *last_slash = strrchr(textadept_home, '/'); +#elif !__OSX__ + char *last_slash = strrchr(textadept_home, '\\'); #endif + if (last_slash) *last_slash = '\0'; +#if GTK #if GLIB_CHECK_VERSION(2,28,0) && SINGLE_INSTANCE - int force = 0; + int force = FALSE; for (int i = 0; i < argc; i++) if (strcmp("-f", argv[i]) == 0 || strcmp("--force", argv[i]) == 0) { - force = 1; + force = TRUE; break; } GApplication *app = g_application_new("textadept.editor", G_APPLICATION_HANDLES_COMMAND_LINE); g_signal_connect(app, "command-line", G_CALLBACK(a_command_line), 0); - gboolean registered = g_application_register(app, NULL, NULL); + int registered = g_application_register(app, NULL, NULL); if (!registered || !g_application_get_is_remote(app) || force) { #endif +#endif setlocale(LC_NUMERIC, "C"); if (lua = luaL_newstate(), !lL_init(lua, argc, argv, FALSE)) return 1; @@ -185,6 +249,7 @@ int main(int argc, char **argv) { gtk_osxapplication_ready(osxapp); #endif +#if GTK #if GLIB_CHECK_VERSION(2,28,0) && SINGLE_INSTANCE gtk_main(); } else g_application_run(app, argc, argv); @@ -192,6 +257,59 @@ int main(int argc, char **argv) { #else gtk_main(); #endif +#elif NCURSES + TermKeyResult res; + TermKeyKey key; + int c = 0; + while ((res = termkey_waitkey(tk, &key)) != TERMKEY_RES_EOF) { + if (res == TERMKEY_RES_ERROR) continue; + switch (key.type) { + case TERMKEY_TYPE_UNICODE: c = key.code.codepoint; break; + case TERMKEY_TYPE_KEYSYM: + switch (key.code.sym) { + case TERMKEY_SYM_BACKSPACE: c = SCK_BACK; break; + case TERMKEY_SYM_TAB: c = SCK_TAB; break; + case TERMKEY_SYM_ENTER: c = SCK_RETURN; break; + case TERMKEY_SYM_ESCAPE: c = SCK_ESCAPE; break; + case TERMKEY_SYM_UP: c = SCK_UP; break; + case TERMKEY_SYM_DOWN: c = SCK_DOWN; break; + case TERMKEY_SYM_LEFT: c = SCK_LEFT; break; + case TERMKEY_SYM_RIGHT: c = SCK_RIGHT; break; + case TERMKEY_SYM_INSERT: c = SCK_INSERT; break; + case TERMKEY_SYM_DELETE: c = SCK_DELETE; break; + case TERMKEY_SYM_PAGEUP: c = SCK_PRIOR; break; + case TERMKEY_SYM_PAGEDOWN: c = SCK_NEXT; break; + case TERMKEY_SYM_HOME: c = SCK_HOME; break; + case TERMKEY_SYM_END: c = SCK_END; break; + default: break; + } + break; + default: continue; + } +// if (c == SCK_ESCAPE && gtk_widget_get_visible(findbox) && +// !gtk_widget_has_focus(command_entry)) { +// gtk_widget_hide(findbox); +// gtk_widget_grab_focus(focused_view); +// } else + curs_set(0); // disable cursor when Scintilla has focus + if (!lL_event(lua, "keypress", LUA_TNUMBER, c, LUA_TBOOLEAN, + key.modifiers & TERMKEY_KEYMOD_SHIFT, LUA_TBOOLEAN, + key.modifiers & TERMKEY_KEYMOD_CTRL, LUA_TBOOLEAN, + key.modifiers & TERMKEY_KEYMOD_ALT, LUA_TBOOLEAN, FALSE, -1)) + scintilla_send_key(focused_view, c, key.modifiers & TERMKEY_KEYMOD_SHIFT, + key.modifiers & TERMKEY_KEYMOD_CTRL, + key.modifiers & TERMKEY_KEYMOD_ALT); + if (quit && lL_event(lua, "quit", -1)) { + l_close(lua); + break; + } else quit = FALSE; +// redrawwin(stdscr); + wrefresh(scintilla_get_window(focused_view)); + redrawwin(scintilla_get_window(focused_view)); + } + endwin(); + termkey_destroy(tk); +#endif free(textadept_home); return 0; @@ -214,6 +332,7 @@ int WINAPI WinMain(HINSTANCE _, HINSTANCE __, LPSTR lpCmdLine, int ___) { * other for buffer status. */ static void new_window() { +#if GTK GList *icon_list = NULL; const char *icons[] = { "16x16", "32x32", "48x48", "64x64", "128x128" }; for (int i = 0; i < 5; i++) { @@ -290,6 +409,11 @@ static void new_window() { gtk_widget_hide(menubar); // hide initially gtk_widget_hide(findbox); // hide initially gtk_widget_hide(command_entry); // hide initially +#elif NCURSES + Scintilla *view = new_view(0); + wresize(scintilla_get_window(view), LINES - 2, COLS); + mvwin(scintilla_get_window(view), 1, 0); +#endif } /** @@ -300,17 +424,21 @@ static void new_window() { * @return Scintilla view * @see lL_addview */ -static GtkWidget *new_view(sptr_t doc) { - GtkWidget *view = scintilla_new(); +static Scintilla *new_view(sptr_t doc) { +#if GTK + Scintilla *view = scintilla_new(); gtk_widget_set_size_request(view, 1, 1); // minimum size - SS(view, SCI_USEPOPUP, 0, 0); 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); +#elif NCURSES + Scintilla *view = scintilla_new(s_notify); +#endif + SS(view, SCI_USEPOPUP, 0, 0); lL_addview(lua, view); - gtk_widget_grab_focus(view); focused_view = view; + focus_view(view); if (doc) { SS(view, SCI_SETDOCPOINTER, 0, doc); l_setglobaldoc(lua, doc); @@ -325,9 +453,9 @@ static GtkWidget *new_view(sptr_t doc) { * @param view The Scintilla view to remove. * @see lL_removeview */ -static void delete_view(GtkWidget *view) { +static void delete_view(Scintilla *view) { lL_removeview(lua, view); - gtk_widget_destroy(view); + scintilla_delete(view); } /** @@ -369,16 +497,18 @@ static void delete_buffer(sptr_t doc) { * @param vertical Flag indicating whether to split the view vertically or * horozontally. */ -static void split_view(GtkWidget *view, int vertical) { - g_object_ref(view); +static void split_view(Scintilla *view, int vertical) { + sptr_t curdoc = SS(view, SCI_GETDOCPOINTER, 0, 0); int first_line = SS(view, SCI_GETFIRSTVISIBLELINE, 0, 0); int current_pos = SS(view, SCI_GETCURRENTPOS, 0, 0); int anchor = SS(view, SCI_GETANCHOR, 0, 0); + +#if GTK GtkAllocation allocation; gtk_widget_get_allocation(view, &allocation); int middle = (vertical ? allocation.width : allocation.height) / 2; - sptr_t curdoc = SS(view, SCI_GETDOCPOINTER, 0, 0); + g_object_ref(view); GtkWidget *view2 = new_view(curdoc); GtkWidget *parent = gtk_widget_get_parent(view); gtk_container_remove(GTK_CONTAINER(parent), view); @@ -387,14 +517,28 @@ static void split_view(GtkWidget *view, int vertical) { gtk_container_add(GTK_CONTAINER(parent), pane); gtk_paned_set_position(GTK_PANED(pane), middle); gtk_widget_show_all(pane); - gtk_widget_grab_focus(view2); + g_object_unref(view); +#elif NCURSES + WINDOW *win = scintilla_get_window(view); + int x, y; + getbegyx(win, y, x); + int width = getmaxx(win) - x, height = getmaxy(win) - y; + wresize(win, vertical ? height : height / 2, vertical ? width / 2 : width); + Scintilla *view2 = new_view(curdoc); + wresize(scintilla_get_window(view2), vertical ? height : height / 2, + vertical ? width / 2 : width); + mvwin(scintilla_get_window(view2), vertical ? y : y + height / 2, + vertical ? x + width / 2 : x); + // TODO: draw split +#endif + focus_view(view2); 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); } +#if GTK /** * Remove all Scintilla views from the given pane and delete them. * @param pane The GTK pane to remove Scintilla views from. @@ -406,6 +550,7 @@ static void remove_views_from_pane(GtkWidget *pane) { GTK_IS_PANED(child1) ? remove_views_from_pane(child1) : delete_view(child1); GTK_IS_PANED(child2) ? remove_views_from_pane(child2) : delete_view(child2); } +#endif /** * Unsplits the pane a given Scintilla view is in and keeps the view. @@ -414,7 +559,8 @@ static void remove_views_from_pane(GtkWidget *pane) { * @see remove_views_from_pane * @see delete_view */ -static int unsplit_view(GtkWidget *view) { +static int unsplit_view(Scintilla *view) { +#if GTK GtkWidget *pane = gtk_widget_get_parent(view); if (!GTK_IS_PANED(pane)) return FALSE; GtkWidget *other = gtk_paned_get_child1(GTK_PANED(pane)); @@ -435,6 +581,9 @@ static int unsplit_view(GtkWidget *view) { gtk_widget_grab_focus(GTK_WIDGET(view)); g_object_unref(view), g_object_unref(other); return TRUE; +#elif NCURSES + return FALSE; +#endif } /******************************************************************************/ @@ -446,7 +595,7 @@ static int unsplit_view(GtkWidget *view) { * Generates 'view_before_switch' and 'view_after_switch' events. * @param view The Scintilla view to focus. */ -static void goto_view(GtkWidget *view) { +static void goto_view(Scintilla *view) { if (!closing) lL_event(lua, "view_before_switch", -1); focused_view = view; l_setglobalview(lua, view); @@ -457,31 +606,32 @@ static void goto_view(GtkWidget *view) { /** * Signal for a Scintilla notification. */ -static void s_notify(GtkWidget *view, gint _, gpointer lParam, gpointer __) { +static void s_notify(Scintilla *view, int _, void *lParam, void*__) { struct SCNotification *n = (struct SCNotification *)lParam; if (focused_view == view || n->nmhdr.code == SCN_URIDROPPED) { if (focused_view != view) goto_view(view); lL_notify(lua, n); } else if (n->nmhdr.code == SCN_SAVEPOINTLEFT) { - GtkWidget *prev = focused_view; + Scintilla *prev = focused_view; goto_view(view); lL_notify(lua, n); goto_view(prev); // do not let a split view steal focus } } +#if GTK /** * Signal for a Scintilla command. * Currently handles SCEN_SETFOCUS. */ -static void s_command(GtkWidget *view, gint wParam, gpointer _, gpointer __) { +static void s_command(GtkWidget *view, int wParam, void*_, void*__) { if (wParam >> 16 == SCEN_SETFOCUS) goto_view(view); } /** * Signal for a Scintilla keypress. */ -static gboolean s_keypress(GtkWidget *view, GdkEventKey *event, gpointer _) { +static int s_keypress(GtkWidget *view, GdkEventKey *event, void*_) { 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, @@ -492,16 +642,16 @@ static gboolean s_keypress(GtkWidget *view, GdkEventKey *event, gpointer _) { /** * Signal for a Scintilla mouse click. */ -static gboolean s_buttonpress(GtkWidget*_, GdkEventButton *event, gpointer __) { +static int s_buttonpress(GtkWidget*_, GdkEventButton *event, void*__) { if (event->type == GDK_BUTTON_PRESS && event->button == 3) - return (lL_showcontextmenu(lua, event), TRUE); + return (lL_showcontextmenu(lua, (void *)event), TRUE); return FALSE; } /** * Signal for a Textadept window focus change. */ -static gboolean w_focus(GtkWidget*_, GdkEventFocus *event, gpointer __) { +static int w_focus(GtkWidget*_, GdkEventFocus *event, void*__) { if (focused_view && !gtk_widget_has_focus(focused_view)) gtk_widget_grab_focus(focused_view); return FALSE; @@ -512,7 +662,7 @@ static gboolean w_focus(GtkWidget*_, GdkEventFocus *event, gpointer __) { * Currently handled keypresses: * - Escape: hides the find box if it is open. */ -static gboolean w_keypress(GtkWidget*_, GdkEventKey *event, gpointer __) { +static int w_keypress(GtkWidget*_, GdkEventKey *event, void*__) { if (event->keyval == 0xff1b && gtk_widget_get_visible(findbox) && !gtk_widget_has_focus(command_entry)) { gtk_widget_hide(findbox); @@ -527,7 +677,7 @@ static gboolean w_keypress(GtkWidget*_, GdkEventKey *event, gpointer __) { * Closes the Lua state and releases resources. * @see l_close */ -static gboolean w_exit(GtkWidget*_, GdkEventAny*__, gpointer ___) { +static int w_exit(GtkWidget*_, GdkEventAny*__, void*___) { if (!lL_event(lua, "quit", -1)) return TRUE; l_close(lua); scintilla_release_resources(); @@ -540,7 +690,7 @@ static gboolean w_exit(GtkWidget*_, GdkEventAny*__, gpointer ___) { * Processes a remote Textadept's command line arguments. */ static int a_command_line(GApplication *app, GApplicationCommandLine *cmdline, - gpointer _) { + void*_) { if (!lua) return 0; // only process argv for secondary/remote instances int argc = 0; char **argv = g_application_command_line_get_arguments(cmdline, &argc); @@ -568,7 +718,7 @@ static int a_command_line(GApplication *app, GApplicationCommandLine *cmdline, * Signal for opening files from OSX. * Generates an 'appleevent_odoc' event for each document sent. */ -static gboolean w_open_osx(GtkOSXApplication*_, char *path, gpointer __) { +static int w_open_osx(GtkOSXApplication*_, char *path, void*__) { lL_event(lua, "appleevent_odoc", LUA_TSTRING, path, -1); return TRUE; } @@ -577,7 +727,7 @@ static gboolean w_open_osx(GtkOSXApplication*_, char *path, gpointer __) { * Signal for block terminating Textadept from OSX. * Generates a 'quit' event. */ -static gboolean w_exit_osx(GtkOSXApplication*_, gpointer __) { +static int w_exit_osx(GtkOSXApplication*_, void*__) { return !lL_event(lua, "quit", -1); } @@ -586,26 +736,30 @@ static gboolean w_exit_osx(GtkOSXApplication*_, gpointer __) { * Closes the Lua state and releases resources. * @see l_close */ -static void w_quit_osx(GtkOSXApplication*_, gpointer __) { +static void w_quit_osx(GtkOSXApplication*_, void*__) { l_close(lua); scintilla_release_resources(); g_object_unref(osxapp); gtk_main_quit(); } #endif +#endif // if GTK /******************************************************************************/ /************************* Find/Replace GUI Interface *************************/ /******************************************************************************/ +#if GTK #define attach(w, x1, x2, y1, y2, xo, yo, xp, yp) \ 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) +#define EXPAND_FILL (GtkAttachOptions)(GTK_EXPAND | GTK_FILL) +#define SHRINK_FILL (GtkAttachOptions)(GTK_SHRINK | GTK_FILL) +#endif /** * Creates the Find box. */ -static GtkWidget *new_findbox() { +static FINDBOX *new_findbox() { +#if GTK 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); @@ -638,18 +792,18 @@ static GtkWidget *new_findbox() { gtk_label_set_mnemonic_widget(GTK_LABEL(flabel), find_entry); gtk_label_set_mnemonic_widget(GTK_LABEL(rlabel), replace_entry); - attach(find_combo, 1, 2, 0, 1, ao_expand, ao_normal, 5, 0); - attach(replace_combo, 1, 2, 1, 2, ao_expand, ao_normal, 5, 0); - attach(flabel, 0, 1, 0, 1, ao_normal, ao_normal, 5, 0); - attach(rlabel, 0, 1, 1, 2, ao_normal, ao_normal, 5, 0); - attach(fnext_button, 2, 3, 0, 1, ao_normal, ao_normal, 0, 0); - attach(fprev_button, 3, 4, 0, 1, ao_normal, ao_normal, 0, 0); - attach(r_button, 2, 3, 1, 2, ao_normal, ao_normal, 0, 0); - attach(ra_button, 3, 4, 1, 2, ao_normal, ao_normal, 0, 0); - attach(match_case_opt, 4, 5, 0, 1, ao_normal, ao_normal, 5, 0); - attach(whole_word_opt, 4, 5, 1, 2, ao_normal, ao_normal, 5, 0); - 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); + attach(find_combo, 1, 2, 0, 1, EXPAND_FILL, SHRINK_FILL, 5, 0); + attach(replace_combo, 1, 2, 1, 2, EXPAND_FILL, SHRINK_FILL, 5, 0); + attach(flabel, 0, 1, 0, 1, SHRINK_FILL, SHRINK_FILL, 5, 0); + attach(rlabel, 0, 1, 1, 2, SHRINK_FILL, SHRINK_FILL, 5, 0); + attach(fnext_button, 2, 3, 0, 1, SHRINK_FILL, SHRINK_FILL, 0, 0); + attach(fprev_button, 3, 4, 0, 1, SHRINK_FILL, SHRINK_FILL, 0, 0); + attach(r_button, 2, 3, 1, 2, SHRINK_FILL, SHRINK_FILL, 0, 0); + attach(ra_button, 3, 4, 1, 2, SHRINK_FILL, SHRINK_FILL, 0, 0); + attach(match_case_opt, 4, 5, 0, 1, SHRINK_FILL, SHRINK_FILL, 5, 0); + attach(whole_word_opt, 4, 5, 1, 2, SHRINK_FILL, SHRINK_FILL, 5, 0); + attach(lua_opt, 5, 6, 0, 1, SHRINK_FILL, SHRINK_FILL, 5, 0); + attach(in_files_opt, 5, 6, 1, 2, SHRINK_FILL, SHRINK_FILL, 5, 0); signal(fnext_button, "clicked", f_clicked); signal(fprev_button, "clicked", f_clicked); @@ -665,6 +819,7 @@ static GtkWidget *new_findbox() { gtk_widget_set_can_focus(whole_word_opt, FALSE); gtk_widget_set_can_focus(lua_opt, FALSE); gtk_widget_set_can_focus(in_files_opt, FALSE); +#endif return findbox; } @@ -676,9 +831,10 @@ static GtkWidget *new_findbox() { /** * 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. + * @param store The LIST_STORE to add the text to. */ -static void find_add_to_history(const char *text, GtkListStore *store) { +static void find_add_to_history(const char *text, LIST_STORE *store) { +#if GTK char *first_item = NULL; GtkTreeIter iter; if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) @@ -691,14 +847,23 @@ static void find_add_to_history(const char *text, GtkListStore *store) { while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)) if (++count > 10) gtk_list_store_remove(store, &iter); // keep 10 items } +#elif NCURSES + if (!store[0] || strcmp(text, store[0]) != 0) { + if (store[9]) free(store[9]); + for (int i = 0; i < 9; i++) store[i + 1] = store[i]; + store[0] = copy(text); + } +#endif } /** * Signal for a find box button click. */ -static void f_clicked(GtkWidget *button, gpointer _) { +static void f_clicked(FIND_BUTTON button, void*_) { +#if GTK const char *find_text = gtk_entry_get_text(GTK_ENTRY(find_entry)); const char *repl_text = gtk_entry_get_text(GTK_ENTRY(replace_entry)); +#endif if (strlen(find_text) == 0) return; if (button == fnext_button || button == fprev_button) { find_add_to_history(find_text, find_store); @@ -719,19 +884,20 @@ static void f_clicked(GtkWidget *button, gpointer _) { /************************ Command Entry GUI Interface *************************/ /******************************************************************************/ +#if GTK /** * The match function for the command entry. * Since the completion list is filled by Lua, every item is a "match". */ static int cc_matchfunc(GtkEntryCompletion*_, const char *__, GtkTreeIter*___, - gpointer ____) { return 1; } + void*____) { return 1; } /** * Replaces the current word (consisting of alphanumeric and underscore * characters) with the match text. */ -static gboolean cc_matchselected(GtkEntryCompletion*_, GtkTreeModel *model, - GtkTreeIter *iter, gpointer __) { +static int cc_matchselected(GtkEntryCompletion*_, GtkTreeModel *model, + GtkTreeIter *iter, void*__) { 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", @@ -755,7 +921,7 @@ static gboolean cc_matchselected(GtkEntryCompletion*_, GtkTreeModel *model, /** * Signal for the 'enter' key being pressed in the Command Entry. */ -static void c_activate(GtkWidget *entry, gpointer _) { +static void c_activate(GtkWidget *entry, void*_) { lL_event(lua, "command_entry_command", LUA_TSTRING, gtk_entry_get_text(GTK_ENTRY(entry)), -1); } @@ -763,13 +929,14 @@ static void c_activate(GtkWidget *entry, gpointer _) { /** * Signal for a keypress inside the Command Entry. */ -static gboolean c_keypress(GtkWidget*_, GdkEventKey *event, gpointer __) { +static int c_keypress(GtkWidget*_, GdkEventKey *event, void*__) { 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_META_MASK, -1); } +#endif // if GTK /******************************************************************************/ /******************************** Lua Interface *******************************/ @@ -847,7 +1014,7 @@ static int lL_init(lua_State *L, int argc, char **argv, int reinit) { 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_setcfunction(L, -1, "menu", lgui_menu); l_setmetatable(L, -1, "ta_gui", lgui__index, lgui__newindex); lua_setglobal(L, "gui"); @@ -872,9 +1039,15 @@ static int lL_init(lua_State *L, int argc, char **argv, int reinit) { #elif __OSX__ lua_pushboolean(L, 1), lua_setglobal(L, "OSX"); #endif +#if GTK const char *charset = 0; g_get_charset(&charset); lua_pushstring(L, charset), lua_setglobal(L, "_CHARSET"); +#elif NCURSES + lua_pushboolean(L, 1), lua_setglobal(L, "NCURSES"); + lua_pushstring(L, "UTF-8"), lua_setglobal(L, "_CHARSET"); // TODO: get charset +#endif + if (lL_dofile(L, "core/init.lua")) { lua_getglobal(L, "_SCINTILLA"); @@ -898,18 +1071,26 @@ static int lL_init(lua_State *L, int argc, char **argv, int reinit) { * @return 1 if there are no errors or 0 in case of errors. */ static int lL_dofile(lua_State *L, const char *filename) { - char *file = g_strconcat(textadept_home, "/", filename, NULL); + char *file = malloc(strlen(textadept_home) + 1 + strlen(filename) + 1); + stpcpy(stpcpy(stpcpy(file, textadept_home), "/"), filename); int ok = (luaL_dofile(L, file) == LUA_OK); if (!ok) { +#if GTK GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s\n", lua_tostring(L, -1)); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); +#elif NCURSES + WINDOW *win = newwin(0, 0, 0, 0); + wprintw(win, lua_tostring(L, -1)), wrefresh(win); + getch(); + delwin(win); +#endif lua_settop(L, 0); } - g_free(file); + free(file); return ok; } @@ -919,9 +1100,9 @@ static int lL_dofile(lua_State *L, const char *filename) { * @param index Stack index of the view. * @return Scintilla view */ -static GtkWidget *l_toview(lua_State *L, int index) { +static Scintilla *l_toview(lua_State *L, int index) { lua_getfield(L, index, "widget_pointer"); - GtkWidget *view = (GtkWidget *)lua_touserdata(L, -1); + Scintilla *view = (Scintilla *)lua_touserdata(L, -1); lua_pop(L, 1); // widget pointer return view; } @@ -931,7 +1112,7 @@ static GtkWidget *l_toview(lua_State *L, int index) { * @param L The Lua state. * @param view The Scintilla view to add. */ -static void lL_addview(lua_State *L, GtkWidget *view) { +static void lL_addview(lua_State *L, Scintilla *view) { lua_getfield(L, LUA_REGISTRYINDEX, "ta_views"); lua_newtable(L); lua_pushlightuserdata(L, view); @@ -954,7 +1135,7 @@ static void lL_addview(lua_State *L, GtkWidget *view) { * @param view The Scintilla view to remove. * @see lL_addview */ -static void lL_removeview(lua_State *L, GtkWidget *view) { +static void lL_removeview(lua_State *L, Scintilla *view) { lua_newtable(L); lua_getfield(L, LUA_REGISTRYINDEX, "ta_views"); lua_pushnil(L); @@ -1020,7 +1201,7 @@ static void lL_removedoc(lua_State *L, sptr_t doc) { lua_pushnil(L); while (lua_next(L, -2)) { if (lua_isnumber(L, -2)) { - GtkWidget *view = l_toview(L, -1); + Scintilla *view = l_toview(L, -1); if (doc == SS(view, SCI_GETDOCPOINTER, 0, 0)) lL_gotodoc(L, view, -1, TRUE); } @@ -1052,7 +1233,7 @@ static void lL_removedoc(lua_State *L, sptr_t doc) { * n of -1 represents the last document. * @param relative Flag indicating whether or not n is relative. */ -static void lL_gotodoc(lua_State *L, GtkWidget *view, int n, int relative) { +static void lL_gotodoc(lua_State *L, Scintilla *view, int n, int relative) { if (relative && n == 0) return; lua_getfield(L, LUA_REGISTRYINDEX, "ta_buffers"); if (relative) { @@ -1091,7 +1272,7 @@ static void l_close(lua_State *L) { lua_pop(L, 1); // value } lua_pop(L, 1); // buffers - gtk_widget_destroy(focused_view); + scintilla_delete(focused_view); lua_close(L); } @@ -1122,7 +1303,7 @@ static void lL_cleartable(lua_State *L, int index) { * @param view The Scintilla view to push. * @see lL_addview */ -static void l_pushview(lua_State *L, GtkWidget *view) { +static void l_pushview(lua_State *L, Scintilla *view) { lua_getfield(L, LUA_REGISTRYINDEX, "ta_views"); lua_pushlightuserdata(L, view), lua_gettable(L, -2); lua_remove(L, -2); // views @@ -1205,17 +1386,17 @@ static long lL_checkscintillaparam(lua_State *L, int *narg, int type) { /** * Checks whether the function argument narg is a Scintilla view and returns - * this view cast to a GtkWidget. + * this view cast to a Scintilla. * @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) { +static Scintilla *lL_checkview(lua_State *L, int narg) { luaL_getmetatable(L, "ta_view"); lua_getmetatable(L, narg); luaL_argcheck(L, lua_compare(L, -1, -2, LUA_OPEQ), narg, "View expected"); lua_getfield(L, (narg > 0) ? narg : narg - 2, "widget_pointer"); - GtkWidget *view = (GtkWidget *)lua_touserdata(L, -1); + Scintilla *view = (Scintilla *)lua_touserdata(L, -1); lua_pop(L, 3); // widget_pointer, metatable, metatable return view; } @@ -1239,16 +1420,17 @@ static void lL_globaldoccheck(lua_State *L, int narg) { } /** - * Pushes a GTK menu created from the table at the given valid index onto the - * stack. + * Pushes a 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 index The stack index of the table to create the menu from. - * @param callback A GCallback associated with each menu item. + * @param callback An optional GTK callback function 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) { +static void l_pushmenu(lua_State *L, int index, void (*callback)(void), + int submenu) { +#if GTK GtkWidget *menu = gtk_menu_new(), *menu_item = 0, *submenu_root = 0; const char *label; lua_pushvalue(L, index); // copy to stack top so relative indices can be used @@ -1266,10 +1448,10 @@ static void l_pushgtkmenu(lua_State *L, int index, GCallback callback, int is_submenu = !lua_isnil(L, -1); lua_pop(L, 1); // title if (is_submenu) { - l_pushgtkmenu(L, -1, callback, TRUE); + l_pushmenu(L, -1, callback, TRUE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), (GtkWidget *)lua_touserdata(L, -1)); - lua_pop(L, 1); // gtkmenu + lua_pop(L, 1); // menu } else if (lua_rawlen(L, -1) == 2 || lua_rawlen(L, -1) == 4) { lua_rawgeti(L, -1, 1); label = lua_tostring(L, -1); @@ -1287,16 +1469,19 @@ static void l_pushgtkmenu(lua_State *L, int index, GCallback callback, if (key || modifiers) gtk_widget_add_accelerator(menu_item, "activate", accel, key, modifiers, GTK_ACCEL_VISIBLE); - g_signal_connect(menu_item, "activate", callback, + g_signal_connect(menu_item, "activate", G_CALLBACK(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"); + } else warn("menu: { '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); +#elif NCURSES + lua_pushnil(L); // TODO: create and push menu (memory management?). +#endif } /******************************************************************************/ @@ -1389,20 +1574,24 @@ static void lL_notify(lua_State *L, struct SCNotification *n) { /** * Shows the context menu for a Scintilla view based on a mouse event. * @param L The Lua state. - * @param event The mouse button event. + * @param event An optional GTK mouse button event. */ -static void lL_showcontextmenu(lua_State *L, GdkEventButton *event) { +static void lL_showcontextmenu(lua_State *L, void *event) { lua_getglobal(L, "gui"); if (lua_istable(L, -1)) { lua_getfield(L, -1, "context_menu"); if (lua_isuserdata(L, -1)) { +#if GTK 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, + event ? ((GdkEventButton *)event)->button : 0, gdk_event_get_time((GdkEvent *)event)); +#elif NCURSES + // TODO: popup context menu. +#endif } else if (!lua_isnil(L, -1)) - warn("gui.context_menu: gtkmenu expected"); + warn("gui.context_menu: menu expected"); lua_pop(L, 1); // gui.context_menu } else lua_pop(L, 1); // non-table } @@ -1470,7 +1659,7 @@ static int l_callscintilla(lua_State *L, int msg, int wtype, int ltype, 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); + if (return_string) free(return_string); return lua_gettop(L) - arg; } @@ -1545,11 +1734,15 @@ static int lview__index(lua_State *L) { 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); + Scintilla *view = lL_checkview(L, 1); +#if GTK if (GTK_IS_PANED(gtk_widget_get_parent(view))) { int pos = gtk_paned_get_position(GTK_PANED(gtk_widget_get_parent(view))); lua_pushinteger(L, pos); } else lua_pushnil(L); +#elif NCURSES + lua_pushnil(L); +#endif } else lua_rawget(L, 1); return 1; } @@ -1559,28 +1752,38 @@ static int lview__newindex(lua_State *L) { if (strcmp(key, "buffer") == 0) luaL_argerror(L, 3, "read-only property"); else if (strcmp(key, "size") == 0) { +#if GTK 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); +#elif NCURSES + // TODO: set size. +#endif } else lua_rawset(L, 1); return 0; } 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) + if (strcmp(key, "statusbar_text") == 0) lua_pushstring(L, statusbar_text); else if (strcmp(key, "clipboard_text") == 0) { +#if GTK char *text = gtk_clipboard_wait_for_text( gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); lua_pushstring(L, text ? text : ""); - if (text) g_free(text); + if (text) free(text); +#elif NCURSES + lua_pushstring(L, ""); // TODO: get Xclipboard text? +#endif } else if (strcmp(key, "size") == 0) { +#if GTK int width, height; gtk_window_get_size(GTK_WINDOW(window), &width, &height); +#elif NCURSES + int width = COLS, height = LINES; +#endif lua_newtable(L); lua_pushinteger(L, width), lua_rawseti(L, -2, 1); lua_pushinteger(L, height), lua_rawseti(L, -2, 2); @@ -1589,24 +1792,36 @@ static int lgui__index(lua_State *L) { } static void set_statusbar_text(const char *text, int bar) { +#if GTK 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); +#elif NCURSES + for (int i = ((bar == 0) ? 0 : 20); i < ((bar == 0) ? 20 : COLS); i++) + mvaddch(LINES - 1, i, ' '); // clear statusbar + mvaddstr(LINES - 1, (bar == 0) ? 0 : COLS - strlen(text), text), refresh(); +#endif } static int lgui__newindex(lua_State *L) { const char *key = lua_tostring(L, 2); - if (strcmp(key, "title") == 0) + if (strcmp(key, "title") == 0) { +#if GTK gtk_window_set_title(GTK_WINDOW(window), lua_tostring(L, 3)); - else if (strcmp(key, "clipboard_text") == 0) +#elif NCURSES + for (int i = 0; i < COLS; i++) mvaddch(0, i, ' '); // clear titlebar + mvaddstr(0, 0, lua_tostring(L, 3)), refresh(); +#endif + } 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(luaL_optstring(L, 3, "")); + if (statusbar_text) free(statusbar_text); + statusbar_text = copy(luaL_optstring(L, 3, "")); set_statusbar_text(statusbar_text, 0); } else if (strcmp(key, "menubar") == 0) { +#if GTK luaL_argcheck(L, lua_istable(L, 3), 3, "table of menus expected"); GtkWidget *new_menubar = gtk_menu_bar_new(); lua_pushnil(L); @@ -1626,22 +1841,37 @@ static int lgui__newindex(lua_State *L) { gtk_osxapplication_set_menu_bar(osxapp, GTK_MENU_SHELL(menubar)); gtk_widget_hide(menubar); #endif +#endif } else if (strcmp(key, "size") == 0) { +#if GTK luaL_argcheck(L, lua_istable(L, 3) && lua_rawlen(L, 3) == 2, 3, "{ width, height } table expected"); 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); +#endif } else lua_rawset(L, 1); return 0; } +#if GTK #define toggled(w) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)) +#elif NCURSES +#define toggled(w) w +#endif static int lfind__index(lua_State *L) { const char *key = lua_tostring(L, 2); if (strcmp(key, "find_entry_text") == 0) +#if GTK lua_pushstring(L, gtk_entry_get_text(GTK_ENTRY(find_entry))); +#elif NCURSES + lua_pushstring(L, find_text); +#endif else if (strcmp(key, "replace_entry_text") == 0) +#if GTK lua_pushstring(L, gtk_entry_get_text(GTK_ENTRY(replace_entry))); +#elif NCURSES + lua_pushstring(L, repl_text); +#endif else if (strcmp(key, "match_case") == 0) lua_pushboolean(L, toggled(match_case_opt)); else if (strcmp(key, "whole_word") == 0) @@ -1655,14 +1885,28 @@ static int lfind__index(lua_State *L) { return 1; } +#if GTK #define toggle(w, b) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), b) +#elif NCURSES +#define toggle(w, b) w = b +#endif static int lfind__newindex(lua_State *L) { const char *key = lua_tostring(L, 2); - if (strcmp(key, "find_entry_text") == 0) + if (strcmp(key, "find_entry_text") == 0) { +#if GTK gtk_entry_set_text(GTK_ENTRY(find_entry), lua_tostring(L, 3)); - else if (strcmp(key, "replace_entry_text") == 0) +#elif NCURSES + if (find_text) free(find_text); + find_text = copy(lua_tostring(L, 3)); +#endif + } else if (strcmp(key, "replace_entry_text") == 0) { +#if GTK gtk_entry_set_text(GTK_ENTRY(replace_entry), lua_tostring(L, 3)); - else if (strcmp(key, "match_case") == 0) +#elif NCURSES + if (repl_text) free(repl_text); + repl_text = copy(lua_tostring(L, 3)); +#endif + } 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)); @@ -1670,6 +1914,7 @@ static int lfind__newindex(lua_State *L) { toggle(lua_opt, lua_toboolean(L, -1)); else if (strcmp(key, "in_files") == 0) toggle(in_files_opt, lua_toboolean(L, -1)); +#if GTK 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) @@ -1690,6 +1935,7 @@ static int lfind__newindex(lua_State *L) { 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)); +#endif else lua_rawset(L, 1); return 0; @@ -1698,7 +1944,11 @@ static int lfind__newindex(lua_State *L) { static int lce__index(lua_State *L) { const char *key = lua_tostring(L, 2); if (strcmp(key, "entry_text") == 0) +#if GTK lua_pushstring(L, gtk_entry_get_text(GTK_ENTRY(command_entry))); +#elif NCURSES + lua_pushstring(L, command_text); +#endif else lua_rawget(L, 1); return 1; @@ -1706,10 +1956,14 @@ static int lce__index(lua_State *L) { static int lce__newindex(lua_State *L) { const char *key = lua_tostring(L, 2); - if (strcmp(key, "entry_text") == 0) + if (strcmp(key, "entry_text") == 0) { +#if GTK gtk_entry_set_text(GTK_ENTRY(command_entry), lua_tostring(L, 3)); - else - lua_rawset(L, 1); +#elif NCURSES + if (command_text) free(command_text); + command_text = copy(lua_tostring(L, 3)); +#endif + } else lua_rawset(L, 1); return 0; } @@ -1751,7 +2005,7 @@ static int lbuffer_text_range(lua_State *L) { tr.lpstrText = malloc(tr.chrg.cpMax - tr.chrg.cpMin + 1); SS(focused_view, SCI_GETTEXTRANGE, 0, (long)(&tr)); lua_pushlstring(L, tr.lpstrText, tr.chrg.cpMax - tr.chrg.cpMin); - g_free(tr.lpstrText); + if (tr.lpstrText) free(tr.lpstrText); return 1; } @@ -1767,6 +2021,7 @@ static int lview_unsplit(lua_State *L) { return 1; } +#if GTK #define child1(p) gtk_paned_get_child1(GTK_PANED(p)) #define child2(p) gtk_paned_get_child2(GTK_PANED(p)) @@ -1787,29 +2042,33 @@ static void l_pushsplittable(lua_State *L, GtkWidget *c1, GtkWidget *c2) { int size = gtk_paned_get_position(GTK_PANED(gtk_widget_get_parent(c1))); lua_pushinteger(L, size), lua_setfield(L, -2, "size"); } +#endif static int lgui_get_split_table(lua_State *L) { +#if GTK 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_pushsplittable(L, child1(pane), child2(pane)); } else l_pushview(L, focused_view); +#elif NCURSES + l_pushview(L, focused_view); // TODO: push split table +#endif return 1; } // 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 lview_goto_buffer(lua_State *L) { - GtkWidget *view = lL_checkview(L, 1), *prev_view = focused_view; + Scintilla *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); 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); + if (switch_focus) SS(view, SCI_SETFOCUS, FALSE, 0), focus_view(prev_view); return 0; } @@ -1852,42 +2111,64 @@ static int lgui_goto_view(lua_State *L) { "no View exists at that index"); lua_rawgeti(L, -1, n); } - GtkWidget *view = l_toview(L, -1); - gtk_widget_grab_focus(view); + Scintilla *view = l_toview(L, -1); + focus_view(view); +#if GTK // 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); +#endif return 0; } -static void m_clicked(GtkWidget *menu, gpointer id) { +#if GTK +static void m_clicked(GtkWidget *menu, void *id) { lL_event(lua, "menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id), -1); } +#endif -static int lgui_gtkmenu(lua_State *L) { +static int lgui_menu(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - l_pushgtkmenu(L, -1, G_CALLBACK(m_clicked), FALSE); +#if GTK + l_pushmenu(L, -1, m_clicked, FALSE); +#elif NCURSES + // TODO: create menu and manage memory. +#endif return 1; } static int lstring_iconv(lua_State *L) { - size_t text_len = 0, conv_len = 0; - const char *text = luaL_checklstring(L, 1, &text_len); + size_t text_len = 0; + char *text = (char *)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); + int converted = FALSE; + iconv_t cd = iconv_open(to, from); + if (cd != (iconv_t) -1) { + char *out = malloc(text_len + 1); + char *outp = out; + size_t inbytesleft = text_len, outbytesleft = text_len; + if (iconv(cd, &text, &inbytesleft, &outp, &outbytesleft) != -1) { + lua_pushlstring(L, out, outp - out); + converted = TRUE; + } + free(out); + iconv_close(cd); + } if (!converted) luaL_error(L, "Conversion failed"); - lua_pushlstring(L, converted, conv_len); - g_free(converted); return 1; } static int lquit(lua_State *L) { +#if GTK GdkEventAny event; event.type = GDK_DELETE; event.window = gtk_widget_get_window(window); event.send_event = TRUE; gdk_event_put((GdkEvent *)(&event)); +#elif NCURSES + quit = true; +#endif return 0; } @@ -1903,7 +2184,8 @@ static int lreset(lua_State *L) { return 0; } -static gboolean emit_timeout(gpointer data) { +#if GTK +static int emit_timeout(void *data) { int *refs = (int *)data; lua_rawgeti(lua, LUA_REGISTRYINDEX, refs[0]); // function int nargs = 0, repeat = TRUE; @@ -1917,8 +2199,10 @@ static gboolean emit_timeout(gpointer data) { lua_pop(lua, 1); // result return repeat; } +#endif static int ltimeout(lua_State *L) { +#if GTK double timeout = luaL_checknumber(L, 1); luaL_argcheck(L, timeout > 0, 1, "timeout must be > 0"); luaL_argcheck(L, lua_isfunction(L, 2), 2, "function expected"); @@ -1930,11 +2214,15 @@ static int ltimeout(lua_State *L) { lua_pushvalue(L, i); refs[i - 2] = luaL_ref(L, LUA_REGISTRYINDEX); } - g_timeout_add(timeout * 1000, emit_timeout, (gpointer)refs); + g_timeout_add(timeout * 1000, emit_timeout, (void *)refs); +#elif NCURSES + luaL_error(L, "not implemented in this environment"); +#endif return 0; } static int lfind_focus(lua_State *L) { +#if GTK if (!gtk_widget_has_focus(findbox)) { gtk_widget_show(findbox); gtk_widget_grab_focus(find_entry); @@ -1943,26 +2231,30 @@ static int lfind_focus(lua_State *L) { gtk_widget_grab_focus(focused_view); gtk_widget_hide(findbox); } +#elif NCURSES + // TODO: toggle findbox focus. +#endif return 0; } static int lfind_next(lua_State *L) { - return (g_signal_emit_by_name(G_OBJECT(fnext_button), "clicked"), 0); + return (f_clicked(fnext_button, NULL), 0); } static int lfind_prev(lua_State *L) { - return (g_signal_emit_by_name(G_OBJECT(fprev_button), "clicked"), 0); + return (f_clicked(fprev_button, NULL), 0); } static int lfind_replace(lua_State *L) { - return (g_signal_emit_by_name(G_OBJECT(r_button), "clicked"), 0); + return (f_clicked(r_button, NULL), 0); } static int lfind_replace_all(lua_State *L) { - return (g_signal_emit_by_name(G_OBJECT(ra_button), "clicked"), 0); + return (f_clicked(ra_button, NULL), 0); } static int lce_focus(lua_State *L) { +#if GTK if (!gtk_widget_has_focus(command_entry)) { gtk_widget_show(command_entry); gtk_widget_grab_focus(command_entry); @@ -1970,10 +2262,14 @@ static int lce_focus(lua_State *L) { gtk_widget_hide(command_entry); gtk_widget_grab_focus(focused_view); } +#elif NCURSES + // TODO: ce toggle focus. +#endif return 0; } static int lce_show_completions(lua_State *L) { +#if GTK luaL_checktype(L, 1, LUA_TTABLE); GtkEntryCompletion *completion = gtk_entry_get_completion( GTK_ENTRY(command_entry)); @@ -1990,5 +2286,6 @@ static int lce_show_completions(lua_State *L) { lua_pop(L, 1); // value } gtk_entry_completion_complete(completion); +#endif return 0; } |