diff --git a/level.cpp b/level.cpp index 83f75de..e5072ce 100644 --- a/level.cpp +++ b/level.cpp @@ -73,7 +73,7 @@ struct editorConfig E; void editorSetStatusMessage(const char* fmt, ...); void editorRefreshScreen(); -char *editorPrompt(const char *prompt); +char *editorPrompt(const char *prompt, void (*callback)(char *, int)); /*** terminal ***/ @@ -208,6 +208,19 @@ 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 += (LEVEL_TAB_STOP - 1) - (cur_rx % LEVEL_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++) { @@ -359,7 +372,7 @@ char* editorRowsToString(int* buflen) { void editorOpen(char *filename) { free(E.filename); -E.filename = strdup(filename); + E.filename = strdup(filename); FILE *fp = fopen(filename, "r"); if (!fp) die("fopen"); @@ -380,7 +393,7 @@ E.filename = strdup(filename); 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"); return; @@ -408,6 +421,61 @@ 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; + } + } + + free(query); +} + +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 (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 { @@ -536,7 +604,7 @@ void editorSetStatusMessage(const char* fmt, ...) { /*** input ***/ -char *editorPrompt(const char* prompt) { +char *editorPrompt(const char* prompt, void (*callback)(char *, int)) { size_t bufsize = 128; char* buf = (char*)malloc(bufsize); @@ -553,11 +621,13 @@ char *editorPrompt(const char* prompt) { if (buflen != 0) buf[--buflen] = '\0'; } else if (c == ESCAPE_CONST) { 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) { @@ -568,6 +638,8 @@ char *editorPrompt(const char* prompt) { buf[buflen++] = c; buf[buflen] = '\0'; } + + if (callback) callback(buf, c); } } @@ -629,6 +701,10 @@ 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: @@ -694,7 +770,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();