aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.def.h22
-rw-r--r--editor.c388
-rw-r--r--editor.h39
-rw-r--r--ui-curses.c568
-rw-r--r--ui-curses.h9
-rw-r--r--ui.h58
-rw-r--r--vis.c89
-rw-r--r--window.c273
-rw-r--r--window.h30
9 files changed, 839 insertions, 637 deletions
diff --git a/config.def.h b/config.def.h
index 2a9e258..b8657a4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,5 +1,4 @@
/** start by reading from the top of vis.c up until config.h is included */
-#define DEFAULT_TERM "xterm" /* default term to use if $TERM isn't set */
/* macros used to specify keys for key bindings */
#define ESC 0x1B
#define NONE(k) { .str = { k }, .code = 0 }
@@ -71,26 +70,6 @@ static Command cmds[] = {
{ /* array terminator */ },
};
-/* draw a statubar, do whatever you want with win->statuswin curses window */
-static void statusbar(EditorWin *win) {
- bool focused = vis->win == win || vis->prompt->editor == win;
- const char *filename = text_filename_get(win->text);
- CursorPos pos = window_cursor_getpos(win->win);
- wattrset(win->statuswin, focused ? A_REVERSE|A_BOLD : A_REVERSE);
- mvwhline(win->statuswin, 0, 0, ' ', win->width);
- mvwprintw(win->statuswin, 0, 0, "%s %s %s %s",
- mode->name && mode->name[0] == '-' ? mode->name : "",
- filename ? filename : "[No Name]",
- text_modified(win->text) ? "[+]" : "",
- vis->recording ? "recording": "");
- char buf[win->width + 1];
- int len = snprintf(buf, win->width, "%zd, %zd", pos.line, pos.col);
- if (len > 0) {
- buf[len] = '\0';
- mvwaddstr(win->statuswin, 0, win->width - len - 1, buf);
- }
-}
-
/* called before any other keybindings are checked, if the function returns false
* the key is completely ignored. */
static bool vis_keypress(Key *key) {
@@ -796,7 +775,6 @@ static Config editors[] = {
{
.name = "vis",
.mode = &vis_modes[VIS_MODE_NORMAL],
- .statusbar = statusbar,
.keypress = vis_keypress,
},
};
diff --git a/editor.c b/editor.c
index a8330d6..668062c 100644
--- a/editor.c
+++ b/editor.c
@@ -5,91 +5,12 @@
#include "editor.h"
#include "util.h"
-#ifdef NCURSES_VERSION
-# ifndef NCURSES_EXT_COLORS
-# define NCURSES_EXT_COLORS 0
-# endif
-# if !NCURSES_EXT_COLORS
-# define MAX_COLOR_PAIRS 256
-# endif
-#endif
-#ifndef MAX_COLOR_PAIRS
-# define MAX_COLOR_PAIRS COLOR_PAIRS
-#endif
-
static EditorWin *editor_window_new_text(Editor *ed, Text *text);
-static void editor_window_free(Editor *ed, EditorWin *win);
+static void editor_window_free(EditorWin *win);
static void editor_windows_invalidate(Editor *ed, size_t start, size_t end);
-static void editor_window_draw(EditorWin *win);
-static void windows_arrange_horizontal(Editor *ed);
-static void windows_arrange_vertical(Editor *ed);
-
-static Prompt *editor_prompt_new();
-static void editor_prompt_free(Prompt *prompt);
-static void editor_prompt_clear(Prompt *prompt);
-static void editor_prompt_resize(Prompt *prompt, int width, int height);
-static void editor_prompt_move(Prompt *prompt, int x, int y);
-static void editor_prompt_draw(Prompt *prompt);
-static void editor_prompt_update(Prompt *prompt);
-static void editor_info_draw(Editor *ed);
-
-static void editor_window_resize(EditorWin *win, int width, int height) {
- window_resize(win->win, width, win->statuswin ? height - 1 : height);
- if (win->statuswin)
- wresize(win->statuswin, 1, width);
- win->width = width;
- win->height = height;
-}
-
-static void editor_window_move(EditorWin *win, int x, int y) {
- window_move(win->win, x, y);
- if (win->statuswin)
- mvwin(win->statuswin, y + win->height - 1, x);
-}
-
-static void editor_window_statusbar_draw(EditorWin *win) {
- if (win->statuswin && win->editor->statusbar)
- win->editor->statusbar(win);
-}
-
-static void editor_window_cursor_moved(Win *winwin, void *data) {
- EditorWin *win = data;
- Filerange sel = window_selection_get(winwin);
- if (text_range_valid(&sel) && sel.start != sel.end) {
- text_mark_intern_set(win->text, MARK_SELECTION_START, sel.start);
- text_mark_intern_set(win->text, MARK_SELECTION_END, sel.end);
- }
- editor_window_statusbar_draw(win);
-}
-void editor_statusbar_set(Editor *ed, void (*statusbar)(EditorWin*)) {
- ed->statusbar = statusbar;
-}
-
-static void windows_arrange_horizontal(Editor *ed) {
- int n = 0, x = 0, y = 0;
- for (EditorWin *win = ed->windows; win; win = win->next)
- n++;
- int height = ed->height / MAX(1, n);
- for (EditorWin *win = ed->windows; win; win = win->next) {
- editor_window_resize(win, ed->width, win->next ? height : ed->height - y);
- editor_window_move(win, x, y);
- y += height;
- }
-}
-
-static void windows_arrange_vertical(Editor *ed) {
- int n = 0, x = 0, y = 0;
- for (EditorWin *win = ed->windows; win; win = win->next)
- n++;
- int width = (ed->width / MAX(1, n)) - 1;
- for (EditorWin *win = ed->windows; win; win = win->next) {
- editor_window_resize(win, win->next ? width : ed->width - x, ed->height);
- editor_window_move(win, x, y);
- x += width;
- if (win->next)
- mvvline(0, x++, ACS_VLINE, ed->height);
- }
+void editor_windows_arrange(Editor *ed, enum UiLayout layout) {
+ ed->ui->arrange(ed->ui, layout);
}
bool editor_window_reload(EditorWin *win) {
@@ -115,16 +36,6 @@ bool editor_window_reload(EditorWin *win) {
return true;
}
-void editor_windows_arrange_vertical(Editor *ed) {
- ed->windows_arrange = windows_arrange_vertical;
- editor_draw(ed);
-}
-
-void editor_windows_arrange_horizontal(Editor *ed) {
- ed->windows_arrange = windows_arrange_horizontal;
- editor_draw(ed);
-}
-
bool editor_window_split(EditorWin *original) {
EditorWin *win = editor_window_new_text(original->editor, original->text);
if (!win)
@@ -201,18 +112,8 @@ size_t editor_window_changelist_next(EditorWin *win) {
return win->changelist.pos;
}
-void editor_resize(Editor *ed, int width, int height) {
- ed->width = width;
- ed->height = height;
- if (ed->info[0]) {
- ed->height--;
- } else if (ed->prompt->active) {
- ed->height--;
- editor_prompt_resize(ed->prompt, ed->width, 1);
- editor_prompt_move(ed->prompt, 0, ed->height);
- editor_prompt_draw(ed->prompt);
- }
- editor_draw(ed);
+void editor_resize(Editor *ed) {
+ ed->ui->resize(ed->ui);
}
void editor_window_next(Editor *ed) {
@@ -222,8 +123,7 @@ void editor_window_next(Editor *ed) {
ed->win = ed->win->next;
if (!ed->win)
ed->win = ed->windows;
- editor_window_statusbar_draw(sel);
- editor_window_statusbar_draw(ed->win);
+ ed->ui->window_focus(ed->win->ui);
}
void editor_window_prev(Editor *ed) {
@@ -233,8 +133,7 @@ void editor_window_prev(Editor *ed) {
ed->win = ed->win->prev;
if (!ed->win)
for (ed->win = ed->windows; ed->win->next; ed->win = ed->win->next);
- editor_window_statusbar_draw(sel);
- editor_window_statusbar_draw(ed->win);
+ ed->ui->window_focus(ed->win->ui);
}
static void editor_windows_invalidate(Editor *ed, size_t start, size_t end) {
@@ -243,10 +142,10 @@ static void editor_windows_invalidate(Editor *ed, size_t start, size_t end) {
Filerange view = window_viewport_get(win->win);
if ((view.start <= start && start <= view.end) ||
(view.start <= end && end <= view.end))
- editor_window_draw(win);
+ win->ui->draw(win->ui);
}
}
- editor_window_draw(ed->win);
+ ed->win->ui->draw(ed->win->ui);
}
int editor_tabwidth_get(Editor *ed) {
@@ -268,7 +167,7 @@ bool editor_syntax_load(Editor *ed, Syntax *syntaxes, Color *colors) {
for (Color *color = colors; color && color->fg; color++) {
if (color->attr == 0)
color->attr = A_NORMAL;
- color->attr |= COLOR_PAIR(editor_color_get(color->fg, color->bg));
+ color->attr |= COLOR_PAIR(ed->ui->color_get(color->fg, color->bg));
}
for (Syntax *syn = syntaxes; syn && syn->name; syn++) {
@@ -303,49 +202,24 @@ void editor_syntax_unload(Editor *ed) {
ed->syntaxes = NULL;
}
-static void editor_window_draw(EditorWin *win) {
- // TODO window_draw draw should restore cursor position
- window_draw(win->win);
- window_cursor_to(win->win, window_cursor_get(win->win));
-}
-
void editor_draw(Editor *ed) {
- erase();
- if (ed->windows) {
- ed->windows_arrange(ed);
- for (EditorWin *win = ed->windows; win; win = win->next) {
- if (ed->win != win)
- editor_window_draw(win);
- }
- editor_window_draw(ed->win);
- }
- if (ed->info[0])
- editor_info_draw(ed);
- wnoutrefresh(stdscr);
+ ed->ui->draw(ed->ui);
}
void editor_update(Editor *ed) {
- for (EditorWin *win = ed->windows; win; win = win->next) {
- if (ed->win != win) {
- if (win->statuswin)
- wnoutrefresh(win->statuswin);
- window_update(win->win);
- }
- }
+ ed->ui->update(ed->ui);
+}
- if (ed->win->statuswin)
- wnoutrefresh(ed->win->statuswin);
- if (ed->prompt && ed->prompt->active)
- editor_prompt_update(ed->prompt);
- window_update(ed->win->win);
+void editor_suspend(Editor *ed) {
+ ed->ui->suspend(ed->ui);
}
-static void editor_window_free(Editor *ed, EditorWin *win) {
+static void editor_window_free(EditorWin *win) {
if (!win)
return;
- window_free(win->win);
- if (win->statuswin)
- delwin(win->statuswin);
+ Editor *ed = win->editor;
+ if (ed && ed->ui)
+ ed->ui->window_free(win->ui);
ringbuf_free(win->jumplist);
bool needed = false;
for (EditorWin *w = ed ? ed->windows : NULL; w; w = w->next) {
@@ -365,14 +239,13 @@ static EditorWin *editor_window_new_text(Editor *ed, Text *text) {
return NULL;
win->editor = ed;
win->text = text;
- win->win = window_new(win->text);
- win->statuswin = newwin(1, ed->width, 0, 0);
win->jumplist = ringbuf_alloc(31);
- if (!win->win || !win->statuswin) {
- editor_window_free(ed, win);
+ win->ui = ed->ui->window_new(ed->ui, text);
+ if (!win->jumplist || !win->ui) {
+ editor_window_free(win);
return NULL;
}
- window_cursor_watch(win->win, editor_window_cursor_moved, win);
+ win->win = win->ui->view_get(win->ui);
window_tabwidth_set(win->win, ed->tabwidth);
if (ed->windows)
ed->windows->prev = win;
@@ -380,6 +253,7 @@ static EditorWin *editor_window_new_text(Editor *ed, Text *text) {
win->prev = NULL;
ed->windows = win;
ed->win = win;
+ ed->ui->window_focus(win->ui);
return win;
}
@@ -441,38 +315,41 @@ bool editor_window_new_fd(Editor *ed, int fd) {
return true;
}
-static void editor_window_detach(Editor *ed, EditorWin *win) {
+void editor_window_close(EditorWin *win) {
+ Editor *ed = win->editor;
if (win->prev)
win->prev->next = win->next;
if (win->next)
win->next->prev = win->prev;
if (ed->windows == win)
ed->windows = win->next;
- win->next = win->prev = NULL;
-}
-
-void editor_window_close(EditorWin *win) {
- Editor *ed = win->editor;
if (ed->win == win)
ed->win = win->next ? win->next : win->prev;
- editor_window_detach(ed, win);
- editor_window_free(ed, win);
+ if (ed->win)
+ ed->ui->window_focus(ed->win->ui);
+ editor_window_free(win);
editor_draw(ed);
}
-Editor *editor_new(int width, int height) {
+Editor *editor_new(Ui *ui) {
+ if (!ui)
+ return NULL;
Editor *ed = calloc(1, sizeof(Editor));
if (!ed)
return NULL;
- if (!(ed->prompt = editor_prompt_new()))
+ ed->ui = ui;
+ ed->ui->init(ed->ui, ed);
+ ed->tabwidth = 8;
+ ed->expandtab = false;
+ if (!(ed->prompt = calloc(1, sizeof(EditorWin))))
+ goto err;
+ if (!(ed->prompt->text = text_load(NULL)))
+ goto err;
+ if (!(ed->prompt->ui = ed->ui->prompt_new(ed->ui, ed->prompt->text)))
goto err;
if (!(ed->search_pattern = text_regex_new()))
goto err;
- ed->width = width;
- ed->height = height;
- ed->tabwidth = 8;
- ed->expandtab = false;
- ed->windows_arrange = windows_arrange_horizontal;
+ ed->prompt->win = ed->prompt->ui->view_get(ed->prompt->ui);
return ed;
err:
editor_free(ed);
@@ -484,11 +361,12 @@ void editor_free(Editor *ed) {
return;
while (ed->windows)
editor_window_close(ed->windows);
- editor_prompt_free(ed->prompt);
+ editor_window_free(ed->prompt);
text_regex_free(ed->search_pattern);
for (int i = 0; i < REG_LAST; i++)
register_free(&ed->registers[i]);
editor_syntax_unload(ed);
+ ed->ui->free(ed->ui);
free(ed);
}
@@ -528,187 +406,39 @@ void editor_delete(Editor *ed, size_t pos, size_t len) {
editor_windows_invalidate(ed, pos, pos + len);
}
-static void editor_prompt_free(Prompt *prompt) {
- if (!prompt)
- return;
- editor_window_free(NULL, prompt->win);
- if (prompt->titlewin)
- delwin(prompt->titlewin);
- free(prompt->title);
- free(prompt);
-}
-
-static Prompt *editor_prompt_new() {
- Text *text = text_load(NULL);
- if (!text)
- return NULL;
- Prompt *prompt = calloc(1, sizeof(Prompt));
- if (!prompt)
- goto err;
-
- if (!(prompt->win = calloc(1, sizeof(EditorWin))))
- goto err;
-
- if (!(prompt->win->win = window_new(text)))
- goto err;
-
- prompt->win->text = text;
-
- if (!(prompt->titlewin = newwin(0, 0, 0, 0)))
- goto err;
-
- return prompt;
-err:
- if (!prompt || !prompt->win)
- text_free(text);
- editor_prompt_free(prompt);
- return NULL;
-}
-
-static void editor_prompt_resize(Prompt *prompt, int width, int height) {
- size_t title_width = strlen(prompt->title);
- wresize(prompt->titlewin, height, title_width);
- editor_window_resize(prompt->win, width - title_width, height);
-}
-
-static void editor_prompt_move(Prompt *prompt, int x, int y) {
- size_t title_width = strlen(prompt->title);
- mvwin(prompt->titlewin, y, x);
- editor_window_move(prompt->win, x + title_width, y);
-}
-
void editor_prompt_show(Editor *ed, const char *title, const char *text) {
- Prompt *prompt = ed->prompt;
- if (prompt->active)
+ if (ed->prompt_window)
return;
- prompt->active = true;
- prompt->editor = ed->win;
- free(prompt->title);
- prompt->title = strdup(title);
- text_insert(prompt->win->text, 0, text, strlen(text));
- window_cursor_to(prompt->win->win, text_size(prompt->win->text));
- ed->win = prompt->win;
- editor_resize(ed, ed->width, ed->height);
-}
-
-static void editor_prompt_draw(Prompt *prompt) {
- mvwaddstr(prompt->titlewin, 0, 0, prompt->title);
-}
-
-static void editor_prompt_update(Prompt *prompt) {
- wnoutrefresh(prompt->titlewin);
-}
-
-static void editor_prompt_clear(Prompt *prompt) {
- Text *text = prompt->win->text;
- while (text_undo(text) != EPOS);
- window_cursor_to(prompt->win->win, 0);
+ ed->prompt_window = ed->win;
+ ed->win = ed->prompt;
+ ed->prompt_type = title[0];
+ ed->ui->prompt(ed->ui, title, text);
}
void editor_prompt_hide(Editor *ed) {
- Prompt *prompt = ed->prompt;
- if (!prompt->active)
+ if (!ed->prompt_window)
return;
- prompt->active = false;
- ed->win = prompt->editor;
- prompt->editor = NULL;
- ed->height++;
- editor_prompt_clear(prompt);
- editor_draw(ed);
-}
-
-void editor_prompt_set(Editor *ed, const char *line) {
- Text *text = ed->prompt->win->text;
- editor_prompt_clear(ed->prompt);
- text_insert(text, 0, line, strlen(line));
- editor_window_draw(ed->prompt->win);
+ ed->ui->prompt_hide(ed->ui);
+ ed->win = ed->prompt_window;
+ ed->prompt_window = NULL;
}
char *editor_prompt_get(Editor *ed) {
- Text *text = ed->prompt->win->text;
- char *buf = malloc(text_size(text) + 1);
- if (!buf)
- return NULL;
- size_t len = text_bytes_get(text, 0, text_size(text), buf);
- buf[len] = '\0';
- return buf;
+ return ed->ui->prompt_input(ed->ui);
}
void editor_info_show(Editor *ed, const char *msg, ...) {
va_list ap;
va_start(ap, msg);
- vsnprintf(ed->info, sizeof(ed->info), msg, ap);
+ ed->ui->info(ed->ui, msg, ap);
va_end(ap);
- editor_resize(ed, ed->width, ed->height);
}
void editor_info_hide(Editor *ed) {
- if (!ed->info[0])
- return;
- ed->info[0] = '\0';
- ed->height++;
- editor_draw(ed);
+ ed->ui->info_hide(ed->ui);
}
-static void editor_info_draw(Editor *ed) {
- attrset(A_BOLD);
- mvaddstr(ed->height, 0, ed->info);
-}
-
-static unsigned int color_hash(short fg, short bg)
-{
- if (fg == -1)
- fg = COLORS;
- if (bg == -1)
- bg = COLORS + 1;
- return fg * (COLORS + 2) + bg;
-}
-
-short editor_color_get(short fg, short bg)
-{
- static bool has_default_colors;
- static short *color2palette, default_fg, default_bg;
- static short color_pairs_max, color_pair_current;
-
- if (!color2palette) {
- pair_content(0, &default_fg, &default_bg);
- if (default_fg == -1)
- default_fg = COLOR_WHITE;
- if (default_bg == -1)
- default_bg = COLOR_BLACK;
- has_default_colors = (use_default_colors() == OK);
- color_pairs_max = MIN(COLOR_PAIRS, MAX_COLOR_PAIRS);
- if (COLORS)
- color2palette = calloc((COLORS + 2) * (COLORS + 2), sizeof(short));
- }
-
- if (fg >= COLORS)
- fg = default_fg;
- if (bg >= COLORS)
- bg = default_bg;
-
- if (!has_default_colors) {
- if (fg == -1)
- fg = default_fg;
- if (bg == -1)
- bg = default_bg;
- }
-
- if (!color2palette || (fg == -1 && bg == -1))
- return 0;
-
- unsigned int index = color_hash(fg, bg);
- if (color2palette[index] == 0) {
- short oldfg, oldbg;
- if (++color_pair_current >= color_pairs_max)
- color_pair_current = 1;
- pair_content(color_pair_current, &oldfg, &oldbg);
- unsigned int old_index = color_hash(oldfg, oldbg);
- if (init_pair(color_pair_current, fg, bg) == OK) {
- color2palette[old_index] = 0;
- color2palette[index] = color_pair_current;
- }
- }
-
- return color2palette[index];
+void editor_window_options(EditorWin *win, enum UiOption options) {
+ win->ui->options(win->ui, options);
}
+
diff --git a/editor.h b/editor.h
index 2be3fa6..ba7d3aa 100644
--- a/editor.h
+++ b/editor.h
@@ -4,14 +4,17 @@
#include <curses.h>
#include <stddef.h>
#include <stdbool.h>
+
+typedef struct Editor Editor;
+typedef struct EditorWin EditorWin;
+
+#include "ui.h"
#include "window.h"
#include "register.h"
#include "macro.h"
#include "syntax.h"
#include "ring-buffer.h"
-typedef struct Editor Editor;
-typedef struct EditorWin EditorWin;
typedef struct {
size_t index; /* #number of changes */
@@ -20,23 +23,14 @@ typedef struct {
struct EditorWin {
Editor *editor; /* editor instance to which this window belongs */
+ UiWin *ui;
Text *text; /* underlying text management */
Win *win; /* window for the text area */
RingBuffer *jumplist; /* LRU jump management */
ChangeList changelist; /* state for iterating through least recently changes */
- WINDOW *statuswin; /* curses window for the statusbar */
- int width, height; /* window size including the statusbar */
EditorWin *prev, *next; /* neighbouring windows */
};
-typedef struct {
- EditorWin *win; /* 1-line height editor window used for the prompt */
- EditorWin *editor; /* active editor window before prompt is shown */
- char *title; /* title displayed to the left of the prompt */
- WINDOW *titlewin; /* the curses window holding the prompt title */
- bool active; /* whether the prompt is currently shown or not */
-} Prompt;
-
enum Reg {
REG_a,
REG_b,
@@ -100,28 +94,29 @@ enum Mark {
};
struct Editor {
- int width, height; /* terminal size, available for all windows */
+ Ui *ui;
EditorWin *windows; /* list of windows */
EditorWin *win; /* currently active window */
Syntax *syntaxes; /* NULL terminated array of syntax definitions */
Register registers[REG_LAST]; /* register used for copy and paste */
Macro macros[26]; /* recorded macros */
Macro *recording, *last_recording;/* currently and least recently recorded macro */
- Prompt *prompt; /* used to get user input */
- char info[255]; /* a user message currently being displayed */
+ EditorWin *prompt; /* 1-line height window to get user input */
+ EditorWin *prompt_window; /* window which was focused before prompt was shown */
+ char prompt_type; /* command ':' or search '/','?' prompt */
Regex *search_pattern; /* last used search pattern */
void (*windows_arrange)(Editor*); /* current layout which places the windows */
- void (*statusbar)(EditorWin*); /* configurable user hook to draw statusbar */
int tabwidth; /* how many spaces should be used to display a tab */
bool expandtab; /* whether typed tabs should be converted to spaces */
bool autoindent; /* whether indentation should be copied from previous line on newline */
};
-Editor *editor_new(int width, int height);
+Editor *editor_new(Ui*);
void editor_free(Editor*);
-void editor_resize(Editor*, int width, int height);
+void editor_resize(Editor*);
void editor_draw(Editor*);
void editor_update(Editor*);
+void editor_suspend(Editor*);
/* these function operate on the currently focused window but make sure
* that all windows which show the affected region are redrawn too. */
@@ -168,8 +163,7 @@ void editor_window_jumplist_invalidate(EditorWin*);
size_t editor_window_changelist_prev(EditorWin*);
size_t editor_window_changelist_next(EditorWin*);
/* rearrange all windows either vertically or horizontally */
-void editor_windows_arrange_vertical(Editor*);
-void editor_windows_arrange_horizontal(Editor*);
+void editor_windows_arrange(Editor*, enum UiLayout);
/* display a user prompt with a certain title and default text */
void editor_prompt_show(Editor*, const char *title, const char *text);
/* hide the user prompt if it is currently shown */
@@ -183,10 +177,7 @@ void editor_prompt_set(Editor*, const char *line);
/* display a message to the user */
void editor_info_show(Editor*, const char *msg, ...);
void editor_info_hide(Editor*);
-
-/* register a callback which is called whenever the statusbar needs to
- * be redrawn */
-void editor_statusbar_set(Editor*, void (*statusbar)(EditorWin*));
+void editor_window_options(EditorWin*, enum UiOption options);
/* look up a curses color pair for the given combination of fore and
* background color */
diff --git a/ui-curses.c b/ui-curses.c
new file mode 100644
index 0000000..4b351e5
--- /dev/null
+++ b/ui-curses.c
@@ -0,0 +1,568 @@
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <curses.h>
+#include <locale.h>
+#include <sys/ioctl.h>
+
+#include "ui.h"
+#include "ui-curses.h"
+#include "util.h"
+
+#ifdef NCURSES_VERSION
+# ifndef NCURSES_EXT_COLORS
+# define NCURSES_EXT_COLORS 0
+# endif
+# if !NCURSES_EXT_COLORS
+# define MAX_COLOR_PAIRS 256
+# endif
+#endif
+#ifndef MAX_COLOR_PAIRS
+# define MAX_COLOR_PAIRS COLOR_PAIRS
+#endif
+
+#if 0
+#define wresize(win, y, x) do { \
+ if (wresize(win, y, x) == ERR) { \
+ printf("ERROR resizing: %d x %d\n", x, y); \
+ } else { \
+ printf("OK resizing: %d x %d\n", x, y); \
+ } \
+ fflush(stdout); \
+} while (0);
+
+#define mvwin(win, y, x) do { \
+ if (mvwin(win, y, x) == ERR) { \
+ printf("ERROR moving: %d x %d\n", x, y); \
+ } else { \
+ printf("OK moving: %d x %d\n", x, y); \
+ } \
+ fflush(stdout); \
+} while (0);
+#endif
+
+typedef struct UiCursesWin UiCursesWin;
+
+typedef struct {
+ Ui ui; /* generic ui interface, has to be the first struct member */
+ Editor *ed; /* editor instance to which this ui belongs */
+ UiCursesWin *windows; /* all windows managed by this ui */
+ UiCursesWin *selwin; /* the currently selected layout */
+ char prompt_title[255]; /* prompt_title[0] == '\0' if prompt isn't shown */
+ UiCursesWin *prompt_win; /* like a normal window but without a status bar */
+ char info[255]; /* info message displayed at the bottom of the screen */
+ int width, height; /* terminal dimensions available for all windows */
+ enum UiLayout layout; /* whether windows are displayed horizontally or vertically */
+} UiCurses;
+
+struct UiCursesWin {
+ UiWin uiwin; /* generic interface, has to be the first struct member */
+ UiCurses *ui; /* ui which manages this window */
+ Text *text; /* underlying text management */
+ Win *view; /* current viewport */
+ WINDOW *win; /* curses window for the text area */
+ WINDOW *winstatus; /* curses window for the status bar */
+ WINDOW *winside; /* curses window for the side bar (line numbers) */
+ int width, height; /* window dimension including status bar */
+ int x, y; /* window position */
+ int sidebar_width; /* width of the sidebar showing line numbers etc. */
+ UiCursesWin *next, *prev; /* pointers to neighbouring windows */
+ enum UiOption options; /* display settings for this window */
+};
+
+static unsigned int color_hash(short fg, short bg) {
+ if (fg == -1)
+ fg = COLORS;
+ if (bg == -1)
+ bg = COLORS + 1;
+ return fg * (COLORS + 2) + bg;
+}
+
+static short color_get(short fg, short bg) {
+ static bool has_default_colors;
+ static short *color2palette, default_fg, default_bg;
+ static short color_pairs_max, color_pair_current;
+
+ if (!color2palette) {
+ pair_content(0, &default_fg, &default_bg);
+ if (default_fg == -1)
+ default_fg = COLOR_WHITE;
+ if (default_bg == -1)
+ default_bg = COLOR_BLACK;
+ has_default_colors = (use_default_colors() == OK);
+ color_pairs_max = MIN(COLOR_PAIRS, MAX_COLOR_PAIRS);
+ if (COLORS)
+ color2palette = calloc((COLORS + 2) * (COLORS + 2), sizeof(short));
+ }
+
+ if (fg >= COLORS)
+ fg = default_fg;
+ if (bg >= COLORS)
+ bg = default_bg;
+
+ if (!has_default_colors) {
+ if (fg == -1)
+ fg = default_fg;
+ if (bg == -1)
+ bg = default_bg;
+ }
+
+ if (!color2palette || (fg == -1 && bg == -1))
+ return 0;
+
+ unsigned int index = color_hash(fg, bg);
+ if (color2palette[index] == 0) {
+ short oldfg, oldbg;
+ if (++color_pair_current >= color_pairs_max)
+ color_pair_current = 1;
+ pair_content(color_pair_current, &oldfg, &oldbg);
+ unsigned int old_index = color_hash(oldfg, oldbg);
+ if (init_pair(color_pair_current, fg, bg) == OK) {
+ color2palette[old_index] = 0;
+ color2palette[index] = color_pair_current;
+ }
+ }
+
+ return color2palette[index];
+}
+
+static void ui_window_resize(UiCursesWin *win, int width, int height) {
+ win->width = width;
+ win->height = height;
+ if (win->winstatus)
+ wresize(win->winstatus, 1, width);
+ wresize(win->win, win->winstatus ? height - 1 : height, width - win->sidebar_width);
+ if (win->winside)
+ wresize(win->winside, height-1, win->sidebar_width);
+ window_resize(win->view, width - win->sidebar_width, win->winstatus ? height - 1 : height);
+}
+
+static void ui_window_move(UiCursesWin *win, int x, int y) {
+ win->x = x;
+ win->y = y;
+ mvwin(win->win, y, x + win->sidebar_width);
+ if (win->winside)
+ mvwin(win->winside, y, x);
+ if (win->winstatus)
+ mvwin(win->winstatus, y + win->height - 1, x);
+}
+
+static void ui_window_draw_status(UiWin *w) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ if (!win->winstatus)
+ return;
+ UiCurses *uic = win->ui;
+ Editor *vis = uic->ed;
+ bool focused = uic->selwin == win;
+ const char *filename = text_filename_get(win->text);
+ CursorPos pos = window_cursor_getpos(win->view);
+ wattrset(win->winstatus, focused ? A_REVERSE|A_BOLD : A_REVERSE);
+ mvwhline(win->winstatus, 0, 0, ' ', win->width);
+ mvwprintw(win->winstatus, 0, 0, "%s %s %s %s",
+ "", // TODO mode->name && mode->name[0] == '-' ? mode->name : "",
+ filename ? filename : "[No Name]",
+ text_modified(win->text) ? "[+]" : "",
+ vis->recording ? "recording": "");
+ char buf[win->width + 1];
+ int len = snprintf(buf, win->width, "%zd, %zd", pos.line, pos.col);
+ if (len > 0) {
+ buf[len] = '\0';
+ mvwaddstr(win->winstatus, 0, win->width - len - 1, buf);
+ }
+}
+
+static void ui_window_draw(UiWin *w) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ if (win->winstatus)
+ ui_window_draw_status((UiWin*)win);
+ window_draw(win->view);
+ window_cursor_to(win->view, window_cursor_get(win->view));
+}
+
+static void ui_window_reload(UiWin *w, Text *text) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ win->text = text;
+ win->sidebar_width = 0;
+ ui_window_draw(w);
+}
+
+static void ui_window_draw_sidebar(UiCursesWin *win, const Line *line) {
+ if (!win->winside)
+ return;
+ int sidebar_width = snprintf(NULL, 0, "%zd", line->lineno + win->height - 2) + 1;
+ if (win->sidebar_width != sidebar_width) {
+ win->sidebar_width = sidebar_width;
+ ui_window_resize(win, win->width, win->height);
+ ui_window_move(win, win->x, win->y);
+ } else {
+ int i = 0;
+ size_t prev_lineno = 0;
+ werase(win->winside);
+ for (const Line *l = line; l; l = l->next, i++) {
+ if (l->lineno != prev_lineno)
+ mvwprintw(win->winside, i, 0, "%*u", sidebar_width-1, l->lineno);
+ prev_lineno = l->lineno;
+ }
+ mvwvline(win->winside, 0, sidebar_width-1, ACS_VLINE, win->height-1);
+ }
+}
+
+static void ui_window_update(UiCursesWin *win) {
+ if (win->winstatus)
+ wnoutrefresh(win->winstatus);
+ if (win->winside)
+ wnoutrefresh(win->winside);
+ wnoutrefresh(win->win);
+}
+
+static void update(Ui *ui) {
+ UiCurses *uic = (UiCurses*)ui;
+ for (UiCursesWin *win = uic->windows; win; win = win->next) {
+ if (win != uic->selwin)
+ ui_window_update(win);
+ }
+
+ if (uic->selwin)
+ ui_window_update(uic->selwin);
+ if (uic->prompt_title[0]) {
+ wnoutrefresh(uic->prompt_win->win);
+ ui_window_update(uic->prompt_win);
+ }
+ doupdate();
+}
+
+static void arrange(Ui *ui, enum UiLayout layout) {
+ UiCurses *uic = (UiCurses*)ui;
+ uic->layout = layout;
+ int n = 0, x = 0, y = 0;
+ for (UiCursesWin *win = uic->windows; win; win = win->next)
+ n++;
+ int max_height = uic->height - !!(uic->prompt_title[0] || uic->info[0]);
+ int width = (uic->width / MAX(1, n)) - 1;
+ int height = max_height / MAX(1, n);
+ for (UiCursesWin *win = uic->windows; win; win = win->next) {
+ if (layout == UI_LAYOUT_HORIZONTAL) {
+ ui_window_resize(win, uic->width, win->next ? height : max_height - y);
+ ui_window_move(win, x, y);
+ y += height;
+ } else {
+ ui_window_resize(win, win->next ? width : uic->width - x, max_height);
+ ui_window_move(win, x, y);
+ x += width;
+ if (win->next)
+ mvvline(0, x++, ACS_VLINE, max_height);
+ }
+ }
+}
+
+static void draw(Ui *ui) {
+ UiCurses *uic = (UiCurses*)ui;
+ erase();
+ arrange(ui, uic->layout);
+
+ for (UiCursesWin *win = uic->windows; win; win = win->next)
+ ui_window_draw((UiWin*)win);
+
+ if (uic->info[0]) {
+ attrset(A_BOLD);
+ mvaddstr(uic->height-1, 0, uic->info);
+ }
+
+ if (uic->prompt_title[0]) {
+ attrset(A_NORMAL);
+ mvaddstr(uic->height-1, 0, uic->prompt_title);
+ ui_window_draw((UiWin*)uic->prompt_win);
+ }
+
+ wnoutrefresh(stdscr);
+}
+
+static void ui_resize_to(Ui *ui, int width, int height) {
+ UiCurses *uic = (UiCurses*)ui;
+ uic->width = width;
+ uic->height = height;
+ if (uic->prompt_title[0]) {
+ size_t title_width = strlen(uic->prompt_title);
+ ui_window_resize(uic->prompt_win, width - title_width, 1);
+ ui_window_move(uic->prompt_win, title_width, height-1);
+ }
+ draw(ui);
+}
+
+static void ui_resize(Ui *ui) {
+ struct winsize ws;
+ int width, height;
+
+ if (ioctl(0, TIOCGWINSZ, &ws) == -1) {
+ getmaxyx(stdscr, height, width);
+ } else {
+ width = ws.ws_col;
+ height = ws.ws_row;
+ }
+
+ resizeterm(height, width);
+ wresize(stdscr, height, width);
+ ui_resize_to(ui, width, height);
+}
+
+static void ui_window_free(UiWin *w) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ if (!win)
+ return;
+ UiCurses *uic = win->ui;
+ if (win->prev)
+ win->prev->next = win->next;
+ if (win->next)
+ win->next->prev = win->prev;
+ if (uic->windows == win)
+ uic->windows = win->next;
+ if (uic->selwin == win)
+ uic->selwin = NULL;
+ win->next = win->prev = NULL;
+ if (win->winstatus)
+ delwin(win->winstatus);
+ if (win->winside)
+ delwin(win->winside);
+ if (win->win)
+ delwin(win->win);
+ window_free(win->view);
+ free(win);
+}
+
+static Win *ui_window_view_get(UiWin *win) {
+ UiCursesWin *cwin = (UiCursesWin*)win;
+ return cwin->view;
+}
+
+static void ui_window_cursor_to(UiWin *w, int x, int y) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ wmove(win->win, y, x);
+ ui_window_draw_status(w);
+}
+
+static void ui_window_draw_text(UiWin *w, const Line *line) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ wmove(win->win, 0, 0);
+ attr_t attr = 0;
+ for (const Line *l = line; l; l = l->next) {
+ /* add a single space in an otherwise empty line to make
+ * the selection cohorent */
+ if (l->width == 0)
+ waddch(win->win, ' ');
+
+ for (int x = 0; x < l->width; x++) {
+ attr_t newattr = l->cells[x].attr;
+ if (newattr != attr) {
+ wattrset(win->win, newattr);
+ attr = newattr;
+ }
+ waddstr(win->win, l->cells[x].data);
+ }
+ wclrtoeol(win->win);
+ }
+ wclrtobot(win->win);
+
+ ui_window_draw_sidebar(win, line);
+}
+
+static void ui_window_focus(UiWin *w) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ UiCursesWin *oldsel = win->ui->selwin;
+ win->ui->selwin = win;
+ if (oldsel)
+ ui_window_draw_status((UiWin*)oldsel);
+ ui_window_draw_status(w);
+}
+
+static void ui_window_options(UiWin *w, enum UiOption options) {
+ UiCursesWin *win = (UiCursesWin*)w;
+ win->options = options;
+ switch (options) {
+ case UI_OPTION_LINE_NUMBERS_NONE:
+ if (win->winside) {
+ delwin(win->winside);
+ win->winside = NULL;
+ win->sidebar_width = 0;
+ }
+ break;
+ case UI_OPTION_LINE_NUMBERS_ABSOLUTE:
+ if (!win->winside)
+ win->winside = newwin(1, 1, 1, 1);
+ break;
+ }
+ ui_window_draw(w);
+}
+
+static UiWin *ui_window_new(Ui *ui, Text *text) {
+ UiCurses *uic = (UiCurses*)ui;
+ UiCursesWin *win = calloc(1, sizeof(UiCursesWin));
+ if (!win)
+ return NULL;
+
+ win->uiwin = (UiWin) {
+ .draw = ui_window_draw,
+ .draw_status = ui_window_draw_status,
+ .draw_text = ui_window_draw_text,
+ .cursor_to = ui_window_cursor_to,
+ .view_get = ui_window_view_get,
+ .options = ui_window_options,
+ .reload = ui_window_reload,
+ };
+
+ if (!(win->view = window_new(text, &win->uiwin, uic->width, uic->height)) ||
+ !(win->win = newwin(0, 0, 0, 0)) ||
+ !(win->winstatus = newwin(1, 0, 0, 0))) {
+ ui_window_free((UiWin*)win);
+ return NULL;
+ }
+
+ win->ui = uic;
+ win->text = text;
+ if (uic->windows)
+ uic->windows->prev = win;
+ win->next = uic->windows;
+ uic->windows = win;
+
+ return &win->uiwin;
+}
+
+static void info(Ui *ui, const char *msg, va_list ap) {
+ UiCurses *uic = (UiCurses*)ui;
+ vsnprintf(uic->info, sizeof(uic->info), msg, ap);
+ draw(ui);
+}
+
+static void info_hide(Ui *ui) {
+ UiCurses *uic = (UiCurses*)ui;
+ if (uic->info[0]) {
+ uic->info[0] = '\0';
+ draw(ui);
+ }
+}
+
+static UiWin *prompt_new(Ui *ui, Text *text) {
+ UiCurses *uic = (UiCurses*)ui;
+ if (uic->prompt_win)
+ return (UiWin*)uic->prompt_win;
+ UiWin *uiwin = ui_window_new(ui, text);
+ UiCursesWin *win = (UiCursesWin*)uiwin;
+ if (!win)
+ return NULL;
+ uic->windows = win->next;
+ if (uic->windows)
+ uic->windows->prev = NULL;
+ if (win->winstatus)
+ delwin(win->winstatus);
+ if (win->winside)
+ delwin(win->winside);
+ win->winstatus = NULL;
+ win->winside = NULL;
+ uic->prompt_win = win;
+ return uiwin;
+}
+
+static void prompt(Ui *ui, const char *title, const char *text) {
+ UiCurses *uic = (UiCurses*)ui;
+ if (uic->prompt_title[0])
+ return;
+ size_t text_len = strlen(text);
+ strncpy(uic->prompt_title, title, sizeof(uic->prompt_title)-1);
+ text_insert(uic->prompt_win->text, 0, text, text_len);
+ window_cursor_to(uic->prompt_win->view, text_len);
+ ui_resize_to(ui, uic->width, uic->height);
+}
+
+static char *prompt_input(Ui *ui) {
+ UiCurses *uic = (UiCurses*)ui;
+ if (!uic->prompt_win)
+ return NULL;
+ Text *text = uic->prompt_win->text;
+ char *buf = malloc(text_size(text) + 1);
+ if (!buf)
+ return NULL;
+ size_t len = text_bytes_get(text, 0, text_size(text), buf);
+ buf[len] = '\0';
+ return buf;
+}
+
+static void prompt_hide(Ui *ui) {
+ UiCurses *uic = (UiCurses*)ui;
+ uic->prompt_title[0] = '\0';
+ if (uic->prompt_win) {
+ while (text_undo(uic->prompt_win->text) != EPOS);
+ window_cursor_to(uic->prompt_win->view, 0);
+ }
+ ui_resize_to(ui, uic->width, uic->height);
+}
+
+static bool ui_init(Ui *ui, Editor *ed) {
+ UiCurses *uic = (UiCurses*)ui;
+ uic->ed = ed;
+ return true;
+}
+
+static void ui_suspend(Ui *ui) {
+ endwin();
+ raise(SIGSTOP);
+}
+
+Ui *ui_curses_new(void) {
+ setlocale(LC_CTYPE, "");
+ if (!getenv("ESCDELAY"))
+ set_escdelay(50);
+ char *term = getenv("TERM");
+ if (!term)
+ term = "xterm";
+ if (!newterm(term, stderr, stdin))
+ return NULL;
+ start_color();
+ raw();
+ noecho();
+ keypad(stdscr, TRUE);
+ meta(stdscr, TRUE);
+ /* needed because we use getch() which implicitly calls refresh() which
+ would clear the screen (overwrite it with an empty / unused stdscr */
+ refresh();
+
+ UiCurses *uic = calloc(1, sizeof(UiCurses));
+ Ui *ui = (Ui*)uic;
+ if (!uic)
+ return NULL;
+
+ *ui = (Ui) {
+ .init = ui_init,
+ .free = ui_curses_free,
+ .suspend = ui_suspend,
+ .resume = ui_resize,
+ .resize = ui_resize,
+ .update = update,
+ .window_new = ui_window_new,
+ .window_free = ui_window_free,
+ .window_focus = ui_window_focus,
+ .prompt_new = prompt_new,
+ .prompt = prompt,
+ .prompt_input = prompt_input,
+ .prompt_hide = prompt_hide,
+ .draw = draw,
+ .arrange = arrange,
+ .info = info,
+ .info_hide = info_hide,
+ .color_get = color_get,
+ };
+
+ ui_resize(ui);
+
+ return ui;
+}
+
+void ui_curses_free(Ui *ui) {
+ UiCurses *uic = (UiCurses*)ui;
+ if (!uic)
+ return;
+ ui_window_free((UiWin*)uic->prompt_win);
+ while (uic->windows)
+ ui_window_free((UiWin*)uic->windows);
+ endwin();
+ free(uic);
+}
+
diff --git a/ui-curses.h b/ui-curses.h
new file mode 100644
index 0000000..74cb920
--- /dev/null
+++ b/ui-curses.h
@@ -0,0 +1,9 @@
+#ifndef UI_CURSES_H
+#define UI_CURSES_H
+
+#include "ui.h"
+
+Ui *ui_curses_new(void);
+void ui_curses_free(Ui*);
+
+#endif
diff --git a/ui.h b/ui.h
new file mode 100644
index 0000000..92123db
--- /dev/null
+++ b/ui.h
@@ -0,0 +1,58 @@
+#ifndef UI_H
+#define UI_H
+
+typedef struct Ui Ui;
+typedef struct UiWin UiWin;
+
+enum UiLayout {
+ UI_LAYOUT_HORIZONTAL,
+ UI_LAYOUT_VERTICAL,
+};
+
+enum UiOption {
+ UI_OPTION_LINE_NUMBERS_NONE,
+ UI_OPTION_LINE_NUMBERS_ABSOLUTE,
+};
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include "text.h"
+#include "window.h"
+#include "editor.h"
+
+struct Ui {
+ bool (*init)(Ui*, Editor*);
+ void (*free)(Ui*);
+ short (*color_get)(short fg, short bg);
+ void (*resize)(Ui*);
+ UiWin* (*window_new)(Ui*, Text*);
+ void (*window_free)(UiWin*);
+ void (*window_focus)(UiWin*);
+ UiWin* (*prompt_new)(Ui*, Text*);
+ void (*prompt)(Ui*, const char *title, const char *value);
+ char* (*prompt_input)(Ui*);
+ void (*prompt_hide)(Ui*);
+ void (*info)(Ui*, const char *msg, va_list ap);
+ void (*info_hide)(Ui*);
+ void (*arrange)(Ui*, enum UiLayout);
+ void (*draw)(Ui*);
+ void (*update)(Ui*);
+ void (*suspend)(Ui*);
+ void (*resume)(Ui*);
+/* TODO main loop integration, signal handling
+ Key getkey(void);
+ bool haskey(void);
+*/
+};
+
+struct UiWin {
+ void (*draw)(UiWin*);
+ void (*draw_text)(UiWin*, const Line*);
+ void (*draw_status)(UiWin*);
+ void (*cursor_to)(UiWin*, int x, int y);
+ void (*reload)(UiWin*, Text*);
+ void (*options)(UiWin*, enum UiOption);
+ Win* (*view_get)(UiWin*);
+};
+
+#endif
diff --git a/vis.c b/vis.c
index 11cf1af..22b61bb 100644
--- a/vis.c
+++ b/vis.c
@@ -19,6 +19,8 @@
#include <string.h>
#include <strings.h>
#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -29,6 +31,7 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include "ui-curses.h"
#include "editor.h"
#include "text-motions.h"
#include "text-objects.h"
@@ -84,7 +87,6 @@ struct Mode {
typedef struct {
char *name; /* is used to match against argv[0] to enable this config */
Mode *mode; /* default mode in which the editor should start in */
- void (*statusbar)(EditorWin*); /* routine which is called whenever the cursor is moved within a window */
bool (*keypress)(Key*); /* called before any other keybindings are checked,
* return value decides whether key should be ignored */
} Config;
@@ -155,6 +157,7 @@ typedef struct { /* command definitions for the ':'-prompt */
/** global variables */
static volatile bool running = true; /* exit main loop once this becomes false */
+static volatile sig_atomic_t need_resize;
static Editor *vis; /* global editor instance, keeps track of all windows etc. */
static Mode *mode; /* currently active mode, used to search for keybindings */
static Mode *mode_prev; /* previsouly active user mode */
@@ -801,11 +804,13 @@ static size_t window_lines_top(const Arg *arg) {
}
static size_t window_lines_middle(const Arg *arg) {
- return window_screenline_goto(vis->win->win, vis->win->height / 2);
+ int h = window_height_get(vis->win->win);
+ return window_screenline_goto(vis->win->win, h/2);
}
static size_t window_lines_bottom(const Arg *arg) {
- return window_screenline_goto(vis->win->win, vis->win->height - action.count);
+ int h = window_height_get(vis->win->win);
+ return window_screenline_goto(vis->win->win, h-action.count);
}
/** key bindings functions of type: void (*func)(const Arg*) */
@@ -865,8 +870,7 @@ static void macro_replay(const Arg *arg) {
}
static void suspend(const Arg *arg) {
- endwin();
- raise(SIGSTOP);
+ editor_suspend(vis);
}
static void repeat(const Arg *arg) {
@@ -1055,7 +1059,7 @@ static void prompt_enter(const Arg *arg) {
* on vis->win.
*/
switchmode_to(mode_before_prompt);
- if (s && *s && exec_command(vis->prompt->title[0], s) && running)
+ if (s && *s && exec_command(vis->prompt_type, s) && running)
switchmode(&(const Arg){ .i = VIS_MODE_NORMAL });
free(s);
editor_draw(vis);
@@ -1102,10 +1106,10 @@ static int argi2lines(const Arg *arg) {
switch (arg->i) {
case -PAGE:
case +PAGE:
- return vis->win->height-1;
+ return window_height_get(vis->win->win);
case -PAGE_HALF:
case +PAGE_HALF:
- return vis->win->height/2;
+ return window_height_get(vis->win->win)/2;
default:
if (action.count > 0)
return action.count;
@@ -1330,7 +1334,7 @@ static void switchmode_to(Mode *new_mode) {
mode_prev = mode;
mode = new_mode;
if (mode == config->mode || (mode->name && mode->name[0] == '-'))
- statusbar(vis->win);
+ vis->win->ui->draw_status(vis->win->ui);
if (mode->enter)
mode->enter(mode_prev);
}
@@ -1467,7 +1471,8 @@ static bool cmd_set(Filerange *range, enum CmdOpt cmdopt, const char *argv[]) {
editor_info_show(vis, "Unknown syntax definition: `%s'", argv[2]);
break;
case OPTION_NUMBER:
- window_line_numbers_show(vis->win->win, arg.b);
+ editor_window_options(vis->win, arg.b ? UI_OPTION_LINE_NUMBERS_ABSOLUTE :
+ UI_OPTION_LINE_NUMBERS_NONE);
break;
}
@@ -1611,26 +1616,26 @@ static bool openfiles(const char **files) {
}
static bool cmd_split(Filerange *range, enum CmdOpt opt, const char *argv[]) {
- editor_windows_arrange_horizontal(vis);
+ editor_windows_arrange(vis, UI_LAYOUT_HORIZONTAL);
if (!argv[1])
return vis_window_split(vis->win);
return openfiles(&argv[1]);
}
static bool cmd_vsplit(Filerange *range, enum CmdOpt opt, const char *argv[]) {
- editor_windows_arrange_vertical(vis);
+ editor_windows_arrange(vis, UI_LAYOUT_VERTICAL);
if (!argv[1])
- return editor_window_split(vis->win);
+ return vis_window_split(vis->win);
return openfiles(&argv[1]);
}
static bool cmd_new(Filerange *range, enum CmdOpt opt, const char *argv[]) {
- editor_windows_arrange_horizontal(vis);
+ editor_windows_arrange(vis, UI_LAYOUT_HORIZONTAL);
return vis_window_new(NULL);
}
static bool cmd_vnew(Filerange *range, enum CmdOpt opt, const char *argv[]) {
- editor_windows_arrange_vertical(vis);
+ editor_windows_arrange(vis, UI_LAYOUT_VERTICAL);
return vis_window_new(NULL);
}
@@ -1883,15 +1888,9 @@ static bool vis_window_split(EditorWin *win) {
return true;
}
-typedef struct Screen Screen;
-static struct Screen {
- int w, h;
- bool need_resize;
-} screen = { .need_resize = true };
-
static void die(const char *errstr, ...) {
va_list ap;
- endwin();
+ editor_free(vis);
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
@@ -1899,43 +1898,10 @@ static void die(const char *errstr, ...) {
}
static void sigwinch_handler(int sig) {
- screen.need_resize = true;
-}
-
-static void resize_screen(Screen *screen) {
- struct winsize ws;
-
- if (ioctl(0, TIOCGWINSZ, &ws) == -1) {
- getmaxyx(stdscr, screen->h, screen->w);
- } else {
- screen->w = ws.ws_col;
- screen->h = ws.ws_row;
- }
-
- resizeterm(screen->h, screen->w);
- wresize(stdscr, screen->h, screen->w);
- screen->need_resize = false;
+ need_resize = true;
}
static void setup() {
- setlocale(LC_CTYPE, "");
- if (!getenv("ESCDELAY"))
- set_escdelay(50);
- char *term = getenv("TERM");
- if (!term)
- term = DEFAULT_TERM;
- if (!newterm(term, stderr, stdin))
- die("Can not initialize terminal\n");
- start_color();
- raw();
- noecho();
- keypad(stdscr, TRUE);
- meta(stdscr, TRUE);
- resize_screen(&screen);
- /* needed because we use getch() which implicitly calls refresh() which
- would clear the screen (overwrite it with an empty / unused stdscr */
- refresh();
-
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
@@ -2046,9 +2012,9 @@ static void mainloop() {
editor_draw(vis);
while (running) {
- if (screen.need_resize) {
- resize_screen(&screen);
- editor_resize(vis, screen.w, screen.h);
+ if (need_resize) {
+ editor_resize(vis);
+ need_resize = false;
}
fd_set fds;
@@ -2056,7 +2022,6 @@ static void mainloop() {
FD_SET(STDIN_FILENO, &fds);
editor_update(vis);
- doupdate();
idle.tv_sec = mode->idle_timeout;
int r = pselect(1, &fds, NULL, NULL, timeout, &emptyset);
if (r == -1 && errno == EINTR)
@@ -2113,11 +2078,10 @@ int main(int argc, char *argv[]) {
mode_prev = mode = config->mode;
setup();
- if (!vis_init() || !(vis = editor_new(screen.w, screen.h)))
+ if (!vis_init() || !(vis = editor_new(ui_curses_new())))
die("Could not allocate editor core\n");
if (!editor_syntax_load(vis, syntaxes, colors))
die("Could not load syntax highlighting definitions\n");
- editor_statusbar_set(vis, config->statusbar);
char *cmd = NULL;
for (int i = 1; i < argc; i++) {
@@ -2157,6 +2121,5 @@ int main(int argc, char *argv[]) {
mainloop();
editor_free(vis);
vis_shutdown();
- endwin();
return 0;
}
diff --git a/window.c b/window.c
index 47fad1a..81bb7b5 100644
--- a/window.c
+++ b/window.c
@@ -19,7 +19,6 @@
#include <ctype.h>
#include <errno.h>
#include <regex.h>
-#include <curses.h>
#include "editor.h"
#include "window.h"
#include "syntax.h"
@@ -27,29 +26,6 @@
#include "text-motions.h"
#include "util.h"
-typedef struct { /* used to calculate the display width of a character */
- char c[7]; /* utf8 encoded bytes */
- size_t len; /* number of bytes of the multibyte sequence */
- wchar_t wchar; /* equivalent converted wide character, needed for wcwidth(3) */
-} Char;
-
-typedef struct {
- unsigned char len; /* number of bytes the character displayed in this cell uses, for
- character which use more than 1 column to display, their lenght
- is stored in the leftmost cell wheras all following cells
- occupied by the same character have a length of 0. */
- char data; /* first byte of the utf8 sequence, used for white space handling */
-} Cell;
-
-typedef struct Line Line;
-struct Line { /* a line on the screen, *not* in the file */
- Line *prev, *next; /* pointer to neighbouring screen lines */
- size_t len; /* line length in terms of bytes */
- size_t lineno; /* line number from start of file */
- int width; /* zero based position of last used column cell */
- Cell cells[]; /* win->width cells storing information about the displayed characters */
-};
-
typedef struct { /* cursor position */
Filepos pos; /* in bytes from the start of the file */
int row, col; /* in terms of zero based screen coordinates */
@@ -58,19 +34,16 @@ typedef struct { /* cursor position */
struct Win { /* window showing part of a file */
Text *text; /* underlying text management */
- WINDOW *win; /* curses window for the text area */
- WINDOW *winnum; /* curses window for the line numbers area */
+ UiWin *ui;
int width, height; /* window text area size */
- int w, h, x, y; /* complete window position & dimension (including line numbers) */
Filepos start, end; /* currently displayed area [start, end] in bytes from the start of the file */
+ size_t lines_size; /* number of allocated bytes for lines (grows only) */
Line *lines; /* win->height number of lines representing window content */
Line *topline; /* top of the window, first line currently shown */
Line *lastline; /* last currently used line, always <= bottomline */
Line *bottomline; /* bottom of screen, might be unused if lastline < bottomline */
Filerange sel; /* selected text range in bytes from start of file */
Cursor cursor; /* current window cursor position */
- void (*cursor_moved)(Win*, void *); /* registered callback, fires whenever the cursor moved */
- void *cursor_moved_data; /* user supplied data, passed as second argument to the above callback */
Line *line; /* used while drawing window content, line where next char will be drawn */
int col; /* used while drawing window content, column where next char will be drawn */
Syntax *syntax; /* syntax highlighting definitions for this window or NULL */
@@ -78,7 +51,7 @@ struct Win { /* window showing part of a file */
};
static void window_clear(Win *win);
-static bool window_addch(Win *win, Char *c);
+static bool window_addch(Win *win, Cell *cell);
static size_t window_cursor_update(Win *win);
/* set/move current cursor position to a given (line, column) pair */
static size_t window_cursor_set(Win *win, Line *line, int col);
@@ -105,55 +78,22 @@ void window_selection_clear(Win *win) {
curs_set(1);
}
-static int window_numbers_width(Win *win) {
- if (!win->winnum)
- return 0;
- return snprintf(NULL, 0, "%zd", win->topline->lineno + win->height - 1) + 1;
-}
-
-static void window_numbers_draw(Win *win) {
- if (!win->winnum)
- return;
- werase(win->winnum);
- size_t prev_lineno = -1;
- int width = window_numbers_width(win), i = 0;
- char fmt[32];
- snprintf(fmt, sizeof fmt, "%%%dd", width - 1);
- for (Line *l = win->topline; l && l <= win->lastline; l = l->next, i++) {
- if (l->lineno != prev_lineno)
- mvwprintw(win->winnum, i, 0, fmt, l->lineno);
- prev_lineno = l->lineno;
- }
- mvwvline(win->winnum, 0, width-1, ACS_VLINE, win->height);
-}
-
/* reset internal window data structures (cell matrix, line offsets etc.) */
static void window_clear(Win *win) {
/* calculate line number of first line */
+ // TODO move elsewhere
win->topline = win->lines;
win->topline->lineno = text_lineno_by_pos(win->text, win->start);
win->lastline = win->topline;
- /* based on which we can calculate how much space is needed to display line numbers */
- int lineno_width = window_numbers_width(win);
- int width = win->w - lineno_width;
- if (win->winnum) {
- wresize(win->winnum, win->h, lineno_width);
- mvwin(win->winnum, win->y, win->x);
- }
-
- wresize(win->win, win->height, width);
- mvwin(win->win, win->y, win->x + lineno_width);
- win->width = width;
-
/* reset all other lines */
size_t line_size = sizeof(Line) + win->width*sizeof(Cell);
size_t end = win->height * line_size;
Line *prev = NULL;
for (size_t i = 0; i < end; i += line_size) {
Line *line = (Line*)(((char*)win->lines) + i);
- line->len = 0;
line->width = 0;
+ line->len = 0;
line->prev = prev;
if (prev)
prev->next = line;
@@ -190,15 +130,15 @@ Filerange window_viewport_get(Win *win) {
}
/* try to add another character to the window, return whether there was space left */
-static bool window_addch(Win *win, Char *c) {
+static bool window_addch(Win *win, Cell *cell) {
if (!win->line)
return false;
int width;
- Cell empty = { .len = 0, .data = '\0' };
+ static Cell empty;
size_t lineno = win->line->lineno;
- switch (c->wchar) {
+ switch (cell->data[0]) {
case '\t':
width = win->tabwidth - (win->col % win->tabwidth);
for (int w = 0; w < width; w++) {
@@ -211,68 +151,53 @@ static bool window_addch(Win *win, Char *c) {
}
if (w == 0) {
/* first cell of a tab has a length of 1 */
- win->line->cells[win->col].len = c->len;
- win->line->len += c->len;
+ win->line->cells[win->col].len = cell->len;
+ win->line->len += cell->len;
} else {
/* all remaining ones have a lenght of zero */
win->line->cells[win->col].len = 0;
}
/* but all are marked as part of a tabstop */
- win->line->cells[win->col].data = '\t';
- win->col++;
+ win->line->cells[win->col].width = 1;
+ win->line->cells[win->col].data[0] = ' ';
+ win->line->cells[win->col].data[1] = '\0';
+ win->line->cells[win->col].istab = true;
win->line->width++;
- waddch(win->win, ' ');
+ win->col++;
}
return true;
case '\n':
- width = 1;
- if (win->col + width > win->width) {
+ cell->width = 1;
+ if (win->col + cell->width > win->width) {
win->line = win->line->next;
win->col = 0;
if (!win->line)
return false;
- win->line->lineno = lineno + 1;
+ win->line->lineno = lineno;
}
- win->line->cells[win->col].len = c->len;
- win->line->len += c->len;
- win->line->cells[win->col].data = '\n';
+ win->line->cells[win->col] = *cell;
+ win->line->len += cell->len;
+ win->line->width += cell->width;
for (int i = win->col + 1; i < win->width; i++)
win->line->cells[i] = empty;
- if (win->line == win->bottomline) {
- /* XXX: curses bug? the wclrtoeol(win->win); implied by waddch(win->win, '\n')
- * doesn't seem to work on the last line!?
- *
- * Thus explicitly clear the remaining of the line.
- */
- for (int i = win->col; i < win->width; i++)
- waddch(win->win, ' ');
- } else if (win->line->width == 0) {
- /* add a single space in an otherwise empty line, makes selection cohorent */
- waddch(win->win, ' ');
- }
-
- waddch(win->win, '\n');
win->line = win->line->next;
if (win->line)
win->line->lineno = lineno + 1;
win->col = 0;
return true;
default:
- if (c->wchar < 128 && !isprint(c->wchar)) {
+ if ((unsigned char)cell->data[0] < 128 && !isprint((unsigned char)cell->data[0])) {
/* non-printable ascii char, represent it as ^(char + 64) */
- Char s = { .c = "^_", .len = 1 };
- s.c[1] = c->c[0] + 64;
- *c = s;
- width = 2;
- } else {
- if ((width = wcwidth(c->wchar)) == -1) {
- /* this should never happen */
- width = 1;
- }
+ *cell = (Cell) {
+ .data = { '^', cell->data[0] + 64, '\0' },
+ .len = 1,
+ .width = 2,
+ .istab = false,
+ };
}
- if (win->col + width > win->width) {
+ if (win->col + cell->width > win->width) {
for (int i = win->col; i < win->width; i++)
win->line->cells[i] = empty;
win->line = win->line->next;
@@ -280,16 +205,14 @@ static bool window_addch(Win *win, Char *c) {
}
if (win->line) {
- win->line->width += width;
- win->line->len += c->len;
+ win->line->width += cell->width;
+ win->line->len += cell->len;
win->line->lineno = lineno;
- win->line->cells[win->col].len = c->len;
- win->line->cells[win->col].data = c->c[0];
+ win->line->cells[win->col] = *cell;
win->col++;
/* set cells of a character which uses multiple columns */
- for (int i = 1; i < width; i++)
+ for (int i = 1; i < cell->width; i++)
win->line->cells[win->col++] = empty;
- waddstr(win->win, c->c);
return true;
}
return false;
@@ -317,9 +240,7 @@ static size_t window_cursor_update(Win *win) {
win->sel.end = cursor->pos;
window_draw(win);
}
- wmove(win->win, cursor->row, cursor->col);
- if (win->cursor_moved)
- win->cursor_moved(win, win->cursor_moved_data);
+ win->ui->cursor_to(win->ui, cursor->col, cursor->row);
return cursor->pos;
}
@@ -385,9 +306,7 @@ void window_cursor_to(Win *win, size_t pos) {
/* redraw the complete with data starting from win->start bytes into the file.
* stop once the screen is full, update win->end, win->lastline */
void window_draw(Win *win) {
- int old_width = win->width;
window_clear(win);
- wmove(win->win, 0, 0);
/* current absolute file position */
size_t pos = win->start;
/* number of bytes to read in one go */
@@ -400,8 +319,6 @@ void window_draw(Win *win) {
text[rem] = '\0';
/* current position into buffer from which to interpret a character */
char *cur = text;
- /* current 'parsed' character' */
- Char c;
/* current selection */
Filerange sel = window_selection_get(win);
/* syntax definition to use */
@@ -414,6 +331,11 @@ void window_draw(Win *win) {
while (rem > 0) {
+ /* current 'parsed' character' */
+ wchar_t wchar;
+ Cell cell;
+ memset(&cell, 0, sizeof cell);
+
if (syntax) {
if (matched && cur >= text + matched->rm_eo) {
/* end of current match */
@@ -460,13 +382,13 @@ void window_draw(Win *win) {
}
}
- size_t len = mbrtowc(&c.wchar, cur, rem, NULL);
+ size_t len = mbrtowc(&wchar, cur, rem, NULL);
if (len == (size_t)-1 && errno == EILSEQ) {
/* ok, we encountered an invalid multibyte sequence,
* replace it with the Unicode Replacement Character
* (FFFD) and skip until the start of the next utf8 char */
for (len = 1; rem > len && !ISUTF8(cur[len]); len++);
- c = (Char){ .c = "\xEF\xBF\xBD", .wchar = 0xFFFD, .len = len };
+ cell = (Cell){ .data = "\xEF\xBF\xBD", .len = len, .width = 1, .istab = false };
} else if (len == (size_t)-2) {
/* not enough bytes available to convert to a
* wide character. advance file position and read
@@ -478,74 +400,65 @@ void window_draw(Win *win) {
continue;
} else if (len == 0) {
/* NUL byte encountered, store it and continue */
- len = 1;
- c = (Char){ .c = "\x00", .wchar = 0x00, .len = len };
+ cell = (Cell){ .data = "\x00", .len = 1, .width = 0, .istab = false };
} else {
for (size_t i = 0; i < len; i++)
- c.c[i] = cur[i];
- c.c[len] = '\0';
- c.len = len;
+ cell.data[i] = cur[i];
+ cell.data[len] = '\0';
+ cell.istab = false;
+ cell.len = len;
+ cell.width = wcwidth(wchar);
+ if (cell.width == -1)
+ cell.width = 1;
}
if (cur[0] == '\r' && rem > 1 && cur[1] == '\n') {
/* convert windows style newline \r\n into a single char with len = 2 */
- len = 2;
- c = (Char){ .c = "\n", .wchar = L'\n', .len = len };
+ cell = (Cell){ .data = "\n", .len = 2, .width = 1, .istab = false };
}
+ cell.attr = attrs;
if (sel.start <= pos && pos < sel.end)
- wattrset(win->win, attrs | A_REVERSE);
- else
- wattrset(win->win, attrs);
-
- if (!window_addch(win, &c))
+ cell.attr |= A_REVERSE;
+ if (!window_addch(win, &cell))
break;
- rem -= len;
- cur += len;
- pos += len;
+ rem -= cell.len;
+ cur += cell.len;
+ pos += cell.len;
}
/* set end of viewing region */
win->end = pos;
win->lastline = win->line ? win->line : win->bottomline;
win->lastline->next = NULL;
- /* and clear the rest of the unused window */
- wclrtobot(win->win);
- /* if the text area width has changed because of the line numbers
- * we have to (re)sync the cursor->line pointer */
- if (win->width != old_width)
- window_cursor_sync(win);
- /* draw line numbers */
- window_numbers_draw(win);
+ window_cursor_sync(win);
+ win->ui->draw_text(win->ui, win->topline);
}
bool window_resize(Win *win, int width, int height) {
- // TODO: only grow memory area
- size_t line_size = sizeof(Line) + width*sizeof(Cell);
- Line *lines = calloc(height, line_size);
- if (!lines)
- return false;
- free(win->lines);
- win->w = win->width = width;
- win->h = win->height = height;
- win->lines = lines;
- window_clear(win);
+ size_t lines_size = height*(sizeof(Line) + width*sizeof(Cell));
+ if (lines_size > win->lines_size) {
+ Line *lines = malloc(lines_size);
+ if (!lines)
+ return false;
+ win->lines = lines;
+ win->lines_size = lines_size;
+ }
+ win->width = width;
+ win->height = height;
+ memset(win->lines, 0, win->lines_size);
+ window_draw(win);
return true;
}
-void window_move(Win *win, int x, int y) {
- win->x = x;
- win->y = y;
+int window_height_get(Win *win) {
+ return win->height;
}
void window_free(Win *win) {
if (!win)
return;
- if (win->winnum)
- delwin(win->winnum);
- if (win->win)
- delwin(win->win);
free(win->lines);
free(win);
}
@@ -554,27 +467,23 @@ void window_reload(Win *win, Text *text) {
win->text = text;
window_selection_clear(win);
window_cursor_to(win, 0);
+ win->ui->reload(win->ui, text);
}
-Win *window_new(Text *text) {
- if (!text)
+Win *window_new(Text *text, UiWin *ui, int width, int height) {
+ if (!text || !ui)
return NULL;
Win *win = calloc(1, sizeof(Win));
- if (!win || !(win->win = newwin(0, 0, 0, 0))) {
- window_free(win);
+ if (!win)
return NULL;
- }
win->text = text;
+ win->ui = ui;
win->tabwidth = 8;
-
- int width, height;
- getmaxyx(win->win, height, width);
if (!window_resize(win, width, height)) {
window_free(win);
return NULL;
}
-
window_selection_clear(win);
window_cursor_to(win, 0);
@@ -633,9 +542,9 @@ static size_t window_cursor_set(Win *win, Line *line, int col) {
}
/* for characters which use more than 1 column, make sure we are on the left most */
- while (col > 0 && line->cells[col].len == 0 && line->cells[col].data != '\t')
+ while (col > 0 && line->cells[col].len == 0)
col--;
- while (col < line->width && line->cells[col].data == '\t')
+ while (col < line->width && line->cells[col].istab)
col++;
/* calculate offset within the line */
@@ -845,12 +754,6 @@ size_t window_screenline_end(Win *win) {
return window_cursor_set(win, cursor->line, col >= 0 ? col : 0);
}
-void window_update(Win *win) {
- if (win->winnum)
- wnoutrefresh(win->winnum);
- wnoutrefresh(win->win);
-}
-
size_t window_delete_key(Win *win) {
Cursor *cursor = &win->cursor;
Line *line = cursor->line;
@@ -899,7 +802,7 @@ size_t window_replace_key(Win *win, const char *c, size_t len) {
Line *line = cursor->line;
size_t pos = cursor->pos;
/* do not overwrite new line which would merge the two lines */
- if (line->cells[cursor->col].data != '\n') {
+ if (line->cells[cursor->col].data[0] != '\n') {
size_t oldlen = line->cells[cursor->col].len;
text_delete(win->text, pos, oldlen);
}
@@ -939,25 +842,9 @@ Syntax *window_syntax_get(Win *win) {
return win->syntax;
}
-void window_cursor_watch(Win *win, void (*cursor_moved)(Win*, void *), void *data) {
- win->cursor_moved = cursor_moved;
- win->cursor_moved_data = data;
-}
-
size_t window_screenline_goto(Win *win, int n) {
size_t pos = win->start;
for (Line *line = win->topline; --n > 0 && line != win->lastline; line = line->next)
pos += line->len;
return pos;
}
-
-void window_line_numbers_show(Win *win, bool show) {
- if (show) {
- if (!win->winnum)
- win->winnum = newwin(0, 0, 0, 0);
- } else {
- if (win->winnum)
- delwin(win->winnum);
- win->winnum = NULL;
- }
-}
diff --git a/window.h b/window.h
index 686f67f..8be069e 100644
--- a/window.h
+++ b/window.h
@@ -4,16 +4,38 @@
#include <stddef.h>
#include <stdbool.h>
#include "text.h"
+#include "ui.h"
#include "syntax.h"
typedef struct Win Win;
typedef struct {
+ int width; /* display width i.e. number of columns ocupied by this character */
+ size_t len; /* number of bytes the character displayed in this cell uses, for
+ character which use more than 1 column to display, their lenght
+ is stored in the leftmost cell wheras all following cells
+ occupied by the same character have a length of 0. */
+ char data[8]; /* utf8 encoded character displayed in this cell might not be the
+ the same as in the underlying text, for example tabs get expanded */
+ bool istab;
+ unsigned int attr;
+} Cell;
+
+typedef struct Line Line;
+struct Line { /* a line on the screen, *not* in the file */
+ Line *prev, *next; /* pointer to neighbouring screen lines */
+ size_t len; /* line length in terms of bytes */
+ size_t lineno; /* line number from start of file */
+ int width; /* zero based position of last used column cell */
+ Cell cells[]; /* win->width cells storing information about the displayed characters */
+};
+
+typedef struct {
size_t line;
size_t col;
} CursorPos;
-Win *window_new(Text*);
+Win *window_new(Text*, UiWin*, int width, int height);
/* change associated text displayed in this window */
void window_reload(Win*, Text*);
void window_free(Win*);
@@ -25,10 +47,8 @@ size_t window_backspace_key(Win*);
size_t window_delete_key(Win*);
bool window_resize(Win*, int width, int height);
-void window_move(Win*, int x, int y);
+int window_height_get(Win*);
void window_draw(Win*);
-/* flush all changes made to the ncurses windows to the screen */
-void window_update(Win*);
/* changes how many spaces are used for one tab (must be >0), redraws the window */
void window_tabwidth_set(Win*, int tabwidth);
@@ -83,8 +103,6 @@ Filerange window_viewport_get(Win*);
/* associate a set of syntax highlighting rules to this window. */
void window_syntax_set(Win*, Syntax*);
Syntax *window_syntax_get(Win*);
-/* whether to show line numbers to the left of the text content */
-void window_line_numbers_show(Win*, bool show);
/* register a user defined function which will be called whenever the cursor has moved */
void window_cursor_watch(Win *win, void (*cursor_moved)(Win*, void*), void *data);