kilo

Kilo: minimal text editor written in C
git clone git://git.dimitrijedobrota.com/kilo.git
Log | Files | Refs

commit 5be27f6bdaff408ce8ec92b0133876f9085419ea
parent fb8f78d58b8f580820bf6ffbbde0942217572e06
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sun,  9 Apr 2023 13:44:55 +0200

Search

Diffstat:
Mkilo.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 80 insertions(+), 4 deletions(-)

diff --git a/kilo.c b/kilo.c @@ -82,7 +82,7 @@ struct editorConfig E; void editorSetStatusMessage(const char *fmt, ...); void editorRefreshScreen(); -char *editorPrompt(char *prompt); +char *editorPrompt(char *prompt, void (*callback)(char *, int)); /*** terminal ***/ @@ -207,6 +207,17 @@ int editorRowCxToRx(erow *row, int cx) { return rx; } +int editorRowRxtoCx(erow *row, int rx) { + int cur_rx = 0, 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 cx; + } + return cx; +} + void editorUpdateRow(erow *row) { int tabs = 0; for (int j = 0; j < row->size; j++) @@ -367,7 +378,7 @@ void editorOpen(char *filename) { void editorSave() { if (E.filename == NULL) { - E.filename = editorPrompt("Save as: %s"); + E.filename = editorPrompt("Save as: %s", NULL); if (E.filename == NULL) { editorSetStatusMessage("Save aborted"); return; @@ -394,6 +405,65 @@ 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; + for (int 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 { @@ -417,7 +487,7 @@ void abFree(struct abuf *ab) { free(ab->b); } /*** input ***/ -char *editorPrompt(char *prompt) { +char *editorPrompt(char *prompt, void (*callback)(char *, int)) { size_t bufsize = 128, buflen; char *buf = malloc(bufsize); buf[buflen = 0] = '\0'; @@ -432,11 +502,13 @@ char *editorPrompt(char *prompt) { if (buflen != 0) buf[--buflen] = '\0'; } else if (c == '\x1b') { editorSetStatusMessage(""); + if (callback) callback(buf, c); free(buf); return NULL; } else if (c == '\r') { if (buflen != 0) { editorSetStatusMessage(""); + if (callback) callback(buf, c); return buf; } } else if (!iscntrl(c) && c < 128) { @@ -447,6 +519,8 @@ char *editorPrompt(char *prompt) { buf[buflen++] = c; buf[buflen] = '\0'; } + + if (callback) callback(buf, c); } } @@ -512,6 +586,8 @@ void editorProcessKeypress() { if (E.cy < E.numrows) E.cx = E.row[E.cy].size; break; + case CTRL_KEY('f'): editorFind(); break; + case BACKSPACE: case CTRL_KEY('h'): case DEL_KEY: @@ -672,7 +748,7 @@ int main(int argc, char *argv[]) { initEditor(); if (argc >= 2) { editorOpen(argv[1]); } - editorSetStatusMessage("HELP: Ctrl-S = save | Ctrl-Q = quit"); + editorSetStatusMessage("HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find"); while (1) { editorRefreshScreen();