aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TECHNOLOGY.md5
-rw-r--r--src/Makefile19
-rw-r--r--src/textadept.c202
3 files changed, 174 insertions, 52 deletions
diff --git a/TECHNOLOGY.md b/TECHNOLOGY.md
index 7cac0192..dab8b6c0 100644
--- a/TECHNOLOGY.md
+++ b/TECHNOLOGY.md
@@ -21,10 +21,6 @@ terminal user interface (TUI).
=[cdk][] - Widget library for terminal applications=
Textadept uses cdk for drawing terminal UI widgets.
-=[curses-windowman][] - Library to manage split views in curses applications=
- Textadept uses curses-windowman for handling split views in the terminal
- version.
-
=[libtermkey][] - Library for processing keyboard entry for terminal apps=
Textadept uses libtermkey for advanced keyboard entry handling.
@@ -75,7 +71,6 @@ Lua and includes a few external libraries.
[LuaFileSystem]: http://keplerproject.github.io/luafilesystem/
[lspawn]: http://foicica.com/hg/lspawn
[gtDialog]: http://foicica.com/gtdialog/
-[curses-windowman]: https://bitbucket.org/jugglerchris/curses-windowman
[ncurses]: http://invisible-island.net/ncurses/
[pdcurses]: http://pdcurses.sourceforge.net/
[cdk]: http://invisible-island.net/cdk/
diff --git a/src/Makefile b/src/Makefile
index 4613ea73..1a02698e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -134,7 +134,6 @@ gtdialog_objs = gtdialog.o gtdialog-curses.o
termkey_unix_objs = driver-ti.o driver-csi.o
termkey_win32_objs = driver-win32-pdcurses.o
termkey_objs = termkey.o $(termkey_unix_objs) $(termkey_win32_objs)
-windowman_objs = windowman.o
cdk_objs = binding.o buttonbox.o cdk.o cdk_display.o cdk_objs.o cdkscreen.o \
draw.o entry.o fselect.o itemlist.o label.o mentry.o popup_label.o \
scroll.o scroller.o select_file.o selection.o traverse.o version.o
@@ -186,8 +185,6 @@ luajit/src/libluajit.osx.a:
$(gtdialog_objs): gtdialog/gtdialog.c
$(CROSS)$(CC) -c $(CFLAGS) -std=c99 -pedantic -D_POSIX_C_SOURCE=200809L \
$(gtdialog_flags) $< -o $@
-$(windowman_objs): %.o: windowman/%.c
- $(CROSS)$(CC) -c $(CFLAGS) -Iwindowman $(CURSES_CFLAGS) $< -o $@
$(cdk_objs): %.o: cdk/%.c
$(CROSS)$(CC) -c $(CFLAGS) -D_GNU_SOURCE -Itermkey -Icdk $(CURSES_CFLAGS) $< \
-o $@
@@ -208,7 +205,7 @@ $(lua_dep_objs): LUA_CFLAGS += -Ilua/src
$(luajit_dep_objs): LUA_CFLAGS += -Iluajit/src
$(textadept_gtk_objs): ta_flags += $(GTK_CFLAGS)
$(textadept_curses_objs): \
- ta_flags += -Iscintilla/term -Itermkey -Iwindowman -Icdk $(CURSES_CFLAGS)
+ ta_flags += -Iscintilla/term -Itermkey -Icdk $(CURSES_CFLAGS)
lspawn.o lspawnjit.o: spawn_flags = -DGTK $(GLIB_CFLAGS)
$(gtdialog_objs): gtdialog_flags = $(plat_flag) -DNOHELP -DLIBRARY
gtdialog.o: gtdialog_flags += $(GTK_CFLAGS)
@@ -227,13 +224,13 @@ textadeptjit: $(sci_objs) $(sci_lex_objs) $(sci_gtk_objs) scintilla-marshal.o \
textadept-curses: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o LexLPeg-curses.o \
textadept-curses.o $(lua_objs) $(lua_lib_objs) \
lspawn-curses.o gtdialog-curses.o termkey.o \
- $(termkey_unix_objs) $(windowman_objs) $(cdk_objs)
+ $(termkey_unix_objs) $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
textadeptjit-curses: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o \
LexLPegjit-curses.o textadeptjit-curses.o \
$(luajit_lib_objs) $(libluajit) lspawnjit-curses.o \
gtdialog-curses.o termkey.o $(termkey_unix_objs) \
- $(windowman_objs) $(cdk_objs)
+ $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
textadept.exe: $(sci_objs) $(sci_lex_objs) $(sci_gtk_objs) scintilla-marshal.o \
LexLPeg.o textadept.o textadept_rc.o $(lua_objs) \
@@ -248,13 +245,13 @@ textadept-curses.exe: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o \
LexLPeg-curses.o textadept-curses.o textadept_rc.o \
$(lua_objs) $(lua_lib_objs) lspawn-curses.o \
gtdialog-curses.o termkey.o $(termkey_win32_objs) \
- $(windowman_objs) $(cdk_objs)
+ $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
textadeptjit-curses.exe: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o \
LexLPegjit-curses.o textadeptjit-curses.o \
textadept_rc.o $(luajit_lib_objs) $(libluajit) \
lspawnjit-curses.o gtdialog-curses.o termkey.o \
- $(termkey_win32_objs) $(windowman_objs) $(cdk_objs)
+ $(termkey_win32_objs) $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
# Install/uninstall.
@@ -361,7 +358,7 @@ osx-app: ../textadept ../textadeptjit ../textadept-curses \
# External dependencies.
base_deps = scintilla scintilla/term scintillua lua lualibs luajit gtdialog \
- windowman cdk ../doc/bombay
+ cdk ../doc/bombay
deps: $(base_deps) termkey
win32-deps: $(base_deps) win32gtk win32curses
osx-deps: $(base_deps) gtkosx termkey
@@ -388,7 +385,6 @@ lspawn_zip = lspawn_1.0.zip
luajit_tgz = LuaJIT-2.0.3.tar.gz
libluajit_tgz = libluajit_2.0.3.x86_64.tgz
gtdialog_zip = gtdialog_1.1.zip
-windowman_zip = 4a75ba194792.zip
cdk_tgz = cdk.tar.gz
termkey_tgz = libtermkey-0.17.tar.gz
win32gtk_zip = gtk+-bundle_2.24.10-20120208_win32.zip
@@ -433,9 +429,6 @@ $(libluajit_tgz): ; wget http://foicica.com/textadept/download/$@
libluajit64: | $(libluajit_tgz) ; tar xzf $|
$(gtdialog_zip): ; wget $(gtdialog_url) -O $@
gtdialog: | $(gtdialog_zip) ; mkdir $@ && unzip -d $@ $| && mv $@/*/* $@
-$(windowman_zip):
- wget https://bitbucket.org/jugglerchris/curses-windowman/get/$@
-windowman: | $(windowman_zip) ; mkdir $@ && unzip -d $@ $| && mv $@/*/* $@
$(cdk_tgz): ; wget http://invisible-island.net/datafiles/release/$@
cdk: cdk.patch | $(cdk_tgz)
mkdir $@ && tar xzf $| -C $@ && mv $@/*/* $@
diff --git a/src/textadept.c b/src/textadept.c
index 9466aed9..0f979a13 100644
--- a/src/textadept.c
+++ b/src/textadept.c
@@ -49,7 +49,6 @@
#include "ScintillaWidget.h"
#elif CURSES
#include "ScintillaTerm.h"
-#include "windowman.h"
#include "cdk_int.h"
#include "termkey.h"
#endif
@@ -143,17 +142,22 @@ static ListStore *find_store, *repl_store;
#define command_entry_focused gtk_widget_has_focus(command_entry)
#elif CURSES
// curses window.
-static struct WindowManager *wm;
+typedef struct Pane {
+ int y, x, rows, cols, split_size; // dimensions
+ enum {SINGLE, VSPLIT, HSPLIT} type; // pane type
+ WINDOW *win; // either the Scintilla curses window or the split bar's window
+ Scintilla *view; // Scintilla view for a non-split view
+ struct Pane *child1, *child2; // each pane in a split view
+} Pane; // Pane implementation based on code by Chris Emerson.
+static Pane *pane;
static int statusbar_length[2], command_entry_focused;
TermKey *ta_tk; // global for CDK use
#define SS(view, msg, w, l) scintilla_send_message(view, msg, w, l)
#define focus_view(view) \
(focused_view ? SS(focused_view, SCI_SETFOCUS, 0, 0) : 0, \
SS(view, SCI_SETFOCUS, 1, 0))
-/** Callback for refreshing a single Scintilla view. */
-static void r_cb(void *view, void*_) {scintilla_refresh((Scintilla *)view);}
#define refresh_all() { \
- wman_walk(wm, r_cb, NULL), wman_refresh(wm); \
+ pane_refresh(pane); \
if (command_entry_focused) scintilla_refresh(command_entry); \
refresh(); \
}
@@ -162,8 +166,7 @@ static void r_cb(void *view, void*_) {scintilla_refresh((Scintilla *)view);}
static CDKSCREEN *findbox;
static CDKENTRY *find_entry, *replace_entry, *focused_entry;
static char *find_text, *repl_text, *flabel, *rlabel;
-typedef int FindButton;
-enum FindButton {fnext_button, r_button, fprev_button, ra_button};
+typedef enum {fnext_button, r_button, fprev_button, ra_button} FindButton;
static int find_options[4];
static int *match_case = &find_options[0], *whole_word = &find_options[1],
*lua_pattern = &find_options[2], *in_files = &find_options[3];
@@ -403,6 +406,20 @@ static char *get_clipboard() {
char *text = malloc(scintilla_get_clipboard(focused_view, NULL));
return (scintilla_get_clipboard(focused_view, text), text);
}
+
+/**
+ * Redraws an entire pane and its children.
+ * @param pane The pane to redraw.
+ */
+static void pane_refresh(Pane *pane) {
+ if (pane->type == VSPLIT) {
+ mvwvline(pane->win, 0, 0, 0, pane->rows), wrefresh(pane->win);
+ pane_refresh(pane->child1), pane_refresh(pane->child2);
+ } else if (pane->type == HSPLIT) {
+ mvwhline(pane->win, 0, 0, 0, pane->cols), wrefresh(pane->win);
+ pane_refresh(pane->child1), pane_refresh(pane->child2);
+ } else scintilla_refresh(pane->view);
+}
#endif
/** `find.focus()` Lua function. */
@@ -614,14 +631,14 @@ static void l_pushsplittable(lua_State *L, GtkWidget *w) {
} else l_pushview(L, w);
}
#elif CURSES
-static void l_pushsplittable(lua_State *L, struct WindowManager *wm) {
- if (wm->dir != SPLIT_LEAF) {
+static void l_pushsplittable(lua_State *L, Pane *pane) {
+ if (pane->type != SINGLE) {
lua_newtable(L);
- l_pushsplittable(L, wm->first), lua_rawseti(L, -2, 1);
- l_pushsplittable(L, wm->second), lua_rawseti(L, -2, 2);
- lua_pushboolean(L, wm->dir == SPLIT_VER), lua_setfield(L, -2, "vertical");
- lua_pushinteger(L, wm->splitpos), lua_setfield(L, -2, "size");
- } else l_pushview(L, wm->view);
+ l_pushsplittable(L, pane->child1), lua_rawseti(L, -2, 1);
+ l_pushsplittable(L, pane->child2), lua_rawseti(L, -2, 2);
+ lua_pushboolean(L, pane->type == VSPLIT), lua_setfield(L, -2, "vertical");
+ lua_pushinteger(L, pane->split_size), lua_setfield(L, -2, "size");
+ } else l_pushview(L, pane->view);
}
#endif
@@ -632,7 +649,7 @@ static int lui_get_split_table(lua_State *L) {
while (GTK_IS_PANED(gtk_widget_get_parent(w))) w = gtk_widget_get_parent(w);
l_pushsplittable(L, w);
#elif CURSES
- l_pushsplittable(L, wm);
+ l_pushsplittable(L, pane);
#endif
return 1;
}
@@ -1657,7 +1674,7 @@ static void delete_view(Scintilla *view) {
#if GTK
/**
- * Remove all Scintilla views from the given pane and delete them.
+ * Removes all Scintilla views from the given pane and deletes them.
* @param pane The GTK pane to remove Scintilla views from.
* @see delete_view
*/
@@ -1668,15 +1685,74 @@ static void remove_views_from_pane(GtkWidget *pane) {
}
#elif CURSES
/**
- * Signal that the curses window manager removed a view.
- * @param view The view removed.
+ * Removes all Scintilla views from the given pane and deletes them along with
+ * the child panes themselves.
+ * @param pane The pane to remove Scintilla views from.
* @see delete_view
*/
-static void view_removed(void *view, void*_) {delete_view((Scintilla *)view);}
+static void remove_views_from_pane(Pane *pane) {
+ if (pane->type == VSPLIT || pane->type == HSPLIT) {
+ remove_views_from_pane(pane->child1), remove_views_from_pane(pane->child2);
+ delwin(pane->win), pane->win = NULL; // delete split bar
+ } else delete_view(pane->view);
+ free(pane);
+}
+
+/**
+ * Resizes and repositions a pane.
+ * @param pane the pane to resize and move.
+ * @param rows The number of rows the pane should show.
+ * @param cols The number of columns the pane should show.
+ * @param y The y-coordinate to place the pane at.
+ * @param x The x-coordinate to place the pane at.
+ */
+static void pane_resize(Pane *pane, int rows, int cols, int y, int x) {
+ if (pane->type == VSPLIT) {
+ int ssize = pane->split_size * cols / max(pane->cols, 1);
+ if (ssize < 1 || ssize >= cols - 1) ssize = (ssize < 1) ? 1 : cols - 2;
+ pane->split_size = ssize;
+ pane_resize(pane->child1, rows, ssize, y, x);
+ pane_resize(pane->child2, rows, cols - ssize - 1, y, x + ssize + 1);
+ wresize(pane->win, rows, 1), mvwin(pane->win, y, x + ssize); // split bar
+ } else if (pane->type == HSPLIT) {
+ int ssize = pane->split_size * rows / max(pane->rows, 1);
+ if (ssize < 1 || ssize >= rows - 1) ssize = (ssize < 1) ? 1 : rows - 2;
+ pane->split_size = ssize;
+ pane_resize(pane->child1, ssize, cols, y, x);
+ pane_resize(pane->child2, rows - ssize - 1, cols, y + ssize + 1, x);
+ wresize(pane->win, 1, cols), mvwin(pane->win, y + ssize, x); // split bar
+ } else wresize(pane->win, rows, cols), mvwin(pane->win, y, x);
+ pane->rows = rows, pane->cols = cols, pane->y = y, pane->x = x;
+}
+
+/**
+ * Helper for unsplitting a view.
+* @param pane The pane that contains the view to unsplit.
+ * @param view The view to unsplit.
+ * @param parent The parent of pane. Used recursively.
+ * @see unsplit_view
+ */
+static int pane_unsplit_view(Pane *pane, Scintilla *view, Pane *parent) {
+ if (pane->type == SINGLE) {
+ if (pane->view != view) return FALSE;
+ remove_views_from_pane((pane == parent->child1) ? parent->child2
+ : parent->child1);
+ delwin(parent->win); // delete split bar
+ // Inherit child's properties.
+ parent->type = pane->type, parent->split_size = pane->split_size;
+ parent->win = pane->win, parent->view = pane->view;
+ parent->child1 = pane->child1, parent->child2 = pane->child2;
+ free(pane);
+ // Update.
+ pane_resize(parent, parent->rows, parent->cols, parent->y, parent->x);
+ return TRUE;
+ } else return pane_unsplit_view(pane->child1, view, pane) ||
+ pane_unsplit_view(pane->child2, view, pane);
+}
#endif
/**
- * Unsplits the pane a given Scintilla view is in and keeps the view.
+ * Unsplits the pane the 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_from_pane
@@ -1702,8 +1778,8 @@ static int unsplit_view(Scintilla *view) {
gtk_widget_grab_focus(GTK_WIDGET(view));
g_object_unref(view), g_object_unref(other);
#elif CURSES
- if (wm->dir == SPLIT_LEAF) return FALSE;
- wman_unsplit_view(wm, view, view_removed), scintilla_refresh(view);
+ if (pane->type == SINGLE) return FALSE;
+ pane_unsplit_view(pane, view, NULL), scintilla_refresh(view);
#endif
return TRUE;
}
@@ -1918,6 +1994,54 @@ static int lview_goto_buffer(lua_State *L) {
return 0;
}
+#if CURSES
+/**
+ * Creates a new pane that contains a Scintilla view.
+ * @param view The Scintilla view to place in the pane.
+ */
+static Pane *pane_new(Scintilla *view) {
+ Pane *p = (Pane *)calloc(1, sizeof(Pane));
+ p->type = SINGLE, p->win = scintilla_get_window(view), p->view = view;
+ return p;
+}
+
+/**
+ * Helper for splitting a view.
+ * Recursively propagates a split to child panes.
+ * @param pane The pane to split.
+ * @param vertical Whether to split the pane vertically or horizontally.
+ * @param view The first Scintilla view to place in the split view.
+ * @param view2 The second Scintilla view to place in the split view.
+ * @see split_view
+ */
+static int pane_split_view(Pane *pane, int vertical, Scintilla *view,
+ Scintilla *view2) {
+ if (pane->type == SINGLE) {
+ if (view != pane->view) return FALSE;
+ Pane *child1 = pane_new(view), *child2 = pane_new(view2);
+ pane->type = vertical ? VSPLIT : HSPLIT;
+ pane->child1 = child1, pane->child2 = child2, pane->view = NULL;
+ // Resize children and create a split bar.
+ if (vertical) {
+ pane->split_size = pane->cols / 2;
+ pane_resize(child1, pane->rows, pane->split_size, pane->y, pane->x);
+ pane_resize(child2, pane->rows, pane->cols - pane->split_size - 1,
+ pane->y, pane->x + pane->split_size + 1);
+ pane->win = newwin(pane->rows, 1, pane->y, pane->x + pane->split_size);
+ } else {
+ pane->split_size = pane->rows / 2;
+ pane_resize(child1, pane->split_size, pane->cols, pane->y, pane->x);
+ pane_resize(child2, pane->rows - pane->split_size - 1, pane->cols,
+ pane->y + pane->split_size + 1, pane->x);
+ pane->win = newwin(1, pane->cols, pane->y + pane->split_size, pane->x);
+ }
+ pane_refresh(pane);
+ return TRUE;
+ } else return pane_split_view(pane->child1, vertical, view, view2) ||
+ pane_split_view(pane->child2, vertical, view, view2);
+}
+#endif
+
/**
* Splits the given Scintilla view into two views.
* The new view shows the same document as the original one.
@@ -1951,7 +2075,7 @@ static void split_view(Scintilla *view, int vertical) {
while (gtk_events_pending()) gtk_main_iteration(); // ensure view2 is painted
#elif CURSES
Scintilla *view2 = new_view(curdoc);
- wman_split_view(wm, vertical, view, view2, scintilla_get_window(view2));
+ pane_split_view(pane, vertical, view, view2);
#endif
focus_view(view2);
SS(view2, SCI_SETSEL, anchor, current_pos);
@@ -1971,6 +2095,20 @@ static int lview_unsplit(lua_State *L) {
return (lua_pushboolean(L, unsplit_view(lL_checkview(L, 1))), 1);
}
+#if CURSES
+/**
+ * Searches for the given view and returns its parent pane.
+ * @param pane The pane that contains the desired view.
+ * @param view The view to get the parent pane of.
+ */
+static Pane *pane_get_parent(Pane *pane, Scintilla *view) {
+ if (pane->type == SINGLE) return NULL;
+ if (pane->child1->view == view || pane->child2->view == view) return pane;
+ Pane *parent = pane_get_parent(pane->child1, view);
+ return parent ? parent : pane_get_parent(pane->child2, view);
+}
+#endif
+
/** `view.__index` Lua metatable. */
static int lview__index(lua_State *L) {
const char *key = lua_tostring(L, 2);
@@ -1984,8 +2122,8 @@ static int lview__index(lua_State *L) {
lua_pushinteger(L, pos);
} else lua_pushnil(L);
#elif CURSES
- struct WindowManager *parent = wman_parent(wm, wman_view_owner(wm, view));
- parent ? lua_pushinteger(L, parent->splitpos) : lua_pushnil(L);
+ Pane *parent = pane_get_parent(pane, view);
+ parent ? lua_pushinteger(L, parent->split_size) : lua_pushnil(L);
#endif
} else lua_rawget(L, 1);
return 1;
@@ -2003,9 +2141,8 @@ static int lview__newindex(lua_State *L) {
GtkWidget *pane = gtk_widget_get_parent(lL_checkview(L, 1));
if (GTK_IS_PANED(pane)) gtk_paned_set_position(GTK_PANED(pane), size);
#elif CURSES
- Scintilla *view = lL_checkview(L, 1);
- struct WindowManager *split = wman_parent(wm, wman_view_owner(wm, view));
- if (split) wman_move_split(split, size);
+ Pane *p = pane_get_parent(pane, lL_checkview(L, 1));
+ if (p) p->split_size = size, pane_resize(p, p->rows, p->cols, p->y, p->x);
#endif
} else lua_rawset(L, 1);
return 0;
@@ -2219,9 +2356,7 @@ static void new_window() {
dummy_view = scintilla_new();
#elif CURSES
- Scintilla *view = new_view(0);
- wm = wman_create(view, scintilla_get_window(view));
- wman_resize(wm, LINES - 2, COLS, 1, 0);
+ pane = pane_new(new_view(0)), pane_resize(pane, LINES - 2, COLS, 1, 0);
command_entry = scintilla_new(NULL);
wresize(scintilla_get_window(command_entry), 1, COLS);
mvwin(scintilla_get_window(command_entry), LINES - 2, 0);
@@ -2235,8 +2370,7 @@ static void new_window() {
static void resize(int signal) {
struct winsize win;
ioctl(0, TIOCGWINSZ, &win);
- resizeterm(win.ws_row, win.ws_col);
- wman_resize(wm, LINES - 2, COLS, 1, 0);
+ resizeterm(win.ws_row, win.ws_col), pane_resize(pane, LINES - 2, COLS, 1, 0);
WINDOW *ce_win = scintilla_get_window(command_entry);
wresize(ce_win, 1, COLS), mvwin(ce_win, LINES - 1 - getmaxy(ce_win), 0);
lL_event(lua, "update_ui", -1);
@@ -2423,7 +2557,7 @@ int main(int argc, char **argv) {
if (quit && !lL_event(lua, "quit", -1)) {
l_close(lua);
// Free some memory.
- free(flabel), free(rlabel);
+ free(pane), free(flabel), free(rlabel);
if (find_text) free(find_text);
if (repl_text) free(repl_text);
for (int i = 0; i < 10; i++) {