# Implementation Tweaks and Bug Fixes
+* Arbitrary command execution (<|> operators)
* Add tag for ctags lookup
* Implement minimal regex search (per Kernighan article)
-* Arbitrary command execution (<|> operators)
* off by one error on scrolling wrapped lines
* block selection should handle brace-balancing
unsigned buf_lscan(Buf* buf, unsigned pos, Rune r);
unsigned buf_rscan(Buf* buf, unsigned pos, Rune r);
void buf_find(Buf* buf, size_t* beg, size_t* end);
+void buf_findstr(Buf* buf, char* str, size_t* beg, size_t* end);
unsigned buf_end(Buf* buf);
unsigned buf_byrune(Buf* buf, unsigned pos, int count);
unsigned buf_byline(Buf* buf, unsigned pos, int count);
void view_select(View* view, size_t row, size_t col);
char* view_fetch(View* view, size_t row, size_t col);
void view_find(View* view, size_t row, size_t col);
+void view_findstr(View* view, char* str);
void view_insert(View* view, Rune rune);
void view_delete(View* view);
void view_bol(View* view);
typedef struct {
char* tag;
- void (*action)(void);
+ union {
+ void (*noarg)(void);
+ void (*arg)(char* arg);
+ } action;
} Tag;
}
}
+static Rune* charstorunes(char* str) {
+ size_t len = 0;
+ Rune* runes = NULL;
+ while (str && *str) {
+ Rune rune = 0;
+ size_t length = 0;
+ while (!utf8decode(&rune, &length, *str++));
+ runes = realloc(runes, (len + 1) * sizeof(Rune));
+ runes[len++] = rune;
+ }
+ if (runes) {
+ runes = realloc(runes, (len + 1) * sizeof(Rune));
+ runes[len++] = '\0';
+ }
+ return runes;
+}
+
+static size_t runelen(Rune* runes) {
+ size_t len = 0;
+ for (; runes[len]; len++);
+ return len;
+}
+
+static int rune_match(Buf* buf, unsigned mbeg, unsigned mend, Rune* runes) {
+ for (; *runes; runes++, mbeg++) {
+ int cmp = *runes - buf_get(buf, mbeg);
+ if (cmp != 0) return cmp;
+ }
+ return 0;
+}
+
+void buf_findstr(Buf* buf, char* str, size_t* beg, size_t* end) {
+ if (!str) return;
+ Rune* runes = charstorunes(str);
+ size_t rlen = runelen(runes);
+ unsigned start = *beg, mbeg = start+1, mend = mbeg + rlen;
+
+ while (mbeg != start) {
+ if ((buf_get(buf, mbeg) == runes[0]) &&
+ (buf_get(buf, mend-1) == runes[rlen-1]) &&
+ (0 == rune_match(buf, mbeg, mend, runes)))
+ {
+ *beg = mbeg;
+ *end = mend;
+ break;
+ }
+ mbeg++, mend++;
+ if (mend >= buf_end(buf))
+ mbeg = 0, mend = rlen;
+ }
+
+ free(runes);
+}
+
unsigned buf_end(Buf* buf) {
size_t bufsz = buf->bufend - buf->bufstart;
size_t gapsz = buf->gapend - buf->gapstart;
}
}
+void view_findstr(View* view, char* str) {
+ Sel sel = view->selection;
+ buf_findstr(&(view->buffer), str, &sel.beg, &sel.end);
+ view->selection = sel;
+ view->sync_needed = true;
+}
+
void view_insert(View* view, Rune rune) {
if (rune == '\b') {
if (num_selected(view->selection))
len += n;
}
}
- str = realloc(str, len+1);
- if (str) str[len] = '\0';
+ if (str) {
+ str = realloc(str, len+1);
+ str[len] = '\0';
+ }
return str;
}
// Input Handlers
static void mouse_handler(MouseAct act, MouseBtn btn, int x, int y);
-static void tag_handler(char* cmd);
+static void tag_handler(char* cmd, char* arg);
static void key_handler(Rune key);
// Drawing Routines
static void cut(void);
static void copy(void);
static void paste(void);
+static void find(char* arg);
// Mouse Handling
static void mouse_left(enum RegionId id, size_t count, size_t row, size_t col);
*****************************************************************************/
static enum RegionId Focused = EDIT;
static Region Regions[NREGIONS] = { 0 };
-static bool TagWinExpanded = false;
static ButtonState MouseBtns[MOUSE_BTN_COUNT] = { 0 };
static XFont Font;
static XConfig Config = {
};
Tag Builtins[] = {
- { "Quit", quit },
- { "Save", save },
- { "Cut", cut },
- { "Copy", copy },
- { "Paste", paste },
- { "Undo", undo },
- { "Redo", redo },
- //{ "Find", NULL },
- { NULL, NULL }
+ { .tag = "Quit", .action.noarg = quit },
+ { .tag = "Save", .action.noarg = save },
+ { .tag = "Cut", .action.noarg = cut },
+ { .tag = "Copy", .action.noarg = copy },
+ { .tag = "Paste", .action.noarg = paste },
+ { .tag = "Undo", .action.noarg = undo },
+ { .tag = "Redo", .action.noarg = redo },
+ { .tag = "Find", .action.arg = find },
+ { .tag = NULL, .action.noarg = NULL }
};
void (*MouseActs[MOUSE_BTN_COUNT])(enum RegionId id, size_t count, size_t row, size_t col) = {
}
}
-static void tag_handler(char* cmd) {
+static void tag_handler(char* cmd, char* arg) {
Tag* tags = Builtins;
while (tags->tag) {
if (!strcmp(tags->tag, cmd)) {
Focused = EDIT;
- tags->action();
+ tags->action.arg(arg);
break;
}
tags++;
free(str);
}
+static void find(char* arg) {
+ view_findstr(getview(EDIT), arg);
+}
+
/* Mouse Handling
*****************************************************************************/
static void mouse_left(enum RegionId id, size_t count, size_t row, size_t col) {
cut();
} else {
char* str = view_fetch(getview(id), row, col);
- tag_handler(str);
+ char* arg = str;
+ if (!str) { return; }
+ /* first check if the arg is in the same selection as the tag/cmd */
+ while (*arg && !isspace(*arg++));
+ if (*arg) {
+ char* temp = stringdup(arg);
+ *arg = '\0', arg = temp;
+ } else {
+ /* if it isn't then check the tags buffer selection */
+ arg = view_getstr(getview(TAGS), NULL);
+ }
+ /* if we still haven't found it, check the edit buffer selection */
+ if (!arg) arg = view_getstr(getview(EDIT), NULL);
+ tag_handler(str, arg);
free(str);
+ free(arg);
}
}