184 lines
4 KiB
C
184 lines
4 KiB
C
#include <ctype.h> // for iscntrl
|
|
#include <stdio.h> // for NULL
|
|
#include <stdlib.h> // for free
|
|
#include <unistd.h> // 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;
|
|
}
|