#include // for iscntrl #include // for NULL #include // for free #include // for STDOUT_FILENO #include "input.h" #include "file.h" // for editorSave #include "fn.h" // for E, editorConfig, erow, CTRL_KEY, editorKey::AR... #include "output.h" // for editorSetStatusMessage, editorDelChar, editorI... #include "search.h" // for editorSearch #include "terminal.h" // for editorReadKey char *editorPrompt(char *prompt, void (*callback)(char *, int)) { size_t bufsize = 128; char *buf = malloc(bufsize); size_t buflen = 0; buf[0] = '\0'; while (1) { editorSetStatusMessage(prompt, buf); editorRefreshScreen(); int c = editorReadKey(); if (c == DEL_KEY || c == CTRL_KEY('h') || c == BACKSPACE) { 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) { if (buflen == bufsize -1) { bufsize *= 2; buf = realloc(buf, bufsize); } buf[buflen++] = c; buf[buflen] = '\0'; } if (callback) callback(buf, c); } } void editorMoveCursor(int key) { erow *row = (E.cy >= E.numrows) ? NULL : &E.row[E.cy]; switch (key) { case ARROW_LEFT: if (E.cx != 0) { E.cx--; } else if (E.cy > 0) { E.cy--; E.cx = E.row[E.cy].size; } break; case ARROW_RIGHT: if (row && E.cx < row->size) { E.cx++; } else if (row && E.cx == row->size) { E.cy++; E.cx = 0; } break; case ARROW_UP: if (E.cy != 0) { E.cy--; } break; case ARROW_DOWN: if (E.cy < E.numrows) { E.cy++; } break; } row = (E.cy >= E.numrows) ? NULL : &E.row[E.cy]; int rowlen = row ? row->size : 0; if (E.cx > rowlen) { E.cx = rowlen; } } void editorProcessKeypress() { static int wantToQuit = 0; int c = editorReadKey(); // Blocking! switch (c) { case '\r': // ENTER if (wantToQuit == 0) { editorInsertNewLine(); } else { editorSetStatusMessage(""); } break; case CTRL_KEY('c'): if (E.dirty) { editorSetStatusMessage("WARNING: Unsaved changes. Exit anyway? [y/N]"); wantToQuit = 1; return; } exitEditor(); break; // Special cases if the user want to quit // TODO: Make a "question mode" with a callback for y and n case 'y': if (wantToQuit == 0) { editorInsertChar(c); } else { exitEditor(); } break; case CTRL_KEY('s'): editorSave(); break; case HOME_KEY: E.cx = 0; break; case END_KEY: if (E.cy < E.numrows) { E.cx = E.row[E.cy].size; } break; case CTRL_KEY('f'): editorSearch(); break; case BACKSPACE: case CTRL_KEY('h'): case DEL_KEY: if (c == DEL_KEY) editorMoveCursor(ARROW_RIGHT); editorDelChar(); break; case PAGE_UP: case PAGE_DOWN: { if (c == PAGE_UP) { E.cy = E.rowoff; } else if (c == PAGE_DOWN) { E.cy = E.rowoff + E.screenrows - 1; if (E.cy > E.numrows) E.cy = E.numrows; } int times = E.screenrows; while(times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN); } break; case ARROW_UP: case ARROW_DOWN: case ARROW_LEFT: case ARROW_RIGHT: editorMoveCursor(c); break; case CTRL_KEY('l'): case '\x1b': // ESC break; default: if (wantToQuit == 1) { wantToQuit = 0; editorSetStatusMessage(""); } else { editorInsertChar(c); } break; } wantToQuit = 0; }