Introduction
Introduction Statistics Contact Development Disclaimer Help
tAdd support for config file - ledit - Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log
Files
Refs
README
LICENSE
---
commit 1b405e16faddabd36b26297c27c746aa7788a2d4
parent aadae71b088e1d224e1f6615524d0cc0d51eae7a
Author: lumidify <[email protected]>
Date: Thu, 26 May 2022 21:53:19 +0200
Add support for config file
Yay, it's another monster commit!
Diffstat:
M IDEAS | 5 +++++
M LICENSE | 4 +++-
M Makefile | 33 ++++++++++++++++++++---------…
M README | 26 ++++++++++++++++++++++----
M buffer.c | 23 ++++++++++++++---------
M buffer.h | 3 +--
M config.h | 9 +++++++++
A configparser.c | 1810 +++++++++++++++++++++++++++++…
A configparser.h | 80 +++++++++++++++++++++++++++++…
M keys.c | 14 --------------
M keys.h | 47 +++++++++++++++++++++++++++++…
M keys_basic.c | 282 ++++++++++++++++++++++++++++-…
M keys_basic.h | 5 +++++
D keys_basic_config.h | 457 -----------------------------…
M keys_command.c | 362 ++++++++++++++++++++---------…
M keys_command.h | 8 ++++++++
D keys_command_config.h | 196 -----------------------------…
M keys_config.h | 203 +++++++++++++++++++++++++++--…
M ledit.1 | 96 ++++++-----------------------…
M ledit.c | 141 ++++++++++++++++++++++++++---…
A leditrc.5 | 347 +++++++++++++++++++++++++++++…
A leditrc.example | 300 +++++++++++++++++++++++++++++…
M memory.c | 26 ++++++++++++++++++++++----
M memory.h | 6 ++++++
D theme.c | 57 -----------------------------…
D theme.h | 39 -----------------------------…
M theme_config.h | 20 +++++++++++++++++---
M txtbuf.c | 59 +++++++++++++++++++++++++++++…
M txtbuf.h | 30 ++++++++++++++++++++++++++++++
A uglycrap.h | 15 +++++++++++++++
M undo.h | 2 ++
M util.c | 20 ++++++++++++++++++++
M util.h | 28 ++++++++++++++++++++++++++++
M view.c | 24 +++++++++++++-----------
M view.h | 21 ++++-----------------
M window.c | 33 ++++++++++++++++++++---------…
M window.h | 10 +++++++---
37 files changed, 3715 insertions(+), 1126 deletions(-)
---
diff --git a/IDEAS b/IDEAS
t@@ -10,3 +10,8 @@
-> I'm not sure it that's even possible in a portable way, though,
since the keyboard layouts can be set in many different ways, so
the entire state would somehow have to be saved to restore it again.
+ -> Wouldn't it also make more sense to avoid the whole keyboard
+ configuration and instead just temporarily switch to the default
+ layout in order to map the keycodes to text? I'm not sure how to do
+ that, though. It might not be possible at all since text can also
+ be inserted through input methods.
diff --git a/LICENSE b/LICENSE
t@@ -1,9 +1,11 @@
Note 1: Some stuff is stolen from st (https://st.suckless.org)
Note 2: Some stuff is stolen from OpenBSD (https://openbsd.org)
+Note 3: pango-compat.{c,h} contains a bit of code copied from
+ Pango in order to be compatible with older versions.
ISC License
-Copyright (c) 2022 lumidify <[email protected]>
+Copyright (c) 2021, 2022 lumidify <[email protected]>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/Makefile b/Makefile
t@@ -8,20 +8,24 @@ MANPREFIX = ${PREFIX}/man
BIN = ${NAME}
MAN1 = ${BIN:=.1}
+MAN5 = leditrc.5
MISCFILES = Makefile README LICENSE IDEAS NOTES TODO
+DEBUG=0
+SANITIZE=0
+
OBJ = \
assert.o \
buffer.o \
view.o \
cache.o \
keys.o \
+ configparser.o \
keys_basic.o \
keys_command.o \
ledit.o \
memory.o \
search.o \
- theme.o \
txtbuf.o \
undo.o \
util.o \
t@@ -38,11 +42,11 @@ HDR = \
cache.h \
common.h \
keys.h \
+ configparser.h \
keys_basic.h \
keys_command.h \
memory.h \
search.h \
- theme.h \
txtbuf.h \
undo.h \
util.h \
t@@ -50,26 +54,27 @@ HDR = \
window.h \
cleanup.h \
macros.h \
- pango-compat.h
+ pango-compat.h \
+ uglycrap.h
CONFIGHDR = \
config.h \
theme_config.h \
- keys_basic_config.h \
- keys_command_config.h \
keys_config.h
-CFLAGS_LEDIT = ${CFLAGS} -g -Wall -Wextra -pedantic -D_POSIX_C_SOURCE=200809L …
-LDFLAGS_LEDIT = ${LDFLAGS} `pkg-config --libs x11 xkbfile pangoxft xext` -lm
+EXTRA_CFLAGS_DEBUG0 = ${CFLAGS}
+EXTRA_LDFLAGS_DEBUG0 = ${LDFLAGS}
+EXTRA_CFLAGS_DEBUG1 = -DLEDIT_DEBUG -g
+EXTRA_FLAGS_SANITIZE1 = -fsanitize=address
+
+CFLAGS_LEDIT = ${EXTRA_FLAGS_SANITIZE${SANITIZE}} ${EXTRA_CFLAGS_DEBUG${DEBUG}…
+LDFLAGS_LEDIT = ${EXTRA_FLAGS_SANITIZE${SANITIZE}} ${EXTRA_LDFLAGS_DEBUG${DEBU…
all: ${BIN}
# FIXME: make this nicer
ledit.o window.o : config.h
-theme.o : theme_config.h
-keys_basic.o : keys_basic_config.h keys_config.h
-keys_command.o : keys_command_config.h keys_config.h
-keys.o : keys_config.h
+configparser.o : keys_config.h theme_config.h
${OBJ} : ${HDR}
t@@ -84,12 +89,16 @@ install: all
cp -f ${BIN} "${DESTDIR}${PREFIX}/bin"
for f in ${BIN}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done
mkdir -p "${DESTDIR}${MANPREFIX}/man1"
+ mkdir -p "${DESTDIR}${MANPREFIX}/man5"
cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1"
+ cp -f ${MAN5} "${DESTDIR}${MANPREFIX}/man5"
for m in ${MAN1}; do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done
+ for m in ${MAN5}; do chmod 644 "${DESTDIR}${MANPREFIX}/man5/$$m"; done
uninstall:
for f in ${BIN}; do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done
for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done
+ for m in ${MAN5}; do rm -f "${DESTDIR}${MANPREFIX}/man5/$$m"; done
clean:
rm -f ${BIN} ${OBJ}
t@@ -97,7 +106,7 @@ clean:
dist:
rm -rf "${NAME}-${VERSION}"
mkdir -p "${NAME}-${VERSION}"
- cp -f ${MAN1} ${SRC} ${HDR} ${CONFIGHDR} ${MISCFILES} "${NAME}-${VERSI…
+ cp -f ${MAN1} ${MAN5} ${SRC} ${HDR} ${CONFIGHDR} ${MISCFILES} "${NAME}…
tar cf - "${NAME}-${VERSION}" | gzip -c > "${NAME}-${VERSION}.tar.gz"
rm -rf "${NAME}-${VERSION}"
diff --git a/README b/README
t@@ -1,9 +1,6 @@
WARNING: This is work in progress! A lot of bugs still need to be fixed
before this can be used as a real text editor.
-Note: The compiler flags currently still include -g to add debug symbols.
-This will be removed when ledit is officially released (if I remember...).
-
ledit is a vi-like text editor for people who switch between keyboard
layouts frequently and/or work with languages that require complex text
layout.
t@@ -18,10 +15,31 @@ On OpenBSD: pango
On MX Linux: libpango1.0-dev, libx11-dev, libxkbfile-dev
(this is just from memory, I need to test it with a fresh system sometime)
-The documentation can be viewed in ledit.1 or at the following locations:
+Installation:
+Simply run 'make' and 'make install'
+To compile with debugging symbols and some debug output, run 'make DEBUG=1'
+To compile with fsanitize=address, run 'make SANITIZE=1'
+
+A sample configuration file can be found in leditrc.example.
+Copy this to ~/.leditrc in order to use it.
+
+The documentation can be viewed in ledit.1 and leditrc.5 or at the following l…
gopher://lumidify.org/0/doc/ledit/ledit-current.txt
gopher://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/0/doc/…
http://lumidify.org/doc/ledit/ledit-current.html
http://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/doc/ledi…
https://lumidify.org/doc/ledit/ledit-current.html
+
+gopher://lumidify.org/0/doc/ledit/leditrc-current.txt
+gopher://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/0/doc/…
+http://lumidify.org/doc/ledit/leditrc-current.html
+http://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/doc/ledi…
+https://lumidify.org/doc/ledit/leditrc-current.html
+
+Note that the documentation is far from finished! None of the functions are
+documented yet in leditrc.5 and ledit.1 is somewhat outdated. This will
+be fixed sometime...
+
+Also note that nothing is stable at the moment. In particular, some of the
+function names mentioned in leditrc.5 will probably be changed still.
diff --git a/buffer.c b/buffer.c
t@@ -17,7 +17,6 @@
#include "util.h"
#include "undo.h"
#include "cache.h"
-#include "theme.h"
#include "memory.h"
#include "common.h"
#include "txtbuf.h"
t@@ -284,10 +283,10 @@ buffer_set_hard_line_based(ledit_buffer *buffer, int hl)…
}
void
-buffer_add_view(ledit_buffer *buffer, ledit_theme *theme, ledit_mode mode, siz…
+buffer_add_view(ledit_buffer *buffer, ledit_mode mode, size_t line, size_t pos…
size_t new_num = add_sz(buffer->views_num, 1);
buffer->views = ledit_reallocarray(buffer->views, new_num, sizeof(ledi…
- buffer->views[buffer->views_num] = view_create(buffer, theme, mode, li…
+ buffer->views[buffer->views_num] = view_create(buffer, mode, line, pos…
set_view_hard_line_text(buffer, buffer->views[buffer->views_num]);
view_scroll(buffer->views[buffer->views_num], scroll_offset);
buffer->views_num = new_num;
t@@ -374,11 +373,11 @@ buffer_load_file(ledit_buffer *buffer, char *filename, s…
buffer->modified = 0;
return 0;
error:
- if (*errstr)
+ if (errstr)
*errstr = strerror(errno);
return 1;
errorclose:
- if (*errstr)
+ if (errstr)
*errstr = strerror(errno);
fclose(file);
return 1;
t@@ -397,11 +396,11 @@ buffer_write_to_file(ledit_buffer *buffer, FILE *file, c…
buffer->modified = 0;
return 0;
error:
- if (*errstr)
+ if (errstr)
*errstr = strerror(errno);
return 1;
errorclose:
- if (*errstr)
+ if (errstr)
*errstr = strerror(errno);
fclose(file);
return 1;
t@@ -413,7 +412,7 @@ buffer_write_to_fd(ledit_buffer *buffer, int fd, char **er…
if (!file) goto error;
return buffer_write_to_file(buffer, file, errstr);
error:
- if (*errstr)
+ if (errstr)
*errstr = strerror(errno);
/* catching errors on the close wouldn't
really make much sense anymore */
t@@ -428,7 +427,7 @@ buffer_write_to_filename(ledit_buffer *buffer, char *filen…
if (!file) goto error;
return buffer_write_to_file(buffer, file, errstr);
error:
- if (*errstr)
+ if (errstr)
*errstr = strerror(errno);
return 1;
}
t@@ -445,6 +444,10 @@ buffer_destroy(ledit_buffer *buffer) {
if (buffer->filename)
free(buffer->filename);
marklist_destroy(buffer->marklist);
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_destroy(buffer->views[i]);
+ }
+ free(buffer->views);
free(buffer);
}
t@@ -854,6 +857,7 @@ line_byte_to_char(ledit_line *line, size_t byte) {
static void
buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, size_t star…
ledit_line *l = buffer_get_line(buffer, line);
+ /* FIXME: somehow make sure this doesn't get optimized out? */
(void)add_sz(start, length); /* just check that no overflow */
ledit_assert(start + length <= l->len);
if (start <= l->gap && start + length >= l->gap) {
t@@ -979,6 +983,7 @@ buffer_delete_with_undo_base(
size_t line_index2, size_t byte_index2,
txtbuf *text_ret) {
/* FIXME: global txtbuf to avoid allocating each time */
+ /* actually, could just use stack variable here */
txtbuf *buf = text_ret != NULL ? text_ret : txtbuf_new();
sort_range(&line_index1, &byte_index1, &line_index2, &byte_index2);
delete_range_base(
diff --git a/buffer.h b/buffer.h
t@@ -79,8 +79,7 @@ void buffer_set_hard_line_based(ledit_buffer *buffer, int hl…
* 'scroll_offset' is the initial pixel scroll offset.
*/
void buffer_add_view(
- ledit_buffer *buffer, ledit_theme *theme,
- ledit_mode mode, size_t line, size_t pos, long scroll_offset
+ ledit_buffer *buffer, ledit_mode mode, size_t line, size_t pos, long scrol…
);
/*
diff --git a/config.h b/config.h
t@@ -1,3 +1,10 @@
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+/*************************
+ * General configuration *
+ *************************/
+
/* Note: These have to be less than one second */
/*
t@@ -17,3 +24,5 @@
* events - events inbetween are discarded (nanoseconds)
*/
#define RESIZE_TICK (long long)200000000
+
+#endif /* _CONFIG_H_ */
diff --git a/configparser.c b/configparser.c
t@@ -0,0 +1,1810 @@
+#ifdef LEDIT_DEBUG
+#include <time.h>
+#include "macros.h"
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "util.h"
+#include "memory.h"
+#include "assert.h"
+#include "configparser.h"
+#include "theme_config.h"
+#include "keys_config.h"
+
+/* FIXME: Replace this entire parser with something sensible.
+ The current handwritten parser is mainly for the lulz. */
+
+/* FIXME: standardize error messages */
+/* FIXME: it isn't entirely correct to give size_t as length for
+ string in print_fmt (supposed to be int) */
+
+struct config {
+ ledit_theme *theme;
+ basic_key_array *basic_keys;
+ command_key_array *command_keys;
+ command_array *cmds;
+ char **langs;
+ size_t num_langs;
+ size_t alloc_langs;
+} config = {NULL};
+
+enum toktype {
+ STRING,
+ LBRACE,
+ RBRACE,
+ EQUALS,
+ NEWLINE,
+ ERROR,
+ END
+};
+
+static const char *
+toktype_str(enum toktype type) {
+ switch (type) {
+ case STRING:
+ return "string";
+ break;
+ case LBRACE:
+ return "left brace";
+ break;
+ case RBRACE:
+ return "right brace";
+ break;
+ case EQUALS:
+ return "equals";
+ break;
+ case NEWLINE:
+ return "newline";
+ break;
+ case ERROR:
+ return "error";
+ break;
+ case END:
+ return "end of file";
+ break;
+ default:
+ return "unknown";
+ }
+}
+
+struct token {
+ char *text;
+ size_t len;
+ enum toktype type;
+ size_t line; /* line in original input */
+ size_t line_offset; /* offset from start of line */
+};
+
+struct lexstate {
+ char *text;
+ size_t len; /* length of text */
+ size_t cur; /* current byte position */
+ size_t cur_line; /* current line */
+ size_t line_start; /* byte offset of start of current line */
+};
+
+static struct token
+next_token(struct lexstate *s) {
+ char c;
+ struct token tok;
+ while (1) {
+ if (s->cur >= s->len)
+ return (struct token){NULL, 0, END, s->cur_line, s->cu…
+ while (isspace(c = s->text[s->cur])) {
+ s->cur++;
+ if (c == '\n') {
+ struct token tok = (struct token){s->text + s-…
+ s->cur_line++;
+ s->line_start = s->cur;
+ return tok;
+ }
+ if (s->cur >= s->len)
+ return (struct token){NULL, 0, END, s->cur_lin…
+ }
+
+ switch (s->text[s->cur]) {
+ case '#':
+ s->cur++;
+ while (s->cur < s->len && s->text[s->cur] != '\n')
+ s->cur++;
+ continue;
+ case '{':
+ tok = (struct token){s->text + s->cur, 1, LBRACE, s->c…
+ s->cur++;
+ break;
+ case '}':
+ tok = (struct token){s->text + s->cur, 1, RBRACE, s->c…
+ s->cur++;
+ break;
+ case '=':
+ tok = (struct token){s->text + s->cur, 1, EQUALS, s->c…
+ s->cur++;
+ break;
+ case '"':
+ /* FIXME: error if next char is not whitespace or end …
+ s->cur++;
+ tok = (struct token){s->text + s->cur, 0, STRING, s->c…
+ size_t shift = 0, bs = 0;
+ int finished = 0;
+ while (s->cur < s->len) {
+ char c = s->text[s->cur];
+ if (c == '\n') {
+ break;
+ } else if (c == '\\') {
+ shift += bs;
+ tok.len += bs;
+ bs = (bs + 1) % 2;
+ } else if (c == '"') {
+ if (bs) {
+ shift++;
+ tok.len++;
+ bs = 0;
+ } else {
+ s->cur++;
+ finished = 1;
+ break;
+ }
+ } else {
+ tok.len++;
+ }
+ s->text[s->cur - shift] = s->text[s->cur];
+ s->cur++;
+ }
+ if (!finished) {
+ tok.text = "Unfinished string";
+ tok.len = strlen("Unfinished string");
+ tok.type = ERROR;
+ }
+ break;
+ default:
+ tok = (struct token){s->text + s->cur, 1, STRING, s->c…
+ s->cur++;
+ while (s->cur < s->len) {
+ char c = s->text[s->cur];
+ if (isspace(c) || c == '{' || c == '}' || c ==…
+ break;
+ } else if (c == '"') {
+ tok.text = "Unexpected start of string…
+ tok.len = strlen("Unexpected start of …
+ tok.type = ERROR;
+ tok.line_offset = s->cur - s->line_sta…
+ }
+ tok.len++;
+ s->cur++;
+ }
+ }
+ return tok;
+ }
+}
+
+typedef struct ast_obj ast_obj;
+
+typedef struct {
+ ast_obj *objs;
+ size_t len, cap;
+} ast_list;
+
+typedef struct {
+ struct token tok;
+} ast_string;
+
+typedef struct {
+ struct token tok;
+ ast_obj *value;
+} ast_assignment;
+
+typedef struct {
+ struct token func_tok;
+ struct token *args;
+ size_t len, cap;
+} ast_statement;
+
+enum objtype {
+ OBJ_LIST,
+ OBJ_STRING,
+ OBJ_ASSIGNMENT,
+ OBJ_STATEMENT
+};
+
+struct ast_obj {
+ struct token tok;
+ union {
+ ast_list list;
+ ast_string str;
+ ast_assignment assignment;
+ ast_statement statement;
+ } obj;
+ enum objtype type;
+};
+
+/* Note: These functions only free everything inside the object
+ so they can be used with stack variables (or array elements)! */
+
+static void destroy_obj(ast_obj *obj);
+
+static void
+destroy_list(ast_list *list) {
+ if (!list)
+ return;
+ for (size_t i = 0; i < list->len; i++) {
+ destroy_obj(&list->objs[i]);
+ }
+ free(list->objs);
+ list->objs = NULL;
+ list->len = list->cap = 0;
+}
+
+static void
+destroy_obj(ast_obj *obj) {
+ if (!obj)
+ return;
+ switch (obj->type) {
+ case OBJ_LIST:
+ destroy_list(&obj->obj.list);
+ break;
+ case OBJ_ASSIGNMENT:
+ destroy_obj(obj->obj.assignment.value);
+ free(obj->obj.assignment.value);
+ obj->obj.assignment.value = NULL;
+ break;
+ case OBJ_STATEMENT:
+ free(obj->obj.statement.args);
+ obj->obj.statement.args = NULL;
+ obj->obj.statement.len = obj->obj.statement.cap = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+/* FIXME: overflow */
+static void
+list_append(ast_list *list, ast_obj o) {
+ list->cap = ideal_array_size(list->cap, add_sz(list->len, 1));
+ list->objs = ledit_reallocarray(list->objs, list->cap, sizeof(ast_obj)…
+ list->objs[list->len++] = o;
+}
+
+static void
+statement_append(ast_statement *statement, struct token tok) {
+ statement->cap = ideal_array_size(statement->cap, add_sz(statement->le…
+ statement->args = ledit_reallocarray(statement->args, statement->cap, …
+ statement->args[statement->len++] = tok;
+}
+
+/* FIXME: make this a bit nicer */
+/* Note: A lot of the ugliness is because of the
+ (failed) attempt to somewhat optimize everything */
+
+static int
+parse_list(struct lexstate *s, ast_list *ret, int implicit_end, char *filename…
+ *ret = (ast_list){NULL, 0, 0};
+ struct token tok = next_token(s);
+ struct token tok2;
+ while (1) {
+ switch (tok.type) {
+ case STRING:
+ tok2 = next_token(s);
+ if (tok2.type == STRING) {
+ ast_statement statement = {tok, NULL, 0, 0};
+ /* FIXME: maybe allow lists in statements? */
+ while (tok2.type == STRING) {
+ statement_append(&statement, tok2);
+ tok2 = next_token(s);
+ }
+ list_append(ret, (ast_obj){.tok = tok, .obj = …
+ tok = tok2;
+ } else if (tok2.type == EQUALS) {
+ ast_assignment assignment = {tok, NULL};
+ assignment.value = ledit_malloc(sizeof(ast_obj…
+ tok2 = next_token(s);
+ assignment.value->tok = tok2;
+ struct token orig_tok = tok;
+ if (tok2.type == STRING) {
+ assignment.value->obj.str = (ast_strin…
+ assignment.value->type = OBJ_STRING;
+ tok = next_token(s);
+ if (tok.type == STRING) {
+ *errstr = print_fmt(
+ "%s: Invalid assignment at…
+ filename, tok.line, tok.li…
+ );
+ free(assignment.value);
+ goto error;
+ }
+ } else if (tok2.type == LBRACE) {
+ assignment.value->type = OBJ_LIST;
+ /* just in case */
+ assignment.value->obj.list = (ast_list…
+ if (parse_list(s, &assignment.value->o…
+ free(assignment.value);
+ goto error;
+ }
+ tok = next_token(s);
+ if (tok.type == STRING) {
+ *errstr = print_fmt(
+ "%s: Invalid assignment at…
+ filename, tok.line, tok.li…
+ );
+ destroy_list(&assignment.value…
+ free(assignment.value);
+ goto error;
+ }
+ } else {
+ *errstr = print_fmt(
+ "%s: Invalid assignment at line %z…
+ filename, tok2.line, tok2.line_off…
+ );
+ free(assignment.value);
+ goto error;
+ }
+ list_append(ret, (ast_obj){.tok = orig_tok, .o…
+ } else {
+ *errstr = print_fmt(
+ "%s: Invalid token '%s' at line %zu, offse…
+ filename, toktype_str(tok2.type), tok2.lin…
+ );
+ goto error;
+ }
+ break;
+ case NEWLINE:
+ tok = next_token(s);
+ break;
+ case RBRACE:
+ if (implicit_end) {
+ *errstr = print_fmt(
+ "%s: Unexpected right brace at line %zu, o…
+ filename, tok.line, tok.line_offset
+ );
+ goto error;
+ } else {
+ return 0;
+ }
+ case END:
+ if (!implicit_end) {
+ *errstr = print_fmt(
+ "%s: Unexpected end of file at line %zu, o…
+ filename, tok.line, tok.line_offset
+ );
+ goto error;
+ } else {
+ return 0;
+ }
+ case LBRACE:
+ case EQUALS:
+ case ERROR:
+ default:
+ *errstr = print_fmt(
+ "%s: Unexpected token '%s' at line %zu, offset %zu…
+ filename, toktype_str(tok.type), tok.line, tok.lin…
+ );
+ goto error;
+ }
+ }
+ return 0;
+error:
+ destroy_list(ret);
+ return 1;
+}
+
+static char *
+load_file(char *filename, size_t *len_ret, char **errstr) {
+ long len;
+ char *file_contents;
+ FILE *file;
+
+ /* FIXME: https://wiki.sei.cmu.edu/confluence/display/c/FIO19-C.+Do+no…
+ file = fopen(filename, "r");
+ if (!file) goto error;
+ if (fseek(file, 0, SEEK_END)) goto errorclose;
+ len = ftell(file);
+ if (len < 0) goto errorclose;
+ if (fseek(file, 0, SEEK_SET)) goto errorclose;
+ file_contents = ledit_malloc(add_sz((size_t)len, 1));
+ clearerr(file);
+ fread(file_contents, 1, (size_t)len, file);
+ if (ferror(file)) goto errorclose;
+ file_contents[len] = '\0';
+ if (fclose(file)) goto error;
+ *len_ret = (size_t)len;
+ return file_contents;
+error:
+ if (errstr)
+ *errstr = strerror(errno);
+ return NULL;
+errorclose:
+ if (errstr)
+ *errstr = strerror(errno);
+ fclose(file);
+ return NULL;
+}
+
+/* FIXME: max recursion depth in parser */
+
+static int
+parse_theme_color(
+ ledit_common *common,
+ void *obj, const char *val, size_t val_len, char *key,
+ char *filename, size_t line, size_t line_offset, char **errstr) {
+ XftColor *dst = (XftColor *)obj;
+ char col[8]; /* 7 for '#' and 6 hex values + 1 for '\0' */
+ if (val_len == 7 && val[0] == '#') {
+ strncpy(col, val, val_len);
+ col[val_len] = '\0';
+ } else if (val_len == 6) {
+ col[0] = '#';
+ strncpy(col + 1, val, val_len);
+ col[val_len + 1] = '\0';
+ } else {
+ goto error;
+ }
+ /* FIXME: XftColorAllocValue */
+ if (!XftColorAllocName(common->dpy, common->vis, common->cm, col, dst))
+ goto error;
+ return 0;
+error:
+ *errstr = print_fmt(
+ "%s: Unable to parse color specification "
+ "'%.*s' for '%s' at line %zu, position %zu",
+ filename, val_len, val, key, line, line_offset
+ );
+ return 1;
+}
+
+static void
+destroy_theme_color(ledit_common *common, void *obj) {
+ XftColor *color = (XftColor *)obj;
+ XftColorFree(common->dpy, common->vis, common->cm, color);
+}
+
+/* based partially on OpenBSD's strtonum */
+static int
+parse_theme_number(
+ ledit_common *common,
+ void *obj, const char *val, size_t val_len, char *key,
+ char *filename, size_t line, size_t line_offset, char **errstr) {
+ (void)common;
+ int *num = (int *)obj;
+ /* the string needs to be nul-terminated
+ if it contains more than 9 digits, it's illegal anyways */
+ if (val_len > 9)
+ goto error;
+ char str[10];
+ strncpy(str, val, val_len);
+ str[val_len] = '\0';
+ char *end;
+ long l = strtol(str, &end, 10);
+ if (str == end || *end != '\0' ||
+ l < 0 || l > INT_MAX || ((l == LONG_MIN ||
+ l == LONG_MAX) && errno == ERANGE)) {
+ goto error;
+ }
+ *num = (int)l;
+ return 0;
+error:
+ *errstr = print_fmt(
+ "%s: Invalid number '%.*s' "
+ "for '%s' at line %zu, position %zu",
+ filename, val_len, val, key, line, line_offset
+ );
+ return 1;
+}
+
+static void
+destroy_theme_number(ledit_common *common, void *obj) {
+ (void)common;
+ (void)obj;
+}
+
+static int
+parse_theme_string(
+ ledit_common *common,
+ void *obj, const char *val, size_t val_len, char *key,
+ char *filename, size_t line, size_t line_offset, char **errstr) {
+ (void)common; (void)key;
+ (void)filename; (void)line; (void)line_offset; (void)errstr;
+
+ char **obj_str = (char **)obj;
+ *obj_str = ledit_strndup(val, val_len);
+ return 0;
+}
+
+static void
+destroy_theme_string(ledit_common *common, void *obj) {
+ (void)common;
+ char **obj_str = (char **)obj;
+ free(*obj_str);
+}
+
+/* FIXME: This interface is absolutely horrible - it's mainly this way to reus…
+ theme array for the destroy function */
+/* If theme is NULL, a new theme is loaded, else it is destroyed */
+static ledit_theme *
+load_destroy_theme(ledit_common *common, ast_list *theme_list, ledit_theme *th…
+ *errstr = NULL;
+ int default_init = theme ? 1 : 0;
+ if (!theme)
+ theme = ledit_malloc(sizeof(ledit_theme));
+
+ struct {
+ char *key;
+ void *obj;
+ int (*parse_func)(
+ ledit_common *common,
+ void *obj, const char *val, size_t val_len, char *key,
+ char *filename, size_t line, size_t line_offset, char **er…
+ );
+ void (*destroy_func)(ledit_common *common, void *obj);
+ const char *default_value;
+ int initialized;
+ } settings[] = {
+ {"text-font", &theme->text_font, &parse_theme_string, &destroy…
+ {"text-size", &theme->text_size, &parse_theme_number, &destroy…
+ {"scrollbar-width", &theme->scrollbar_width, &parse_theme_numb…
+ {"scrollbar-step", &theme->scrollbar_step, &parse_theme_number…
+ {"text-fg", &theme->text_fg, &parse_theme_color, &destroy_them…
+ {"text-bg", &theme->text_bg, &parse_theme_color, &destroy_them…
+ {"cursor-fg", &theme->cursor_fg, &parse_theme_color, &destroy_…
+ {"cursor-bg", &theme->cursor_bg, &parse_theme_color, &destroy_…
+ {"selection-fg", &theme->selection_fg, &parse_theme_color, &de…
+ {"selection-bg", &theme->selection_bg, &parse_theme_color, &de…
+ {"bar-fg", &theme->bar_fg, &parse_theme_color, &destroy_theme_…
+ {"bar-bg", &theme->bar_bg, &parse_theme_color, &destroy_theme_…
+ {"bar-cursor", &theme->bar_cursor, &parse_theme_color, &destro…
+ {"scrollbar-fg", &theme->scrollbar_fg, &parse_theme_color, &de…
+ {"scrollbar-bg", &theme->scrollbar_bg, &parse_theme_color, &de…
+ };
+
+ if (default_init)
+ goto cleanup;
+
+ if (theme_list) {
+ for (size_t i = 0; i < theme_list->len; i++) {
+ size_t line = theme_list->objs[i].tok.line;
+ size_t line_offset = theme_list->objs[i].tok.line_offs…
+ if (theme_list->objs[i].type != OBJ_ASSIGNMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid statement in theme configurat…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto cleanup;
+ } else if (theme_list->objs[i].obj.assignment.value->t…
+ *errstr = print_fmt(
+ "%s: Invalid assignment in theme configura…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto cleanup;
+ }
+
+ char *key = theme_list->objs[i].obj.assignment.tok.tex…
+ size_t key_len = theme_list->objs[i].obj.assignment.to…
+ char *val = theme_list->objs[i].obj.assignment.value->…
+ size_t val_len = theme_list->objs[i].obj.assignment.va…
+
+ int found = 0;
+ /* FIXME: use binary search maybe */
+ for (size_t j = 0; j < LENGTH(settings); j++) {
+ if (str_array_equal(settings[j].key, key, key_…
+ /* FIXME: maybe just make this a warni…
+ if (settings[j].initialized) {
+ *errstr = print_fmt(
+ "%s: Duplicate definition …
+ "'%.*s' at line %zu, posit…
+ filename, key_len, key, li…
+ );
+ goto cleanup;
+ }
+ if (settings[j].parse_func(
+ common, settings[j].obj, val, val_…
+ settings[j].key, filename, line, l…
+ goto cleanup;
+ }
+ settings[j].initialized = 1;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ *errstr = print_fmt(
+ "%s: Invalid theme setting "
+ "'%.*s' at line %zu, position %zu",
+ filename, key_len, key, line, line_offset
+ );
+ goto cleanup;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < LENGTH(settings); i++) {
+ if (!settings[i].initialized) {
+ /* FIXME: kind of inefficient to calculate strlen at r…
+ /* FIXME: line number doesn't make sense */
+ if (settings[i].parse_func(
+ common, settings[i].obj, settings[i].default_value,
+ strlen(settings[i].default_value), settings[i].key,
+ "default config", 0, 0, errstr)) {
+ goto cleanup;
+ }
+ }
+ }
+
+ return theme;
+cleanup:
+ for (size_t i = 0; i < LENGTH(settings); i++) {
+ if (settings[i].initialized) {
+ settings[i].destroy_func(common, settings[i].obj);
+ }
+ }
+ free(theme);
+ return NULL;
+}
+
+static ledit_theme *
+load_theme(ledit_common *common, ast_list *theme_list, char *filename, char **…
+ return load_destroy_theme(common, theme_list, NULL, filename, errstr);
+}
+
+static void
+destroy_theme(ledit_common *common, ledit_theme *theme) {
+ char *errstr = NULL;
+ if (!theme)
+ return;
+ (void)load_destroy_theme(common, NULL, theme, NULL, &errstr);
+ /* shouldn't happen... */
+ if (errstr)
+ free(errstr);
+}
+
+/* This only destroys the members inside 'cfg' since the config
+ * struct itself is usually not on the heap. */
+static void
+config_destroy(ledit_common *common, struct config *cfg) {
+ if (cfg->theme)
+ destroy_theme(common, cfg->theme);
+ cfg->theme = NULL;
+ for (size_t i = 0; i < cfg->num_langs; i++) {
+ for (size_t j = 0; j < cfg->basic_keys[i].num_keys; j++) {
+ free(cfg->basic_keys[i].keys[j].text);
+ }
+ free(cfg->basic_keys[i].keys);
+ for (size_t j = 0; j < cfg->command_keys[i].num_keys; j++) {
+ free(cfg->command_keys[i].keys[j].text);
+ }
+ free(cfg->command_keys[i].keys);
+ for (size_t j = 0; j < cfg->cmds[i].num_cmds; j++) {
+ free(cfg->cmds[i].cmds[j].text);
+ }
+ free(cfg->cmds[i].cmds);
+ free(cfg->langs[i]);
+ }
+ free(cfg->basic_keys);
+ free(cfg->command_keys);
+ free(cfg->cmds);
+ free(cfg->langs);
+ cfg->basic_keys = NULL;
+ cfg->command_keys = NULL;
+ cfg->cmds = NULL;
+ cfg->langs = NULL;
+ cfg->num_langs = cfg->alloc_langs = 0;
+}
+
+void
+config_cleanup(ledit_common *common) {
+ config_destroy(common, &config);
+}
+
+/* FIXME: which additional ones are needed here? */
+static struct keysym_mapping {
+ char *name;
+ KeySym keysym;
+} keysym_map[] = {
+ {"backspace", XK_BackSpace},
+ {"begin", XK_Begin},
+ {"break", XK_Break},
+ {"cancel", XK_Cancel},
+ {"clear", XK_Clear},
+ {"delete", XK_Delete},
+ {"down", XK_Down},
+ {"end", XK_End},
+ {"escape", XK_Escape},
+ {"execute", XK_Execute},
+
+ {"f1", XK_F1},
+ {"f10", XK_F10},
+ {"f11", XK_F11},
+ {"f12", XK_F12},
+ {"f13", XK_F13},
+ {"f14", XK_F14},
+ {"f15", XK_F15},
+ {"f16", XK_F16},
+ {"f17", XK_F17},
+ {"f18", XK_F18},
+ {"f19", XK_F19},
+ {"f2", XK_F2},
+ {"f20", XK_F20},
+ {"f21", XK_F21},
+ {"f22", XK_F22},
+ {"f23", XK_F23},
+ {"f24", XK_F24},
+ {"f25", XK_F25},
+ {"f26", XK_F26},
+ {"f27", XK_F27},
+ {"f28", XK_F28},
+ {"f29", XK_F29},
+ {"f3", XK_F3},
+ {"f30", XK_F30},
+ {"f31", XK_F31},
+ {"f32", XK_F32},
+ {"f33", XK_F33},
+ {"f34", XK_F34},
+ {"f35", XK_F35},
+ {"f4", XK_F4},
+ {"f5", XK_F5},
+ {"f6", XK_F6},
+ {"f7", XK_F7},
+ {"f8", XK_F8},
+ {"f9", XK_F9},
+
+ {"find", XK_Find},
+ {"help", XK_Help},
+ {"home", XK_Home},
+ {"insert", XK_Insert},
+
+ {"kp-0", XK_KP_0},
+ {"kp-1", XK_KP_1},
+ {"kp-2", XK_KP_2},
+ {"kp-3", XK_KP_3},
+ {"kp-4", XK_KP_4},
+ {"kp-5", XK_KP_5},
+ {"kp-6", XK_KP_6},
+ {"kp-7", XK_KP_7},
+ {"kp-8", XK_KP_8},
+ {"kp-9", XK_KP_9},
+ {"kp-add", XK_KP_Add},
+ {"kp-begin", XK_KP_Begin},
+ {"kp-decimal", XK_KP_Decimal},
+ {"kp-delete", XK_KP_Delete},
+ {"kp-divide", XK_KP_Divide},
+ {"kp-down", XK_KP_Down},
+ {"kp-end", XK_KP_End},
+ {"kp-enter", XK_KP_Enter},
+ {"kp-equal", XK_KP_Equal},
+ {"kp-f1", XK_KP_F1},
+ {"kp-f2", XK_KP_F2},
+ {"kp-f3", XK_KP_F3},
+ {"kp-f4", XK_KP_F4},
+ {"kp-home", XK_KP_Home},
+ {"kp-insert", XK_KP_Insert},
+ {"kp-left", XK_KP_Left},
+ {"kp-multiply", XK_KP_Multiply},
+ {"kp-next", XK_KP_Next},
+ {"kp-page-down", XK_KP_Page_Down},
+ {"kp-page-up", XK_KP_Page_Up},
+ {"kp-prior", XK_KP_Prior},
+ {"kp-right", XK_KP_Right},
+ {"kp-separator", XK_KP_Separator},
+ {"kp-space", XK_KP_Space},
+ {"kp-subtract", XK_KP_Subtract},
+ {"kp-tab", XK_KP_Tab},
+ {"kp-up", XK_KP_Up},
+
+ {"l1", XK_L1},
+ {"l10", XK_L10},
+ {"l2", XK_L2},
+ {"l3", XK_L3},
+ {"l4", XK_L4},
+ {"l5", XK_L5},
+ {"l6", XK_L6},
+ {"l7", XK_L7},
+ {"l8", XK_L8},
+ {"l9", XK_L9},
+
+ {"left", XK_Left},
+ {"linefeed", XK_Linefeed},
+ {"menu", XK_Menu},
+ {"mode-switch", XK_Mode_switch},
+ {"next", XK_Next},
+ {"num-lock", XK_Num_Lock},
+ {"page-down", XK_Page_Down},
+ {"page-up", XK_Page_Up},
+ {"pause", XK_Pause},
+ {"print", XK_Print},
+ {"prior", XK_Prior},
+
+ {"r1", XK_R1},
+ {"r10", XK_R10},
+ {"r11", XK_R11},
+ {"r12", XK_R12},
+ {"r13", XK_R13},
+ {"r14", XK_R14},
+ {"r15", XK_R15},
+ {"r2", XK_R2},
+ {"r3", XK_R3},
+ {"r4", XK_R4},
+ {"r5", XK_R5},
+ {"r6", XK_R6},
+ {"r7", XK_R7},
+ {"r8", XK_R8},
+ {"r9", XK_R9},
+
+ {"redo", XK_Redo},
+ {"return", XK_Return},
+ {"right", XK_Right},
+ {"script-switch", XK_script_switch},
+ {"scroll-lock", XK_Scroll_Lock},
+ {"select", XK_Select},
+ {"space", XK_space},
+ {"sysreq", XK_Sys_Req},
+ {"tab", XK_Tab},
+ {"up", XK_Up},
+ {"undo", XK_Undo},
+};
+
+GEN_CB_MAP_HELPERS(keysym_map, struct keysym_mapping, name)
+
+static int
+parse_keysym(char *keysym_str, size_t len, KeySym *sym) {
+ struct keysym_mapping *km = keysym_map_get_entry(keysym_str, len);
+ if (!km)
+ return 1;
+ *sym = km->keysym;
+ return 0;
+}
+
+static int
+parse_modemask(char *modemask_str, size_t len, ledit_mode *mode_ret) {
+ size_t cur = 0;
+ *mode_ret = 0;
+ while (cur < len) {
+ if (str_array_equal("normal", modemask_str + cur, LEDIT_MIN(6,…
+ cur += 6;
+ *mode_ret |= NORMAL;
+ } else if (str_array_equal("visual", modemask_str + cur, LEDIT…
+ cur += 6;
+ *mode_ret |= VISUAL;
+ } else if (str_array_equal("insert", modemask_str + cur, LEDIT…
+ cur += 6;
+ *mode_ret |= INSERT;
+ } else {
+ return 1;
+ }
+ if (cur < len && modemask_str[cur] != '|')
+ return 1;
+ else
+ cur++;
+ }
+ return 0;
+}
+
+static int
+parse_modmask(char *modmask_str, size_t len, unsigned int *mask_ret) {
+ size_t cur = 0;
+ *mask_ret = 0;
+ while (cur < len) {
+ if (str_array_equal("shift", modmask_str + cur, LEDIT_MIN(5, l…
+ cur += 5;
+ *mask_ret |= ShiftMask;
+ } else if (str_array_equal("lock", modmask_str + cur, LEDIT_MI…
+ cur += 4;
+ *mask_ret |= LockMask;
+ } else if (str_array_equal("control", modmask_str + cur, LEDIT…
+ cur += 7;
+ *mask_ret |= ControlMask;
+ } else if (str_array_equal("mod1", modmask_str + cur, LEDIT_MI…
+ cur += 4;
+ *mask_ret |= Mod1Mask;
+ } else if (str_array_equal("mod2", modmask_str + cur, LEDIT_MI…
+ cur += 4;
+ *mask_ret |= Mod2Mask;
+ } else if (str_array_equal("mod3", modmask_str + cur, LEDIT_MI…
+ cur += 4;
+ *mask_ret |= Mod3Mask;
+ } else if (str_array_equal("mod4", modmask_str + cur, LEDIT_MI…
+ cur += 4;
+ *mask_ret |= Mod4Mask;
+ } else if (str_array_equal("any", modmask_str + cur, LEDIT_MIN…
+ cur += 3;
+ *mask_ret = UINT_MAX;
+ } else {
+ return 1;
+ }
+ if (cur < len && modmask_str[cur] != '|')
+ return 1;
+ else
+ cur++;
+ }
+ return 0;
+}
+
+/* FIXME: it would probably be safer to not write the string lengths by hand..…
+static int
+parse_command_modemask(char *mode_str, size_t len, command_mode *mode_ret) {
+ size_t cur = 0;
+ *mode_ret = 0;
+ /* IMPORTANT: these need to be sorted appropriately so e.g. edit doesn…
+ while (cur < len) {
+ if (str_array_equal("substitute", mode_str + cur, LEDIT_MIN(10…
+ cur += 10;
+ *mode_ret |= CMD_SUBSTITUTE;
+ } else if (str_array_equal("edit-search-backwards", mode_str +…
+ cur += 21;
+ *mode_ret |= CMD_EDITSEARCHB;
+ } else if (str_array_equal("edit-search", mode_str + cur, LEDI…
+ cur += 11;
+ *mode_ret |= CMD_EDITSEARCH;
+ } else if (str_array_equal("edit", mode_str + cur, LEDIT_MIN(4…
+ cur += 4;
+ *mode_ret |= CMD_EDIT;
+ } else {
+ return 1;
+ }
+ if (cur < len && mode_str[cur] != '|') {
+ return 1;
+ } else {
+ cur++;
+ }
+ }
+ return 0;
+}
+
+/* FIXME: generic dynamic array */
+
+static void
+push_lang(struct config *cfg) {
+ if (cfg->num_langs == cfg->alloc_langs) {
+ cfg->alloc_langs = ideal_array_size(cfg->alloc_langs, add_sz(c…
+ cfg->basic_keys = ledit_reallocarray(cfg->basic_keys, cfg->all…
+ cfg->command_keys = ledit_reallocarray(cfg->command_keys, cfg-…
+ cfg->cmds = ledit_reallocarray(cfg->cmds, cfg->alloc_langs, si…
+ cfg->langs = ledit_reallocarray(cfg->langs, cfg->alloc_langs, …
+ }
+ basic_key_array *arr1 = &cfg->basic_keys[cfg->num_langs];
+ arr1->keys = NULL;
+ arr1->num_keys = arr1->alloc_keys = 0;
+ command_key_array *arr2 = &cfg->command_keys[cfg->num_langs];
+ arr2->keys = NULL;
+ arr2->num_keys = arr2->alloc_keys = 0;
+ command_array *arr3 = &cfg->cmds[cfg->num_langs];
+ arr3->cmds = NULL;
+ arr3->num_cmds = arr3->alloc_cmds = 0;
+ cfg->langs[cfg->num_langs] = NULL;
+ cfg->num_langs++;
+}
+
+#define GEN_PARSE_STATEMENT(name, cb_type, mapping_type, mode_parse_func) …
+static int …
+name(ast_statement *st, mapping_type *m, char *filename, char **errstr) { …
+ size_t line = st->func_tok.line; …
+ size_t line_offset = st->func_tok.line_offset; …
+ m->cb = NULL; …
+ m->text = NULL; …
+ m->mods = 0; …
+ m->modes = 0; …
+ m->keysym = 0; …
+ char *msg = NULL; …
+ if (!str_array_equal("bind", st->func_tok.text, st->func_tok.len) || s…
+ msg = "Invalid statement"; …
+ goto error; …
+ } …
+ m->cb = cb_type##_map_get_entry(st->args[0].text, st->args[0].len); …
+ if (!m->cb) { …
+ msg = "Invalid function specification"; …
+ goto error; …
+ } …
+ int text_init = 0, keysym_init = 0, modes_init = 0, mods_init = 0; …
+ for (size_t i = 1; i < st->len; i++) { …
+ line = st->args[i].line; …
+ line_offset = st->args[i].line_offset; …
+ if (str_array_equal("mods", st->args[i].text, st->args[i].len)…
+ if (mods_init) { …
+ msg = "Duplicate mods specification"; …
+ goto error; …
+ } else if (i == st->len - 1) { …
+ msg = "Unfinished statement"; …
+ goto error; …
+ } …
+ i++; …
+ if (parse_modmask(st->args[i].text, st->args[i].len, &…
+ msg = "Invalid mods specification"; …
+ goto error; …
+ } …
+ mods_init = 1; …
+ } else if (str_array_equal("modes", st->args[i].text, st->args…
+ if (modes_init) { …
+ msg = "Duplicate modes specification"; …
+ goto error; …
+ } else if (i == st->len - 1) { …
+ msg = "Unfinished statement"; …
+ goto error; …
+ } …
+ i++; …
+ if (mode_parse_func(st->args[i].text, st->args[i].len,…
+ msg = "Invalid modes specification"; …
+ goto error; …
+ } else if (!cb_type##_modemask_is_valid(m->cb, m->mode…
+ msg = "Function not defined for all given mode…
+ goto error; …
+ } …
+ modes_init = 1; …
+ } else if (str_array_equal("keysym", st->args[i].text, st->arg…
+ if (text_init) { …
+ msg = "Text already specified"; …
+ goto error; …
+ } else if (keysym_init) { …
+ msg = "Duplicate keysym specification"; …
+ goto error; …
+ } else if (i == st->len - 1) { …
+ msg = "Unfinished statement"; …
+ goto error; …
+ } …
+ i++; …
+ if (parse_keysym(st->args[i].text, st->args[i].len, &m…
+ msg = "Invalid keysym specification"; …
+ goto error; …
+ } …
+ keysym_init = 1; …
+ } else if (str_array_equal("text", st->args[i].text, st->args[…
+ if (keysym_init) { …
+ msg = "Keysym already specified"; …
+ goto error; …
+ } else if (text_init) { …
+ msg = "Duplicate text specification"; …
+ goto error; …
+ } else if (i == st->len - 1) { …
+ msg = "Unfinished statement"; …
+ goto error; …
+ } …
+ i++; …
+ m->text = ledit_strndup(st->args[i].text, st->args[i].…
+ text_init = 1; …
+ } else if (str_array_equal("catchall", st->args[i].text, st->a…
+ if (keysym_init) { …
+ msg = "Keysym already specified"; …
+ goto error; …
+ } else if (text_init) { …
+ msg = "Duplicate text specification"; …
+ goto error; …
+ } …
+ m->text = ledit_strdup(""); …
+ text_init = 1; …
+ } else { …
+ msg = "Invalid statement"; …
+ goto error; …
+ } …
+ } …
+ if (!text_init && !keysym_init) { …
+ msg = "No text or keysym specified"; …
+ goto error; …
+ } …
+ if (!modes_init) { …
+ msg = "No modes specified"; …
+ goto error; …
+ } …
+ return 0; …
+error: …
+ if (msg) { …
+ *errstr = print_fmt( …
+ "%s, line %zu, offset %zu: %s", filename, line, line_offse…
+ ); …
+ } …
+ if (m->text) …
+ free(m->text); …
+ return 1; …
+}
+
+GEN_PARSE_STATEMENT(parse_basic_key_statement, basic_key_cb, basic_key_mapping…
+GEN_PARSE_STATEMENT(parse_command_key_statement, command_key_cb, command_key_m…
+
+static int
+parse_command_statement(ast_statement *st, command_mapping *m, char *filename,…
+ size_t line = st->func_tok.line;
+ size_t line_offset = st->func_tok.line_offset;
+ m->cb = NULL;
+ m->text = NULL;
+ char *msg = NULL;
+ if (!str_array_equal("bind", st->func_tok.text, st->func_tok.len) || s…
+ msg = "Invalid statement";
+ goto error;
+ }
+ m->cb = command_cb_map_get_entry(st->args[0].text, st->args[0].len);
+ if (!m->cb) {
+ msg = "Invalid function specification";
+ goto error;
+ }
+ m->text = ledit_strndup(st->args[1].text, st->args[1].len);
+ return 0;
+error:
+ if (msg) {
+ *errstr = print_fmt(
+ "%s, line %zu, offset %zu: %s", filename, line, line_offse…
+ );
+ }
+ /* I guess this is unnecessary */
+ if (m->text)
+ free(m->text);
+ return 1;
+}
+
+static void
+push_basic_key_mapping(basic_key_array *arr, basic_key_mapping m) {
+ if (arr->num_keys == arr->alloc_keys) {
+ arr->alloc_keys = ideal_array_size(arr->alloc_keys, add_sz(arr…
+ arr->keys = ledit_reallocarray(arr->keys, arr->alloc_keys, siz…
+ }
+ arr->keys[arr->num_keys] = m;
+ arr->num_keys++;
+}
+
+static void
+push_command_key_mapping(command_key_array *arr, command_key_mapping m) {
+ if (arr->num_keys == arr->alloc_keys) {
+ arr->alloc_keys = ideal_array_size(arr->alloc_keys, add_sz(arr…
+ arr->keys = ledit_reallocarray(arr->keys, arr->alloc_keys, siz…
+ }
+ arr->keys[arr->num_keys] = m;
+ arr->num_keys++;
+}
+
+static void
+push_command_mapping(command_array *arr, command_mapping m) {
+ if (arr->num_cmds == arr->alloc_cmds) {
+ arr->alloc_cmds = ideal_array_size(arr->alloc_cmds, add_sz(arr…
+ arr->cmds = ledit_reallocarray(arr->cmds, arr->alloc_cmds, siz…
+ }
+ arr->cmds[arr->num_cmds] = m;
+ arr->num_cmds++;
+}
+
+/* FIXME: This could be made a lot nicer and less repetitive */
+static int
+load_bindings(struct config *cfg, ast_list *list, char *filename, char **errst…
+ int basic_keys_init = 0, command_keys_init = 0, commands_init = 0;
+ size_t cur_lang = cfg->num_langs - 1; /* FIXME: ensure no underflow */
+ for (size_t i = 0; i < list->len; i++) {
+ size_t line = list->objs[i].tok.line;
+ size_t line_offset = list->objs[i].tok.line_offset;
+ if (list->objs[i].type != OBJ_ASSIGNMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid statement in bindings configuration "
+ "at list %zu, offset %zu", filename, line, line_o…
+ );
+ goto error;
+ }
+ char *key = list->objs[i].obj.assignment.tok.text;
+ size_t key_len = list->objs[i].obj.assignment.tok.len;
+ if (str_array_equal("language", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_ST…
+ *errstr = print_fmt(
+ "%s: Invalid language setting in bindings …
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (cfg->langs[cur_lang]) {
+ *errstr = print_fmt(
+ "%s: Duplicate language setting in binding…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ char *val = list->objs[i].obj.assignment.value->obj.st…
+ size_t val_len = list->objs[i].obj.assignment.value->o…
+ cfg->langs[cur_lang] = ledit_strndup(val, val_len);
+ } else if (str_array_equal("basic-keys", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_LI…
+ *errstr = print_fmt(
+ "%s: Invalid basic-keys setting in binding…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (basic_keys_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate basic-keys setting in bindi…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ ast_list *slist = &list->objs[i].obj.assignment.value-…
+ for (size_t j = 0; j < slist->len; j++) {
+ line = slist->objs[j].tok.line;
+ line_offset = slist->objs[j].tok.line_offset;
+ if (slist->objs[j].type != OBJ_STATEMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid basic-keys setting in…
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ basic_key_mapping m;
+ if (parse_basic_key_statement(&slist->objs[j].…
+ goto error;
+ push_basic_key_mapping(&cfg->basic_keys[0], m);
+ }
+ basic_keys_init = 1;
+ } else if (str_array_equal("command-keys", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_LI…
+ *errstr = print_fmt(
+ "%s: Invalid command-keys setting in bindi…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (command_keys_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate command-keys setting in bin…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ ast_list *slist = &list->objs[i].obj.assignment.value-…
+ for (size_t j = 0; j < slist->len; j++) {
+ line = slist->objs[j].tok.line;
+ line_offset = slist->objs[j].tok.line_offset;
+ if (slist->objs[j].type != OBJ_STATEMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid command-keys setting …
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ command_key_mapping m;
+ if (parse_command_key_statement(&slist->objs[j…
+ goto error;
+ push_command_key_mapping(&cfg->command_keys[0]…
+ }
+ command_keys_init = 1;
+ } else if (str_array_equal("commands", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_LI…
+ *errstr = print_fmt(
+ "%s: Invalid commands setting in bindings …
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (commands_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate commands setting in binding…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ ast_list *slist = &list->objs[i].obj.assignment.value-…
+ for (size_t j = 0; j < slist->len; j++) {
+ line = slist->objs[j].tok.line;
+ line_offset = slist->objs[j].tok.line_offset;
+ if (slist->objs[j].type != OBJ_STATEMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid commands setting in b…
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ command_mapping m;
+ if (parse_command_statement(&slist->objs[j].ob…
+ goto error;
+ push_command_mapping(&cfg->cmds[0], m);
+ }
+ commands_init = 1;
+ }
+ }
+
+ /* FIXME: the behavior here is a bit weird - if there is nothing other…
+ setting in the bindings configuration, all actual bindings are defa…
+ associated language is different */
+ if (!cfg->langs[cur_lang]) {
+ cfg->langs[cur_lang] = ledit_strdup(language_default);
+ }
+ /* FIXME: avoid calling strlen */
+ if (!basic_keys_init) {
+ ledit_debug("No basic keys configured in bindings; loading def…
+ basic_key_mapping m;
+ for (size_t i = 0; i < LENGTH(basic_keys_default); i++) {
+ m.cb = basic_key_cb_map_get_entry(basic_keys_default[i…
+ if (!m.cb) {
+ *errstr = print_fmt("default config: Invalid b…
+ goto error;
+ } else if (!basic_key_cb_modemask_is_valid(m.cb, basic…
+ *errstr = print_fmt("default config: Function …
+ goto error;
+ }
+ m.text = basic_keys_default[i].text ? ledit_strdup(bas…
+ m.mods = basic_keys_default[i].mods;
+ m.modes = basic_keys_default[i].modes;
+ m.keysym = basic_keys_default[i].keysym;
+ push_basic_key_mapping(&cfg->basic_keys[0], m);
+ }
+ }
+ if (!command_keys_init) {
+ ledit_debug("No command keys configured in bindings; loading d…
+ command_key_mapping m;
+ for (size_t i = 0; i < LENGTH(command_keys_default); i++) {
+ m.cb = command_key_cb_map_get_entry(command_keys_defau…
+ if (!m.cb) {
+ *errstr = print_fmt("default config: Invalid c…
+ goto error;
+ } else if (!command_key_cb_modemask_is_valid(m.cb, com…
+ *errstr = print_fmt("default config: Function …
+ goto error;
+ }
+ m.text = command_keys_default[i].text ? ledit_strdup(c…
+ m.mods = command_keys_default[i].mods;
+ m.modes = command_keys_default[i].modes;
+ m.keysym = command_keys_default[i].keysym;
+ push_command_key_mapping(&cfg->command_keys[0], m);
+ }
+ }
+ /* FIXME: guard against NULL text in default config! */
+ if (!commands_init) {
+ ledit_debug("No commands configured in bindings; loading defau…
+ command_mapping m;
+ for (size_t i = 0; i < LENGTH(commands_default); i++) {
+ m.cb = command_cb_map_get_entry(commands_default[i].fu…
+ if (!m.cb) {
+ *errstr = print_fmt("default config: Invalid c…
+ goto error;
+ }
+ m.text = ledit_strdup(commands_default[i].text);
+ push_command_mapping(&cfg->cmds[0], m);
+ }
+ }
+ return 0;
+/* FIXME: simplify error handling by doing more here */
+error:
+ return 1;
+}
+
+static int
+load_mapping(struct config *cfg, ast_list *list, char *filename, char **errstr…
+ int key_mapping_init = 0, command_mapping_init = 0;
+ size_t cur_lang = cfg->num_langs - 1; /* FIXME: ensure no underflow */
+ for (size_t i = 0; i < list->len; i++) {
+ size_t line = list->objs[i].tok.line;
+ size_t line_offset = list->objs[i].tok.line_offset;
+ if (list->objs[i].type != OBJ_ASSIGNMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid statement in language mapping config…
+ "at list %zu, offset %zu", filename, line, line_o…
+ );
+ goto error;
+ }
+ char *key = list->objs[i].obj.assignment.tok.text;
+ size_t key_len = list->objs[i].obj.assignment.tok.len;
+ basic_key_array *bkmap = &cfg->basic_keys[cur_lang];
+ command_key_array *ckmap = &cfg->command_keys[cur_lang];
+ command_array *cmap = &cfg->cmds[cur_lang];
+ if (str_array_equal("language", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_ST…
+ *errstr = print_fmt(
+ "%s: Invalid language setting in language …
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (cfg->langs[cur_lang]) {
+ *errstr = print_fmt(
+ "%s: Duplicate language setting in languag…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ char *val = list->objs[i].obj.assignment.value->obj.st…
+ size_t val_len = list->objs[i].obj.assignment.value->o…
+ cfg->langs[cur_lang] = ledit_strndup(val, val_len);
+ } else if (str_array_equal("key-mapping", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_LI…
+ *errstr = print_fmt(
+ "%s: Invalid key-mapping setting in langua…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (key_mapping_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate key-mapping setting in lang…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ ast_list *slist = &list->objs[i].obj.assignment.value-…
+ for (size_t j = 0; j < slist->len; j++) {
+ line = slist->objs[j].tok.line;
+ line_offset = slist->objs[j].tok.line_offset;
+ if (slist->objs[j].type != OBJ_STATEMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid key-mapping setting i…
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ ast_statement *st = &slist->objs[j].obj.statem…
+ if (!str_array_equal("map", st->func_tok.text,…
+ *errstr = print_fmt(
+ "%s: Invalid key-mapping statement…
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ /* FIXME: any way to speed this up? I guess on…
+ for (size_t k = 0; k < bkmap->num_keys; k++) {
+ if (bkmap->keys[k].text && str_array_e…
+ free(bkmap->keys[k].text);
+ bkmap->keys[k].text = ledit_st…
+ }
+ }
+ for (size_t k = 0; k < ckmap->num_keys; k++) {
+ if (ckmap->keys[k].text && str_array_e…
+ free(ckmap->keys[k].text);
+ ckmap->keys[k].text = ledit_st…
+ }
+ }
+ }
+ key_mapping_init = 1;
+ } else if (str_array_equal("command-mapping", key, key_len)) {
+ if (list->objs[i].obj.assignment.value->type != OBJ_LI…
+ *errstr = print_fmt(
+ "%s: Invalid command-mapping setting in la…
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ } else if (command_mapping_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate command-mapping setting in …
+ "at line %zu, offset %zu", filename, line,…
+ );
+ goto error;
+ }
+ ast_list *slist = &list->objs[i].obj.assignment.value-…
+ for (size_t j = 0; j < slist->len; j++) {
+ line = slist->objs[j].tok.line;
+ line_offset = slist->objs[j].tok.line_offset;
+ if (slist->objs[j].type != OBJ_STATEMENT) {
+ *errstr = print_fmt(
+ "%s: Invalid command-mapping setti…
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ ast_statement *st = &slist->objs[j].obj.statem…
+ if (!str_array_equal("map", st->func_tok.text,…
+ *errstr = print_fmt(
+ "%s: Invalid command-mapping state…
+ "at line %zu, offset %zu", filenam…
+ );
+ goto error;
+ }
+ for (size_t k = 0; k < cmap->num_cmds; k++) {
+ if (str_array_equal(cmap->cmds[k].text…
+ free(cmap->cmds[k].text);
+ cmap->cmds[k].text = ledit_str…
+ }
+ }
+ }
+ command_mapping_init = 1;
+ }
+ }
+ if (!cfg->langs[cur_lang]) {
+ /* FIXME: pass actual beginning line and offset so this doesn'…
+ use the line and offset of the first list element */
+ if (list->len > 0) {
+ *errstr = print_fmt(
+ "%s: Missing language setting in language mapping …
+ "at line %zu, offset %zu", filename, list->objs[0]…
+ );
+ } else {
+ *errstr = print_fmt("%s: Missing language setting in l…
+ }
+ goto error;
+ }
+ return 0;
+error:
+ return 1;
+}
+
+static void
+append_mapping(struct config *cfg) {
+ push_lang(cfg);
+ ledit_assert(cfg->num_langs > 1);
+
+ /* first duplicate original mappings before replacing the text */
+ /* FIXME: optimize this to avoid useless reallocations */
+ size_t cur_lang = cfg->num_langs - 1;
+ basic_key_array *arr1 = &cfg->basic_keys[cur_lang];
+ arr1->num_keys = arr1->alloc_keys = cfg->basic_keys[0].num_keys;
+ arr1->keys = ledit_reallocarray(NULL, arr1->num_keys, sizeof(basic_key…
+ memmove(arr1->keys, cfg->basic_keys[0].keys, arr1->num_keys * sizeof(b…
+ for (size_t i = 0; i < arr1->num_keys; i++) {
+ if (arr1->keys[i].text)
+ arr1->keys[i].text = ledit_strdup(arr1->keys[i].text);
+ }
+
+
+ command_key_array *arr2 = &cfg->command_keys[cur_lang];
+ arr2->num_keys = arr2->alloc_keys = cfg->command_keys[0].num_keys;
+ arr2->keys = ledit_reallocarray(NULL, arr2->num_keys, sizeof(command_k…
+ memmove(arr2->keys, cfg->command_keys[0].keys, arr2->num_keys * sizeof…
+ for (size_t i = 0; i < arr2->num_keys; i++) {
+ if (arr2->keys[i].text)
+ arr2->keys[i].text = ledit_strdup(arr2->keys[i].text);
+ }
+
+ command_array *arr3 = &cfg->cmds[cur_lang];
+ arr3->num_cmds = arr3->alloc_cmds = cfg->cmds[0].num_cmds;
+ arr3->cmds = ledit_reallocarray(NULL, arr3->num_cmds, sizeof(command_m…
+ memmove(arr3->cmds, cfg->cmds[0].cmds, arr3->num_cmds * sizeof(command…
+ for (size_t i = 0; i < arr3->num_cmds; i++) {
+ arr3->cmds[i].text = ledit_strdup(arr3->cmds[i].text);
+ }
+}
+
+#ifdef LEDIT_DEBUG
+static void
+debug_print_obj(ast_obj *obj, int shiftwidth) {
+ for (int i = 0; i < shiftwidth; i++) {
+ fprintf(stderr, " ");
+ }
+ switch (obj->type) {
+ case OBJ_STRING:
+ fprintf(stderr, "STRING: %.*s\n", (int)obj->obj.str.tok.len, o…
+ break;
+ case OBJ_STATEMENT:
+ fprintf(stderr, "STATEMENT: %.*s ", (int)obj->obj.statement.fu…
+ for (size_t i = 0; i < obj->obj.statement.len; i++) {
+ fprintf(stderr, "%.*s ", (int)obj->obj.statement.args[…
+ }
+ fprintf(stderr, "\n");
+ break;
+ case OBJ_ASSIGNMENT:
+ fprintf(stderr, "ASSIGNMENT: %.*s =\n", (int)obj->obj.assignme…
+ debug_print_obj(obj->obj.assignment.value, shiftwidth + 4);
+ break;
+ case OBJ_LIST:
+ fprintf(stderr, "LIST:\n");
+ for (size_t i = 0; i < obj->obj.list.len; i++) {
+ debug_print_obj(&obj->obj.list.objs[i], shiftwidth + 4…
+ }
+ break;
+ }
+}
+#endif
+
+/* WARNING: *errstr must be freed! */
+int
+config_loadfile(ledit_common *common, char *filename, char **errstr) {
+ #ifdef LEDIT_DEBUG
+ struct timespec now, elapsed, last;
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ #endif
+ size_t len;
+ *errstr = NULL;
+ ast_list list = {.objs = NULL, .len = 0, .cap = 0};
+ char *file_contents = NULL;
+ if (filename) {
+ file_contents = load_file(filename, &len, errstr);
+ if (!file_contents) return 1;
+ #ifdef LEDIT_DEBUG
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &last, &elapsed);
+ ledit_debug_fmt(
+ "Time to load config file: %lld seconds, %ld nanoseconds\n…
+ (long long)elapsed.tv_sec, elapsed.tv_nsec
+ );
+ last = now;
+ #endif
+ /* start at line 1 to make error messages more useful */
+ struct lexstate s = {file_contents, len, 0, 1, 0};
+ if (parse_list(&s, &list, 1, filename, errstr)) {
+ free(file_contents);
+ return 1;
+ }
+ #ifdef LEDIT_DEBUG
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &last, &elapsed);
+ ledit_debug_fmt(
+ "Time to parse config file: %lld seconds, %ld nanoseconds\…
+ (long long)elapsed.tv_sec, elapsed.tv_nsec
+ );
+ #endif
+ }
+
+ #ifdef LEDIT_DEBUG
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ for (size_t i = 0; i < list.len; i++) {
+ debug_print_obj(&list.objs[i], 0);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &last, &elapsed);
+ ledit_debug_fmt(
+ "Time to print useless information: %lld seconds, %ld nanoseconds\…
+ (long long)elapsed.tv_sec, elapsed.tv_nsec
+ );
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ #endif
+
+ struct config cfg = {NULL};
+ int theme_init = 0, bindings_init = 0, mappings_init = 0;
+ ast_assignment *assignment;
+ for (size_t i = 0; i < list.len; i++) {
+ switch (list.objs[i].type) {
+ case OBJ_ASSIGNMENT:
+ assignment = &list.objs[i].obj.assignment;
+ if (str_array_equal("theme", assignment->tok.text, ass…
+ if (theme_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate theme definition at…
+ filename, assignment->tok.line, as…
+ );
+ goto error;
+ } else if (assignment->value->type != OBJ_LIST…
+ *errstr = print_fmt(
+ "%s: Invalid theme definition at l…
+ filename, assignment->tok.line, as…
+ );
+ goto error;
+ }
+ cfg.theme = load_theme(common, &assignment->va…
+ if (!cfg.theme)
+ goto error;
+ theme_init = 1;
+ } else if (str_array_equal("bindings", assignment->tok…
+ if (bindings_init) {
+ *errstr = print_fmt(
+ "%s: Duplicate definition of bindi…
+ filename, assignment->tok.line, as…
+ );
+ goto error;
+ }
+ push_lang(&cfg);
+ if (assignment->value->type != OBJ_LIST) {
+ *errstr = print_fmt(
+ "%s: Invalid definition of binding…
+ filename, assignment->tok.line, as…
+ );
+ goto error;
+ }
+ if (load_bindings(&cfg, &assignment->value->ob…
+ goto error;
+ bindings_init = 1;
+ } else if (str_array_equal("language-mapping", assignm…
+ if (cfg.num_langs == 0) {
+ ledit_debug("No key/command bindings c…
+ push_lang(&cfg);
+ /* load default config */
+ ast_list empty_list = {.objs = NULL, .…
+ /* shouldn't usually happen */
+ if (load_bindings(&cfg, &empty_list, f…
+ goto error;
+ bindings_init = 1;
+ } else if (assignment->value->type != OBJ_LIST…
+ *errstr = print_fmt(
+ "%s: Invalid definition of languag…
+ filename, assignment->tok.line, as…
+ );
+ goto error;
+ }
+
+ append_mapping(&cfg);
+
+ if (load_mapping(&cfg, &assignment->value->obj…
+ goto error;
+ mappings_init = 1;
+ } else {
+ *errstr = print_fmt(
+ "%s: Invalid assignment at line %zu, offse…
+ filename, assignment->tok.line, assignment…
+ );
+ goto error;
+ }
+ break;
+ default:
+ *errstr = print_fmt(
+ "%s: Invalid statement at line %zu, offset %zu",
+ filename, list.objs[i].tok.line, list.objs[i].tok.…
+ );
+ goto error;
+ }
+ }
+ if (!theme_init) {
+ ledit_debug("No theme configured; loading defaults\n");
+ cfg.theme = load_theme(common, NULL, NULL, errstr);
+ if (!cfg.theme)
+ goto error;
+ }
+ if (!bindings_init) {
+ ledit_debug("No key/command bindings configured; loading defau…
+ push_lang(&cfg);
+ /* load default config */
+ ast_list empty_list = {.objs = NULL, .len = 0, .cap = 0};
+ /* shouldn't usually happen */
+ if (load_bindings(&cfg, &empty_list, NULL, errstr))
+ goto error;
+ }
+ if (!mappings_init) {
+ ledit_debug("No key/command mappings configured; loading defau…
+ for (size_t i = 0; i < LENGTH(mappings_default); i++) {
+ append_mapping(&cfg);
+ size_t cur_lang = cfg.num_langs - 1;
+ cfg.langs[cur_lang] = ledit_strdup(mappings_default[i]…
+ basic_key_array *bkmap = &cfg.basic_keys[cur_lang];
+ command_key_array *ckmap = &cfg.command_keys[cur_lang];
+ command_array *cmap = &cfg.cmds[cur_lang];
+ /* FIXME: any way to speed this up? I guess once the k…
+ /* FIXME: duplicated code from above */
+ for (size_t j = 0; j < mappings_default[i].keys_len; j…
+ for (size_t k = 0; k < bkmap->num_keys; k++) {
+ if (bkmap->keys[k].text && !strcmp(bkm…
+ free(bkmap->keys[k].text);
+ bkmap->keys[k].text = ledit_st…
+ }
+ }
+ for (size_t k = 0; k < ckmap->num_keys; k++) {
+ if (ckmap->keys[k].text && !strcmp(ckm…
+ free(ckmap->keys[k].text);
+ ckmap->keys[k].text = ledit_st…
+ }
+ }
+ }
+ for (size_t j = 0; j < mappings_default[i].cmds_len; j…
+ for (size_t k = 0; k < cmap->num_cmds; k++) {
+ if (!strcmp(cmap->cmds[k].text, mappin…
+ free(cmap->cmds[k].text);
+ cmap->cmds[k].text = ledit_str…
+ }
+ }
+ }
+ }
+ }
+ destroy_list(&list);
+ free(file_contents);
+ config_destroy(common, &config);
+ config = cfg;
+ #ifdef LEDIT_DEBUG
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &last, &elapsed);
+ ledit_debug_fmt(
+ "Time to interpret config file: %lld seconds, %ld nanoseconds\n",
+ (long long)elapsed.tv_sec, elapsed.tv_nsec
+ );
+ #endif
+ return 0;
+error:
+ destroy_list(&list);
+ free(file_contents);
+ config_destroy(common, &cfg);
+ return 1;
+}
+
+ledit_theme *
+config_get_theme(void) {
+ ledit_assert(config.theme != NULL);
+ return config.theme;
+}
+
+basic_key_array *
+config_get_basic_keys(size_t lang_index) {
+ ledit_assert(lang_index < config.num_langs);
+ return &config.basic_keys[lang_index];
+}
+
+command_key_array *
+config_get_command_keys(size_t lang_index) {
+ ledit_assert(lang_index < config.num_langs);
+ return &config.command_keys[lang_index];
+}
+
+command_array *
+config_get_commands(size_t lang_index) {
+ ledit_assert(lang_index < config.num_langs);
+ return &config.cmds[lang_index];
+}
+
+int
+config_get_language_index(char *lang, size_t *idx_ret) {
+ for (size_t i = 0; i < config.num_langs; i++) {
+ if (!strcmp(lang, config.langs[i])) {
+ *idx_ret = i;
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/configparser.h b/configparser.h
t@@ -0,0 +1,80 @@
+#ifndef _CONFIGPARSER_H_
+#define _CONFIGPARSER_H_
+
+#include "common.h"
+#include "uglycrap.h"
+#include "keys_command.h"
+#include "keys_basic.h"
+
+typedef struct {
+ int scrollbar_width;
+ int scrollbar_step;
+ int text_size;
+ XftColor text_fg;
+ XftColor text_bg;
+ XftColor cursor_fg;
+ XftColor cursor_bg;
+ XftColor selection_fg;
+ XftColor selection_bg;
+ XftColor bar_fg;
+ XftColor bar_bg;
+ XftColor bar_cursor;
+ XftColor scrollbar_fg;
+ XftColor scrollbar_bg;
+ const char *text_font;
+} ledit_theme;
+
+typedef struct {
+ char *text; /* for keys that correspond with text */
+ unsigned int mods; /* modifier mask */
+ KeySym keysym; /* for other keys, e.g. arrow keys */
+ ledit_mode modes; /* modes in which this keybinding is functional */
+ basic_key_cb *cb; /* callback */
+} basic_key_mapping;
+
+typedef struct {
+ char *text; /* for keys that correspond with text */
+ unsigned int mods; /* modifier mask */
+ KeySym keysym; /* for other keys, e.g. arrow keys */
+ command_mode modes; /* substitute, etc. */
+ command_key_cb *cb; /* callback */
+} command_key_mapping;
+
+typedef struct {
+ char *text; /* text typed to call command */
+ command_cb *cb; /* callback */
+} command_mapping;
+
+typedef struct {
+ basic_key_mapping *keys;
+ size_t num_keys;
+ size_t alloc_keys;
+} basic_key_array;
+
+typedef struct {
+ command_key_mapping *keys;
+ size_t num_keys;
+ size_t alloc_keys;
+} command_key_array;
+
+typedef struct {
+ command_mapping *cmds;
+ size_t num_cmds;
+ size_t alloc_cmds;
+} command_array;
+
+/* Note: The config is initialized immediately when ledit starts, so these
+ * should not return NULL (unless an invalid language index is given), but
+ * it's still better to check just in case. */
+
+/* Note: The returned pointers are invalidated if the config is reloaded. */
+
+ledit_theme *config_get_theme(void);
+basic_key_array *config_get_basic_keys(size_t lang_index);
+command_key_array *config_get_command_keys(size_t lang_index);
+command_array *config_get_commands(size_t lang_index);
+int config_get_language_index(char *lang, size_t *idx_ret);
+int config_loadfile(ledit_common *common, char *filename, char **errstr);
+void config_cleanup(ledit_common *common);
+
+#endif
diff --git a/keys.c b/keys.c
t@@ -10,22 +10,8 @@
#include "memory.h"
#include "common.h"
#include "txtbuf.h"
-#include "theme.h"
#include "window.h"
#include "keys.h"
-#include "keys_config.h"
-
-KEY_LANGS;
-
-int
-get_language_index(char *lang) {
- for (size_t i = 0; i < LENGTH(key_langs); i++) {
- if (!strcmp(key_langs[i], lang)) {
- return i;
- }
- }
- return -1;
-}
/* FIXME: Does this break anything? */
/*static unsigned int importantmod = ShiftMask | ControlMask | Mod1Mask | Mod2…
diff --git a/keys.h b/keys.h
t@@ -19,4 +19,51 @@ void preprocess_key(
char *buf_ret, int buf_size, int *buf_len_ret
);
+/* FIXME: documentation */
+#define GEN_CB_MAP_HELPERS(name, typename, cmp_entry) \
+ \
+static int name##_sorted = 0; \
+ \
+/* \
+ * IMPORTANT: The text passed to *_get_entry may not be nul-terminated, \
+ * so a txtbuf has to be used for the bsearch comparison helper. \
+ */ \
+ \
+static int \
+name##_search_helper(const void *keyv, const void *entryv) { \
+ txtbuf *key = (txtbuf *)keyv; \
+ typename *entry = (typename *)entryv; \
+ int ret = strncmp(key->text, entry->cmp_entry, key->len); \
+ if (ret == 0) { \
+ if (entry->cmp_entry[key->len] == '\0') \
+ return 0; \
+ else \
+ return -1; \
+ } \
+ return ret; \
+} \
+ \
+static int \
+name##_sort_helper(const void *entry1v, const void *entry2v) { \
+ typename *entry1 = (typename *)entry1v; \
+ typename *entry2 = (typename *)entry2v; \
+ return strcmp(entry1->cmp_entry, entry2->cmp_entry); \
+} \
+ \
+typename * \
+name##_get_entry(char *text, size_t len) { \
+ /* just in case */ \
+ if (!name##_sorted) { \
+ qsort( \
+ name, LENGTH(name), \
+ sizeof(name[0]), &name##_sort_helper); \
+ name##_sorted = 1; \
+ } \
+ txtbuf tmp = {.len = len, .cap = len, .text = text}; \
+ return bsearch( \
+ &tmp, name, LENGTH(name), \
+ sizeof(name[0]), &name##_search_helper \
+ ); \
+}
+
#endif
diff --git a/keys_basic.c b/keys_basic.c
t@@ -12,6 +12,8 @@
they are now not allowed at all */
/* FIXME: a lot of error checking in the individual functions may be redundant
now that more checking is done beforehand for the allowed keys */
+/* FIXME: sort functions a bit better, maybe split file */
+/* FIXME: documentation */
#include <stdio.h>
#include <stdlib.h>
t@@ -29,17 +31,216 @@
#include "txtbuf.h"
#include "undo.h"
#include "cache.h"
-#include "theme.h"
#include "window.h"
#include "buffer.h"
#include "view.h"
#include "search.h"
#include "keys.h"
-#include "keys_config.h"
#include "keys_basic.h"
#include "keys_command.h"
-#include "keys_basic_config.h"
+#include "configparser.h"
+
+/*************************************************************************
+ * Declarations for all functions that can be used in the configuration. *
+ *************************************************************************/
+
+static struct action backspace(ledit_view *view, char *text, size_t len);
+static struct action cursor_left(ledit_view *view, char *text, size_t len);
+static struct action cursor_right(ledit_view *view, char *text, size_t len);
+static struct action cursor_up(ledit_view *view, char *text, size_t len);
+static struct action cursor_down(ledit_view *view, char *text, size_t len);
+static struct action return_key(ledit_view *view, char *text, size_t len);
+static struct action delete_key(ledit_view *view, char *text, size_t len);
+static struct action escape_key(ledit_view *view, char *text, size_t len);
+static struct action enter_insert(ledit_view *view, char *text, size_t len);
+static struct action cursor_to_beginning(ledit_view *view, char *text, size_t …
+static struct action key_0(ledit_view *view, char *text, size_t len);
+static struct action push_0(ledit_view *view, char *text, size_t len);
+static struct action push_1(ledit_view *view, char *text, size_t len);
+static struct action push_2(ledit_view *view, char *text, size_t len);
+static struct action push_3(ledit_view *view, char *text, size_t len);
+static struct action push_4(ledit_view *view, char *text, size_t len);
+static struct action push_5(ledit_view *view, char *text, size_t len);
+static struct action push_6(ledit_view *view, char *text, size_t len);
+static struct action push_7(ledit_view *view, char *text, size_t len);
+static struct action push_8(ledit_view *view, char *text, size_t len);
+static struct action push_9(ledit_view *view, char *text, size_t len);
+static struct action delete(ledit_view *view, char *text, size_t len);
+static struct action enter_visual(ledit_view *view, char *text, size_t len);
+static struct action switch_selection_end(ledit_view *view, char *text, size_t…
+static struct action clipcopy(ledit_view *view, char *text, size_t len);
+static struct action clippaste(ledit_view *view, char *text, size_t len);
+static struct action show_line(ledit_view *view, char *text, size_t len);
+static struct action enter_commandedit(ledit_view *view, char *text, size_t le…
+static struct action enter_searchedit_backward(ledit_view *view, char *text, s…
+static struct action enter_searchedit_forward(ledit_view *view, char *text, si…
+static struct action key_search_next(ledit_view *view, char *text, size_t len);
+static struct action key_search_prev(ledit_view *view, char *text, size_t len);
+static struct action undo(ledit_view *view, char *text, size_t len);
+static struct action redo(ledit_view *view, char *text, size_t len);
+static struct action insert_mode_insert_text(ledit_view *view, char *text, siz…
+static struct action repeat_command(ledit_view *view, char *text, size_t len);
+static struct action screen_up(ledit_view *view, char *text, size_t len);
+static struct action screen_down(ledit_view *view, char *text, size_t len);
+static struct action scroll_with_cursor_up(ledit_view *view, char *text, size_…
+static struct action scroll_with_cursor_down(ledit_view *view, char *text, siz…
+static struct action scroll_lines_up(ledit_view *view, char *text, size_t len);
+static struct action scroll_lines_down(ledit_view *view, char *text, size_t le…
+static struct action move_to_line(ledit_view *view, char *text, size_t len);
+static struct action paste_normal(ledit_view *view, char *text, size_t len);
+static struct action paste_normal_backwards(ledit_view *view, char *text, size…
+static struct action change(ledit_view *view, char *text, size_t len);
+static struct action move_to_eol(ledit_view *view, char *text, size_t len);
+static struct action mark_line(ledit_view *view, char *text, size_t len);
+static struct action jump_to_mark(ledit_view *view, char *text, size_t len);
+static struct action next_word(ledit_view *view, char *text, size_t len);
+static struct action next_word_end(ledit_view *view, char *text, size_t len);
+static struct action next_bigword(ledit_view *view, char *text, size_t len);
+static struct action next_bigword_end(ledit_view *view, char *text, size_t len…
+static struct action prev_word(ledit_view *view, char *text, size_t len);
+static struct action prev_bigword(ledit_view *view, char *text, size_t len);
+static struct action append_after_eol(ledit_view *view, char *text, size_t len…
+static struct action append_after_cursor(ledit_view *view, char *text, size_t …
+static struct action append_line_above(ledit_view *view, char *text, size_t le…
+static struct action append_line_below(ledit_view *view, char *text, size_t le…
+static struct action find_next_char_forwards(ledit_view *view, char *text, siz…
+static struct action find_next_char_backwards(ledit_view *view, char *text, si…
+static struct action find_char_forwards(ledit_view *view, char *text, size_t l…
+static struct action find_char_backwards(ledit_view *view, char *text, size_t …
+static struct action change_to_eol(ledit_view *view, char *text, size_t len);
+static struct action delete_to_eol(ledit_view *view, char *text, size_t len);
+static struct action delete_chars_forwards(ledit_view *view, char *text, size_…
+static struct action delete_chars_backwards(ledit_view *view, char *text, size…
+static struct action yank(ledit_view *view, char *text, size_t len);
+static struct action yank_lines(ledit_view *view, char *text, size_t len);
+static struct action replace(ledit_view *view, char *text, size_t len);
+static struct action cursor_to_first_non_ws(ledit_view *view, char *text, size…
+static struct action join_lines(ledit_view *view, char *text, size_t len);
+static struct action insert_at_beginning(ledit_view *view, char *text, size_t …
+static struct action toggle_hard_line_based(ledit_view *view, char *text, size…
+
+/***********************************************
+ * String-function mapping for config parsing. *
+ ***********************************************/
+
+/* FIXME: delete-backwards, delete-forwards should be renamed;
+ *key functions should be renamed (they're very vague) */
+
+typedef enum {
+ KEY_FLAG_NONE = 0,
+ KEY_FLAG_JUMP_TO_CURSOR = 1,
+ KEY_FLAG_LOCK_ALLOWED = 2
+} basic_key_cb_flags;
+
+typedef struct action (*basic_key_cb_func)(ledit_view *, char *, size_t);
+
+struct basic_key_cb {
+ char *text;
+ basic_key_cb_func func;
+ basic_key_cb_flags flags;
+ ledit_mode allowed_modes;
+};
+
+int
+basic_key_cb_modemask_is_valid(basic_key_cb *cb, ledit_mode modes) {
+ return (~cb->allowed_modes & modes) == 0;
+}
+
+/* FIXME: make functions work in more modes (e.g. cursor-to-first-non-whitespa…
+static struct basic_key_cb basic_key_cb_map[] = {
+ {"append-after-cursor", &append_after_cursor, KEY_FLAG_JUMP_TO_CURSOR,…
+ {"append-after-eol", &append_after_eol, KEY_FLAG_JUMP_TO_CURSOR, NORMA…
+ {"append-line-above", &append_line_above, KEY_FLAG_JUMP_TO_CURSOR, NOR…
+ {"append-line-below", &append_line_below, KEY_FLAG_JUMP_TO_CURSOR, NOR…
+ {"backspace", &backspace, KEY_FLAG_JUMP_TO_CURSOR, INSERT},
+ {"change", &change, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|VISUAL},
+ {"change-to-eol", &change_to_eol, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"clipboard-copy", &clipcopy, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_AL…
+ {"clipboard-paste", &clippaste, KEY_FLAG_JUMP_TO_CURSOR, INSERT},
+ {"cursor-down", &cursor_down, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_AL…
+ {"cursor-left", &cursor_left, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_AL…
+ {"cursor-right", &cursor_right, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_…
+ {"cursor-to-beginning", &cursor_to_beginning, KEY_FLAG_JUMP_TO_CURSOR|…
+ {"cursor-to-first-non-whitespace", &cursor_to_first_non_ws, KEY_FLAG_J…
+ {"cursor-up", &cursor_up, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWE…
+ {"delete", &delete, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|VISUAL},
+ {"delete-backwards", &delete_chars_backwards, KEY_FLAG_JUMP_TO_CURSOR,…
+ {"delete-forwards", &delete_chars_forwards, KEY_FLAG_JUMP_TO_CURSOR, N…
+ {"delete-key", &delete_key, KEY_FLAG_JUMP_TO_CURSOR, INSERT},
+ {"delete-to-eol", &delete_to_eol, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"enter-commandedit", &enter_commandedit, KEY_FLAG_NONE|KEY_FLAG_LOCK_…
+ {"enter-insert", &enter_insert, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|VISUAL…
+ {"enter-searchedit-backwards", &enter_searchedit_backward, KEY_FLAG_NO…
+ {"enter-searchedit-forwards", &enter_searchedit_forward, KEY_FLAG_NONE…
+ {"enter-visual", &enter_visual, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"escape-key", &escape_key, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLO…
+ {"find-char-backwards", &find_char_backwards, KEY_FLAG_JUMP_TO_CURSOR|…
+ {"find-char-forwards", &find_char_forwards, KEY_FLAG_JUMP_TO_CURSOR|KE…
+ {"find-next-char-backwards", &find_next_char_backwards, KEY_FLAG_JUMP_…
+ {"find-next-char-forwards", &find_next_char_forwards, KEY_FLAG_JUMP_TO…
+ {"insert-at-beginning", &insert_at_beginning, KEY_FLAG_JUMP_TO_CURSOR,…
+ {"insert-text", &insert_mode_insert_text, KEY_FLAG_JUMP_TO_CURSOR, INS…
+ {"join-lines", &join_lines, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"jump-to-mark", &jump_to_mark, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_…
+ {"key-0", &key_0, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NORMA…
+ {"mark-line", &mark_line, KEY_FLAG_NONE|KEY_FLAG_LOCK_ALLOWED, NORMAL|…
+ {"move-to-eol", &move_to_eol, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_AL…
+ {"move-to-line", &move_to_line, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_…
+ {"next-bigword", &next_bigword, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_…
+ {"next-bigword-end", &next_bigword_end, KEY_FLAG_JUMP_TO_CURSOR|KEY_FL…
+ {"next-word", &next_word, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWE…
+ {"next-word-end", &next_word_end, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOC…
+ {"paste-normal", &paste_normal, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"paste-normal-backwards", &paste_normal_backwards, KEY_FLAG_JUMP_TO_C…
+ {"previous-bigword", &prev_bigword, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_L…
+ {"previous-word", &prev_word, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_AL…
+ {"push-0", &push_0, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-1", &push_1, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-2", &push_2, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-3", &push_3, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-4", &push_4, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-5", &push_5, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-6", &push_6, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-7", &push_7, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-8", &push_8, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"push-9", &push_9, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NOR…
+ {"redo", &redo, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|INSERT},
+ {"repeat-command", &repeat_command, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"replace", &replace, KEY_FLAG_JUMP_TO_CURSOR, NORMAL},
+ {"return-key", &return_key, KEY_FLAG_JUMP_TO_CURSOR, INSERT},
+ {"screen-down", &screen_down, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_AL…
+ {"screen-up", &screen_up, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWE…
+ {"scroll-lines-down", &scroll_lines_down, KEY_FLAG_JUMP_TO_CURSOR|KEY_…
+ {"scroll-lines-up", &scroll_lines_up, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG…
+ {"scroll-with-cursor-down", &scroll_with_cursor_down, KEY_FLAG_JUMP_TO…
+ {"scroll-with-cursor-up", &scroll_with_cursor_up, KEY_FLAG_JUMP_TO_CUR…
+ {"search-next", &key_search_next, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOC…
+ {"search-previous", &key_search_prev, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG…
+ {"show-line", &show_line, KEY_FLAG_LOCK_ALLOWED, NORMAL|VISUAL},
+ {"switch-selection-end", &switch_selection_end, KEY_FLAG_JUMP_TO_CURSO…
+ {"toggle-hard-line-based", &toggle_hard_line_based, KEY_FLAG_NONE|KEY_…
+ {"undo", &undo, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|INSERT},
+ {"yank", &yank, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLOWED, NORMAL|…
+ {"yank-lines", &yank_lines, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOCK_ALLO…
+};
+
+GEN_CB_MAP_HELPERS(basic_key_cb_map, basic_key_cb, text)
+
+/***************************************************
+ * General global variables and utility functions. *
+ ***************************************************/
+
+enum key_type {
+ KEY_INVALID = 0,
+ KEY_MOTION_CHAR = 4,
+ KEY_MOTION_LINE = 8,
+ KEY_MOTION = 4|8,
+ KEY_MOTIONALLOWED = 16,
+ KEY_NUMBER = 32,
+ KEY_NUMBERALLOWED = 64,
+ KEY_ANY = 0xFF
+};
/* note: this is supposed to be global for all views/buffers */
int paste_buffer_line_based = 0;
t@@ -310,6 +511,10 @@ static void
discard_repetition_stack(void) {
if (repetition_stack.replaying)
return;
+ for (size_t i = 0; i < repetition_stack.tmp_len; i++) {
+ free(repetition_stack.tmp_stack[i].key_text);
+ repetition_stack.tmp_stack[i].key_text = NULL;
+ }
repetition_stack.tmp_len = 0;
}
t@@ -323,6 +528,10 @@ finalize_repetition_stack(void) {
if (repetition_stack.replaying)
return;
size_t tmp;
+ for (size_t i = 0; i < repetition_stack.len; i++) {
+ free(repetition_stack.stack[i].key_text);
+ repetition_stack.stack[i].key_text = NULL;
+ }
struct repetition_stack_elem *tmpstack;
repetition_stack.len = repetition_stack.tmp_len;
repetition_stack.tmp_len = 0;
t@@ -485,6 +694,10 @@ delete_selection(ledit_view *view) {
return 0;
}
+/********************************************
+ * Functions that were declared at the top. *
+ ********************************************/
+
/* FIXME: should these delete characters or graphemes? */
static struct action
delete_chars_forwards(ledit_view *view, char *text, size_t len) {
t@@ -549,6 +762,7 @@ delete_chars_backwards(ledit_view *view, char *text, size_…
/* used to set cursor - I guess this is sort of a hack */
static void
push_undo_empty_insert(ledit_view *view, size_t line, size_t index, int start_…
+ /* WARNING: Don't abuse txtbuf like this unless you're stupid like me.…
txtbuf ins_buf = {.text = "", .len = 0, .cap = 0};
ledit_range ins_range = {.line1 = line, .byte1 = index, .line2 = line,…
ledit_range cur_range = {.line1 = line, .byte1 = index, .line2 = line,…
t@@ -1271,6 +1485,18 @@ paste_normal_backwards(ledit_view *view, char *text, si…
return (struct action){ACTION_NONE, NULL};
}
+static struct action
+key_0(ledit_view *view, char *text, size_t len) {
+ struct key_stack_elem *e = peek_key_stack();
+ if (!e || (e->key & KEY_MOTIONALLOWED)) {
+ return cursor_to_beginning(view, text, len);
+ } else if (e->key & KEY_NUMBER) {
+ return push_0(view, text, len);
+ } else {
+ return err_invalid_key(view);
+ }
+}
+
static void
push_num(ledit_view *view, int num) {
struct key_stack_elem *e = peek_key_stack();
t@@ -2242,10 +2468,9 @@ toggle_hard_line_based(ledit_view *view, char *text, si…
}
static struct action
-handle_key(ledit_view *view, char *key_text, size_t len, KeySym sym, unsigned …
- struct key *cur_keys = keys[lang_index].keys;
- int num_keys = keys[lang_index].num_keys;
- struct key_stack_elem *e = peek_key_stack();
+handle_key(ledit_view *view, char *key_text, size_t len, KeySym sym, unsigned …
+ basic_key_array *cur_keys = config_get_basic_keys(lang_index);
+ size_t num_keys = cur_keys->num_keys;
/* FIXME: check if control chars in text */
/* FIXME: this is a bit of a hack because it's hardcoded */
if (grab_char_cb && sym == XK_Escape) {
t@@ -2253,31 +2478,32 @@ handle_key(ledit_view *view, char *key_text, size_t le…
return (struct action){ACTION_NONE, NULL};
} else if (len > 0 && grab_char_cb) {
*found = 1;
- *type = 0;
return grab_char_cb(view, key_text, len);
}
*found = 0;
- for (int i = 0; i < num_keys; i++) {
- if (cur_keys[i].text) {
+ for (size_t i = 0; i < num_keys; i++) {
+ if (cur_keys->keys[i].text) {
if (len > 0 &&
- (cur_keys[i].modes & view->mode) &&
- (cur_keys[i].prev_keys == KEY_ANY || (!e && (cur_k…
- ((!strncmp(cur_keys[i].text, key_text, len) &&
- match_key(cur_keys[i].mods, key_state & ~ShiftM…
- cur_keys[i].text[0] == '\0')) {
+ (cur_keys->keys[i].modes & view->mode) &&
+ ((!strncmp(cur_keys->keys[i].text, key_text, len)…
+ match_key(cur_keys->keys[i].mods, key_state & ~…
+ cur_keys->keys[i].text[0] == '\0')) {
/* FIXME: seems a bit hacky to remove shift, b…
is needed to make keys that use shift match…
- *type = cur_keys[i].type;
+ *flags = cur_keys->keys[i].cb->flags;
*found = 1;
- return cur_keys[i].func(view, key_text, len);
+ if (!(*flags & KEY_FLAG_LOCK_ALLOWED) && view-…
+ return view_locked_error(view);
+ return cur_keys->keys[i].cb->func(view, key_te…
}
- } else if ((cur_keys[i].modes & view->mode) &&
- cur_keys[i].keysym == sym &&
- (cur_keys[i].prev_keys == KEY_ANY || (!e && (cur_ke…
- match_key(cur_keys[i].mods, key_state)) {
- *type = cur_keys[i].type;
+ } else if ((cur_keys->keys[i].modes & view->mode) &&
+ cur_keys->keys[i].keysym == sym &&
+ match_key(cur_keys->keys[i].mods, key_state)) {
+ *flags = cur_keys->keys[i].cb->flags;
*found = 1;
- return cur_keys[i].func(view, key_text, len);
+ if (!(*flags & KEY_FLAG_LOCK_ALLOWED) && view->lock_te…
+ return view_locked_error(view);
+ return cur_keys->keys[i].cb->func(view, key_text, len);
}
}
return (struct action){ACTION_NONE, NULL};
t@@ -2299,13 +2525,13 @@ repeat_command(ledit_view *view, char *text, size_t le…
return (struct action){ACTION_NONE, NULL};
}
int found;
- enum key_type type;
+ basic_key_cb_flags flags;
repetition_stack.replaying = 1;
for (int i = 0; i < num; i++) {
unwind_repetition_stack();
struct repetition_stack_elem *e = get_cur_repetition_stack_ele…
while (e) {
- (void)handle_key(view, e->key_text, e->len, e->sym, e-…
+ (void)handle_key(view, e->key_text, e->len, e->sym, e-…
advance_repetition_stack();
e = get_cur_repetition_stack_elem();
}
t@@ -2338,14 +2564,14 @@ basic_key_handler(ledit_view *view, XEvent *event, int…
int found = 0;
int msg_shown = view->window->message_shown;
view->window->message_shown = 0; /* FIXME: this is hacky */
- enum key_type type;
- struct action act = handle_key(view, buf, (size_t)n, sym, key_state, l…
+ basic_key_cb_flags flags;
+ struct action act = handle_key(view, buf, (size_t)n, sym, key_state, l…
if (found && n > 0 && !view->window->message_shown)
window_hide_message(view->window);
else if (msg_shown)
view->window->message_shown = msg_shown;
- if (found && (type & KEY_ENSURE_CURSOR_SHOWN))
+ if (found && (flags & KEY_FLAG_JUMP_TO_CURSOR))
view_ensure_cursor_shown(view);
if (!found && n > 0) {
window_show_message(view->window, "Invalid key", -1);
diff --git a/keys_basic.h b/keys_basic.h
t@@ -4,6 +4,11 @@
#include <X11/Xlib.h>
#include "view.h"
+typedef struct basic_key_cb basic_key_cb;
+
+basic_key_cb *basic_key_cb_map_get_entry(char *text, size_t len);
+int basic_key_cb_modemask_is_valid(basic_key_cb *cb, ledit_mode modes);
+
/* perform cleanup of global data */
void basic_key_cleanup(void);
struct action basic_key_handler(ledit_view *view, XEvent *event, int lang_inde…
diff --git a/keys_basic_config.h b/keys_basic_config.h
t@@ -1,457 +0,0 @@
-/*
- * These are all the regular keys used in normal, visual, and insert mode.
- */
-
-/*
- * Note: The key types are currently very inconsistent and don't always make
- * sense. This will hopefully be fixed sometime. (FIXME)
- */
-
-enum key_type {
- KEY_INVALID = 0,
- KEY_NONE = 2, /* FIXME: perhaps rather KEY_EMPTY? */
- KEY_MOTION_CHAR = 4,
- KEY_MOTION_LINE = 8,
- KEY_MOTION = 4|8,
- KEY_MOTIONALLOWED = 16,
- KEY_NUMBER = 32,
- KEY_NUMBERALLOWED = 64,
- KEY_ENSURE_CURSOR_SHOWN = 128, /* jump to cursor if it is off screen *…
- KEY_ANY = 0xFF
-};
-
-struct key {
- char *text; /* for keys that …
- unsigned int mods; /* modifier mask …
- KeySym keysym; /* for other keys…
- ledit_mode modes; /* modes in which…
- enum key_type prev_keys; /* allowed previo…
- enum key_type type; /* type of key - …
- struct action (*func)(ledit_view *, char *, size_t); /* callback funct…
-};
-
-static struct action backspace(ledit_view *view, char *text, size_t len);
-static struct action cursor_left(ledit_view *view, char *text, size_t len);
-static struct action cursor_right(ledit_view *view, char *text, size_t len);
-static struct action cursor_up(ledit_view *view, char *text, size_t len);
-static struct action cursor_down(ledit_view *view, char *text, size_t len);
-static struct action return_key(ledit_view *view, char *text, size_t len);
-static struct action delete_key(ledit_view *view, char *text, size_t len);
-static struct action escape_key(ledit_view *view, char *text, size_t len);
-static struct action enter_insert(ledit_view *view, char *text, size_t len);
-static struct action cursor_to_beginning(ledit_view *view, char *text, size_t …
-static struct action push_0(ledit_view *view, char *text, size_t len);
-static struct action push_1(ledit_view *view, char *text, size_t len);
-static struct action push_2(ledit_view *view, char *text, size_t len);
-static struct action push_3(ledit_view *view, char *text, size_t len);
-static struct action push_4(ledit_view *view, char *text, size_t len);
-static struct action push_5(ledit_view *view, char *text, size_t len);
-static struct action push_6(ledit_view *view, char *text, size_t len);
-static struct action push_7(ledit_view *view, char *text, size_t len);
-static struct action push_8(ledit_view *view, char *text, size_t len);
-static struct action push_9(ledit_view *view, char *text, size_t len);
-static struct action delete(ledit_view *view, char *text, size_t len);
-static struct action enter_visual(ledit_view *view, char *text, size_t len);
-static struct action switch_selection_end(ledit_view *view, char *text, size_t…
-static struct action clipcopy(ledit_view *view, char *text, size_t len);
-static struct action clippaste(ledit_view *view, char *text, size_t len);
-static struct action show_line(ledit_view *view, char *text, size_t len);
-static struct action enter_commandedit(ledit_view *view, char *text, size_t le…
-static struct action enter_searchedit_backward(ledit_view *view, char *text, s…
-static struct action enter_searchedit_forward(ledit_view *view, char *text, si…
-static struct action key_search_next(ledit_view *view, char *text, size_t len);
-static struct action key_search_prev(ledit_view *view, char *text, size_t len);
-static struct action undo(ledit_view *view, char *text, size_t len);
-static struct action redo(ledit_view *view, char *text, size_t len);
-static struct action insert_mode_insert_text(ledit_view *view, char *text, siz…
-static struct action repeat_command(ledit_view *view, char *text, size_t len);
-static struct action screen_up(ledit_view *view, char *text, size_t len);
-static struct action screen_down(ledit_view *view, char *text, size_t len);
-static struct action scroll_with_cursor_up(ledit_view *view, char *text, size_…
-static struct action scroll_with_cursor_down(ledit_view *view, char *text, siz…
-static struct action scroll_lines_up(ledit_view *view, char *text, size_t len);
-static struct action scroll_lines_down(ledit_view *view, char *text, size_t le…
-static struct action move_to_line(ledit_view *view, char *text, size_t len);
-static struct action paste_normal(ledit_view *view, char *text, size_t len);
-static struct action paste_normal_backwards(ledit_view *view, char *text, size…
-static struct action change(ledit_view *view, char *text, size_t len);
-static struct action move_to_eol(ledit_view *view, char *text, size_t len);
-static struct action mark_line(ledit_view *view, char *text, size_t len);
-static struct action jump_to_mark(ledit_view *view, char *text, size_t len);
-static struct action next_word(ledit_view *view, char *text, size_t len);
-static struct action next_word_end(ledit_view *view, char *text, size_t len);
-static struct action next_bigword(ledit_view *view, char *text, size_t len);
-static struct action next_bigword_end(ledit_view *view, char *text, size_t len…
-static struct action prev_word(ledit_view *view, char *text, size_t len);
-static struct action prev_bigword(ledit_view *view, char *text, size_t len);
-static struct action append_after_eol(ledit_view *view, char *text, size_t len…
-static struct action append_after_cursor(ledit_view *view, char *text, size_t …
-static struct action append_line_above(ledit_view *view, char *text, size_t le…
-static struct action append_line_below(ledit_view *view, char *text, size_t le…
-static struct action find_next_char_forwards(ledit_view *view, char *text, siz…
-static struct action find_next_char_backwards(ledit_view *view, char *text, si…
-static struct action find_char_forwards(ledit_view *view, char *text, size_t l…
-static struct action find_char_backwards(ledit_view *view, char *text, size_t …
-static struct action change_to_eol(ledit_view *view, char *text, size_t len);
-static struct action delete_to_eol(ledit_view *view, char *text, size_t len);
-static struct action delete_chars_forwards(ledit_view *view, char *text, size_…
-static struct action delete_chars_backwards(ledit_view *view, char *text, size…
-static struct action yank(ledit_view *view, char *text, size_t len);
-static struct action yank_lines(ledit_view *view, char *text, size_t len);
-static struct action replace(ledit_view *view, char *text, size_t len);
-static struct action cursor_to_first_non_ws(ledit_view *view, char *text, size…
-static struct action join_lines(ledit_view *view, char *text, size_t len);
-static struct action insert_at_beginning(ledit_view *view, char *text, size_t …
-static struct action toggle_hard_line_based(ledit_view *view, char *text, size…
-
-/* FIXME: maybe sort these and use binary search
- -> but that would mess with the catch-all keys */
-static struct key keys_en[] = {
- {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &bac…
- {NULL, 0, XK_Left, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, 0, XK_Right, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|K…
- {NULL, 0, XK_Up, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {NULL, 0, XK_Down, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, XK_ANY_MOD, XK_Return, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN…
- {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &delete…
- {NULL, 0, XK_Escape, NORMAL|VISUAL|INSERT, KEY_ANY, KEY_ENSURE_CURSOR_…
- {"i", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter_…
- {"h", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"l", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"j", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"k", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"h", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"t", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &toggle_hard_…
- {NULL, 0, XK_space, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUM…
- {"j", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"n", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"p", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &push…
- {"1", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"2", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"3", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"4", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"5", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"6", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"7", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"8", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"9", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"x", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &de…
- {"X", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &de…
- {"d", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"y", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"Y", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &ya…
- {"c", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"v", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter_visual},
- {"o", 0, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &switch_select…
- {"c", ControlMask, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &cli…
- {"v", ControlMask, 0, INSERT, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &cli…
- {"g", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &show_line},
- {":", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &enter_commandedit},
- {"?", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_backward},
- {"/", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_forward},
- {"n", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_ne…
- {"N", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_pr…
- {"u", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &un…
- {"U", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &re…
- {".", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &re…
- {"z", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &undo…
- {"y", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &redo…
- {"b", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"f", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"e", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"y", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"d", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"u", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"$", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"w", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"e", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"W", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"E", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"b", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"B", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"G", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"J", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &jo…
- {"I", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &insert_at_beg…
- {"p", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_normal},
- {"P", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_normal_…
- {"A", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_after_…
- {"a", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_after_…
- {"O", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line_a…
- {"o", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line_b…
- {"m", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &mark_line},
- {"'", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"C", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &change_to_eol…
- {"D", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &delete_to_eol…
- {"r", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &replace},
- {"^", 0, 0, NORMAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CURSOR_SHO…
- {"t", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"T", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"f", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"F", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"", 0, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &insert_mode_inse…
-};
-
-static struct key keys_de[] = {
- {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &bac…
- {NULL, 0, XK_Left, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, 0, XK_Right, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|K…
- {NULL, 0, XK_Up, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {NULL, 0, XK_Down, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, XK_ANY_MOD, XK_Return, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN…
- {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &delete…
- {NULL, 0, XK_Escape, NORMAL|VISUAL|INSERT, KEY_ANY, KEY_ENSURE_CURSOR_…
- {"i", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter_…
- {"h", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"l", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"j", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"k", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KEY…
- {"h", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"t", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &toggle_hard_…
- {NULL, 0, XK_space, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUM…
- {"j", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"n", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"p", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_N…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &push…
- {"1", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"2", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"3", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"4", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"5", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"6", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"7", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"8", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"9", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"x", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &de…
- {"X", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &de…
- {"d", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"z", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"Z", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &ya…
- {"c", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"v", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter_visual},
- {"o", 0, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &switch_select…
- {"c", ControlMask, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &cli…
- {"v", ControlMask, 0, INSERT, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &cli…
- {"g", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &show_line},
- {"Ö", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &enter_commandedit},
- {"_", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_backward},
- {"-", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_forward},
- {"n", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_ne…
- {"N", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_pr…
- {"u", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &un…
- {"U", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &re…
- {".", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &re…
- {"y", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &undo…
- {"z", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &redo…
- {"b", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"f", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"e", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"z", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"d", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"u", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_…
- {"$", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"w", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"e", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"W", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"E", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"b", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"B", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"G", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"J", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &jo…
- {"I", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &insert_at_beg…
- {"p", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_normal},
- {"P", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_normal_…
- {"A", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_after_…
- {"a", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_after_…
- {"O", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line_a…
- {"o", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line_b…
- {"m", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &mark_line},
- {"ä", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CU…
- {"C", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &change_to_eol…
- {"D", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &delete_to_eol…
- {"r", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &replace},
- {"&", 0, 0, NORMAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CURSOR_SHO…
- {"t", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"T", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"f", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"F", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"", 0, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &insert_mode_inse…
-};
-
-static struct key keys_ur[] = {
- {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &bac…
- {NULL, 0, XK_Left, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, 0, XK_Right, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|K…
- {NULL, 0, XK_Up, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {NULL, 0, XK_Down, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, XK_ANY_MOD, XK_Return, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN…
- {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &delete…
- {NULL, 0, XK_Escape, NORMAL|VISUAL|INSERT, KEY_ANY, KEY_ENSURE_CURSOR_…
- {"ی", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter…
- {"ح", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KE…
- {"ل", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KE…
- {"ج", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KE…
- {"ک", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, KE…
- {"ح", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {"ت", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &toggle_hard…
- {NULL, 0, XK_space, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUM…
- {"ج", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {"ن", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {"پ", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &push…
- {"1", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"2", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"3", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"4", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"5", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"6", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"7", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"8", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"9", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"ش", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &d…
- {"ژ", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &d…
- {"د", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ے", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"َ", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &y…
- {"چ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ط", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter_visual…
- {"ہ", 0, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &switch_selec…
- {"چ", ControlMask, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &cl…
- {"ط", ControlMask, 0, INSERT, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &cl…
- {"گ", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &show_line},
- {":", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &enter_commandedit},
- {"؟", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_backward},
- {"/", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_forward},
- {"ن", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_n…
- {"ں", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_p…
- {"ء", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &u…
- {"ئ", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &r…
- {"۔", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &r…
- {"ز", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &und…
- {"َ", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &red…
- {"ب", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR…
- {"ف", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR…
- {"ع", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR…
- {"ے", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR…
- {"د", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR…
- {"ء", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR…
- {"$", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"و", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ع", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ؤ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ٰ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ب", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {".", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KEY…
- {"غ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ض", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &j…
- {"ِ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &insert_at_be…
- {"پ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_normal…
- {"ُ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_normal…
- {"آ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_after…
- {"ا", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_after…
- {"ۃ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line_…
- {"ہ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line_…
- {"م", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &mark_line},
- {"'", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"ث", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &change_to_eo…
- {"ڈ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &delete_to_eo…
- {"ر", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &replace},
- {"^", 0, 0, NORMAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CURSOR_SHO…
- {"ت", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ٹ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ف", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"ّ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, KE…
- {"", 0, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &insert_mode_inse…
-};
-
-static struct key keys_hi[] = {
- {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &bac…
- {NULL, 0, XK_Left, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, 0, XK_Right, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|K…
- {NULL, 0, XK_Up, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_…
- {NULL, 0, XK_Down, VISUAL|INSERT|NORMAL, KEY_NONE|KEY_MOTIONALLOWED|KE…
- {NULL, XK_ANY_MOD, XK_Return, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN…
- {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &delete…
- {NULL, 0, XK_Escape, NORMAL|VISUAL|INSERT, KEY_ANY, KEY_ENSURE_CURSOR_…
- {"ि", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &ente…
- {"ह", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, K…
- {"ल", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, K…
- {"ज", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, K…
- {"क", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUMBER, K…
- {"ह", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY…
- {"त", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &toggle_har…
- {NULL, 0, XK_space, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY_NUM…
- {"ज", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY…
- {"न", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY…
- {"प", ControlMask, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED|KEY…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"0", 0, 0, NORMAL|VISUAL, KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &push…
- {"1", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"2", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"3", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"4", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"5", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"6", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"7", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"8", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"9", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_NUMBERALLOWED, KEY…
- {"्", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &…
- {"ॉ", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &…
- {"द", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"य", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ञ", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &…
- {"च", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ड", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &enter_visua…
- {"ो", 0, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &switch_sele…
- {"च", ControlMask, 0, VISUAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &c…
- {"ड", ControlMask, 0, INSERT, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &c…
- {"ग", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_NONE, &show_line},
- {":", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &enter_commandedit},
- {"?", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_backward},
- {"/", 0, 0, NORMAL, KEY_NONE, KEY_NONE, &enter_searchedit_forward},
- {"न", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_…
- {"ण", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &key_search_…
- {"ु", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &…
- {"ू", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &…
- {".", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &re…
- {"श", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &un…
- {"य", ControlMask, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &re…
- {"ब", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSO…
- {"ट", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSO…
- {"े", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSO…
- {"य", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSO…
- {"द", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSO…
- {"ु", ControlMask, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSO…
- {"$", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"व", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"े", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ॐ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ै", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ब", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"भ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"घ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"झ", 0, 0, NORMAL, KEY_NONE|KEY_NUMBER, KEY_ENSURE_CURSOR_SHOWN, &…
- {"ी", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &insert_at_b…
- {"प", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_norma…
- {"फ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &paste_norma…
- {"आ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_afte…
- {"ा", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_afte…
- {"ौ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line…
- {"ो", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &append_line…
- {"म", 0, 0, NORMAL|VISUAL, KEY_NONE, KEY_NONE, &mark_line},
- {"'", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CUR…
- {"छ", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &change_to_e…
- {"ध", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &delete_to_e…
- {"र", 0, 0, NORMAL, KEY_NONE, KEY_ENSURE_CURSOR_SHOWN, &replace},
- {"^", 0, 0, NORMAL, KEY_NONE|KEY_MOTIONALLOWED, KEY_ENSURE_CURSOR_SHO…
- {"त", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"थ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ट", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"ठ", 0, 0, NORMAL|VISUAL, KEY_NONE|KEY_NUMBER|KEY_MOTIONALLOWED, K…
- {"", 0, 0, INSERT, KEY_ANY, KEY_ENSURE_CURSOR_SHOWN, &insert_mode_inse…
-};
-
-GEN_KEY_ARRAY(struct key, keys_en, keys_de, keys_ur, keys_hi);
diff --git a/keys_command.c b/keys_command.c
t@@ -1,3 +1,4 @@
+/* FIXME: remove CHECK_VIEW_LOCKED when it is confirmed that the new system wo…
/* FIXME: Parse commands properly and allow combinations of commands */
#include <stdio.h>
#include <ctype.h>
t@@ -18,7 +19,6 @@
#include "txtbuf.h"
#include "undo.h"
#include "cache.h"
-#include "theme.h"
#include "window.h"
#include "buffer.h"
#include "view.h"
t@@ -27,9 +27,113 @@
#include "util.h"
#include "keys.h"
-#include "keys_config.h"
#include "keys_command.h"
-#include "keys_command_config.h"
+#include "configparser.h"
+
+/*************************************************************************
+ * Declarations for all functions that can be used in the configuration. *
+ *************************************************************************/
+
+static int substitute_yes(ledit_view *view, char *key_text, size_t len, size_t…
+static int substitute_yes_all(ledit_view *view, char *key_text, size_t len, si…
+static int substitute_no(ledit_view *view, char *key_text, size_t len, size_t …
+static int substitute_no_all(ledit_view *view, char *key_text, size_t len, siz…
+static int edit_insert_text(ledit_view *view, char *key_text, size_t len, size…
+static int edit_cursor_left(ledit_view *view, char *key_text, size_t len, size…
+static int edit_cursor_right(ledit_view *view, char *key_text, size_t len, siz…
+static int edit_cursor_to_end(ledit_view *view, char *key_text, size_t len, si…
+static int edit_cursor_to_beginning(ledit_view *view, char *key_text, size_t l…
+static int edit_backspace(ledit_view *view, char *key_text, size_t len, size_t…
+static int edit_delete(ledit_view *view, char *key_text, size_t len, size_t la…
+static int edit_submit(ledit_view *view, char *key_text, size_t len, size_t la…
+static int edit_prevcommand(ledit_view *view, char *key_text, size_t len, size…
+static int edit_nextcommand(ledit_view *view, char *key_text, size_t len, size…
+static int edit_prevsearch(ledit_view *view, char *key_text, size_t len, size_…
+static int edit_nextsearch(ledit_view *view, char *key_text, size_t len, size_…
+static int editsearch_submit(ledit_view *view, char *key_text, size_t len, siz…
+static int editsearchb_submit(ledit_view *view, char *key_text, size_t len, si…
+static int edit_discard(ledit_view *view, char *key_text, size_t len, size_t l…
+
+static int create_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int close_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int handle_write(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int handle_quit(ledit_view *view, char *cmd, size_t l1, size_t l2);
+static int handle_write_quit(ledit_view *view, char *cmd, size_t l1, size_t l2…
+static int handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2…
+
+/***********************************************
+ * String-function mapping for config parsing. *
+ ***********************************************/
+
+typedef enum {
+ KEY_FLAG_NONE = 0,
+ KEY_FLAG_JUMP_TO_CURSOR = 1,
+ KEY_FLAG_LOCK_ALLOWED = 2
+} command_key_cb_flags;
+
+typedef enum {
+ CMD_FLAG_NONE = 0,
+ CMD_FLAG_OPTIONAL_RANGE = 1,
+ CMD_FLAG_LOCK_ALLOWED = 2
+} command_cb_flags;
+
+typedef int (*command_key_cb_func)(ledit_view *, char *, size_t, size_t);
+struct command_key_cb {
+ char *text;
+ command_key_cb_func func;
+ command_key_cb_flags flags;
+ command_mode allowed_modes;
+};
+
+typedef int (*command_cb_func)(ledit_view *view, char *cmd, size_t l1, size_t …
+struct command_cb {
+ char *text;
+ command_cb_func func;
+ command_cb_flags flags;
+};
+
+int
+command_key_cb_modemask_is_valid(command_key_cb *cb, command_mode modes) {
+ return (~cb->allowed_modes & modes) == 0;
+}
+
+static command_key_cb command_key_cb_map[] = {
+ {"edit-backspace", &edit_backspace, KEY_FLAG_LOCK_ALLOWED, CMD_EDIT|CM…
+ {"edit-cursor-left", &edit_cursor_left, KEY_FLAG_LOCK_ALLOWED, CMD_EDI…
+ {"edit-cursor-right", &edit_cursor_right, KEY_FLAG_LOCK_ALLOWED, CMD_E…
+ {"edit-cursor-to-beginning", &edit_cursor_to_beginning, KEY_FLAG_LOCK_…
+ {"edit-cursor-to-end", &edit_cursor_to_end, KEY_FLAG_LOCK_ALLOWED, CMD…
+ {"edit-delete", &edit_delete, KEY_FLAG_LOCK_ALLOWED, CMD_EDIT|CMD_EDIT…
+ {"edit-discard", &edit_discard, KEY_FLAG_LOCK_ALLOWED, CMD_EDIT|CMD_ED…
+ {"edit-insert-text", &edit_insert_text, KEY_FLAG_LOCK_ALLOWED, CMD_EDI…
+ {"edit-next-command", &edit_nextcommand, KEY_FLAG_LOCK_ALLOWED, CMD_ED…
+ {"edit-next-search", &edit_nextsearch, KEY_FLAG_LOCK_ALLOWED, CMD_EDIT…
+ {"edit-previous-command", &edit_prevcommand, KEY_FLAG_LOCK_ALLOWED, CM…
+ {"edit-previous-search", &edit_prevsearch, KEY_FLAG_LOCK_ALLOWED, CMD_…
+ {"edit-submit", &edit_submit, KEY_FLAG_LOCK_ALLOWED, CMD_EDIT},
+ {"edit-submit-backwards-search", &editsearchb_submit, KEY_FLAG_LOCK_AL…
+ {"edit-submit-search", &editsearch_submit, KEY_FLAG_LOCK_ALLOWED, CMD_…
+ {"substitute-no", &substitute_no, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOC…
+ {"substitute-no-all", &substitute_no_all, KEY_FLAG_JUMP_TO_CURSOR|KEY_…
+ {"substitute-yes", &substitute_yes, KEY_FLAG_JUMP_TO_CURSOR, CMD_SUBST…
+ {"substitute-yes-all", &substitute_yes_all, KEY_FLAG_JUMP_TO_CURSOR, C…
+};
+
+static command_cb command_cb_map[] = {
+ {"close-view", &close_view, CMD_FLAG_LOCK_ALLOWED},
+ {"create-view", &create_view, CMD_FLAG_LOCK_ALLOWED},
+ {"quit", &handle_quit, CMD_FLAG_LOCK_ALLOWED},
+ {"substitute", &handle_substitute, CMD_FLAG_OPTIONAL_RANGE},
+ {"write", &handle_write, CMD_FLAG_OPTIONAL_RANGE|CMD_FLAG_LOCK_ALLOWED…
+ {"write-quit", &handle_write_quit, CMD_FLAG_OPTIONAL_RANGE|CMD_FLAG_LO…
+};
+
+GEN_CB_MAP_HELPERS(command_key_cb_map, command_key_cb, text)
+GEN_CB_MAP_HELPERS(command_cb_map, command_cb, text)
+
+/***************************************************
+ * General global variables and utility functions. *
+ ***************************************************/
static struct {
char *search;
t@@ -99,20 +203,17 @@ view_locked_error(ledit_view *view) {
#define CHECK_VIEW_LOCKED(view) if (view->lock_text) return view_locked_error(…
-static int create_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
-static int close_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
-static int handle_write(ledit_view *view, char *cmd, size_t l1, size_t l2);
-static int handle_quit(ledit_view *view, char *cmd, size_t l1, size_t l2);
-static int handle_write_quit(ledit_view *view, char *cmd, size_t l1, size_t l2…
-static int handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2…
+/********************************************************************
+ * Functions for handling commands typed in line editor (:w, etc.). *
+ ********************************************************************/
+
static int parse_range(
- ledit_view *view, char *cmd, size_t len, char **cmd_ret,
+ ledit_view *view, char *cmd, size_t len, size_t *idx_ret,
size_t *line1_ret, size_t *line2_ret, int *l1_valid, int *l2_valid,
char **errstr_ret
);
-static int handle_cmd(ledit_view *view, char *cmd, size_t len);
+static int handle_cmd(ledit_view *view, char *cmd, size_t len, size_t lang_ind…
-/* FIXME: remove command name before passing to handlers */
static int
handle_write(ledit_view *view, char *cmd, size_t l1, size_t l2) {
(void)l1;
t@@ -120,7 +221,6 @@ handle_write(ledit_view *view, char *cmd, size_t l1, size_…
/* FIXME: allow writing only part of file */
char *filename = view->buffer->filename;
int stored = 1;
- cmd++; /* remove 'w' */
int force = 0;
if (*cmd == '!') {
force = 1;
t@@ -132,7 +232,7 @@ handle_write(ledit_view *view, char *cmd, size_t l1, size_…
stored = 0;
}
/* FIXME: file locks */
- char *errstr;
+ char *errstr = NULL;
if (filename) {
struct stat sb;
/* There technically is a race between checking stat and actua…
t@@ -176,7 +276,6 @@ static int
handle_quit(ledit_view *view, char *cmd, size_t l1, size_t l2) {
(void)l1;
(void)l2;
- cmd++;
int force = 0;
if (*cmd == '!')
force = 1;
t@@ -194,7 +293,7 @@ create_view(ledit_view *view, char *cmd, size_t l1, size_t…
(void)cmd;
(void)l1;
(void)l2;
- buffer_add_view(view->buffer, view->theme, view->mode, view->cur_line,…
+ buffer_add_view(view->buffer, view->mode, view->cur_line, view->cur_in…
return 0;
}
t@@ -205,7 +304,6 @@ close_view(ledit_view *view, char *cmd, size_t l1, size_t …
(void)l2;
/* FIXME: This will lead to problems if I add something that
requires access to the view after the command is handled. */
- cmd++;
int force = 0;
if (*cmd == '!')
force = 1;
t@@ -220,7 +318,7 @@ close_view(ledit_view *view, char *cmd, size_t l1, size_t …
static int
handle_write_quit(ledit_view *view, char *cmd, size_t l1, size_t l2) {
- handle_write(view, cmd + 1, l1, l2);
+ handle_write(view, cmd, l1, l2);
ledit_cleanup();
exit(0);
return 0;
t@@ -328,7 +426,6 @@ substitute_all_remaining(ledit_view *view) {
static int
handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2) {
CHECK_VIEW_LOCKED(view);
- cmd++; /* remove 's' at beginning */
size_t len = strlen(cmd);
char *sep = NULL;
if (len == 0) goto error;
t@@ -399,34 +496,19 @@ enum cmd_type {
CMD_OPTIONAL_RANGE
};
-static const struct {
- char *cmd;
- enum cmd_type type;
- int (*handler)(ledit_view *view, char *cmd, size_t l1, size_t l2);
-} cmds[] = {
- {"wq", CMD_OPTIONAL_RANGE, &handle_write_quit},
- {"w", CMD_OPTIONAL_RANGE, &handle_write},
- {"q", CMD_NORMAL, &handle_quit},
- {"v", CMD_NORMAL, &create_view},
- {"c", CMD_NORMAL, &close_view},
- {"s", CMD_OPTIONAL_RANGE, &handle_substitute}
-};
-
/*
. current line
$ last line
% all lines
*/
-/* FIXME: ACTUALLY USE LEN!!! */
/* NOTE: Marks are only recognized here if they are one unicode character! */
/* NOTE: Only the line range of the selection is used at the moment. */
static int
parse_range(
- ledit_view *view, char *cmd, size_t len, char **cmd_ret,
+ ledit_view *view, char *cmd, size_t len, size_t *idx_ret,
size_t *line1_ret, size_t *line2_ret, int *l1_valid, int *l2_valid,
char **errstr_ret) {
- (void)len;
*errstr_ret = "";
enum {
START_LINENO = 1,
t@@ -437,8 +519,10 @@ parse_range(
size_t l1 = 0, l2 = 0;
*l1_valid = 0;
*l2_valid = 0;
- char *c = cmd;
- while (*c != '\0') {
+ size_t cur = 0;
+ char *c;
+ while (cur < len) {
+ c = &cmd[cur];
if (isdigit(*c)) {
if (s & IN_LINENO) {
size_t *final = &l2;
t@@ -466,22 +550,20 @@ parse_range(
s = IN_LINENO;
}
} else if (*c == '\'' && (s & START_LINENO)) {
- if (c[1] == '\0' || c[2] == '\0') {
+ if (len - cur <= 2) {
*errstr_ret = "Invalid range";
return 1;
}
- char *aftermark = next_utf8(c + 2);
- size_t marklen = aftermark - (c + 1);
+ size_t aftermark_idx = next_utf8_len(c + 2, len - cur …
+ size_t marklen = aftermark_idx - (cur + 1);
size_t l, b;
- if (!strncmp(c + 1, "<", strlen("<")) && view->sel_val…
+ if (*(c + 1) == '<' && view->sel_valid) {
l = view->sel.line1 < view->sel.line2 ? view->…
- } else if (!strncmp(c + 1, ">", strlen(">")) && view->…
+ } else if (*(c + 1) == '>' && view->sel_valid) {
l = view->sel.line1 > view->sel.line2 ? view->…
- } else {
- if (buffer_get_mark(view->buffer, c + 1, markl…
- *errstr_ret = "Invalid mark";
- return 1;
- }
+ } else if (buffer_get_mark(view->buffer, c + 1, markle…
+ *errstr_ret = "Invalid mark";
+ return 1;
}
if (!*l1_valid) {
l1 = l + 1;
t@@ -490,7 +572,7 @@ parse_range(
l2 = l + 1;
*l2_valid = 1;
}
- c = aftermark;
+ cur = aftermark_idx;
s = 0;
continue;
} else if (*c == ',' && !(s & START_RANGE)) {
t@@ -505,7 +587,7 @@ parse_range(
l1 = 1;
l2 = view->lines_num;
*l1_valid = *l2_valid = 1;
- c++;
+ cur++;
s = 0;
break;
} else {
t@@ -543,7 +625,7 @@ parse_range(
} else {
break;
}
- c++;
+ cur++;
}
if ((!*l1_valid || !*l2_valid) && !(s & START_RANGE)) {
*errstr_ret = "Invalid range";
t@@ -553,7 +635,7 @@ parse_range(
*errstr_ret = "Invalid line number in range";
return 1;
}
- *cmd_ret = c;
+ *idx_ret = cur;
/* ranges are given 1-indexed by user */
*line1_ret = l1 - 1;
*line2_ret = l2 - 1;
t@@ -561,36 +643,58 @@ parse_range(
}
static int
-handle_cmd(ledit_view *view, char *cmd, size_t len) {
+handle_cmd(ledit_view *view, char *cmd, size_t len, size_t lang_index) {
if (len < 1)
return 0;
push_cmdhistory(cmd, len);
- char *c;
size_t l1, l2;
int l1_valid, l2_valid;
char *errstr;
- if (parse_range(view, cmd, len, &c, &l1, &l2, &l1_valid, &l2_valid, &e…
+ size_t start_idx;
+ if (parse_range(view, cmd, len, &start_idx, &l1, &l2, &l1_valid, &l2_v…
window_show_message(view->window, errstr, -1);
return 0;
}
+ if (start_idx >= len) {
+ window_show_message(view->window, "Invalid command", -1);
+ return 0;
+ }
+ size_t rem_len = len - start_idx;
+ char *cur_str = cmd + start_idx;
int range_given = l1_valid && l2_valid;
if (!range_given) {
l1 = l2 = view->cur_line;
}
- for (size_t i = 0; i < LENGTH(cmds); i++) {
- if (!strncmp(cmds[i].cmd, c, strlen(cmds[i].cmd)) &&
- (!range_given || cmds[i].type == CMD_OPTIONAL_RANGE)) {
- return cmds[i].handler(view, c, l1, l2);
+ command_array *cur_cmds = config_get_commands(lang_index);
+ char *cmd_text;
+ size_t text_len;
+ for (size_t i = 0; i < cur_cmds->num_cmds; i++) {
+ cmd_text = cur_cmds->cmds[i].text;
+ text_len = strlen(cmd_text);
+ if (rem_len < text_len)
+ continue;
+ if (!strncmp(cmd_text, cur_str, text_len)) {
+ if (range_given && !(cur_cmds->cmds[i].cb->flags & CMD…
+ window_show_message(view->window, "Command doe…
+ return 0;
+ } else if (view->lock_text && !(cur_cmds->cmds[i].cb->…
+ window_show_message(view->window, view->lock_t…
+ return 0;
+ }
+ return cur_cmds->cmds[i].cb->func(view, cur_str + text…
}
}
window_show_message(view->window, "Invalid command", -1);
return 0;
}
+/***********************************
+ * Functions called on keypresses. *
+ ***********************************/
+
static int
-substitute_yes(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+substitute_yes(ledit_view *view, char *key_text, size_t len, size_t lang_index…
+ (void)key_text; (void)len; (void)lang_index;
substitute_single(view);
buffer_recalc_line(view->buffer, sub_state.line);
if (!sub_state.global) {
t@@ -606,18 +710,16 @@ substitute_yes(ledit_view *view, char *key_text, size_t …
}
static int
-substitute_yes_all(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+substitute_yes_all(ledit_view *view, char *key_text, size_t len, size_t lang_i…
+ (void)key_text; (void)len; (void)lang_index;
substitute_all_remaining(view);
show_num_substituted(view);
return 0;
}
static int
-substitute_no(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+substitute_no(ledit_view *view, char *key_text, size_t len, size_t lang_index)…
+ (void)key_text; (void)len; (void)lang_index;
if (!sub_state.global) {
sub_state.line++;
sub_state.byte = 0;
t@@ -631,16 +733,16 @@ substitute_no(ledit_view *view, char *key_text, size_t l…
}
static int
-substitute_no_all(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+substitute_no_all(ledit_view *view, char *key_text, size_t len, size_t lang_in…
+ (void)key_text; (void)len; (void)lang_index;
buffer_unlock_all_views(view->buffer);
show_num_substituted(view);
return 0;
}
static int
-edit_insert_text(ledit_view *view, char *key_text, size_t len) {
+edit_insert_text(ledit_view *view, char *key_text, size_t len, size_t lang_ind…
+ (void)lang_index;
/* FIXME: overflow */
window_insert_bottom_bar_text(view->window, key_text, len);
window_set_bottom_bar_cursor(
t@@ -650,57 +752,50 @@ edit_insert_text(ledit_view *view, char *key_text, size_…
}
static int
-edit_cursor_to_end(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_cursor_to_end(ledit_view *view, char *key_text, size_t len, size_t lang_i…
+ (void)key_text; (void)len; (void)lang_index;
window_bottom_bar_cursor_to_end(view->window);
return 1;
}
static int
-edit_cursor_to_beginning(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_cursor_to_beginning(ledit_view *view, char *key_text, size_t len, size_t …
+ (void)key_text; (void)len; (void)lang_index;
window_bottom_bar_cursor_to_beginning(view->window);
return 1;
}
static int
-edit_cursor_left(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_cursor_left(ledit_view *view, char *key_text, size_t len, size_t lang_ind…
+ (void)key_text; (void)len; (void)lang_index;
window_move_bottom_bar_cursor(view->window, -1);
return 1;
}
static int
-edit_cursor_right(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_cursor_right(ledit_view *view, char *key_text, size_t len, size_t lang_in…
+ (void)key_text; (void)len; (void)lang_index;
window_move_bottom_bar_cursor(view->window, 1);
return 1;
}
static int
-edit_backspace(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_backspace(ledit_view *view, char *key_text, size_t len, size_t lang_index…
+ (void)key_text; (void)len; (void)lang_index;
window_delete_bottom_bar_char(view->window, -1);
return 1;
}
static int
-edit_delete(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_delete(ledit_view *view, char *key_text, size_t len, size_t lang_index) {
+ (void)key_text; (void)len; (void)lang_index;
window_delete_bottom_bar_char(view->window, 1);
return 1;
}
static int
-edit_submit(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_submit(ledit_view *view, char *key_text, size_t len, size_t lang_index) {
+ (void)key_text; (void)len;
window_set_bottom_bar_text_shown(view->window, 0);
char *text = window_get_bottom_bar_text(view->window);
int min_pos = window_get_bottom_bar_min_pos(view->window);
t@@ -714,15 +809,14 @@ edit_submit(ledit_view *view, char *key_text, size_t len…
}
/* FIXME: this is hacky */
char *cmd = ledit_strndup(text, textlen);
- int ret = handle_cmd(view, cmd, (size_t)textlen);
+ int ret = handle_cmd(view, cmd, (size_t)textlen, lang_index);
free(cmd);
return ret;
}
static int
-edit_prevcommand(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_prevcommand(ledit_view *view, char *key_text, size_t len, size_t lang_ind…
+ (void)key_text; (void)len; (void)lang_index;
if (cmdhistory.cur > 0) {
cmdhistory.cur--;
window_set_bottom_bar_realtext(view->window, cmdhistory.cmds[c…
t@@ -732,9 +826,8 @@ edit_prevcommand(ledit_view *view, char *key_text, size_t …
}
static int
-edit_nextcommand(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_nextcommand(ledit_view *view, char *key_text, size_t len, size_t lang_ind…
+ (void)key_text; (void)len; (void)lang_index;
if (cmdhistory.len > 0 && cmdhistory.cur < cmdhistory.len - 1) {
cmdhistory.cur++;
window_set_bottom_bar_realtext(view->window, cmdhistory.cmds[c…
t@@ -747,9 +840,8 @@ edit_nextcommand(ledit_view *view, char *key_text, size_t …
}
static int
-edit_prevsearch(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_prevsearch(ledit_view *view, char *key_text, size_t len, size_t lang_inde…
+ (void)key_text; (void)len; (void)lang_index;
if (searchhistory.cur > 0) {
searchhistory.cur--;
window_set_bottom_bar_realtext(view->window, searchhistory.cmd…
t@@ -759,9 +851,8 @@ edit_prevsearch(ledit_view *view, char *key_text, size_t l…
}
static int
-edit_nextsearch(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+edit_nextsearch(ledit_view *view, char *key_text, size_t len, size_t lang_inde…
+ (void)key_text; (void)len; (void)lang_index;
if (searchhistory.len > 0 && searchhistory.cur < searchhistory.len - 1…
searchhistory.cur++;
window_set_bottom_bar_realtext(view->window, searchhistory.cmd…
t@@ -795,9 +886,8 @@ search_prev(ledit_view *view) {
}
static int
-editsearch_submit(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+editsearch_submit(ledit_view *view, char *key_text, size_t len, size_t lang_in…
+ (void)key_text; (void)len; (void)lang_index;
window_set_bottom_bar_text_shown(view->window, 0);
char *text = window_get_bottom_bar_text(view->window);
int min_pos = window_get_bottom_bar_min_pos(view->window);
t@@ -818,9 +908,8 @@ editsearch_submit(ledit_view *view, char *key_text, size_t…
}
static int
-editsearchb_submit(ledit_view *view, char *key_text, size_t len) {
- (void)key_text;
- (void)len;
+editsearchb_submit(ledit_view *view, char *key_text, size_t len, size_t lang_i…
+ (void)key_text; (void)len; (void)lang_index;
window_set_bottom_bar_text_shown(view->window, 0);
char *text = window_get_bottom_bar_text(view->window);
int min_pos = window_get_bottom_bar_min_pos(view->window);
t@@ -841,9 +930,8 @@ editsearchb_submit(ledit_view *view, char *key_text, size_…
}
static int
-edit_discard(ledit_view *view, char *key_text, size_t len) {
- (void)view;
- (void)key_text;
+edit_discard(ledit_view *view, char *key_text, size_t len, size_t lang_index) {
+ (void)view; (void)key_text; (void)lang_index;
(void)len;
window_set_bottom_bar_text_shown(view->window, 0);
return 0;
t@@ -854,28 +942,46 @@ command_key_handler(ledit_view *view, XEvent *event, int…
char buf[64];
KeySym sym;
int n;
- struct key *cur_keys = keys[lang_index].keys;
- int num_keys = keys[lang_index].num_keys;
+ command_key_array *cur_keys = config_get_command_keys(lang_index);
+ size_t num_keys = cur_keys->num_keys;
unsigned int key_state = event->xkey.state;
preprocess_key(view->window, event, &sym, buf, sizeof(buf), &n);
- int grabkey = 1;
- for (int i = 0; i < num_keys; i++) {
- if (cur_keys[i].text) {
+ int grabkey = 1, found = 0;
+ command_key_cb_flags flags = KEY_FLAG_NONE;
+ for (size_t i = 0; i < num_keys; i++) {
+ if (cur_keys->keys[i].text) {
if (n > 0 &&
- (cur_keys[i].type == view->cur_command_type) &&
- ((!strncmp(cur_keys[i].text, buf, n) &&
- match_key(cur_keys[i].mods, key_state & ~ShiftMa…
- cur_keys[i].text[0] == '\0')) {
- grabkey = cur_keys[i].func(view, buf, (size_t)…
+ (cur_keys->keys[i].modes & view->cur_command_type)…
+ ((!strncmp(cur_keys->keys[i].text, buf, n) &&
+ match_key(cur_keys->keys[i].mods, key_state & ~S…
+ cur_keys->keys[i].text[0] == '\0')) {
+ flags = cur_keys->keys[i].cb->flags;
+ if (!(flags & KEY_FLAG_LOCK_ALLOWED) && view->…
+ (void)view_locked_error(view);
+ grabkey = 0;
+ break;
+ }
+ grabkey = cur_keys->keys[i].cb->func(view, buf…
+ found = 1;
+ break;
+ }
+ } else if ((cur_keys->keys[i].modes & view->cur_command_type) …
+ (cur_keys->keys[i].keysym == sym) &&
+ (match_key(cur_keys->keys[i].mods, key_state))) {
+ flags = cur_keys->keys[i].cb->flags;
+ if (!(flags & KEY_FLAG_LOCK_ALLOWED) && view->lock_tex…
+ (void)view_locked_error(view);
+ grabkey = 0;
break;
}
- } else if ((cur_keys[i].type == view->cur_command_type) &&
- (cur_keys[i].keysym == sym) &&
- (match_key(cur_keys[i].mods, key_state))) {
- grabkey = cur_keys[i].func(view, buf, (size_t)n);
+ grabkey = cur_keys->keys[i].cb->func(view, buf, (size_…
+ found = 1;
break;
}
}
+ if (found && (flags & KEY_FLAG_JUMP_TO_CURSOR))
+ view_ensure_cursor_shown(view);
+ /* FIXME: proper error on invalid key */
if (grabkey)
return (struct action){ACTION_GRABKEY, &command_key_handler};
else
diff --git a/keys_command.h b/keys_command.h
t@@ -3,6 +3,14 @@
#include <X11/Xlib.h>
#include "view.h"
+#include "uglycrap.h"
+
+typedef struct command_key_cb command_key_cb;
+typedef struct command_cb command_cb;
+
+int command_key_cb_modemask_is_valid(command_key_cb *cb, command_mode modes);
+command_key_cb *command_key_cb_map_get_entry(char *text, size_t len);
+command_cb *command_cb_map_get_entry(char *text, size_t len);
/* these are only here so they can also be used by keys_basic */
void search_next(ledit_view *view);
diff --git a/keys_command_config.h b/keys_command_config.h
t@@ -1,196 +0,0 @@
-/*
- * These are the keys used by special commands that require a special key
- * handler. This includes keys used to edit the line entry at the bottom
- * and keys used for confirmation (e.g. when substituting).
- */
-
-static int substitute_yes(ledit_view *view, char *key_text, size_t len);
-static int substitute_yes_all(ledit_view *view, char *key_text, size_t len);
-static int substitute_no(ledit_view *view, char *key_text, size_t len);
-static int substitute_no_all(ledit_view *view, char *key_text, size_t len);
-static int edit_insert_text(ledit_view *view, char *key_text, size_t len);
-static int edit_cursor_left(ledit_view *view, char *key_text, size_t len);
-static int edit_cursor_right(ledit_view *view, char *key_text, size_t len);
-static int edit_cursor_to_end(ledit_view *view, char *key_text, size_t len);
-static int edit_cursor_to_beginning(ledit_view *view, char *key_text, size_t l…
-static int edit_backspace(ledit_view *view, char *key_text, size_t len);
-static int edit_delete(ledit_view *view, char *key_text, size_t len);
-static int edit_submit(ledit_view *view, char *key_text, size_t len);
-static int edit_prevcommand(ledit_view *view, char *key_text, size_t len);
-static int edit_nextcommand(ledit_view *view, char *key_text, size_t len);
-static int edit_prevsearch(ledit_view *view, char *key_text, size_t len);
-static int edit_nextsearch(ledit_view *view, char *key_text, size_t len);
-static int editsearch_submit(ledit_view *view, char *key_text, size_t len);
-static int editsearchb_submit(ledit_view *view, char *key_text, size_t len);
-static int edit_discard(ledit_view *view, char *key_text, size_t len);
-
-struct key {
- char *text; /* for keys that correspond…
- unsigned int mods; /* modifier mask */
- KeySym keysym; /* for other keys, e.g. arr…
- enum ledit_command_type type; /* substitute, etc. */
- int (*func)(ledit_view *, char *, size_t); /* callback function */
-};
-
-/* "" means catch-all, i.e. all keys with text are given to that callback */
-static struct key keys_en[] = {
- {"y", 0, 0, CMD_SUBSTITUTE, &substitute_yes},
- {"Y", 0, 0, CMD_SUBSTITUTE, &substitute_yes_all},
- {"n", 0, 0, CMD_SUBSTITUTE, &substitute_no},
- {"N", 0, 0, CMD_SUBSTITUTE, &substitute_no_all},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDIT, &edit_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCH, &editsearch_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit},
- {NULL, 0, XK_Left, CMD_EDIT, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCH, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCHB, &edit_cursor_left},
- {NULL, 0, XK_Right, CMD_EDIT, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCH, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCHB, &edit_cursor_right},
- {NULL, 0, XK_Up, CMD_EDIT, &edit_prevcommand},
- {NULL, 0, XK_Up, CMD_EDITSEARCH, &edit_prevsearch},
- {NULL, 0, XK_Up, CMD_EDITSEARCHB, &edit_prevsearch},
- {NULL, 0, XK_Down, CMD_EDIT, &edit_nextcommand},
- {NULL, 0, XK_Down, CMD_EDITSEARCH, &edit_nextsearch},
- {NULL, 0, XK_Down, CMD_EDITSEARCHB, &edit_nextsearch},
- {NULL, 0, XK_BackSpace, CMD_EDIT, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCH, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCHB, &edit_backspace},
- {NULL, 0, XK_Delete, CMD_EDIT, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCH, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCHB, &edit_delete},
- {NULL, 0, XK_End, CMD_EDIT, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCH, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCHB, &edit_cursor_to_end},
- {NULL, 0, XK_Home, CMD_EDIT, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCH, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCHB, &edit_cursor_to_beginning},
- {NULL, 0, XK_Escape, CMD_EDIT, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCH, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCHB, &edit_discard},
- {"", 0, 0, CMD_EDIT, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCH, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}
-};
-
-static struct key keys_de[] = {
- {"z", 0, 0, CMD_SUBSTITUTE, &substitute_yes},
- {"Z", 0, 0, CMD_SUBSTITUTE, &substitute_yes_all},
- {"n", 0, 0, CMD_SUBSTITUTE, &substitute_no},
- {"N", 0, 0, CMD_SUBSTITUTE, &substitute_no_all},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDIT, &edit_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCH, &editsearch_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit},
- {NULL, 0, XK_Left, CMD_EDIT, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCH, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCHB, &edit_cursor_left},
- {NULL, 0, XK_Right, CMD_EDIT, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCH, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCHB, &edit_cursor_right},
- {NULL, 0, XK_Up, CMD_EDIT, &edit_prevcommand},
- {NULL, 0, XK_Up, CMD_EDITSEARCH, &edit_prevsearch},
- {NULL, 0, XK_Up, CMD_EDITSEARCHB, &edit_prevsearch},
- {NULL, 0, XK_Down, CMD_EDIT, &edit_nextcommand},
- {NULL, 0, XK_Down, CMD_EDITSEARCH, &edit_nextsearch},
- {NULL, 0, XK_Down, CMD_EDITSEARCHB, &edit_nextsearch},
- {NULL, 0, XK_BackSpace, CMD_EDIT, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCH, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCHB, &edit_backspace},
- {NULL, 0, XK_Delete, CMD_EDIT, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCH, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCHB, &edit_delete},
- {NULL, 0, XK_End, CMD_EDIT, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCH, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCHB, &edit_cursor_to_end},
- {NULL, 0, XK_Home, CMD_EDIT, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCH, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCHB, &edit_cursor_to_beginning},
- {NULL, 0, XK_Escape, CMD_EDIT, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCH, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCHB, &edit_discard},
- {"", 0, 0, CMD_EDIT, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCH, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}
-};
-
-static struct key keys_ur[] = {
- {"ے", 0, 0, CMD_SUBSTITUTE, &substitute_yes},
- {"َ", 0, 0, CMD_SUBSTITUTE, &substitute_yes_all},
- {"ن", 0, 0, CMD_SUBSTITUTE, &substitute_no},
- {"ں", 0, 0, CMD_SUBSTITUTE, &substitute_no_all},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDIT, &edit_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCH, &editsearch_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit},
- {NULL, 0, XK_Left, CMD_EDIT, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCH, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCHB, &edit_cursor_left},
- {NULL, 0, XK_Right, CMD_EDIT, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCH, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCHB, &edit_cursor_right},
- {NULL, 0, XK_Up, CMD_EDIT, &edit_prevcommand},
- {NULL, 0, XK_Up, CMD_EDITSEARCH, &edit_prevsearch},
- {NULL, 0, XK_Up, CMD_EDITSEARCHB, &edit_prevsearch},
- {NULL, 0, XK_Down, CMD_EDIT, &edit_nextcommand},
- {NULL, 0, XK_Down, CMD_EDITSEARCH, &edit_nextsearch},
- {NULL, 0, XK_Down, CMD_EDITSEARCHB, &edit_nextsearch},
- {NULL, 0, XK_BackSpace, CMD_EDIT, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCH, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCHB, &edit_backspace},
- {NULL, 0, XK_Delete, CMD_EDIT, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCH, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCHB, &edit_delete},
- {NULL, 0, XK_End, CMD_EDIT, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCH, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCHB, &edit_cursor_to_end},
- {NULL, 0, XK_Home, CMD_EDIT, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCH, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCHB, &edit_cursor_to_beginning},
- {NULL, 0, XK_Escape, CMD_EDIT, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCH, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCHB, &edit_discard},
- {"", 0, 0, CMD_EDIT, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCH, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}
-};
-
-static struct key keys_hi[] = {
- {"य", 0, 0, CMD_SUBSTITUTE, &substitute_yes},
- {"ञ", 0, 0, CMD_SUBSTITUTE, &substitute_yes_all},
- {"न", 0, 0, CMD_SUBSTITUTE, &substitute_no},
- {"ण", 0, 0, CMD_SUBSTITUTE, &substitute_no_all},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDIT, &edit_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCH, &editsearch_submit},
- {NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit},
- {NULL, 0, XK_Left, CMD_EDIT, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCH, &edit_cursor_left},
- {NULL, 0, XK_Left, CMD_EDITSEARCHB, &edit_cursor_left},
- {NULL, 0, XK_Right, CMD_EDIT, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCH, &edit_cursor_right},
- {NULL, 0, XK_Right, CMD_EDITSEARCHB, &edit_cursor_right},
- {NULL, 0, XK_Up, CMD_EDIT, &edit_prevcommand},
- {NULL, 0, XK_Up, CMD_EDITSEARCH, &edit_prevsearch},
- {NULL, 0, XK_Up, CMD_EDITSEARCHB, &edit_prevsearch},
- {NULL, 0, XK_Down, CMD_EDIT, &edit_nextcommand},
- {NULL, 0, XK_Down, CMD_EDITSEARCH, &edit_nextsearch},
- {NULL, 0, XK_Down, CMD_EDITSEARCHB, &edit_nextsearch},
- {NULL, 0, XK_BackSpace, CMD_EDIT, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCH, &edit_backspace},
- {NULL, 0, XK_BackSpace, CMD_EDITSEARCHB, &edit_backspace},
- {NULL, 0, XK_Delete, CMD_EDIT, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCH, &edit_delete},
- {NULL, 0, XK_Delete, CMD_EDITSEARCHB, &edit_delete},
- {NULL, 0, XK_End, CMD_EDIT, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCH, &edit_cursor_to_end},
- {NULL, 0, XK_End, CMD_EDITSEARCHB, &edit_cursor_to_end},
- {NULL, 0, XK_Home, CMD_EDIT, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCH, &edit_cursor_to_beginning},
- {NULL, 0, XK_Home, CMD_EDITSEARCHB, &edit_cursor_to_beginning},
- {NULL, 0, XK_Escape, CMD_EDIT, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCH, &edit_discard},
- {NULL, 0, XK_Escape, CMD_EDITSEARCHB, &edit_discard},
- {"", 0, 0, CMD_EDIT, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCH, &edit_insert_text},
- {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}
-};
-
-GEN_KEY_ARRAY(struct key, keys_en, keys_de, keys_hi, keys_ur);
diff --git a/keys_config.h b/keys_config.h
t@@ -1,31 +1,182 @@
#ifndef _KEYS_CONFIG_H_
#define _KEYS_CONFIG_H_
+#include "X11/Xlib.h"
+#include "X11/keysym.h"
+
+#include "common.h"
#include "keys.h"
-/*
- * These are the language strings compared with the language strings that
- * xkb gives in order to change the key mapping on layout change events.
- */
-#define KEY_LANGS \
-static char *key_langs[] = { \
- "English (US)", \
- "German", \
- "Urdu (Pakistan)", \
- "Hindi (Bolnagri)" \
-}
-
-#define GEN_KEY_ARRAY(key_struct, en, de, ur, hi) \
-static struct { \
- key_struct *keys; \
- int num_keys; \
-} keys[] = { \
- {en, LENGTH(en)}, \
- {de, LENGTH(de)}, \
- {ur, LENGTH(ur)}, \
- {hi, LENGTH(hi)} \
-}
-
-#define LANG_KEYS(index) &keys[index]
-
-#endif
+/*********************************
+ * Key and command configuration *
+ *********************************/
+
+char *language_default = "English (US)";
+
+/* FIXME: binary search keys */
+struct {
+ char *func_name;
+ char *text;
+ unsigned int mods;
+ KeySym keysym;
+ ledit_mode modes;
+} basic_keys_default[] = {
+ {"backspace", NULL, 0, XK_BackSpace, INSERT},
+ {"cursor-left", NULL, 0, XK_Left, VISUAL|INSERT|NORMAL},
+ {"cursor-right", NULL, 0, XK_Right, VISUAL|INSERT|NORMAL},
+ {"cursor-up", NULL, 0, XK_Up, VISUAL|INSERT|NORMAL},
+ {"cursor-down", NULL, 0, XK_Down, VISUAL|INSERT|NORMAL},
+ {"return-key", NULL, XK_ANY_MOD, XK_Return, INSERT},
+ {"delete-key", NULL, 0, XK_Delete, INSERT},
+ {"escape-key", NULL, 0, XK_Escape, NORMAL|VISUAL|INSERT},
+ {"enter-insert", "i", 0, 0, NORMAL|VISUAL},
+ {"cursor-left", "h", 0, 0, NORMAL|VISUAL},
+ {"cursor-left", "h", ControlMask, 0, NORMAL|VISUAL},
+ {"cursor-right", "l", 0, 0, NORMAL|VISUAL},
+ {"cursor-up", "k", 0, 0, NORMAL|VISUAL},
+ {"cursor-down", "j", 0, 0, NORMAL|VISUAL},
+ {"toggle-hard-line-based", "t", ControlMask, 0, NORMAL|VISUAL}, /* FIX…
+ {"cursor-right", NULL, 0, XK_space, NORMAL|VISUAL},
+ {"cursor-down", "j", ControlMask, 0, NORMAL|VISUAL},
+ {"cursor-down", "n", ControlMask, 0, NORMAL|VISUAL},
+ {"cursor-up", "p", ControlMask, 0, NORMAL|VISUAL},
+ {"key-0", "0", 0, 0, NORMAL|VISUAL},
+ {"push-1", "1", 0, 0, NORMAL|VISUAL},
+ {"push-2", "2", 0, 0, NORMAL|VISUAL},
+ {"push-3", "3", 0, 0, NORMAL|VISUAL},
+ {"push-4", "4", 0, 0, NORMAL|VISUAL},
+ {"push-5", "5", 0, 0, NORMAL|VISUAL},
+ {"push-6", "6", 0, 0, NORMAL|VISUAL},
+ {"push-7", "7", 0, 0, NORMAL|VISUAL},
+ {"push-8", "8", 0, 0, NORMAL|VISUAL},
+ {"push-9", "9", 0, 0, NORMAL|VISUAL},
+ {"delete-forwards", "x", 0, 0, NORMAL},
+ {"delete-backwards", "X", 0, 0, NORMAL},
+ {"delete", "d", 0, 0, NORMAL|VISUAL},
+ {"yank", "y", 0, 0, NORMAL|VISUAL},
+ {"yank-lines", "Y", 0, 0, NORMAL},
+ {"change", "c", 0, 0, NORMAL|VISUAL},
+ {"enter-visual", "v", 0, 0, NORMAL},
+ {"switch-selection-end", "o", 0, 0, VISUAL},
+ {"clipboard-copy", "c", ControlMask, 0, VISUAL},
+ {"clipboard-paste", "v", ControlMask, 0, INSERT},
+ {"show-line", "g", ControlMask, 0, NORMAL|VISUAL},
+ {"enter-commandedit", ":", 0, 0, NORMAL|VISUAL},
+ {"enter-searchedit-backwards", "?", 0, 0, NORMAL},
+ {"enter-searchedit-forwards", "/", 0, 0, NORMAL},
+ {"search-next", "n", 0, 0, NORMAL},
+ {"search-previous", "N", 0, 0, NORMAL},
+ {"undo", "u", 0, 0, NORMAL},
+ {"redo", "U", 0, 0, NORMAL},
+ {"repeat-command", ".", 0, 0, NORMAL}, /* FIXME: only allow after fini…
+ {"undo", "z", ControlMask, 0, INSERT},
+ {"redo", "y", ControlMask, 0, INSERT}, /* FIXME: this is confusing wit…
+ {"screen-up", "b", ControlMask, 0, NORMAL},
+ {"screen-down", "f", ControlMask, 0, NORMAL},
+ {"scroll-with-cursor-down", "e", ControlMask, 0, NORMAL},
+ {"scroll-with-cursor-up", "y", ControlMask, 0, NORMAL},
+ {"scroll-lines-down", "d", ControlMask, 0, NORMAL},
+ {"scroll-lines-up", "u", ControlMask, 0, NORMAL},
+ {"move-to-eol", "$", 0, 0, NORMAL|VISUAL},
+ {"next-word", "w", 0, 0, NORMAL|VISUAL},
+ {"next-word-end", "e", 0, 0, NORMAL|VISUAL},
+ {"next-bigword", "W", 0, 0, NORMAL|VISUAL},
+ {"next-bigword-end", "E", 0, 0, NORMAL|VISUAL},
+ {"previous-word", "b", 0, 0, NORMAL|VISUAL},
+ {"previous-bigword", "B", 0, 0, NORMAL|VISUAL},
+ {"move-to-line", "G", 0, 0, NORMAL|VISUAL},
+ {"join-lines", "J", 0, 0, NORMAL},
+ {"insert-at-beginning", "I", 0, 0, NORMAL},
+ {"paste-normal", "p", 0, 0, NORMAL},
+ {"paste-normal-backwards", "P", 0, 0, NORMAL},
+ {"append-after-eol", "A", 0, 0, NORMAL},
+ {"append-after-cursor", "a", 0, 0, NORMAL},
+ {"append-line-above", "O", 0, 0, NORMAL},
+ {"append-line-below", "o", 0, 0, NORMAL},
+ {"mark-line", "m", 0, 0, NORMAL|VISUAL},
+ {"jump-to-mark", "'", 0, 0, NORMAL|VISUAL},
+ {"change-to-eol", "C", 0, 0, NORMAL},
+ {"delete-to-eol", "D", 0, 0, NORMAL},
+ {"replace", "r", 0, 0, NORMAL},
+ {"cursor-to-first-non-whitespace", "^", 0, 0, NORMAL},
+ {"find-next-char-forwards", "t", 0, 0, NORMAL|VISUAL},
+ {"find-next-char-backwards", "T", 0, 0, NORMAL|VISUAL},
+ {"find-char-forwards", "f", 0, 0, NORMAL|VISUAL},
+ {"find-char-backwards", "F", 0, 0, NORMAL|VISUAL},
+ {"insert-text", "", 0, 0, INSERT}
+};
+
+struct {
+ char *func_name;
+ char *text;
+ unsigned int mods;
+ KeySym keysym;
+ command_mode modes;
+} command_keys_default[] = {
+ {"substitute-yes", "y", 0, 0, CMD_SUBSTITUTE},
+ {"substitute-yes-all", "Y", 0, 0, CMD_SUBSTITUTE},
+ {"substitute-no", "n", 0, 0, CMD_SUBSTITUTE},
+ {"substitute-no-all", "N", 0, 0, CMD_SUBSTITUTE},
+ {"edit-submit", NULL, XK_ANY_MOD, XK_Return, CMD_EDIT},
+ {"edit-submit-search", NULL, XK_ANY_MOD, XK_Return, CMD_EDITSEARCH},
+ {"edit-submit-backwards-search", NULL, XK_ANY_MOD, XK_Return, CMD_EDIT…
+ {"edit-cursor-left", NULL, 0, XK_Left, CMD_EDIT|CMD_EDITSEARCH|CMD_EDI…
+ {"edit-cursor-right", NULL, 0, XK_Right, CMD_EDIT|CMD_EDITSEARCH|CMD_E…
+ {"edit-cursor-right", NULL, 0, XK_Right, CMD_EDIT|CMD_EDITSEARCH|CMD_E…
+ {"edit-previous-command", NULL, 0, XK_Up, CMD_EDIT},
+ {"edit-next-command", NULL, 0, XK_Down, CMD_EDIT},
+ {"edit-previous-search", NULL, 0, XK_Up, CMD_EDITSEARCH|CMD_EDITSEARCH…
+ {"edit-next-search", NULL, 0, XK_Down, CMD_EDITSEARCH|CMD_EDITSEARCHB},
+ {"edit-backspace", NULL, 0, XK_BackSpace, CMD_EDIT|CMD_EDITSEARCH|CMD_…
+ {"edit-delete", NULL, 0, XK_Delete, CMD_EDIT|CMD_EDITSEARCH|CMD_EDITSE…
+ {"edit-cursor-to-end", NULL, 0, XK_End, CMD_EDIT|CMD_EDITSEARCH|CMD_ED…
+ {"edit-cursor-to-beginning", NULL, 0, XK_Home, CMD_EDIT|CMD_EDITSEARCH…
+ {"edit-discard", NULL, 0, XK_Escape, CMD_EDIT|CMD_EDITSEARCH|CMD_EDITS…
+ {"edit-insert-text", "", 0, 0, CMD_EDIT|CMD_EDITSEARCH|CMD_EDITSEARCHB}
+};
+
+struct {
+ char *func_name;
+ char *text;
+} commands_default[] = {
+ {"write-quit", "wg"},
+ {"write", "w"},
+ {"quit", "q"},
+ {"create-view", "v"},
+ {"close-view", "c"},
+ {"substitute", "s"}
+};
+
+/*****************************************
+ * Key and command mapping configuration *
+ *****************************************/
+
+struct mapping {
+ char *from;
+ char *to;
+};
+
+struct language_mapping {
+ char *lang;
+ struct mapping *keys;
+ struct mapping *cmds;
+ size_t keys_len;
+ size_t cmds_len;
+};
+
+struct mapping key_mapping_de[] = {
+ {"z", "y"},
+ {"y", "z"},
+ {"Z", "Y"},
+ {"Y", "Z"},
+ {"Ö", ":"},
+ {"_", "?"},
+ {"-", "/"},
+ {"ä", "'"}
+};
+
+struct language_mapping mappings_default[] = {
+ {"German", key_mapping_de, NULL, LENGTH(key_mapping_de), 0}
+};
+
+#endif /* _KEYS_CONFIG_H_ */
diff --git a/ledit.1 b/ledit.1
t@@ -1,6 +1,6 @@
.\" WARNING: Some parts of this are stolen shamelessly from OpenBSD's
.\" vi(1) manpage!
-.Dd December 26, 2021
+.Dd May 26, 2022
.Dt LEDIT 1
.Os
.Sh NAME
t@@ -8,6 +8,7 @@
.Nd weird text editor
.Sh SYNOPSIS
.Nm
+.Op Fl c Ar config
.Op Ar file
.Sh DESCRIPTION
.Nm
t@@ -45,6 +46,17 @@ that is not the main goal.
.Pp
.Nm
is not a good text editor.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl c Ar config
+Load the configuration file given by
+.Ar config .
+If this option is not specified,
+.Nm
+will attempt to read the configuration file
+.Pa .leditrc
+in the user's home directory before using the defaults.
+.El
.Sh BASIC CONCEPTS
Some terminology should probably be explained in order to understand the
rest of this manual.
t@@ -693,12 +705,6 @@ Also note that the commands which take filenames currentl…
the line as the filename instead of doing any string parsing.
This may be changed in the future.
.Pp
-The commands do not fit in very well with the rest of the program since they
-are hard-coded in English and cannot be remapped in other languages.
-This is because it isn't entirely clear how a remapping would even work
-because the commands are shown on screen, which might look weird, especially
-if they are remapped to non-printable characters.
-.Pp
.Bl -tag -width Ds -compact
.It Xo
.Cm :w
t@@ -819,71 +825,8 @@ Note that the text is pasted at the current cursor positi…
position of the mouse cursor.
The author prefers this way.
.Sh CONFIGURATION
-.Nm
-currently has to be configured entirely by changing header files and
-recompiling.
-This will probably be changed in the future, but there hasn't been
-time for it yet.
-.Pp
-There are five configuration headers:
-.Bl -tag -width Ds
-.It Pa config.h
-This contains several timing parameters that most users will probably
-not need to change.
-.It Pa keys_config.h
-This contains the list of languages for which keys are available.
-The language strings in
-.Va key_langs
-are matched exactly with the strings returned by XKB, which seem to
-sometimes be different on different systems, so they will probably
-need to be configured properly. Also note that there are many
-variants of some keyboard layouts, all with small differences, so
-the mappings will often have to be adjusted slightly.
-.It Pa keys_basic_config.h
-This contains the keys used during regular text editing.
-The first entry in each key is the text that is associated with the text.
-If this is
-.Dv NULL ,
-the third entry, which may contain a symbolic key name, is used for the
-matching instead.
-If the key text is an empty string, it is a catch-all, and the actual
-text is given to the handling function.
-.Pp
-Note that the list of keys is currently traversed from top to bottom,
-so catch-all keys should all be in the end in order to not inferfere
-with other mappings.
-.Pp
-The second entry is a mask of modifier keys that need to be
-pressed during the key press.
-If this is set to
-.Dv XK_ANY_MOD ,
-the modifier keys are ignored.
-.Pp
-The other entries should not be touched unless the actual handling
-function implemented in
-.Pa keys_basic.c
-has been changed.
-.Pp
-Note that the key handling is currently a bit weird, so there might
-be unexpected results sometimes.
-Please report these.
-.It Pa keys_command_config.h
-This is similar to
-.Pa keys_basic_config.h ,
-but contains the keys used during line editing mode or while performing
-commands such as substitution with confirmation.
-.It Pa theme_config.h
-This contains the configuration of the theme.
-The configuration options are described in the file itself.
-.El
-.Pp
-This short explanation of the configuration is not very good currently.
-That will hopefully be changed in the future.
-.Pp
-Note that there are a few actions that are currently hard-coded and cannot
-be configured.
-This includes all mouse actions and using escape to cancel a multi-key
-command.
+See
+.Xr leditrc 5 .
.Sh MISCELLANEOUS
.Nm
includes a fair number of sanity checks (asserts) to make sure some illegal
t@@ -930,7 +873,8 @@ Pango developers decided to hide spaces at the end of a li…
.Sh SEE ALSO
.Xr ed 1 ,
.Xr vi 1 ,
-.Xr vim 1
+.Xr vim 1 ,
+.Xr leditrc 5
.Sh AUTHORS
.An lumidify Aq Mt [email protected]
.Sh BUGS
t@@ -938,8 +882,4 @@ Too many to count.
See
.Sx TINY SUBSET OF BUGS .
.Sh TINY SUBSET OF BUGS
-The keyboard mapping is currently only changed when a keyboard change event
-occurs.
-This means that it always is the default mapping when
-.Nm
-starts, regardless of the current keyboard layout.
+Well, I guess I'm too lazy to collect bugs right now.
diff --git a/ledit.c b/ledit.c
t@@ -10,6 +10,7 @@
/* FIXME: horizontal scrolling (also need cache to avoid too large pixmaps) */
/* TODO: allow extending selection with shift+mouse like in e.g. gtk */
+#include <pwd.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
t@@ -24,8 +25,8 @@
#include <X11/extensions/Xdbe.h>
#include <X11/extensions/XKBrules.h>
+#include "util.h"
#include "view.h"
-#include "theme.h"
#include "buffer.h"
#include "common.h"
#include "window.h"
t@@ -37,6 +38,7 @@
#include "keys.h"
#include "keys_basic.h"
#include "keys_command.h"
+#include "configparser.h"
static void mainloop(void);
static void setup(int argc, char *argv[]);
t@@ -45,10 +47,9 @@ static void redraw(void);
static void change_keyboard(char *lang);
static void key_press(ledit_view *view, XEvent *event);
-ledit_theme *theme = NULL;
ledit_buffer *buffer = NULL;
ledit_common common;
-int cur_lang = 0;
+size_t cur_lang = 0;
static void
mainloop(void) {
t@@ -76,7 +77,7 @@ mainloop(void) {
);
XSync(common.dpy, False);
int running = 1;
- int change_kbd = 0;
+ int change_kbd = 1;
redraw();
/* store last draw time so framerate can be limited */
t@@ -193,13 +194,33 @@ mainloop(void) {
}
}
+extern char *optarg;
+extern int optind;
+
static void
setup(int argc, char *argv[]) {
setlocale(LC_CTYPE, "");
XSetLocaleModifiers("");
+ char c;
+ char *opt_filename = NULL;
+ while ((c = getopt(argc, argv, "c:")) != -1) {
+ switch (c) {
+ case 'c':
+ opt_filename = optarg;
+ break;
+ default:
+ fprintf(stderr, "USAGE: ledit [-c config] [file]\n");
+ exit(1);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
common.dpy = XOpenDisplay(NULL);
common.screen = DefaultScreen(common.dpy);
+ /* FIXME: fallback when no db support */
/* based on http://wili.cc/blog/xdbe.html */
int major, minor;
if (XdbeQueryExtension(common.dpy, &major, &minor)) {
t@@ -233,6 +254,8 @@ setup(int argc, char *argv[]) {
exit(1);
}
common.vis = xvisinfo_match->visual;
+ XFree(xvisinfo_match);
+ XdbeFreeVisualInfo(info);
} else {
fprintf(stderr, "No Xdbe support.\n");
ledit_cleanup();
t@@ -242,15 +265,83 @@ setup(int argc, char *argv[]) {
common.depth = DefaultDepth(common.dpy, common.screen);
common.cm = DefaultColormap(common.dpy, common.screen);
- theme = theme_create(&common);
+ #ifdef LEDIT_DEBUG
+ struct timespec now, elapsed, last;
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ #endif
+
+ char *stat_errstr = NULL, *load_errstr = NULL, *load_default_errstr = …
+ char *cfgfile = NULL;
+ if (!opt_filename) {
+ uid_t uid = getuid();
+ struct passwd *pw = getpwuid(uid);
+ if (!pw)
+ fprintf(stderr, "Unable to determine home directory\n"…
+ else
+ cfgfile = ledit_strcat(pw->pw_dir, "/.leditrc");
+ struct stat cfgst;
+ if (stat(cfgfile, &cfgst)) {
+ free(cfgfile);
+ cfgfile = NULL;
+ }
+ } else {
+ struct stat cfgst;
+ if (stat(opt_filename, &cfgst)) {
+ stat_errstr = print_fmt("Unable to load configuration …
+ fprintf(stderr, "%s\n", stat_errstr);
+ } else {
+ cfgfile = ledit_strdup(opt_filename);
+ }
+ }
+ if (config_loadfile(&common, cfgfile, &load_errstr)) {
+ fprintf(stderr, "%s\n", load_errstr);
+ int failure = 1;
+ if (cfgfile) {
+ /* retry with default config */
+ failure = config_loadfile(&common, NULL, &load_default…
+ }
+ if (failure) {
+ fprintf(stderr, "Unable to load configuration: %s\n", …
+ if (load_default_errstr)
+ fprintf(stderr, "Also unable to load default c…
+ free(stat_errstr);
+ free(load_errstr);
+ free(load_default_errstr);
+ ledit_cleanup();
+ exit(1);
+ }
+ }
+ free(load_default_errstr);
+ free(cfgfile);
+
+ #ifdef LEDIT_DEBUG
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ledit_timespecsub(&now, &last, &elapsed);
+ ledit_debug_fmt("Time to load config (total): %lld seconds, %ld nanose…
+ #endif
+
buffer = buffer_create(&common);
- buffer_add_view(buffer, theme, NORMAL, 0, 0, 0);
+ buffer_add_view(buffer, NORMAL, 0, 0, 0);
/* FIXME: don't access view directly here */
ledit_view *view = buffer->views[0];
+ /* FIXME: this message may be wiped immediately */
+ /* -> maybe allow showing multiple messages? */
+ /* currently, the more important message is just prioritized */
+ int show_error = 0;
+ if (stat_errstr || load_errstr) {
+ show_error = 1;
+ if (stat_errstr)
+ window_show_message(view->window, stat_errstr, -1);
+ else if (load_errstr)
+ window_show_message(view->window, load_errstr, -1);
+ free(stat_errstr);
+ free(load_errstr);
+ }
view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ /* FIXME: maybe also log all errors instead of just showing them on sc…
/* FIXME: Support multiple buffers/files */
/* FIXME: check if file may be binary */
- if (argc > 1) {
+ if (argc >= 1) {
/* FIXME: move this to different file */
char *load_err;
struct stat sb;
t@@ -258,7 +349,7 @@ setup(int argc, char *argv[]) {
int readonly = 0;
int error = 0;
/* FIXME: maybe copy vi and open file in /tmp by default? */
- if (stat(argv[1], &sb)) {
+ if (stat(argv[0], &sb)) {
if (errno == ENOENT) {
/* note that there may still be a failure
when trying to write if a directory in
t@@ -267,32 +358,35 @@ setup(int argc, char *argv[]) {
} else {
window_show_message_fmt(
view->window, "Error opening file '%s': %s…
- argv[1], strerror(errno)
+ argv[0], strerror(errno)
);
error = 1;
}
}
- if (access(argv[1], W_OK)) {
+ if (access(argv[0], W_OK)) {
readonly = 1;
}
if (!newfile) {
- if (buffer_load_file(buffer, argv[1], 0, &load_err)) {
+ if (buffer_load_file(buffer, argv[0], 0, &load_err)) {
window_show_message_fmt(
view->window, "Error opening file '%s': %s…
- argv[1], load_err
+ argv[0], load_err
);
error = 1;
}
buffer->file_mtime = sb.st_mtim;
}
if (!error) {
- buffer->filename = ledit_strdup(argv[1]);
- if (newfile) {
- window_show_message_fmt(view->window, "%s: new…
- } else if (readonly) {
- window_show_message_fmt(view->window, "%s: rea…
- } else {
- window_show_message(view->window, argv[1], -1);
+ buffer->filename = ledit_strdup(argv[0]);
+ /* FIXME: show this *in addition* to error */
+ if (!show_error) {
+ if (newfile) {
+ window_show_message_fmt(view->window, …
+ } else if (readonly) {
+ window_show_message_fmt(view->window, …
+ } else {
+ window_show_message(view->window, argv…
+ }
}
}
}
t@@ -302,6 +396,8 @@ setup(int argc, char *argv[]) {
void
ledit_emergencydump(void) {
+ /* FIXME: pre-allocate memory for template to avoid memory errors?
+ -> probably overkill since something else will fail anyways */
if (!buffer)
return;
/* FIXME: maybe write assertion message to file? */
t@@ -355,8 +451,7 @@ ledit_cleanup(void) {
command_key_cleanup();
if (buffer)
buffer_destroy(buffer);
- if (theme)
- theme_destroy(&common, theme);
+ config_cleanup(&common);
XCloseDisplay(common.dpy);
}
t@@ -369,8 +464,8 @@ redraw(void) {
static void
change_keyboard(char *lang) {
- cur_lang = get_language_index(lang);
- if (cur_lang < 0) {
+ ledit_debug_fmt("New keyboard layout: %s\n", lang);
+ if (config_get_language_index(lang, &cur_lang)) {
for (size_t i = 0; i < buffer->views_num; i++) {
window_show_message_fmt(
buffer->views[i]->window,
diff --git a/leditrc.5 b/leditrc.5
t@@ -0,0 +1,347 @@
+.Dd May 26, 2022
+.Dt LEDITRC 5
+.Os
+.Sh NAME
+.Nm leditrc
+.Nd configuration file for
+.Xr ledit 1
+.Sh DESCRIPTION
+.Nm
+is the configuration file for the text editor
+.Xr ledit 1 ,
+which can be used to configure the theme and key bindings used.
+.Pp
+The parser recognizes four different types of structures:
+strings, lists, statements, and assignments.
+.Pp
+A string is simply any sequence of characters surrounded by double quotes.
+Double quotes must be backslash-escaped.
+If a string does not contain any whitespace or the special
+characters
+.Sq \&" ,
+.Sq { ,
+.Sq } ,
+or
+.Sq = ,
+the double quotes are not required.
+.Pp
+A statement is a sequence of strings, separated by whitespace and
+all on the same line.
+.Pp
+An assignment is of the form
+.Aq identifier
+=
+.Aq structure ,
+where
+.Aq identifier
+is a string and
+.Aq structure
+is a string or a list.
+.Pp
+A list is a sequence of assignments and/or statements that is
+enclosed by curly braces.
+The assignments/statements must be separated by newlines.
+.Pp
+The configuration file consists of several top-level assignments
+which are described in the following sections.
+.Sh THEME
+The theme may be configured by assigning
+.Ar theme
+to a list of assignments, each of which sets one of the following
+possible properties.
+Colors are given in the form #RRGGBB, where the
+.Sq #
+is optional (mainly because
+.Sq #
+also starts comments in the configuration file format).
+.Bl -tag -width Ds
+.It Ar text-font
+Font used for all text.
+Default: Monospace
+.It Ar text-size
+Text size (in points or whatever pango uses).
+Default: 12
+.It Ar text-fg
+Text color in main editing area.
+Default: #000000
+.It Ar text-bg
+Background color in main editing area.
+Default: #FFFFFF
+.It Ar cursor-fg
+Color of text under cursor.
+Default: #FFFFFF
+.It Ar cursor-bg
+Color of text cursor.
+Default: #000000
+.It Ar selection-fg
+Color of selected text.
+Default: #FFFFFF
+.It Ar selection-bg
+Color of selection.
+Default: #000000
+.It Ar bar-fg
+Color of text in status bar/line editor.
+Default: #000000
+.It Ar bar-bg
+Background color of status bar/line editor.
+Default: #CCCCCC
+.It Ar bar-cursor
+Color of text cursor in line editor.
+Default: #000000
+.It Ar scrollbar-width
+Width of scrollbar in pixels.
+Default: 10
+.It Ar scrollbar-step
+Number of pixels scrolled with each scroll event.
+Default: 20
+.It Ar scrollbar-bg
+Background color of scrollbar.
+Default: #CCCCCC
+.It Ar scrollbar-fg
+Color of scrollbar handle.
+Default: #000000
+.El
+.Sh BINDINGS
+The key bindings may be configured by assigning
+.Ar bindings
+to a list of the following assignments.
+.Bl -tag -width Ds
+.It Ar language
+.Pp
+This is the language string for the key layout, as given by XKB.
+.It Ar basic-keys
+.Pp
+This is a list of statements of the form
+.Pp
+.Sy bind
+.Aq func_name
+.Op Sy keysym Aq keysym
+.Op Sy text Aq text
+.Op Sy catchall
+.Op Sy modes Aq modes
+.Op Sy mods Aq mods
+.Pp
+.Sy keysym
+is the symbolic description for a key, such as
+.Ar space .
+The full list is not documented yet (FIXME!).
+.Sy text
+is the text corresponding to a key.
+.Sy catchall
+is a catchall for any key which can for instance be used to insert text.
+Note that a key binding containing
+.Sy catchall
+should always be at the end of the list so it does not prevent
+any other key bindings from being used.
+.Pp
+Exactly one of
+.Sy text ,
+.Sy keysym ,
+and
+.Sy catchall
+must be specified.
+.Pp
+.Sy mods
+specifies modifier keys.
+The current options are
+.Ar shift ,
+.Ar lock ,
+.Ar control ,
+.Ar mod1 ,
+.Ar mod2 ,
+.Ar mod3 ,
+.Ar mod4 ,
+.Ar mod5 ,
+and
+.Ar any .
+.Pp
+.Sy modes
+specifies the allowed modes and can be a combination of
+.Ar normal ,
+.Ar visual ,
+and
+.Ar insert .
+.Pp
+Multiple mods or modes can be given by joining them with
+.Sq | .
+.Pp
+.Aq func_name
+may be one of the following functions.
+The possible modes are listed beside the function names.
+.Bl -tag -width Ds
+.It Ar append-after-cursor Op normal
+.It Ar append-after-eol Op normal
+.It Ar append-line-above Op normal
+.It Ar append-line-below Op normal
+.It Ar backspace Op insert
+.It Ar change Op normal, visual
+.It Ar change-to-eol Op normal
+.It Ar clipboard-copy Op visual
+.It Ar clipboard-paste Op insert
+.It Ar cursor-down Op normal, visual, insert
+.It Ar cursor-left Op normal, visual, insert
+.It Ar cursor-right Op normal, visual, insert
+.It Ar cursor-to-beginning Op normal, visual
+.It Ar cursor-to-first-non-whitespace Op normal
+.It Ar cursor-up Op normal, visual, insert
+.It Ar delete Op normal, visual
+.It Ar delete-backwards Op normal
+.It Ar delete-forwards Op normal
+.It Ar delete-key Op insert
+.It Ar delete-to-eol Op normal
+.It Ar enter-commandedit Op normal, visual
+.It Ar enter-insert Op normal, visual
+.It Ar enter-searchedit-backwards Op normal
+.It Ar enter-searchedit-forwards Op normal
+.It Ar enter-visual Op normal
+.It Ar escape-key Op normal, visual, insert
+.It Ar find-char-backwards Op normal, visual
+.It Ar find-char-forwards Op normal, visual
+.It Ar find-next-char-backwards Op normal, visual
+.It Ar find-next-char-forwards Op normal, visual
+.It Ar insert-at-beginning Op normal
+.It Ar insert-text Op insert
+.It Ar join-lines Op normal
+.It Ar jump-to-mark Op normal, visual
+.It Ar key-0 Op normal, visual
+.It Ar mark-line Op normal, visual
+.It Ar move-to-eol Op normal, visual
+.It Ar move-to-line Op normal, visual
+.It Ar next-bigword Op normal, visual
+.It Ar next-bigword-end Op normal, visual
+.It Ar next-word Op normal, visual
+.It Ar next-word-end Op normal, visual
+.It Ar paste-normal Op normal
+.It Ar paste-normal-backwards normal
+.It Ar previous-bigword Op normal, visual
+.It Ar previous-word Op normal, visual
+.It Ar push-0 Op normal, visual
+.It Ar push-1 Op normal, visual
+.It Ar push-2 Op normal, visual
+.It Ar push-3 Op normal, visual
+.It Ar push-4 Op normal, visual
+.It Ar push-5 Op normal, visual
+.It Ar push-6 Op normal, visual
+.It Ar push-7 Op normal, visual
+.It Ar push-8 Op normal, visual
+.It Ar push-9 Op normal, visual
+.It Ar redo Op normal, insert
+.It Ar repeat-command Op normal
+.It Ar replace Op normal
+.It Ar return-key Op insert
+.It Ar screen-down Op normal
+.It Ar screen-up Op normal
+.It Ar scroll-lines-down Op normal
+.It Ar scroll-lines-up Op normal
+.It Ar scroll-with-cursor-down Op normal
+.It Ar scroll-with-cursor-up Op normal
+.It Ar search-next Op normal
+.It Ar search-previous Op normal
+.It Ar show-line Op normal, visual
+.It Ar switch-selection-end Op visual
+.It Ar toggle-hard-line-based Op normal, visual
+.It Ar undo Op normal, insert
+.It Ar yank Op normal, visual
+.It Ar yank-lines Op normal
+.El
+.Pp
+Note that some of these functions should work in other modes
+as well, but I still need to fix that (FIXME!).
+.It Ar command-keys
+.Pp
+This is the same as
+.Ar basic-keys ,
+except that
+.Sy modes
+must be a combination of
+.Ar substitute ,
+.Ar edit ,
+.Ar edit-search ,
+and
+.Ar edit-search-backwards .
+.Pp
+The possible functions are given in the following list, with
+the possible modes listed beside each function.
+.Bl -tag -width Ds
+.It Ar edit-backspace Op edit, edit-search, edit-search-backwards
+.It Ar edit-cursor-left Op edit, edit-search, edit-search-backwards
+.It Ar edit-cursor-right Op edit, edit-search, edit-search-backwards
+.It Ar edit-cursor-to-beginning Op edit, edit-search, edit-search-backwards
+.It Ar edit-cursor-to-end Op edit, edit-search, edit-search-backwards
+.It Ar edit-delete Op edit, edit-search, edit-search-backwards
+.It Ar edit-discard Op edit, edit-search, edit-search-backwards
+.It Ar edit-insert-text Op edit, edit-search, edit-search-backwards
+.It Ar edit-next-command Op edit
+.It Ar edit-next-search Op edit-search, edit-search-backwards
+.It Ar edit-previous-command Op edit
+.It Ar edit-previous-search Op edit-search, edit-search-backwards
+.It Ar edit-submit Op edit
+.It Ar edit-submit-backwards-search Op edit-search-backwards
+.It Ar edit-submit-search Op edit-search
+.It Ar substitute-no Op substitute
+.It Ar substitute-no-all Op substitute
+.It Ar substitute-yes Op substitute
+.It Ar substitute-yes-all Op substitute
+.El
+.It Ar commands
+.Pp
+This is a list of statements of the form
+.Pp
+.Sy bind
+.Aq func_name
+.Aq text
+.Pp
+The possible functions are given in the following list.
+.Bl -tag -width Ds
+.It Ar close-view
+.It Ar create-view
+.It Ar quit
+.It Ar substitute
+.It Ar write
+.It Ar write-quit
+.El
+.El
+.Pp
+If the
+.Ar bindings
+configuration or any part of it is left out, the
+default is used.
+.Sh LANGUAGE MAPPINGS
+A language mapping defines a mapping for the text associated with each
+key or command so the bindings still work with other keyboard layouts.
+Language mappings may be defined by assigning
+.Ar language-mapping
+to a list of the following assignments, once for each language.
+Note that any definition of
+.Ar language-mapping
+must come after
+.Ar bindings .
+.Bl -tag -width Ds
+.It Ar language
+.Pp
+This is the language string for the key layout, as in
+.Ar bindings .
+.It Ar key-mapping
+.Pp
+This is a list of statements of the form
+.Pp
+.Sy map
+.Aq foreign
+.Aq native
+.Pp
+where
+.Aq foreign
+is the key text in the new language mapping and
+.Aq native
+is the key text given in
+.Ar bindings .
+.It Ar command-mapping
+.Pp
+This is the same as
+.Ar key-mapping ,
+but for the commands.
+.El
+.Sh SEE ALSO
+.Xr ledit 1
+.Sh AUTHORS
+.An lumidify Aq Mt [email protected]
diff --git a/leditrc.example b/leditrc.example
t@@ -0,0 +1,300 @@
+theme = {
+ text-font = Monospace
+ text-size = 12
+ text-fg = 000000
+ text-bg = FFFFFF
+ cursor-fg = FFFFFF
+ cursor-bg = 000000
+ selection-fg = ffffff
+ selection-bg = 000000
+ bar-fg = 000000
+ bar-bg = CCCCCC
+ bar-cursor = 000000
+ scrollbar-width = 10
+ scrollbar-step = 20
+ scrollbar-bg = CCCCCC
+ scrollbar-fg = 000000
+}
+
+bindings = {
+ language = "English (US)"
+ basic-keys = {
+ bind backspace keysym backspace modes insert
+ bind cursor-left keysym left modes visual|insert|normal
+ bind cursor-right keysym right modes visual|insert|normal
+ bind cursor-up keysym up modes visual|insert|normal
+ bind cursor-down keysym down modes visual|insert|normal
+ bind return-key keysym return modes insert mods any
+ bind delete-key keysym delete modes insert mods any
+ bind escape-key keysym escape modes normal|visual|insert mods …
+ bind enter-insert text "i" modes normal|visual
+ bind cursor-left text "h" modes normal|visual
+ bind cursor-right text "l" modes normal|visual
+ bind cursor-down text "j" modes normal|visual
+ bind cursor-up text "k" modes normal|visual
+ bind cursor-left text "h" modes normal|visual mods control
+ bind toggle-hard-line-based text "t" modes normal|visual mods …
+ bind cursor-right keysym space modes normal|visual
+ bind cursor-down text "j" modes normal|visual mods control
+ bind cursor-down text "n" modes normal|visual mods control
+ bind cursor-up text "p" modes normal|visual mods control
+ bind key-0 text "0" modes normal|visual
+ bind push-1 text "1" modes normal|visual
+ bind push-2 text "2" modes normal|visual
+ bind push-3 text "3" modes normal|visual
+ bind push-4 text "4" modes normal|visual
+ bind push-5 text "5" modes normal|visual
+ bind push-6 text "6" modes normal|visual
+ bind push-7 text "7" modes normal|visual
+ bind push-8 text "8" modes normal|visual
+ bind push-9 text "9" modes normal|visual
+ bind delete-forwards text "x" modes normal
+ bind delete-backwards text "X" modes normal
+ bind delete text "d" modes normal|visual
+ bind yank text "y" modes normal|visual
+ bind yank-lines text "Y" modes normal
+ bind change text "c" modes normal|visual
+ bind enter-visual text "v" modes normal
+ bind switch-selection-end text "o" modes visual
+ bind clipboard-copy text "c" modes visual mods control
+ bind clipboard-paste text "v" modes insert mods control
+ bind show-line text "g" modes normal|visual mods control
+ bind enter-commandedit text ":" modes normal|visual
+ bind enter-searchedit-backwards text "?" modes normal
+ bind enter-searchedit-forwards text "/" modes normal
+ bind search-next text "n" modes normal
+ bind search-previous text "N" modes normal
+ bind undo text "u" modes normal
+ bind redo text "U" modes normal
+ bind repeat-command text "." modes normal
+ bind undo text "z" modes insert mods control
+ bind redo text "y" modes insert mods control
+ bind screen-up text "b" modes normal mods control
+ bind screen-down text "f" modes normal mods control
+ bind scroll-with-cursor-down text "e" modes normal mods control
+ bind scroll-with-cursor-up text "y" modes normal mods control
+ bind scroll-lines-down text "d" modes normal mods control
+ bind scroll-lines-up text "u" modes normal mods control
+ bind move-to-eol text "$" modes normal|visual
+ bind next-word text "w" modes normal|visual
+ bind next-word-end text "e" modes normal|visual
+ bind next-bigword text "W" modes normal|visual
+ bind next-bigword-end text "E" modes normal|visual
+ bind previous-word text "b" modes normal|visual
+ bind previous-bigword text "B" modes normal|visual
+ bind move-to-line text "G" modes normal|visual
+ bind join-lines text "J" modes normal
+ bind insert-at-beginning text "I" modes normal
+ bind paste-normal text "p" modes normal
+ bind paste-normal-backwards text "P" modes normal
+ bind append-after-eol text "A" modes normal
+ bind append-after-cursor text "a" modes normal
+ bind append-line-above text "O" modes normal
+ bind append-line-below text "o" modes normal
+ bind mark-line text "m" modes normal|visual
+ bind jump-to-mark text "'" modes normal|visual
+ bind change-to-eol text "C" modes normal
+ bind delete-to-eol text "D" modes normal
+ bind replace text "r" modes normal
+ bind cursor-to-first-non-whitespace text "^" modes normal
+ bind find-next-char-forwards text "t" modes normal|visual
+ bind find-next-char-backwards text "T" modes normal|visual
+ bind find-char-forwards text "f" modes normal|visual
+ bind find-char-backwards text "F" modes normal|visual
+ bind insert-text catchall modes insert
+ }
+ command-keys = {
+ bind substitute-yes text "y" modes substitute
+ bind substitute-yes-all text "Y" modes substitute
+ bind substitute-no text "n" modes substitute
+ bind substitute-no-all text "N" modes substitute
+ bind edit-submit keysym return mods any modes edit
+ bind edit-submit-search keysym return mods any modes edit-sear…
+ bind edit-submit-backwards-search keysym return mods any modes…
+ bind edit-cursor-left keysym left modes edit|edit-search|edit-…
+ bind edit-cursor-right keysym right modes edit|edit-search|edi…
+ bind edit-previous-command keysym up modes edit
+ bind edit-next-command keysym down modes edit
+ bind edit-previous-search keysym up modes edit-search|edit-sea…
+ bind edit-next-search keysym down modes edit-search|edit-searc…
+ bind edit-backspace keysym backspace modes edit|edit-search|ed…
+ bind edit-delete keysym delete modes edit|edit-search|edit-sea…
+ bind edit-cursor-to-end keysym end modes edit|edit-search|edit…
+ bind edit-cursor-to-beginning keysym home modes edit|edit-sear…
+ bind edit-discard keysym escape modes edit|edit-search|edit-se…
+ bind edit-insert-text catchall modes edit|edit-search|edit-sea…
+ }
+ commands = {
+ bind write-quit "wq"
+ bind write "w"
+ bind quit "q"
+ bind create-view "v"
+ bind close-view "c"
+ bind substitute "s"
+ }
+}
+
+language-mapping = {
+ language = "German"
+ key-mapping = {
+ map "z" "y"
+ map "y" "z"
+ map "Z" "Y"
+ map "Ö" ":"
+ map "_" "?"
+ map "-" "/"
+ map "ä" "'"
+ }
+ command-mapping = {
+ map "wq" "wq"
+ map "w" "w"
+ map "q" "q"
+ map "v" "v"
+ map "c" "c"
+ map "s" "s"
+ }
+}
+
+language-mapping = {
+ language = "Hindi (Bolnagri)"
+ key-mapping = {
+ map "0" "0"
+ map "1" "1"
+ map "2" "2"
+ map "3" "3"
+ map "4" "4"
+ map "5" "5"
+ map "6" "6"
+ map "7" "7"
+ map "8" "8"
+ map "9" "9"
+ map "ा" "a"
+ map "आ" "A"
+ map "ब" "b"
+ map "भ" "B"
+ map "च" "c"
+ map "छ" "C"
+ map "द" "d"
+ map "ध" "D"
+ map "े" "e"
+ map "ै" "E"
+ map "ट" "f"
+ map "ठ" "F"
+ map "ग" "g"
+ map "घ" "G"
+ map "ह" "h"
+ map "ि" "i"
+ map "ी" "I"
+ map "ज" "j"
+ map "झ" "J"
+ map "क" "k"
+ map "ल" "l"
+ map "म" "m"
+ map "न" "n"
+ map "ण" "N"
+ map "ो" "o"
+ map "ौ" "O"
+ map "प" "p"
+ map "फ" "P"
+ map "र" "r"
+ map "त" "t"
+ map "थ" "T"
+ map "ु" "u"
+ map "ू" "U"
+ map "ड" "v"
+ map "व" "w"
+ map "ॐ" "W"
+ map "्" "x"
+ map "ॉ" "X"
+ map "य" "y"
+ map "ञ" "Y"
+ map "श" "z"
+ map ":" ":"
+ map "?" "?"
+ map "/" "/"
+ map "." "."
+ map "$" "$"
+ map "'" "'"
+ map "^" "^"
+ }
+ command-mapping = {
+ map "वग" "wq"
+ map "व" "w"
+ map "‌" "q"
+ map "ड" "v"
+ map "च" "c"
+ map "स" "s"
+ }
+}
+
+language-mapping = {
+ language = "Urdu (Pakistan)"
+ key-mapping = {
+ map "0" "0"
+ map "1" "1"
+ map "2" "2"
+ map "3" "3"
+ map "4" "4"
+ map "5" "5"
+ map "6" "6"
+ map "7" "7"
+ map "8" "8"
+ map "9" "9"
+ map "ا" "a"
+ map "آ" "A"
+ map "ب" "b"
+ map "." "B"
+ map "چ" "c"
+ map "ث" "C"
+ map "د" "d"
+ map "ڈ" "D"
+ map "ع" "e"
+ map "ٰ" "E"
+ map "ف" "f"
+ map "ّ" "F"
+ map "گ" "g"
+ map "غ" "G"
+ map "ح" "h"
+ map "ی" "i"
+ map "ِ" "I"
+ map "ج" "j"
+ map "ض" "J"
+ map "ک" "k"
+ map "ل" "l"
+ map "م" "m"
+ map "ن" "n"
+ map "ں" "N"
+ map "ہ" "o"
+ map "ۃ" "O"
+ map "پ" "p"
+ map "ُ" "P"
+ map "ر" "r"
+ map "ت" "t"
+ map "ٹ" "T"
+ map "ء" "u"
+ map "ئ" "U"
+ map "ط" "v"
+ map "و" "w"
+ map "ؤ" "W"
+ map "ش" "x"
+ map "ژ" "X"
+ map "ے" "y"
+ map "َ" "Y"
+ map "ز" "z"
+ map ":" ":"
+ map "؟" "?"
+ map "/" "/"
+ map "۔" "."
+ map "$" "$"
+ map "'" "'"
+ map "^" "^"
+ }
+ command-mapping = {
+ map "وگ" "wq"
+ map "و" "w"
+ map "ق" "q"
+ map "ط" "v"
+ map "چ" "c"
+ map "س" "s"
+ }
+}
diff --git a/memory.c b/memory.c
t@@ -10,6 +10,7 @@
static void
fatal_err(const char *msg) {
fprintf(stderr, "%s", msg);
+ /* FIXME: maybe don't cleanup here - it will probably fail anyways */
ledit_cleanup();
exit(1);
}
t@@ -82,6 +83,23 @@ ledit_strcat(const char *str1, const char *str2) {
return ret;
}
+char *
+print_fmt(char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int len = vsnprintf(NULL, 0, fmt, args);
+ /* FIXME: what should be done on error? */
+ if (len < 0)
+ fatal_err("Error in vsnprintf called from print_fmt");
+ /* FIXME: overflow */
+ char *str = ledit_malloc(len + 1);
+ va_end(args);
+ va_start(args, fmt);
+ vsnprintf(str, len + 1, fmt, args);
+ va_end(args);
+ return str;
+}
+
/*
* This (reallocarray) is from OpenBSD (adapted to exit on error):
* Copyright (c) 2008 Otto Moerbeek <[email protected]>
t@@ -96,11 +114,11 @@ ledit_strcat(const char *str1, const char *str2) {
void *
ledit_reallocarray(void *optr, size_t nmemb, size_t size)
{
- if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
- nmemb > 0 && SIZE_MAX / nmemb < size) {
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
err_overflow();
- }
- return ledit_realloc(optr, size * nmemb);
+ }
+ return ledit_realloc(optr, size * nmemb);
}
void
diff --git a/memory.h b/memory.h
t@@ -3,6 +3,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <stdarg.h>
/*
* These functions all wrap the regular functions but exit on error.
t@@ -19,6 +20,11 @@ void *ledit_realloc(void *ptr, size_t size);
*/
char *ledit_strcat(const char *str1, const char *str2);
+/* This acts like snprintf but automatically allocates
+ a string of the appropriate size.
+ Like the other functions here, it exits on error. */
+char *print_fmt(char *fmt, ...);
+
/*
* This is like OpenBSD's reallocarray but exits on error.
*/
diff --git a/theme.c b/theme.c
t@@ -1,57 +0,0 @@
-#include <stddef.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xft/Xft.h>
-
-#include "memory.h"
-#include "common.h"
-#include "theme.h"
-#include "theme_config.h"
-
-ledit_theme *
-theme_create(ledit_common *common) {
- ledit_theme *theme = ledit_malloc(sizeof(ledit_theme));
- theme->scrollbar_width = SCROLLBAR_WIDTH;
- theme->scrollbar_step = SCROLLBAR_STEP;
- theme->text_font = TEXT_FONT;
- theme->text_size = TEXT_SIZE;
- theme->text_fg_hex = TEXT_FG;
- theme->text_bg_hex = TEXT_BG;
- theme->cursor_fg_hex = CURSOR_FG;
- theme->cursor_bg_hex = CURSOR_BG;
- theme->selection_fg_hex = SELECTION_FG;
- theme->selection_bg_hex = SELECTION_BG;
- theme->bar_fg_hex = BAR_FG;
- theme->bar_bg_hex = BAR_BG;
- theme->bar_cursor_hex = BAR_CURSOR;
- theme->scrollbar_fg_hex = SCROLLBAR_FG;
- theme->scrollbar_bg_hex = SCROLLBAR_BG;
- XftColorAllocName(common->dpy, common->vis, common->cm, TEXT_FG, &them…
- XftColorAllocName(common->dpy, common->vis, common->cm, TEXT_BG, &them…
- XftColorAllocName(common->dpy, common->vis, common->cm, CURSOR_FG, &th…
- XftColorAllocName(common->dpy, common->vis, common->cm, CURSOR_BG, &th…
- XftColorAllocName(common->dpy, common->vis, common->cm, SELECTION_FG, …
- XftColorAllocName(common->dpy, common->vis, common->cm, SELECTION_BG, …
- XftColorAllocName(common->dpy, common->vis, common->cm, BAR_FG, &theme…
- XftColorAllocName(common->dpy, common->vis, common->cm, BAR_BG, &theme…
- XftColorAllocName(common->dpy, common->vis, common->cm, BAR_CURSOR, &t…
- XftColorAllocName(common->dpy, common->vis, common->cm, SCROLLBAR_FG, …
- XftColorAllocName(common->dpy, common->vis, common->cm, SCROLLBAR_BG, …
- return theme;
-}
-
-void
-theme_destroy(ledit_common *common, ledit_theme *theme) {
- XftColorFree(common->dpy, common->vis, common->cm, &theme->text_fg);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->text_bg);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->cursor_fg);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->cursor_bg);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->selection_f…
- XftColorFree(common->dpy, common->vis, common->cm, &theme->selection_b…
- XftColorFree(common->dpy, common->vis, common->cm, &theme->bar_fg);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->bar_bg);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->bar_cursor);
- XftColorFree(common->dpy, common->vis, common->cm, &theme->scrollbar_f…
- XftColorFree(common->dpy, common->vis, common->cm, &theme->scrollbar_b…
- free(theme);
-}
diff --git a/theme.h b/theme.h
t@@ -1,39 +0,0 @@
-#ifndef _THEME_H_
-#define _THEME_H_
-
-#include <X11/Xft/Xft.h>
-#include "common.h"
-
-typedef struct {
- int scrollbar_width;
- int scrollbar_step;
- int text_size;
- XftColor text_fg;
- XftColor text_bg;
- XftColor cursor_fg;
- XftColor cursor_bg;
- XftColor selection_fg;
- XftColor selection_bg;
- XftColor bar_fg;
- XftColor bar_bg;
- XftColor bar_cursor;
- XftColor scrollbar_fg;
- XftColor scrollbar_bg;
- const char *text_font;
- const char *text_fg_hex;
- const char *text_bg_hex;
- const char *cursor_fg_hex;
- const char *cursor_bg_hex;
- const char *selection_fg_hex;
- const char *selection_bg_hex;
- const char *bar_fg_hex;
- const char *bar_bg_hex;
- const char *bar_cursor_hex;
- const char *scrollbar_fg_hex;
- const char *scrollbar_bg_hex;
-} ledit_theme;
-
-ledit_theme *theme_create(ledit_common *common);
-void theme_destroy(ledit_common *common, ledit_theme *theme);
-
-#endif
diff --git a/theme_config.h b/theme_config.h
t@@ -1,7 +1,19 @@
+#ifndef _THEME_CONFIG_H_
+#define _THEME_CONFIG_H_
+
+/***********************
+ * Theme configuration *
+ ***********************/
+
+/* Note: Integer values have to be given as strings because
+ that simplifies some things in the config parser. */
+
+/* FIXME: Check what happens when 0 is given for integer values */
+
/* font used for all text */
static const char *TEXT_FONT = "Monospace";
/* size used for text in points or whatever pango uses */
-static const int TEXT_SIZE = 12;
+static const char *TEXT_SIZE = "12";
/* text color of main text area */
static const char *TEXT_FG = "#000000";
/* background color of main text area */
t@@ -24,10 +36,12 @@ static const char *BAR_CURSOR = "#000000";
/* FIXME: give in units other than pixels */
/* scrollbar width in pixels */
-static const int SCROLLBAR_WIDTH = 10;
+static const char *SCROLLBAR_WIDTH = "10";
/* number of pixels scrolled with every scroll event */
-static const int SCROLLBAR_STEP = 20;
+static const char *SCROLLBAR_STEP = "20";
/* background color of scrollbar */
static const char *SCROLLBAR_BG = "#CCCCCC";
/* color of scrollbar handle */
static const char *SCROLLBAR_FG = "#000000";
+
+#endif /* _THEME_CONFIG_H_ */
diff --git a/txtbuf.c b/txtbuf.c
t@@ -1,5 +1,7 @@
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include "util.h"
#include "memory.h"
t@@ -14,16 +16,49 @@ txtbuf_new(void) {
return buf;
}
+txtbuf *
+txtbuf_new_from_char(char *str) {
+ txtbuf *buf = ledit_malloc(sizeof(txtbuf));
+ buf->text = ledit_strdup(str);
+ buf->len = strlen(str);
+ buf->cap = buf->len + 1;
+ return buf;
+}
+
+txtbuf *
+txtbuf_new_from_char_len(char *str, size_t len) {
+ txtbuf *buf = ledit_malloc(sizeof(txtbuf));
+ buf->text = ledit_strndup(str, len);
+ buf->len = len;
+ buf->cap = len + 1;
+ return buf;
+}
+
+void
+txtbuf_fmt(txtbuf *buf, char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int len = vsnprintf(buf->text, buf->cap, fmt, args);
+ /* FIXME: len can never be negative, right? */
+ /* FIXME: maybe also shrink here */
+ if ((size_t)len >= buf->cap) {
+ va_end(args);
+ va_start(args, fmt);
+ txtbuf_resize(buf, len);
+ vsnprintf(buf->text, buf->cap, fmt, args);
+ }
+ buf->len = len;
+ va_end(args);
+}
+
void
txtbuf_resize(txtbuf *buf, size_t sz) {
/* always leave room for extra \0 */
- /* FIXME: '\0' isn't actually used anywhere */
size_t cap = ideal_array_size(buf->cap, add_sz(sz, 1));
if (cap != buf->cap) {
buf->text = ledit_realloc(buf->text, cap);
buf->cap = cap;
}
- ledit_assert(buf->cap >= add_sz(sz, 1));
}
void
t@@ -38,6 +73,7 @@ void
txtbuf_copy(txtbuf *dst, txtbuf *src) {
txtbuf_resize(dst, src->len);
memcpy(dst->text, src->text, src->len);
+ dst->text[src->len] = '\0';
dst->len = src->len;
}
t@@ -47,3 +83,22 @@ txtbuf_dup(txtbuf *src) {
txtbuf_copy(dst, src);
return dst;
}
+
+int
+txtbuf_cmp(txtbuf *buf1, txtbuf *buf2) {
+ /* FIXME: I guess strcmp would be possible as well since it's nul-term…
+ /* FIXME: Test this because I was tired while writing it */
+ int cmp = strncmp(buf1->text, buf2->text, LEDIT_MIN(buf1->len, buf2->l…
+ if (cmp == 0) {
+ if (buf1->len < buf2->len)
+ return -1;
+ else if (buf1->len > buf2->len)
+ return 1;
+ }
+ return cmp;
+}
+
+int
+txtbuf_eql(txtbuf *buf1, txtbuf *buf2) {
+ return txtbuf_cmp(buf1, buf2) == 0;
+}
diff --git a/txtbuf.h b/txtbuf.h
t@@ -5,6 +5,7 @@
/*
* txtbuf is really just a string data type that is badly named.
+ * The stored text is always nul-terminated.
*/
typedef struct {
t@@ -18,6 +19,35 @@ typedef struct {
txtbuf *txtbuf_new(void);
/*
+ * Create a new txtbuf, initializing it with the nul-terminated
+ * string 'str'. The input string is copied.
+ */
+txtbuf *txtbuf_new_from_char(char *str);
+
+/*
+ * Create a new txtbuf, initializing it with the string 'str'
+ * of length 'len'. The input string is copied.
+ */
+txtbuf *txtbuf_new_from_char_len(char *str, size_t len);
+
+/*
+ * Replace the stored text in 'buf' with the text generated by
+ * 'snprintf' when called with the given format string and args.
+ */
+void txtbuf_fmt(txtbuf *buf, char *fmt, ...);
+
+/*
+ * Compare the text of two txtbuf's like 'strcmp'.
+ */
+int txtbuf_cmp(txtbuf *buf1, txtbuf *buf2);
+
+/*
+ * Convenience function for calling 'txtbuf_cmp' and checking if the
+ * return value is 0, i.e. the strings are equal.
+ */
+int txtbuf_eql(txtbuf *buf1, txtbuf *buf2);
+
+/*
* Make sure the txtbuf has space for at least the given size,
* plus '\0' at the end.
*/
diff --git a/uglycrap.h b/uglycrap.h
t@@ -0,0 +1,15 @@
+#ifndef _UGLYCRAP_H_
+#define _UGLYCRAP_H_
+
+/* FIXME: Figure out where to put it - it would make sens to put it in
+ keys_command.h, but it is needed by view.h to make the command mode
+ per-view, but I don't want view.* to depend on keys_command.h */
+
+typedef enum command_mode {
+ CMD_EDIT = 1, /* edit command */
+ CMD_EDITSEARCH = 2, /* edit search term */
+ CMD_EDITSEARCHB = 4, /* edit search term for backwards search */
+ CMD_SUBSTITUTE = 8 /* confirm substitution */
+} command_mode;
+
+#endif
diff --git a/undo.h b/undo.h
t@@ -73,6 +73,7 @@ void undo_change_mode_group(undo_stack *undo);
/*
* Push an insert action onto the undo stack.
* See documentation at top for details on the other arguments.
+ * 'text' is copied, so the original should be freed.
*/
void undo_push_insert(
undo_stack *undo, txtbuf *text,
t@@ -83,6 +84,7 @@ void undo_push_insert(
/*
* Push an delete action onto the undo stack.
* See documentation at top for details on the other arguments.
+ * 'text' is copied, so the original should be freed.
*/
void undo_push_delete(
undo_stack *undo, txtbuf *text,
diff --git a/util.c b/util.c
t@@ -1,3 +1,4 @@
+#include <string.h>
#include <stddef.h>
#include "memory.h"
t@@ -9,6 +10,15 @@ next_utf8(char *str) {
}
size_t
+next_utf8_len(char *str, size_t len) {
+ size_t cur = 0;
+ while (cur < len && (str[cur] & 0xC0) == 0x80)
+ cur++;
+ return cur;
+}
+
+/* FIXME: change these to macros somehow */
+size_t
add_sz(size_t a, size_t b) {
if (a > SIZE_MAX - b)
err_overflow();
t@@ -38,3 +48,13 @@ sort_range(size_t *l1, size_t *b1, size_t *l2, size_t *b2) {
swap_sz(b1, b2);
}
}
+
+int
+str_array_equal(char *terminated, char *array, size_t len) {
+ if (!strncmp(terminated, array, len)) {
+ /* 'terminated' and 'array' are equal for the first 'len'
+ characters, so this index in 'terminated' must exist */
+ return terminated[len] == '\0';
+ }
+ return 0;
+}
diff --git a/util.h b/util.h
t@@ -9,6 +9,13 @@
char *next_utf8(char *str);
/*
+ * Same as above, but also works with non-nul-terminated strings.
+ * Instead of a pointer, the index of the next utf8 char is
+ * returned.
+ */
+size_t next_utf8_len(char *str, size_t len);
+
+/*
* Add size_t values and abort if overflow would occur.
* FIXME: Maybe someone with actual experience could tell me
* if this overflow checking actually works.
t@@ -19,4 +26,25 @@ size_t add_sz3(size_t a, size_t b, size_t c);
void swap_sz(size_t *a, size_t *b);
void sort_range(size_t *l1, size_t *b1, size_t *l2, size_t *b2);
+/*
+ * Compare the nul-terminated string 'terminated' with the char
+ * array 'array' with length 'len'.
+ * Returns non-zero if they are equal, 0 otherwise.
+ */
+/* Note: this doesn't work if array contains '\0'. */
+int str_array_equal(char *terminated, char *array, size_t len);
+
+#define LEDIT_MIN(x, y) ((x) < (y) ? (x) : (y))
+#define LEDIT_MAX(x, y) ((x) > (y) ? (x) : (y))
+
+/* Apparently, ISO C99 requires at least one argument for
+ variadic macros, so there are two versions of the macro here. */
+#ifdef LEDIT_DEBUG
+ #define ledit_debug(fmt) do {fprintf(stderr, "%s:%d: " fmt, __FILE__, …
+ #define ledit_debug_fmt(fmt, ...) do {fprintf(stderr, "%s:%d: " fmt, _…
+#else
+ #define ledit_debug(fmt) do {} while (0)
+ #define ledit_debug_fmt(fmt, ...) do {} while (0)
+#endif
+
#endif
diff --git a/view.c b/view.c
t@@ -18,10 +18,10 @@
#include "txtbuf.h"
#include "undo.h"
#include "cache.h"
-#include "theme.h"
#include "window.h"
#include "buffer.h"
#include "assert.h"
+#include "configparser.h"
/* Basic attributes set for all text. */
static PangoAttrList *basic_attrs = NULL;
t@@ -96,7 +96,7 @@ view_set_mode(ledit_view *view, ledit_mode mode) {
}
ledit_view *
-view_create(ledit_buffer *buffer, ledit_theme *theme, ledit_mode mode, size_t …
+view_create(ledit_buffer *buffer, ledit_mode mode, size_t line, size_t pos) {
if (basic_attrs == NULL) {
basic_attrs = pango_attr_list_new();
#if PANGO_VERSION_CHECK(1, 44, 0)
t@@ -108,8 +108,7 @@ view_create(ledit_buffer *buffer, ledit_theme *theme, ledi…
ledit_view *view = ledit_malloc(sizeof(ledit_view));
view->mode = mode;
view->buffer = buffer;
- view->window = window_create(buffer->common, theme, mode);
- view->theme = theme;
+ view->window = window_create(buffer->common, mode);
view->cache = cache_create(buffer->common->dpy);
view->lock_text = NULL;
view->cur_action = (struct action){ACTION_NONE, NULL};
t@@ -328,12 +327,13 @@ get_pango_attributes(size_t start_byte, size_t end_byte,…
/* this takes layout directly to possibly avoid infinite recursion */
static void
set_line_layout_attrs(ledit_view *view, size_t line, PangoLayout *layout) {
+ ledit_theme *theme = config_get_theme();
ledit_line *ll = buffer_get_line(view->buffer, line);
ledit_view_line *vl = view_get_line(view, line);
PangoAttrList *list = NULL;
if (view->sel_valid) {
- XRenderColor fg = view->theme->selection_fg.color;
- XRenderColor bg = view->theme->selection_bg.color;
+ XRenderColor fg = theme->selection_fg.color;
+ XRenderColor bg = theme->selection_bg.color;
ledit_range sel = view->sel;
sort_range(&sel.line1, &sel.byte1, &sel.line2, &sel.byte2);
if (sel.line1 < line && sel.line2 > line) {
t@@ -349,8 +349,8 @@ set_line_layout_attrs(ledit_view *view, size_t line, Pango…
list = get_pango_attributes(0, sel.byte2, fg, bg);
}
} else if (vl->cursor_index_valid) {
- XRenderColor fg = view->theme->cursor_fg.color;
- XRenderColor bg = view->theme->cursor_bg.color;
+ XRenderColor fg = theme->cursor_fg.color;
+ XRenderColor bg = theme->cursor_bg.color;
/* FIXME: does just adding one really do the right thing? */
list = get_pango_attributes(vl->cursor_index, vl->cursor_index…
}
t@@ -392,6 +392,7 @@ line_visible_callback(void *data, size_t line) {
/* FIXME: standardize variable names (line/line_index, etc.) */
void
render_line(ledit_view *view, size_t line_index) {
+ ledit_theme *theme = config_get_theme();
/* FIXME: check for <= 0 on size */
ledit_view_line *ll = view_get_line(view, line_index);
ledit_assert(!ll->h_dirty); /* FIXME */
t@@ -430,8 +431,8 @@ render_line(ledit_view *view, size_t line_index) {
pix->h = new_h;
XftDrawChange(pix->draw, pix->pixmap);
}
- XftDrawRect(pix->draw, &view->theme->text_bg, 0, 0, ll->w, ll->h);
- pango_xft_render_layout(pix->draw, &view->theme->text_fg, layout, 0, 0…
+ XftDrawRect(pix->draw, &theme->text_bg, 0, 0, ll->w, ll->h);
+ pango_xft_render_layout(pix->draw, &theme->text_fg, layout, 0, 0);
ll->dirty = 0;
}
t@@ -1839,6 +1840,7 @@ view_button_handler(void *data, XEvent *event) {
static void
view_redraw_text(ledit_view *view) {
+ ledit_theme *theme = config_get_theme();
int h = 0;
int cur_line_y = 0;
int cursor_displayed = 0;
t@@ -1884,7 +1886,7 @@ view_redraw_text(ledit_view *view) {
h += vline->h;
}
- XSetForeground(view->buffer->common->dpy, view->window->gc, view->them…
+ XSetForeground(view->buffer->common->dpy, view->window->gc, theme->cur…
PangoRectangle strong, weak;
ledit_line *cur_line = buffer_get_line(view->buffer, view->cur_line);
PangoLayout *layout = get_pango_layout(view, view->cur_line);
diff --git a/view.h b/view.h
t@@ -10,8 +10,8 @@
#include "common.h"
#include "txtbuf.h"
#include "window.h"
-#include "theme.h"
#include "cache.h"
+#include "uglycrap.h"
typedef struct ledit_view ledit_view;
t@@ -49,24 +49,14 @@ typedef struct {
char h_dirty; /* whether height needs to be recalculated …
} ledit_view_line;
-/* FIXME: It's kind of ugly to put this here instead of keys_command.h,
- but it has to be per-view, so I don't know any other option. */
-enum ledit_command_type {
- CMD_EDIT, /* edit command */
- CMD_EDITSEARCH, /* edit search term */
- CMD_EDITSEARCHB, /* edit search term for backwards search */
- CMD_SUBSTITUTE /* confirm substitution */
-};
-
struct ledit_view {
ledit_buffer *buffer; /* parent buffer */
ledit_window *window; /* window showing this view */
- ledit_theme *theme; /* current theme in use */
ledit_cache *cache; /* cache for pixmaps and pango layouts */
ledit_view_line *lines; /* array of lines, stored as gap buffer */
char *lock_text; /* text to show if view is locked, i.e. no e…
/* current command type - used by key handler in keys_command.c */
- enum ledit_command_type cur_command_type;
+ command_mode cur_command_type;
struct action cur_action; /* current action to execute on key press */
size_t lines_cap; /* size of lines array */
size_t lines_gap; /* position of gap for line gap buffer */
t@@ -98,14 +88,11 @@ enum delete_mode {
void view_set_mode(ledit_view *view, ledit_mode mode);
/*
- * Create a view with associated buffer 'buffer' and theme 'theme'.
+ * Create a view with associated buffer 'buffer'
* The initial mode, line, and byte position are given, respectively,
* by 'mode', 'line', and 'pos'.
*/
-ledit_view *view_create(
- ledit_buffer *buffer, ledit_theme *theme,
- ledit_mode mode, size_t line, size_t pos
-);
+ledit_view *view_create(ledit_buffer *buffer, ledit_mode mode, size_t line, si…
/*
* Lock a view.
diff --git a/window.c b/window.c
t@@ -14,7 +14,6 @@
#include <X11/extensions/Xdbe.h>
#include "util.h"
-#include "theme.h"
#include "memory.h"
#include "common.h"
#include "txtbuf.h"
t@@ -23,6 +22,7 @@
#include "config.h"
#include "assert.h"
#include "draw_util.h"
+#include "configparser.h"
/* FIXME: Everything to do with the bottom bar is extremely hacky */
struct bottom_bar {
t@@ -94,10 +94,11 @@ window_get_primary_clipboard_buffer(void) {
/* FIXME: guard against negative width/height */
static void
recalc_text_size(ledit_window *window) {
+ ledit_theme *theme = config_get_theme();
int bar_h = window->bb->mode_h;
if (window->bottom_text_shown || window->message_shown)
bar_h = window->bb->line_h;
- window->text_w = window->w - window->theme->scrollbar_width;
+ window->text_w = window->w - theme->scrollbar_width;
window->text_h = window->h - bar_h;
if (window->text_w < 0)
window->text_w = 0;
t@@ -120,12 +121,13 @@ resize_line_text(ledit_window *window, int min_size) {
static void
redraw_line_text(ledit_window *window) {
+ ledit_theme *theme = config_get_theme();
/* FIXME: set_text doesn't really belong here */
pango_layout_set_text(window->bb->line, window->bb->line_text, window-…
pango_layout_get_pixel_size(window->bb->line, &window->bb->line_w, &wi…
draw_grow(window, window->bb->line_draw, window->bb->line_w, window->b…
- XftDrawRect(window->bb->line_draw->xftdraw, &window->theme->bar_bg, 0,…
- pango_xft_render_layout(window->bb->line_draw->xftdraw, &window->theme…
+ XftDrawRect(window->bb->line_draw->xftdraw, &theme->bar_bg, 0, 0, wind…
+ pango_xft_render_layout(window->bb->line_draw->xftdraw, &theme->bar_fg…
recalc_text_size(window);
window->redraw = 1;
}
t@@ -332,6 +334,7 @@ window_hide_message(ledit_window *window) {
void
window_set_mode(ledit_window *window, ledit_mode mode) {
+ ledit_theme *theme = config_get_theme();
window->mode = mode;
char *text;
switch (mode) {
t@@ -353,8 +356,8 @@ window_set_mode(ledit_window *window, ledit_mode mode) {
free(final_text);
pango_layout_get_pixel_size(window->bb->mode, &window->bb->mode_w, &wi…
draw_grow(window, window->bb->mode_draw, window->bb->mode_w, window->b…
- XftDrawRect(window->bb->mode_draw->xftdraw, &window->theme->bar_bg, 0,…
- pango_xft_render_layout(window->bb->mode_draw->xftdraw, &window->theme…
+ XftDrawRect(window->bb->mode_draw->xftdraw, &theme->bar_bg, 0, 0, wind…
+ pango_xft_render_layout(window->bb->mode_draw->xftdraw, &theme->bar_fg…
recalc_text_size(window);
window->redraw = 1;
}
t@@ -510,10 +513,13 @@ xximspot(ledit_window *window, int x, int y) {
}
ledit_window *
-window_create(ledit_common *common, ledit_theme *theme, ledit_mode mode) {
+window_create(ledit_common *common, ledit_mode mode) {
XGCValues gcv;
+ ledit_theme *theme = config_get_theme();
+
ledit_window *window = ledit_malloc(sizeof(ledit_window));
+ window->first_resize = 1;
window->mode = mode;
window->scroll_dragging = 0;
t@@ -569,7 +575,6 @@ window_create(ledit_common *common, ledit_theme *theme, le…
XSetWMProtocols(common->dpy, window->xwin, &window->wm_delete_msg, 1);
window->common = common;
- window->theme = theme;
window->bb = ledit_malloc(sizeof(bottom_bar));
window->bb->mode = pango_layout_new(window->context);
t@@ -652,6 +657,7 @@ window_destroy(ledit_window *window) {
/*g_object_unref(window->context);*/
g_object_unref(window->fontmap);
+ XFreeGC(window->common->dpy, window->gc);
if (window->spotlist)
XFree(window->spotlist);
XDestroyWindow(window->common->dpy, window->xwin);
t@@ -671,7 +677,8 @@ window_cleanup(void) {
void
window_clear(ledit_window *window) {
- XSetForeground(window->common->dpy, window->gc, window->theme->text_bg…
+ ledit_theme *theme = config_get_theme();
+ XSetForeground(window->common->dpy, window->gc, theme->text_bg.pixel);
XFillRectangle(
window->common->dpy, window->drawable, window->gc, 0, 0, window->w…
);
t@@ -679,7 +686,7 @@ window_clear(ledit_window *window) {
void
window_redraw(ledit_window *window) {
- ledit_theme *t = window->theme;
+ ledit_theme *t = config_get_theme();
if (window->scroll_max > window->text_h) {
XSetForeground(window->common->dpy, window->gc, t->scrollbar_b…
XFillRectangle(
t@@ -791,7 +798,7 @@ window_handle_filtered_events(ledit_window *window) {
if (window->last_resize_valid) {
clock_gettime(CLOCK_MONOTONIC, &now);
ledit_timespecsub(&now, &window->last_resize, &elapsed);
- if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= RESIZE_TICK) {
+ if (window->first_resize || elapsed.tv_sec > 0 || elapsed.tv_n…
window_resize(
window,
window->last_resize_event.xconfigure.width,
t@@ -800,6 +807,7 @@ window_handle_filtered_events(ledit_window *window) {
window->last_resize = now;
window->last_resize_valid = 0;
window->redraw = 1;
+ window->first_resize = 0;
}
}
}
t@@ -1036,6 +1044,7 @@ window_register_motion(ledit_window *window, XEvent *eve…
/* FIXME: improve set_scroll_pos; make it a bit clearer */
void
window_button_press(ledit_window *window, XEvent *event, int scroll_num) {
+ ledit_theme *theme = config_get_theme();
int x = event->xbutton.x;
int y = event->xbutton.y;
double scroll_h, scroll_y;
t@@ -1062,7 +1071,7 @@ window_button_press(ledit_window *window, XEvent *event,…
break;
case Button4:
case Button5:
- window->scroll_offset += scroll_num * window->theme->s…
+ window->scroll_offset += scroll_num * theme->scrollbar…
if (window->scroll_offset < 0)
window->scroll_offset = 0;
if (window->scroll_offset + window->text_h > window->s…
diff --git a/window.h b/window.h
t@@ -16,7 +16,6 @@
#include <X11/extensions/Xdbe.h>
#include <pango/pangoxft.h>
-#include "theme.h"
#include "common.h"
#include "txtbuf.h"
t@@ -65,6 +64,12 @@ typedef struct {
int last_scroll_valid;
int last_motion_valid;
int last_resize_valid;
+ /* This is a hack to make the first resizing of the window go quickly …
+ of being delayed due to the event filtering - this is noticeable in…
+ window managers that resize the window immediately after it is crea…
+ The whole event filtering system needs to be rethought anyways, but…
+ at least sort of works for the time being. (FIXME) */
+ int first_resize;
int scroll_num;
int scroll_delta;
t@@ -75,7 +80,6 @@ typedef struct {
XVaNestedList spotlist;
ledit_common *common;
- ledit_theme *theme;
/* various callbacks */
void (*paste_callback)(void *, char *, size_t);
t@@ -94,7 +98,7 @@ typedef struct {
/*
* Create a window with initial mode 'mode'.
*/
-ledit_window *window_create(ledit_common *common, ledit_theme *theme, ledit_mo…
+ledit_window *window_create(ledit_common *common, ledit_mode mode);
/*
* Destroy a window.
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.