From 2d54f521dd0da50dfffee3a4f3472956df07f279 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 4 Nov 2016 20:20:00 -0400 Subject: [PATCH] general cleanup of warnings and switch over to C99 instead og GNU99. Also first, very rough, implementation of graphical pick command --- Makefile | 7 +- inc/X.h | 2 +- inc/edit.h | 1 + inc/vec.h | 120 +++++++++ libedit/buf.c | 8 +- libedit/charset.c | 14 +- libedit/tolower.c | 674 ++++++++++++++++++++++++++++++++++++++++++++++ libedit/utf8.c | 1 + libedit/utils.c | 10 +- libx/x11.c | 20 +- xpick.c | 173 +++++++++++- 11 files changed, 1006 insertions(+), 24 deletions(-) create mode 100644 inc/vec.h create mode 100644 libedit/tolower.c diff --git a/Makefile b/Makefile index 7a305fd..71c69db 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ CC = c99 LDFLAGS = -L/usr/X11/lib -lX11 -lXft -lfontconfig -CFLAGS = -Os -Iinc/ -I/usr/X11/include -I/usr/X11/include/freetype2 +CFLAGS = -Os $(INCS) +INCS = \ + -Iinc/ \ + -I/usr/X11/include \ + -I/usr/X11/include/freetype2 \ + -I/usr/include/freetype2 LIBEDIT_OBJS = \ libedit/buf.o \ diff --git a/inc/X.h b/inc/X.h index 0301c94..02c64af 100644 --- a/inc/X.h +++ b/inc/X.h @@ -1,5 +1,4 @@ #include -#include typedef enum { MOUSE_ACT_UP, @@ -134,3 +133,4 @@ void x11_warp_mouse(int x, int y); void x11_font_load(XFont* font, char* name); void x11_font_getglyph(XFont* font, XftGlyphFontSpec* spec, uint32_t rune); size_t x11_font_getglyphs(XftGlyphFontSpec* specs, const XGlyph* glyphs, int len, XFont* font, int x, int y); +void x11_draw_utf8(XFont* font, int fg, int bg, int x, int y, char* str); diff --git a/inc/edit.h b/inc/edit.h index ef1645d..80d4693 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -10,6 +10,7 @@ void funmap(FMap file); uint32_t getmillis(void); bool risword(Rune r); bool risblank(Rune r); +char* stringdup(const char* str); /* Buffer management functions *****************************************************************************/ diff --git a/inc/vec.h b/inc/vec.h new file mode 100644 index 0000000..c7b6113 --- /dev/null +++ b/inc/vec.h @@ -0,0 +1,120 @@ +/** + @brief Generic vector implementation. + @author Michael D. Lowis + @license BSD 2-clause License +*/ +#ifndef VEC_H +#define VEC_H + +#include +#include +#include +#include +#include + +typedef struct { + size_t elem_count; + size_t elem_size; + size_t elem_capacity; + uint8_t* elem_buffer; +} vec_t; + +typedef int (*vec_cmpfn_t)(const void*,const void*); + +#ifndef DEFAULT_VEC_CAPACITY +#define DEFAULT_VEC_CAPACITY (size_t)8 +#endif + +static void vec_init(vec_t* vec, size_t elem_size) { + vec->elem_size = elem_size; + vec->elem_count = 0; + vec->elem_capacity = DEFAULT_VEC_CAPACITY; + vec->elem_buffer = malloc(elem_size * vec->elem_capacity); +} + +static size_t vec_size(vec_t* vec) { + return vec->elem_count; +} + +static bool vec_empty(vec_t* vec) { + return (vec->elem_count == 0); +} + +static size_t vec_capacity(vec_t* vec) { + return vec->elem_capacity; +} + +static size_t vec_next_capacity(size_t req_size) { + size_t next_power = req_size; + size_t num_bits = sizeof(size_t) * 8; + size_t bit_n; + + /* Find the next highest power of 2 */ + next_power--; + for (bit_n = 1; bit_n < num_bits; bit_n = bit_n << 1) + next_power = next_power | (next_power >> bit_n); + next_power++; + + return next_power; +} + +static void vec_reserve(vec_t* vec, size_t size) { + vec->elem_buffer = realloc(vec->elem_buffer, size * vec->elem_size); + vec->elem_capacity = size; +} + +static void vec_resize(vec_t* vec, size_t count, void* fillval) { + if (count > vec->elem_count) { + vec_reserve(vec, vec_next_capacity(count+1)); + for (; vec->elem_count < count; vec->elem_count++) + memcpy(&(vec->elem_buffer[vec->elem_count * vec->elem_size]), fillval, vec->elem_size); + } else if (count < vec->elem_count) { + vec->elem_count = count; + } +} + +static void vec_shrink_to_fit(vec_t* vec) { + vec->elem_buffer = realloc(vec->elem_buffer, vec->elem_count * vec->elem_size); + vec->elem_capacity = vec->elem_count; +} + +static void* vec_at(vec_t* vec, size_t index) { + return &(vec->elem_buffer[index * vec->elem_size]); +} + +static void vec_set(vec_t* vec, size_t index, void* data) { + memcpy(&(vec->elem_buffer[index * vec->elem_size]), data, vec->elem_size); +} + +static bool vec_insert(vec_t* vec, size_t index, size_t num_elements, ...) { + (void)vec; + (void)index; + (void)num_elements; + return false; +} + +static bool vec_erase(vec_t* vec, size_t start_idx, size_t end_idx) { + (void)vec; + (void)start_idx; + (void)end_idx; + return false; +} + +static void vec_push_back(vec_t* vec, void* data) { + vec_resize(vec, vec->elem_count+1, data); +} + +static void vec_pop_back(vec_t* vec, void* outdata) { + vec->elem_count--; + memcpy(outdata, &(vec->elem_buffer[vec->elem_count * vec->elem_size]), vec->elem_size); +} + +static void vec_clear(vec_t* vec) { + vec->elem_count = 0; +} + +static void vec_sort(vec_t* vec, int (*cmpfn)(const void*,const void*)) { + qsort(vec->elem_buffer, vec->elem_count, vec->elem_size, cmpfn); +} + +#endif /* VEC_H */ diff --git a/libedit/buf.c b/libedit/buf.c index 63f257d..591a183 100644 --- a/libedit/buf.c +++ b/libedit/buf.c @@ -8,10 +8,10 @@ void buf_load(Buf* buf, char* path) { buf->charset = UTF_8; Rune r; while (RUNE_EOF != (r = fgetrune(stdin))) - buf_ins(buf, buf_end(&Buffer), r); + buf_ins(buf, buf_end(buf), r); } else { FMap file = fmap(path); - buf->path = strdup(path); + buf->path = stringdup(path); buf->charset = (file.buf ? charset(file.buf, file.len, &buf->crlf) : UTF_8); /* load the file contents if it has any */ if (buf->charset > UTF_8) { @@ -22,8 +22,8 @@ void buf_load(Buf* buf, char* path) { utf8load(buf, file); } /* new files should have a newline in the buffer */ - if (!file.buf) - buf_ins(buf, 0, (Rune)'\n'); + //if (!file.buf) + // buf_ins(buf, 0, (Rune)'\n'); funmap(file); } buf_setlocked(buf, true); diff --git a/libedit/charset.c b/libedit/charset.c index 6051db1..336e317 100644 --- a/libedit/charset.c +++ b/libedit/charset.c @@ -5,13 +5,13 @@ static const struct { int type; int len; - char* seq; + uchar* seq; } BOMS[] = { - { .type = UTF_8, .len = 3, .seq = (char[]){ 0xEF, 0xBB, 0xBF }}, - { .type = UTF_16BE, .len = 2, .seq = (char[]){ 0xFE, 0xFF }}, - { .type = UTF_16LE, .len = 2, .seq = (char[]){ 0xFF, 0xFE }}, - { .type = UTF_32BE, .len = 4, .seq = (char[]){ 0x00, 0x00, 0xFE, 0xFF }}, - { .type = UTF_32LE, .len = 4, .seq = (char[]){ 0xFF, 0xFE, 0x00, 0x00 }}, + { .type = UTF_8, .len = 3, .seq = (uchar[]){ 0xEFu, 0xBBu, 0xBFu }}, + { .type = UTF_16BE, .len = 2, .seq = (uchar[]){ 0xFEu, 0xFFu }}, + { .type = UTF_16LE, .len = 2, .seq = (uchar[]){ 0xFFu, 0xFEu }}, + { .type = UTF_32BE, .len = 4, .seq = (uchar[]){ 0x00u, 0x00u, 0xFEu, 0xFFu }}, + { .type = UTF_32LE, .len = 4, .seq = (uchar[]){ 0xFFu, 0xFEu, 0x00u, 0x00u }}, }; static const char Utf8Valid[256] = { @@ -30,7 +30,7 @@ int charset(const uint8_t* buf, size_t len, int* crlf) { size_t lfs = 0; /* look for a BOM and parse it */ for (size_t i = 0; i < (sizeof(BOMS)/sizeof(BOMS[0])); i++) - if (!strncmp((char*)buf, BOMS[i].seq, BOMS[i].len)) + if (!strncmp((char*)buf, (char*)BOMS[i].seq, BOMS[i].len)) return BOMS[i].type; /* look for bytes that are invalid in utf-8 */ int type = UTF_8; diff --git a/libedit/tolower.c b/libedit/tolower.c new file mode 100644 index 0000000..bbe0311 --- /dev/null +++ b/libedit/tolower.c @@ -0,0 +1,674 @@ +#include + +static Rune ranges[112][3] = { + { 0x41, 0x5a, 32 }, + { 0xc0, 0xd6, 32 }, + { 0xd8, 0xde, 32 }, + { 0x130, 0x130, -199 }, + { 0x178, 0x178, -121 }, + { 0x181, 0x181, 210 }, + { 0x186, 0x186, 206 }, + { 0x189, 0x18a, 205 }, + { 0x18e, 0x18e, 79 }, + { 0x18f, 0x18f, 202 }, + { 0x190, 0x190, 203 }, + { 0x193, 0x193, 205 }, + { 0x194, 0x194, 207 }, + { 0x196, 0x196, 211 }, + { 0x197, 0x197, 209 }, + { 0x19c, 0x19c, 211 }, + { 0x19d, 0x19d, 213 }, + { 0x19f, 0x19f, 214 }, + { 0x1a6, 0x1a6, 218 }, + { 0x1a9, 0x1a9, 218 }, + { 0x1ae, 0x1ae, 218 }, + { 0x1b1, 0x1b2, 217 }, + { 0x1b7, 0x1b7, 219 }, + { 0x1c4, 0x1c4, 2 }, + { 0x1c7, 0x1c7, 2 }, + { 0x1ca, 0x1ca, 2 }, + { 0x1f1, 0x1f1, 2 }, + { 0x1f6, 0x1f6, -97 }, + { 0x1f7, 0x1f7, -56 }, + { 0x220, 0x220, -130 }, + { 0x23a, 0x23a, 10795 }, + { 0x23d, 0x23d, -163 }, + { 0x23e, 0x23e, 10792 }, + { 0x243, 0x243, -195 }, + { 0x244, 0x244, 69 }, + { 0x245, 0x245, 71 }, + { 0x37f, 0x37f, 116 }, + { 0x386, 0x386, 38 }, + { 0x388, 0x38a, 37 }, + { 0x38c, 0x38c, 64 }, + { 0x38e, 0x38f, 63 }, + { 0x391, 0x3a1, 32 }, + { 0x3a3, 0x3ab, 32 }, + { 0x3cf, 0x3cf, 8 }, + { 0x3f4, 0x3f4, -60 }, + { 0x3f9, 0x3f9, -7 }, + { 0x3fd, 0x3ff, -130 }, + { 0x400, 0x40f, 80 }, + { 0x410, 0x42f, 32 }, + { 0x4c0, 0x4c0, 15 }, + { 0x531, 0x556, 48 }, + { 0x10a0, 0x10c5, 7264 }, + { 0x10c7, 0x10c7, 7264 }, + { 0x10cd, 0x10cd, 7264 }, + { 0x13a0, 0x13ef, 38864 }, + { 0x13f0, 0x13f5, 8 }, + { 0x1e9e, 0x1e9e, -7615 }, + { 0x1f08, 0x1f0f, -8 }, + { 0x1f18, 0x1f1d, -8 }, + { 0x1f28, 0x1f2f, -8 }, + { 0x1f38, 0x1f3f, -8 }, + { 0x1f48, 0x1f4d, -8 }, + { 0x1f59, 0x1f59, -8 }, + { 0x1f5b, 0x1f5b, -8 }, + { 0x1f5d, 0x1f5d, -8 }, + { 0x1f5f, 0x1f5f, -8 }, + { 0x1f68, 0x1f6f, -8 }, + { 0x1f88, 0x1f8f, -8 }, + { 0x1f98, 0x1f9f, -8 }, + { 0x1fa8, 0x1faf, -8 }, + { 0x1fb8, 0x1fb9, -8 }, + { 0x1fba, 0x1fbb, -74 }, + { 0x1fbc, 0x1fbc, -9 }, + { 0x1fc8, 0x1fcb, -86 }, + { 0x1fcc, 0x1fcc, -9 }, + { 0x1fd8, 0x1fd9, -8 }, + { 0x1fda, 0x1fdb, -100 }, + { 0x1fe8, 0x1fe9, -8 }, + { 0x1fea, 0x1feb, -112 }, + { 0x1fec, 0x1fec, -7 }, + { 0x1ff8, 0x1ff9, -128 }, + { 0x1ffa, 0x1ffb, -126 }, + { 0x1ffc, 0x1ffc, -9 }, + { 0x2126, 0x2126, -7517 }, + { 0x212a, 0x212a, -8383 }, + { 0x212b, 0x212b, -8262 }, + { 0x2132, 0x2132, 28 }, + { 0x2160, 0x216f, 16 }, + { 0x24b6, 0x24cf, 26 }, + { 0x2c00, 0x2c2e, 48 }, + { 0x2c62, 0x2c62, -10743 }, + { 0x2c63, 0x2c63, -3814 }, + { 0x2c64, 0x2c64, -10727 }, + { 0x2c6d, 0x2c6d, -10780 }, + { 0x2c6e, 0x2c6e, -10749 }, + { 0x2c6f, 0x2c6f, -10783 }, + { 0x2c70, 0x2c70, -10782 }, + { 0x2c7e, 0x2c7f, -10815 }, + { 0xa77d, 0xa77d, -35332 }, + { 0xa78d, 0xa78d, -42280 }, + { 0xa7aa, 0xa7aa, -42308 }, + { 0xa7ab, 0xa7ab, -42319 }, + { 0xa7ac, 0xa7ac, -42315 }, + { 0xa7ad, 0xa7ad, -42305 }, + { 0xa7b0, 0xa7b0, -42258 }, + { 0xa7b1, 0xa7b1, -42282 }, + { 0xa7b2, 0xa7b2, -42261 }, + { 0xa7b3, 0xa7b3, 928 }, + { 0xff21, 0xff3a, 32 }, + { 0x10400, 0x10427, 40 }, + { 0x10c80, 0x10cb2, 64 }, + { 0x118a0, 0x118bf, 32 }, +}; + +static Rune singles[531] = { + 0x100, + 0x102, + 0x104, + 0x106, + 0x108, + 0x10a, + 0x10c, + 0x10e, + 0x110, + 0x112, + 0x114, + 0x116, + 0x118, + 0x11a, + 0x11c, + 0x11e, + 0x120, + 0x122, + 0x124, + 0x126, + 0x128, + 0x12a, + 0x12c, + 0x12e, + 0x132, + 0x134, + 0x136, + 0x139, + 0x13b, + 0x13d, + 0x13f, + 0x141, + 0x143, + 0x145, + 0x147, + 0x14a, + 0x14c, + 0x14e, + 0x150, + 0x152, + 0x154, + 0x156, + 0x158, + 0x15a, + 0x15c, + 0x15e, + 0x160, + 0x162, + 0x164, + 0x166, + 0x168, + 0x16a, + 0x16c, + 0x16e, + 0x170, + 0x172, + 0x174, + 0x176, + 0x179, + 0x17b, + 0x17d, + 0x182, + 0x184, + 0x187, + 0x18b, + 0x191, + 0x198, + 0x1a0, + 0x1a2, + 0x1a4, + 0x1a7, + 0x1ac, + 0x1af, + 0x1b3, + 0x1b5, + 0x1b8, + 0x1bc, + 0x1c5, + 0x1c8, + 0x1cb, + 0x1cd, + 0x1cf, + 0x1d1, + 0x1d3, + 0x1d5, + 0x1d7, + 0x1d9, + 0x1db, + 0x1de, + 0x1e0, + 0x1e2, + 0x1e4, + 0x1e6, + 0x1e8, + 0x1ea, + 0x1ec, + 0x1ee, + 0x1f2, + 0x1f4, + 0x1f8, + 0x1fa, + 0x1fc, + 0x1fe, + 0x200, + 0x202, + 0x204, + 0x206, + 0x208, + 0x20a, + 0x20c, + 0x20e, + 0x210, + 0x212, + 0x214, + 0x216, + 0x218, + 0x21a, + 0x21c, + 0x21e, + 0x222, + 0x224, + 0x226, + 0x228, + 0x22a, + 0x22c, + 0x22e, + 0x230, + 0x232, + 0x23b, + 0x241, + 0x246, + 0x248, + 0x24a, + 0x24c, + 0x24e, + 0x370, + 0x372, + 0x376, + 0x3d8, + 0x3da, + 0x3dc, + 0x3de, + 0x3e0, + 0x3e2, + 0x3e4, + 0x3e6, + 0x3e8, + 0x3ea, + 0x3ec, + 0x3ee, + 0x3f7, + 0x3fa, + 0x460, + 0x462, + 0x464, + 0x466, + 0x468, + 0x46a, + 0x46c, + 0x46e, + 0x470, + 0x472, + 0x474, + 0x476, + 0x478, + 0x47a, + 0x47c, + 0x47e, + 0x480, + 0x48a, + 0x48c, + 0x48e, + 0x490, + 0x492, + 0x494, + 0x496, + 0x498, + 0x49a, + 0x49c, + 0x49e, + 0x4a0, + 0x4a2, + 0x4a4, + 0x4a6, + 0x4a8, + 0x4aa, + 0x4ac, + 0x4ae, + 0x4b0, + 0x4b2, + 0x4b4, + 0x4b6, + 0x4b8, + 0x4ba, + 0x4bc, + 0x4be, + 0x4c1, + 0x4c3, + 0x4c5, + 0x4c7, + 0x4c9, + 0x4cb, + 0x4cd, + 0x4d0, + 0x4d2, + 0x4d4, + 0x4d6, + 0x4d8, + 0x4da, + 0x4dc, + 0x4de, + 0x4e0, + 0x4e2, + 0x4e4, + 0x4e6, + 0x4e8, + 0x4ea, + 0x4ec, + 0x4ee, + 0x4f0, + 0x4f2, + 0x4f4, + 0x4f6, + 0x4f8, + 0x4fa, + 0x4fc, + 0x4fe, + 0x500, + 0x502, + 0x504, + 0x506, + 0x508, + 0x50a, + 0x50c, + 0x50e, + 0x510, + 0x512, + 0x514, + 0x516, + 0x518, + 0x51a, + 0x51c, + 0x51e, + 0x520, + 0x522, + 0x524, + 0x526, + 0x528, + 0x52a, + 0x52c, + 0x52e, + 0x1e00, + 0x1e02, + 0x1e04, + 0x1e06, + 0x1e08, + 0x1e0a, + 0x1e0c, + 0x1e0e, + 0x1e10, + 0x1e12, + 0x1e14, + 0x1e16, + 0x1e18, + 0x1e1a, + 0x1e1c, + 0x1e1e, + 0x1e20, + 0x1e22, + 0x1e24, + 0x1e26, + 0x1e28, + 0x1e2a, + 0x1e2c, + 0x1e2e, + 0x1e30, + 0x1e32, + 0x1e34, + 0x1e36, + 0x1e38, + 0x1e3a, + 0x1e3c, + 0x1e3e, + 0x1e40, + 0x1e42, + 0x1e44, + 0x1e46, + 0x1e48, + 0x1e4a, + 0x1e4c, + 0x1e4e, + 0x1e50, + 0x1e52, + 0x1e54, + 0x1e56, + 0x1e58, + 0x1e5a, + 0x1e5c, + 0x1e5e, + 0x1e60, + 0x1e62, + 0x1e64, + 0x1e66, + 0x1e68, + 0x1e6a, + 0x1e6c, + 0x1e6e, + 0x1e70, + 0x1e72, + 0x1e74, + 0x1e76, + 0x1e78, + 0x1e7a, + 0x1e7c, + 0x1e7e, + 0x1e80, + 0x1e82, + 0x1e84, + 0x1e86, + 0x1e88, + 0x1e8a, + 0x1e8c, + 0x1e8e, + 0x1e90, + 0x1e92, + 0x1e94, + 0x1ea0, + 0x1ea2, + 0x1ea4, + 0x1ea6, + 0x1ea8, + 0x1eaa, + 0x1eac, + 0x1eae, + 0x1eb0, + 0x1eb2, + 0x1eb4, + 0x1eb6, + 0x1eb8, + 0x1eba, + 0x1ebc, + 0x1ebe, + 0x1ec0, + 0x1ec2, + 0x1ec4, + 0x1ec6, + 0x1ec8, + 0x1eca, + 0x1ecc, + 0x1ece, + 0x1ed0, + 0x1ed2, + 0x1ed4, + 0x1ed6, + 0x1ed8, + 0x1eda, + 0x1edc, + 0x1ede, + 0x1ee0, + 0x1ee2, + 0x1ee4, + 0x1ee6, + 0x1ee8, + 0x1eea, + 0x1eec, + 0x1eee, + 0x1ef0, + 0x1ef2, + 0x1ef4, + 0x1ef6, + 0x1ef8, + 0x1efa, + 0x1efc, + 0x1efe, + 0x2183, + 0x2c60, + 0x2c67, + 0x2c69, + 0x2c6b, + 0x2c72, + 0x2c75, + 0x2c80, + 0x2c82, + 0x2c84, + 0x2c86, + 0x2c88, + 0x2c8a, + 0x2c8c, + 0x2c8e, + 0x2c90, + 0x2c92, + 0x2c94, + 0x2c96, + 0x2c98, + 0x2c9a, + 0x2c9c, + 0x2c9e, + 0x2ca0, + 0x2ca2, + 0x2ca4, + 0x2ca6, + 0x2ca8, + 0x2caa, + 0x2cac, + 0x2cae, + 0x2cb0, + 0x2cb2, + 0x2cb4, + 0x2cb6, + 0x2cb8, + 0x2cba, + 0x2cbc, + 0x2cbe, + 0x2cc0, + 0x2cc2, + 0x2cc4, + 0x2cc6, + 0x2cc8, + 0x2cca, + 0x2ccc, + 0x2cce, + 0x2cd0, + 0x2cd2, + 0x2cd4, + 0x2cd6, + 0x2cd8, + 0x2cda, + 0x2cdc, + 0x2cde, + 0x2ce0, + 0x2ce2, + 0x2ceb, + 0x2ced, + 0x2cf2, + 0xa640, + 0xa642, + 0xa644, + 0xa646, + 0xa648, + 0xa64a, + 0xa64c, + 0xa64e, + 0xa650, + 0xa652, + 0xa654, + 0xa656, + 0xa658, + 0xa65a, + 0xa65c, + 0xa65e, + 0xa660, + 0xa662, + 0xa664, + 0xa666, + 0xa668, + 0xa66a, + 0xa66c, + 0xa680, + 0xa682, + 0xa684, + 0xa686, + 0xa688, + 0xa68a, + 0xa68c, + 0xa68e, + 0xa690, + 0xa692, + 0xa694, + 0xa696, + 0xa698, + 0xa69a, + 0xa722, + 0xa724, + 0xa726, + 0xa728, + 0xa72a, + 0xa72c, + 0xa72e, + 0xa732, + 0xa734, + 0xa736, + 0xa738, + 0xa73a, + 0xa73c, + 0xa73e, + 0xa740, + 0xa742, + 0xa744, + 0xa746, + 0xa748, + 0xa74a, + 0xa74c, + 0xa74e, + 0xa750, + 0xa752, + 0xa754, + 0xa756, + 0xa758, + 0xa75a, + 0xa75c, + 0xa75e, + 0xa760, + 0xa762, + 0xa764, + 0xa766, + 0xa768, + 0xa76a, + 0xa76c, + 0xa76e, + 0xa779, + 0xa77b, + 0xa77e, + 0xa780, + 0xa782, + 0xa784, + 0xa786, + 0xa78b, + 0xa790, + 0xa792, + 0xa796, + 0xa798, + 0xa79a, + 0xa79c, + 0xa79e, + 0xa7a0, + 0xa7a2, + 0xa7a4, + 0xa7a6, + 0xa7a8, + 0xa7b4, + 0xa7b6, +}; + +static int runecmp(const void* a, const void* b) { + Rune* ra = (Rune*)a; + Rune* rb = (Rune*)b; + return *ra - *rb; +} + +static int runerangecmp(const void* a, const void* b) { + Rune* ra = (Rune*)a; + Rune* rb = (Rune*)b; + if (rb[0] > *ra) + return -1; + else if (rb[1] < *ra) + return 1; + else + return 0; +} + +Rune tolowerrune(Rune ch) { + Rune* to = bsearch(&ch, ranges, 112, 3 * sizeof(Rune), &runerangecmp); + if (to) return (ch + to[2]); + to = bsearch(&ch, singles, 531, sizeof(Rune), &runecmp); + return (to ? (ch + 1) : ch); +} diff --git a/libedit/utf8.c b/libedit/utf8.c index c96a7a6..78325dc 100644 --- a/libedit/utf8.c +++ b/libedit/utf8.c @@ -1,6 +1,7 @@ #include #include #include +#define __USE_XOPEN #include const uint8_t UTF8_SeqBits[] = { 0x00u, 0x80u, 0xC0u, 0xE0u, 0xF0u, 0xF8u, 0xFCu, 0xFEu }; diff --git a/libedit/utils.c b/libedit/utils.c index 7003c33..4a6d231 100644 --- a/libedit/utils.c +++ b/libedit/utils.c @@ -1,13 +1,13 @@ #include #include #include -#include -#include #include #include #include #include #include +#include +#include #ifdef __MACH__ #define CLOCK_MONOTONIC 0 @@ -66,3 +66,9 @@ bool risword(Rune r) { bool risblank(Rune r) { return (r == ' ' || r == '\t' || r == '\n' || r == '\r' || r == RUNE_CRLF); } + +char* stringdup(const char* s) { + char* ns = (char*)malloc(strlen(s) + 1); + strcpy(ns,s); + return ns; +} diff --git a/libx/x11.c b/libx/x11.c index 9a51160..60e7c22 100644 --- a/libx/x11.c +++ b/libx/x11.c @@ -5,6 +5,7 @@ #include #include +static bool Running = true; static struct { Window root; Display* display; @@ -33,7 +34,7 @@ static void xftcolor(XftColor* xc, uint32_t c) { } void x11_deinit(void) { - XCloseDisplay(X.display); + Running = false; } void x11_init(XConfig* cfg) { @@ -184,7 +185,7 @@ static void handle_mouse(XEvent* e) { void x11_loop(void) { XEvent e; - while (true) { + while (Running) { XPeekEvent(X.display,&e); while (XPending(X.display)) { XNextEvent(X.display, &e); @@ -210,6 +211,7 @@ void x11_loop(void) { XCopyArea(X.display, X.pixmap, X.window, X.gc, 0, 0, X.width, X.height, 0, 0); XFlush(X.display); } + XCloseDisplay(X.display); } void x11_draw_rect(int color, int x, int y, int width, int height) { @@ -334,6 +336,20 @@ size_t x11_font_getglyphs(XftGlyphFontSpec* specs, const XGlyph* glyphs, int len return numspecs; } +void x11_draw_utf8(XFont* font, int fg, int bg, int x, int y, char* str) { + static XftGlyphFontSpec specs[256]; + size_t nspecs = 0; + while (*str && nspecs < 256) { + x11_font_getglyph(font, &(specs[nspecs]), *str); + specs[nspecs].x = x; + specs[nspecs].y = y; + x += font->base.width; + nspecs++; + str++; + } + x11_draw_glyphs(fg, bg, specs, nspecs); +} + void x11_warp_mouse(int x, int y) { XWarpPointer(X.display, X.window, X.window, 0, 0, X.width, X.height, x, y); } diff --git a/xpick.c b/xpick.c index 9f3ef7d..257c28b 100644 --- a/xpick.c +++ b/xpick.c @@ -2,18 +2,31 @@ #include #include #include +#include +#include static void redraw(int width, int height); static void mouse_input(MouseAct act, MouseBtn btn, int x, int y); static void keyboard_input(uint32_t key); -Buf Buffer; +typedef struct { + float score; + char* string; + size_t length; + size_t match_start; + size_t match_end; +} Choice; + +static unsigned Pos = 0; +static Buf Query; +static vec_t Choices = {0}; +static size_t ChoiceIdx = 0; static XFont Fonts; static XConfig Config = { .redraw = redraw, .handle_key = keyboard_input, .handle_mouse = mouse_input, - .palette = { + .palette = { /* ARGB color values */ 0xff002b36, 0xff073642, @@ -34,11 +47,128 @@ static XConfig Config = { } }; +static char* rdline(FILE* fin) { + if (feof(fin) || ferror(fin)) + return NULL; + size_t size = 256; + size_t index = 0; + char* str = (char*)malloc(size); + while (true) { + char ch = fgetc(fin); + if (ch == EOF) break; + str[index++] = ch; + str[index] = '\0'; + if (index+1 >= size) { + size = size << 1; + str = realloc(str, size); + } + if (ch == '\n') break; + } + return str; +} + +static int by_score(const void* a, const void* b) { + Choice* ca = ((Choice*)a); + Choice* cb = ((Choice*)b); + if (ca->score < cb->score) + return 1; + else if (ca->score > cb->score) + return -1; + else + return strcmp(ca->string, cb->string); +} + +static void load_choices(void) { + char* choice_text; + Choice choice = {0}; + vec_init(&Choices, sizeof(Choice)); + while ((choice_text = rdline(stdin)) != NULL) { + choice_text[strlen(choice_text)-1] = '\0'; + if (strlen(choice_text) > 0) { + choice.string = choice_text; + choice.length = strlen(choice_text); + choice.score = 1.0; + vec_push_back(&Choices, &choice); + } + } + vec_sort(&Choices, by_score); +} + +static char* find_match_start(char *str, int ch) { + for (; *str; str++) + if (tolower(*str) == tolower(ch)) + return str; + return NULL; +} + +static bool match(char *string, size_t offset, size_t *start, size_t *end) { + unsigned qpos = 0; + char* s = find_match_start(&string[offset], buf_get(&Query, qpos)); + char* e = s; + /* bail if no match for first char */ + if (s == NULL) return 0; + /* find the end of the match */ + for (unsigned bend = buf_end(&Query); qpos < bend; qpos++) + if ((e = find_match_start(e, buf_get(&Query, qpos))) == NULL) + return false; + /* make note of the matching range */ + *start = s - string; + *end = e - string; + /* Less than or equal is used in order to obtain the left-most match. */ + if (match(string, offset + 1, start, end) && (size_t)(e - s) <= *end - *start) { + *start = s - string; + *end = e - string; + } + return true; +} + +static void score(void) { + for (int i = 0; i < vec_size(&Choices); i++) { + Choice* choice = (Choice*)vec_at(&Choices, i); + float qlen = (float)buf_end(&Query); + if (match(choice->string, 0, &choice->match_start, &choice->match_end)) { + float clen = (float)(choice->match_end - choice->match_start); + choice->score = qlen / clen / (float)(choice->length); + } else { + choice->match_start = 0; + choice->match_end = 0; + choice->score = 0.0f; + } + } + vec_sort(&Choices, by_score); +} + +static void draw_runes(unsigned x, unsigned y, int fg, int bg, XGlyph* glyphs, size_t rlen) { + XftGlyphFontSpec specs[rlen]; + while (rlen) { + size_t nspecs = x11_font_getglyphs(specs, glyphs, rlen, &Fonts, x, y); + x11_draw_glyphs(fg, bg, specs, nspecs); + rlen -= nspecs; + } +} + static void redraw(int width, int height) { /* draw the background colors */ x11_draw_rect(CLR_BASE03, 0, 0, width, height); x11_draw_rect(CLR_BASE02, 0, 0, width, Fonts.base.height); x11_draw_rect(CLR_BASE01, 0, Fonts.base.height, width, 1); + /* create the array for the query glyphs */ + height = height / Fonts.base.height - 1, + width = width / Fonts.base.width; + XGlyph glyphs[width], *text = glyphs; + /* draw the query */ + unsigned start = 0, end = buf_end(&Query); + while (start < end) + (text++)->rune = buf_get(&Query, start++); + draw_runes(0, 0, CLR_BASE3, CLR_BASE03, glyphs, text - glyphs); + + for (size_t i = 0; i < vec_size(&Choices) && i < height; i++) { + Choice* choice = vec_at(&Choices, i); + if (i == ChoiceIdx) + x11_draw_utf8(&Fonts, CLR_BASE03, CLR_BASE1, 0, (i+2) * Fonts.base.height, choice->string); + else + x11_draw_utf8(&Fonts, CLR_BASE1, CLR_BASE03, 0, (i+2) * Fonts.base.height, choice->string); + } } static void mouse_input(MouseAct act, MouseBtn btn, int x, int y) { @@ -49,18 +179,47 @@ static void mouse_input(MouseAct act, MouseBtn btn, int x, int y) { } static void keyboard_input(uint32_t key) { - (void)key; + switch (key) { + case KEY_UP: + if (ChoiceIdx > 0) ChoiceIdx--; + break; + case KEY_DOWN: + if (ChoiceIdx+1 < vec_size(&Choices)) ChoiceIdx++; + break; + case KEY_ESCAPE: + ChoiceIdx = SIZE_MAX; + // fall-through + case '\n': case '\r': + x11_deinit(); + break; + case '\b': + if (Pos > 0) + buf_del(&Query, --Pos); + break; + case RUNE_ERR: + break; + default: + ChoiceIdx = 0; + buf_ins(&Query, Pos++, key); + break; + } + score(); } int main(int argc, char** argv) { - /* load the buffer */ - buf_init(&Buffer); - buf_setlocked(&Buffer, false); + load_choices(); + /* initialize the filter edit buffer */ + buf_init(&Query); + buf_setlocked(&Query, false); /* initialize the display engine */ x11_init(&Config); - x11_window("pick", Width, Height); + x11_dialog("pick", Width, Height); x11_show(); x11_font_load(&Fonts, FONTNAME); x11_loop(); + /* print out the choice */ + Choice* choice = (Choice*)vec_at(&Choices, ChoiceIdx); + if (vec_size(&Choices) && ChoiceIdx != SIZE_MAX) + puts(choice->string); return 0; } -- 2.49.0