diff --git a/kilo.c b/kilo.c index 1dd38dd..efe4073 100644 --- a/kilo.c +++ b/kilo.c @@ -69,7 +69,7 @@ struct editorConfig E; void editorSetStatusMessage(const char *fmt, ...); void editorRefreshScreen(); -char *editorPrompt(char *prompt); +char *editorPrompt(char *prompt, void (*callback)(char *, int)); /*** terminal ***/ @@ -269,6 +269,27 @@ int editorRowCxToRx(erow *row, int cx) return rx; } +int editorRowRxToCx(erow *row, int rx) +{ + int cur_rx = 0; + int cx; + for (cx = 0; cx < row->size; cx++) + { + if (row->chars[cx] == '\t') + { + cur_rx += (KILO_TAB_STOP - 1) - (cur_rx % KILO_TAB_STOP); + } + cur_rx++; + + if (cur_rx > rx) + { + return rx; + } + } + + return cx; +} + void editorUpdateRow(erow *row) { int tabs = 0; @@ -501,7 +522,7 @@ void editorSave() { if (E.filename == NULL) { - E.filename = editorPrompt("Save as: %s (ESC to cancel)"); + E.filename = editorPrompt("Save as: %s (ESC to cancel)", NULL); if (E.filename == NULL) { editorSetStatusMessage("Save aborted"); @@ -532,6 +553,87 @@ void editorSave() editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno)); } +/*** find ***/ + +void editorFindCallback(char *query, int key) +{ + static int last_match = -1; + static int direction = 1; + + if (key == '\r' || key == '\x1b') + { + last_match = -1; + direction = 1; + return; + } + else if (key == ARROW_RIGHT || key == ARROW_DOWN) + { + direction = 1; + } + else if (key == ARROW_LEFT || key == ARROW_UP) + { + direction = -1; + } + else + { + last_match = -1; + direction = 1; + } + + if (last_match == -1) + { + direction = 1; + } + int current = last_match; + int i; + for (i = 0; i < E.numrows; i++) + { + current += direction; + if (current == -1) + { + current = E.numrows -1; + } + else if (current == E.numrows) + { + current = 0; + } + + erow *row = &E.row[current]; + char *match = strstr(row->render, query); + if (match) + { + last_match = current; + E.cy = current; + E.cx = editorRowRxToCx(row, match - row->render); + E.rowoff = E.numrows; + break; + } + } +} + +void editorFind() +{ + int saved_cx = E.cx; + int saved_cy = E.cy; + int saved_coloff = E.coloff; + int saved_rowoff = E.rowoff; + + char *query = editorPrompt("Search: %s (Use ESC/Arrows/Enter)", + editorFindCallback); + + if (query) + { + free(query); + } + else + { + E.cx = saved_cx; + E.cy = saved_cy; + E.coloff = saved_coloff; + E.rowoff = saved_rowoff; + } +} + /*** append buffer ***/ struct abuf { @@ -735,7 +837,7 @@ void editorSetStatusMessage(const char *fmt, ...) /*** input ***/ -char *editorPrompt(char *prompt) +char *editorPrompt(char *prompt, void (*callback)(char *, int)) { size_t bufsize = 128; char *buf = malloc(bufsize); @@ -759,6 +861,10 @@ char *editorPrompt(char *prompt) else if (c == '\x1b') { editorSetStatusMessage(""); + if (callback) + { + callback(buf, c); + } free(buf); return NULL; } @@ -767,6 +873,10 @@ char *editorPrompt(char *prompt) if (buflen != 0) { editorSetStatusMessage(""); + if (callback) + { + callback(buf, c); + } return buf; } } @@ -780,6 +890,11 @@ char *editorPrompt(char *prompt) buf[buflen++] = c; buf[buflen] = '\0'; } + + if (callback) + { + callback(buf, c); + } } } @@ -876,6 +991,10 @@ void editorProcessKeypress() } break; + case CTRL_KEY('f'): + editorFind(); + break; + case BACKSPACE: case CTRL_KEY('h'): case DEL_KEY: @@ -962,7 +1081,8 @@ int main(int argc, char *argv[]) editorOpen(argv[1]); } - editorSetStatusMessage("HELP: Ctrl-S = save | Ctrl-Q = quit"); + editorSetStatusMessage( + "HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find"); while (1) {