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 \
#include <X11/Xft/Xft.h>
-#include <stdint.h>
typedef enum {
MOUSE_ACT_UP,
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);
uint32_t getmillis(void);
bool risword(Rune r);
bool risblank(Rune r);
+char* stringdup(const char* str);
/* Buffer management functions
*****************************************************************************/
--- /dev/null
+/**
+ @brief Generic vector implementation.
+ @author Michael D. Lowis
+ @license BSD 2-clause License
+*/
+#ifndef VEC_H
+#define VEC_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 */
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) {
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);
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] = {
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;
--- /dev/null
+#include <carl.h>
+
+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);
+}
#include <stdc.h>
#include <utf.h>
#include <edit.h>
+#define __USE_XOPEN
#include <wchar.h>
const uint8_t UTF8_SeqBits[] = { 0x00u, 0x80u, 0xC0u, 0xE0u, 0xF0u, 0xF8u, 0xFCu, 0xFEu };
#include <stdc.h>
#include <utf.h>
#include <edit.h>
-#include <time.h>
-#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
#ifdef __MACH__
#define CLOCK_MONOTONIC 0
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;
+}
#include <utf.h>
#include <locale.h>
+static bool Running = true;
static struct {
Window root;
Display* display;
}
void x11_deinit(void) {
- XCloseDisplay(X.display);
+ Running = false;
}
void x11_init(XConfig* cfg) {
void x11_loop(void) {
XEvent e;
- while (true) {
+ while (Running) {
XPeekEvent(X.display,&e);
while (XPending(X.display)) {
XNextEvent(X.display, &e);
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) {
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);
}
#include <X.h>
#include <utf.h>
#include <edit.h>
+#include <vec.h>
+#include <ctype.h>
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,
}
};
+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) {
}
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;
}