Open dodona2 opened 5 years ago
that is a warning, it still compiles.
> make
> cc -o kilo kilo.c -Wall -W -pedantic -std=c99
> In file included from /usr/include/termios.h:25,
> from kilo.c:40:
> /usr/include/features.h:184:3: warning: #warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-Wcpp]
> # warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"
> ^~~~~~~
> kilo.c: In function ‘editorRefreshScreen’:
> kilo.c:953:19: warning: implicit declaration of function ‘time’; did you mean ‘tee’? [-Wimplicit-function-declaration]
> if (msglen && time(NULL)-E.statusmsg_time < 5)
>
with linux.gcc 9.2.1:
_/usr/include/features.h:185:3: warning: #warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-Wcpp]
185 | # warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"
| ^~~
kilo.c: In function ‘editorRefreshScreen’:
kilo.c:953:19: warning: implicit declaration of function ‘time’ [-Wimplicit-function-declaration]
953 | if (msglen && time(NULL)-E.statusmsgtime < 5)
| ^~~~
it's very easy to avoid the warnings. I just paste the corrected code:
/* Kilo -- A very simple editor in less than 1-kilo lines of code (as counted
/ #define _BSD_SOURCE -dod /
/ #include <sys/time.h> -dod /
/ Syntax highlight types /
struct editorSyntax { char filematch; char keywords; char singleline_comment_start[2]; char multiline_comment_start[3]; char multiline_comment_end[3]; int flags; };
/ This structure represents a single line of the file we are editing. / typedef struct erow { int idx; / Row index in the file, zero-based. / int size; / Size of the row, excluding the null term. / int rsize; / Size of the rendered row. / char chars; / Row content. / char render; / Row content "rendered" for screen (for TABs). / unsigned char hl; / Syntax highlight type for each character in render./ int hl_oc; / Row had open comment at end in last syntax highlight check. */ } erow;
typedef struct hlcolor { int r,g,b; } hlcolor;
struct editorConfig { int cx,cy; / Cursor x and y position in characters / int rowoff; / Offset of row displayed. / int coloff; / Offset of column displayed. / int screenrows; / Number of rows that we can show / int screencols; / Number of cols that we can show / int numrows; / Number of rows / int rawmode; / Is terminal raw mode enabled? / erow row; / Rows / int dirty; / File modified but not saved. / char filename; / Currently open filename / char statusmsg[80]; time_t statusmsg_time; struct editorSyntax syntax; / Current syntax highlight, or NULL. */ };
static struct editorConfig E;
enum KEY_ACTION{ KEY_NULL = 0, / NULL / CTRL_C = 3, / Ctrl-c / CTRL_D = 4, / Ctrl-d / CTRL_F = 6, / Ctrl-f / CTRL_H = 8, / Ctrl-h / TAB = 9, / Tab / CTRL_L = 12, / Ctrl+l / ENTER = 13, / Enter / CTRL_Q = 17, / Ctrl-q / CTRL_S = 19, / Ctrl-s / CTRL_U = 21, / Ctrl-u / ESC = 27, / Escape / BACKSPACE = 127, / Backspace / /* The following are just soft codes, not really reported by the
void editorSetStatusMessage(const char *fmt, ...);
/ =========================== Syntax highlights DB =========================
/ C / C++ / char C_HL_extensions[] = {".c",".cpp",NULL}; char C_HL_keywords[] = { / A few C / C++ keywords / "switch","if","while","for","break","continue","return","else", "struct","union","typedef","static","enum","class", / C types / "int|","long|","double|","float|","char|","unsigned|","signed|", "void|",NULL };
/* Here we define an array of syntax highlights by extensions, keywords,
/ ======================= Low level terminal handling ====================== /
static struct termios orig_termios; / In order to restore at exit./
void disableRawMode(int fd) { / Don't even check the return value as it's too late. / if (E.rawmode) { tcsetattr(fd,TCSAFLUSH,&orig_termios); E.rawmode = 0; } }
/ Called at exit to avoid remaining in raw mode. / void editorAtExit(void) { disableRawMode(STDIN_FILENO); }
/ Raw mode: 1960 magic shit. / int enableRawMode(int fd) { struct termios raw;
if (E.rawmode) return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO)) goto fatal;
atexit(editorAtExit);
if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
raw = orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char,
* no start/stop output control. */
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
/* output modes - disable post processing */
raw.c_oflag &= ~(OPOST);
/* control modes - set 8 bit chars */
raw.c_cflag |= (CS8);
/* local modes - choing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* control chars - set return condition: min number of bytes and timer. */
raw.c_cc[VMIN] = 0; /* Return each byte, or zero for timeout. */
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
/* put terminal in raw mode after flushing */
if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
E.rawmode = 1;
return 0;
fatal: errno = ENOTTY; return -1; }
/* Read a key from the terminal put in raw mode, trying to handle
escape sequences. */ int editorReadKey(int fd) { int nread; char c, seq[3]; while ((nread = read(fd,&c,1)) == 0); if (nread == -1) exit(1);
while(1) { switch(c) { case ESC: / escape sequence / / If this is just an ESC, we'll timeout here. / if (read(fd,seq,1) == 0) return ESC; if (read(fd,seq+1,1) == 0) return ESC;
/* ESC [ sequences. */
if (seq[0] == '[') {
if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */
if (read(fd,seq+2,1) == 0) return ESC;
if (seq[2] == '~') {
switch(seq[1]) {
case '3': return DEL_KEY;
case '5': return PAGE_UP;
case '6': return PAGE_DOWN;
}
}
} else {
switch(seq[1]) {
case 'A': return ARROW_UP;
case 'B': return ARROW_DOWN;
case 'C': return ARROW_RIGHT;
case 'D': return ARROW_LEFT;
case 'H': return HOME_KEY;
case 'F': return END_KEY;
}
}
}
/* ESC O sequences. */
else if (seq[0] == 'O') {
switch(seq[1]) {
case 'H': return HOME_KEY;
case 'F': return END_KEY;
}
}
break;
default:
return c;
}
} }
/* Use the ESC [6n escape sequence to query the horizontal cursor position
cursor is stored at rows and cols and 0 is returned. / int getCursorPosition(int ifd, int ofd, int rows, int *cols) { char buf[32]; unsigned int i = 0;
/ Report cursor location / if (write(ofd, "\x1b[6n", 4) != 4) return -1;
/ Read the response: ESC [ rows ; cols R / while (i < sizeof(buf)-1) { if (read(ifd,buf+i,1) != 1) break; if (buf[i] == 'R') break; i++; } buf[i] = '\0';
/ Parse it. / if (buf[0] != ESC || buf[1] != '[') return -1; if (sscanf(buf+2,"%d;%d",rows,cols) != 2) return -1; return 0; }
/* Try to get the number of columns in the current terminal. If the ioctl()
Returns 0 on success, -1 on error. / int getWindowSize(int ifd, int ofd, int rows, int *cols) { struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { / ioctl() failed. Try to query the terminal itself. / int orig_row, orig_col, retval;
/* Get the initial position so we can restore it later. */
retval = getCursorPosition(ifd,ofd,&orig_row,&orig_col);
if (retval == -1) goto failed;
/* Go to right/bottom margin and get position. */
if (write(ofd,"\x1b[999C\x1b[999B",12) != 12) goto failed;
retval = getCursorPosition(ifd,ofd,rows,cols);
if (retval == -1) goto failed;
/* Restore position. */
char seq[32];
snprintf(seq,32,"\x1b[%d;%dH",orig_row,orig_col);
if (write(ofd,seq,strlen(seq)) == -1) {
/* Can't recover... */
}
return 0;
} else { cols = ws.ws_col; rows = ws.ws_row; return 0; }
failed: return -1; }
/ ====================== Syntax highlight color scheme ==================== /
int is_separator(int c) { return c == '\0' || isspace(c) || strchr(",.()+-/*=~%[];",c) != NULL; }
/* Return true if the specified row last char is part of a multi line comment
/* Set every byte of row->hl (that corresponds to every character in the line)
to the right syntax highlight type (HL_ defines). / void editorUpdateSyntax(erow *row) { row->hl = realloc(row->hl,row->rsize); memset(row->hl,HL_NORMAL,row->rsize);
if (E.syntax == NULL) return; / No syntax, everything is HL_NORMAL. /
int i, prev_sep, in_string, in_comment; char *p; char *keywords = E.syntax->keywords; char scs = E.syntax->singleline_comment_start; char mcs = E.syntax->multiline_comment_start; char mce = E.syntax->multiline_comment_end;
/ Point to the first non-space char. / p = row->render; i = 0; / Current char offset / while(p && isspace(p)) { p++; i++; } prev_sep = 1; / Tell the parser if 'i' points to start of word. / in_string = 0; / Are we inside "" or '' ? / in_comment = 0; / Are we inside multi-line comment? /
/* If the previous line has an open comment, this line starts
while(p) { / Handle // comments. / if (prev_sep && p == scs[0] && (p+1) == scs[1]) { / From here to end is a comment */ memset(row->hl+i,HL_COMMENT,row->size-i); return; }
/* Handle multi line comments. */
if (in_comment) {
row->hl[i] = HL_MLCOMMENT;
if (*p == mce[0] && *(p+1) == mce[1]) {
row->hl[i+1] = HL_MLCOMMENT;
p += 2; i += 2;
in_comment = 0;
prev_sep = 1;
continue;
} else {
prev_sep = 0;
p++; i++;
continue;
}
} else if (*p == mcs[0] && *(p+1) == mcs[1]) {
row->hl[i] = HL_MLCOMMENT;
row->hl[i+1] = HL_MLCOMMENT;
p += 2; i += 2;
in_comment = 1;
prev_sep = 0;
continue;
}
/* Handle "" and '' */
if (in_string) {
row->hl[i] = HL_STRING;
if (*p == '\\') {
row->hl[i+1] = HL_STRING;
p += 2; i += 2;
prev_sep = 0;
continue;
}
if (*p == in_string) in_string = 0;
p++; i++;
continue;
} else {
if (*p == '"' || *p == '\'') {
in_string = *p;
row->hl[i] = HL_STRING;
p++; i++;
prev_sep = 0;
continue;
}
}
/* Handle non printable chars. */
if (!isprint(*p)) {
row->hl[i] = HL_NONPRINT;
p++; i++;
prev_sep = 0;
continue;
}
/* Handle numbers */
if ((isdigit(*p) && (prev_sep || row->hl[i-1] == HL_NUMBER)) ||
(*p == '.' && i >0 && row->hl[i-1] == HL_NUMBER)) {
row->hl[i] = HL_NUMBER;
p++; i++;
prev_sep = 0;
continue;
}
/* Handle keywords and lib calls */
if (prev_sep) {
int j;
for (j = 0; keywords[j]; j++) {
int klen = strlen(keywords[j]);
int kw2 = keywords[j][klen-1] == '|';
if (kw2) klen--;
if (!memcmp(p,keywords[j],klen) &&
is_separator(*(p+klen)))
{
/* Keyword */
memset(row->hl+i,kw2 ? HL_KEYWORD2 : HL_KEYWORD1,klen);
p += klen;
i += klen;
break;
}
}
if (keywords[j] != NULL) {
prev_sep = 0;
continue; /* We had a keyword match */
}
}
/* Not special chars */
prev_sep = is_separator(*p);
p++; i++;
}
/* Propagate syntax change to the next row if the open commen
/ Maps syntax highlight token types to terminal colors. / int editorSyntaxToColor(int hl) { switch(hl) { case HL_COMMENT: case HL_MLCOMMENT: return 36; / cyan / case HL_KEYWORD1: return 33; / yellow / case HL_KEYWORD2: return 32; / green / case HL_STRING: return 35; / magenta / case HL_NUMBER: return 31; / red / case HL_MATCH: return 34; / blu / default: return 37; / white / } }
/* Select the syntax highlight scheme depending on the filename,
/ ======================= Editor rows implementation ======================= /
/ Update the rendered version and the syntax highlight of a row. / void editorUpdateRow(erow *row) { int tabs = 0, nonprint = 0, j, idx;
/* Create a version of the row we can directly print on the screen,
respecting tabs, substituting non printable characters with '?'. */ free(row->render); for (j = 0; j < row->size; j++) if (row->chars[j] == TAB) tabs++;
row->render = malloc(row->size + tabs8 + nonprint9 + 1); idx = 0; for (j = 0; j < row->size; j++) { if (row->chars[j] == TAB) { row->render[idx++] = ' '; while((idx+1) % 8 != 0) row->render[idx++] = ' '; } else { row->render[idx++] = row->chars[j]; } } row->rsize = idx; row->render[idx] = '\0';
/ Update the syntax highlighting attributes of the row. / editorUpdateSyntax(row); }
/* Insert a row at the specified position, shifting the other rows on the bottom
/ Free row's heap allocated stuff. / void editorFreeRow(erow *row) { free(row->render); free(row->chars); free(row->hl); }
/* Remove the row at the specified position, shifting the remainign on the
top. / void editorDelRow(int at) { erow row;
if (at >= E.numrows) return; row = E.row+at; editorFreeRow(row); memmove(E.row+at,E.row+at+1,sizeof(E.row[0])*(E.numrows-at-1)); for (int j = at; j < E.numrows-1; j++) E.row[j].idx++; E.numrows--; E.dirty++; }
/* Turn the editor rows into a single heap-allocated string.
the final nulterm. / char editorRowsToString(int buflen) { char buf = NULL, *p; int totlen = 0; int j;
/ Compute count of bytes / for (j = 0; j < E.numrows; j++) totlen += E.row[j].size+1; / +1 is for "\n" at end of every row / buflen = totlen; totlen++; / Also make space for nulterm */
p = buf = malloc(totlen); for (j = 0; j < E.numrows; j++) { memcpy(p,E.row[j].chars,E.row[j].size); p += E.row[j].size; p = '\n'; p++; } p = '\0'; return buf; }
/* Insert a character at the specified position in a row, moving the remaining
/ Append the string 's' at the end of a row / void editorRowAppendString(erow row, char s, size_t len) { row->chars = realloc(row->chars,row->size+len+1); memcpy(row->chars+row->size,s,len); row->size += len; row->chars[row->size] = '\0'; editorUpdateRow(row); E.dirty++; }
/ Delete the character at offset 'at' from the specified row. / void editorRowDelChar(erow *row, int at) { if (row->size <= at) return; memmove(row->chars+at,row->chars+at+1,row->size-at); editorUpdateRow(row); row->size--; E.dirty++; }
/ Insert the specified char at the current prompt position. / void editorInsertChar(int c) { int filerow = E.rowoff+E.cy; int filecol = E.coloff+E.cx; erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
/* If the row where the cursor is currently located does not exist in our
* logical representaion of the file, add enough empty rows as needed. */
if (!row) {
while(E.numrows <= filerow)
editorInsertRow(E.numrows,"",0);
}
row = &E.row[filerow];
editorRowInsertChar(row,filecol,c);
if (E.cx == E.screencols-1)
E.coloff++;
else
E.cx++;
E.dirty++;
}
/* Inserting a newline is slightly complex as we have to handle inserting a
newline in the middle of a line, splitting the line as needed. / void editorInsertNewline(void) { int filerow = E.rowoff+E.cy; int filecol = E.coloff+E.cx; erow row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row) { if (filerow == E.numrows) { editorInsertRow(filerow,"",0); goto fixcursor; } return; } /* If the cursor is over the current line size, we want to conceptually
/ Delete the char at the current prompt position. / void editorDelChar() { int filerow = E.rowoff+E.cy; int filecol = E.coloff+E.cx; erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row || (filecol == 0 && filerow == 0)) return;
if (filecol == 0) {
/* Handle the case of column 0, we need to move the current line
* on the right of the previous one. */
filecol = E.row[filerow-1].size;
editorRowAppendString(&E.row[filerow-1],row->chars,row->size);
editorDelRow(filerow);
row = NULL;
if (E.cy == 0)
E.rowoff--;
else
E.cy--;
E.cx = filecol;
if (E.cx >= E.screencols) {
int shift = (E.screencols-E.cx)+1;
E.cx -= shift;
E.coloff += shift;
}
} else {
editorRowDelChar(row,filecol-1);
if (E.cx == 0 && E.coloff)
E.coloff--;
else
E.cx--;
}
if (row) editorUpdateRow(row);
E.dirty++;
}
/* Load the specified program in the editor memory and returns 0 on success
or 1 on error. / int editorOpen(char filename) { FILE *fp;
E.dirty = 0; free(E.filename); E.filename = strdup(filename);
fp = fopen(filename,"r"); if (!fp) { if (errno != ENOENT) { perror("Opening file"); exit(1); } return 1; }
char *line = NULL; size_t linecap = 0; ssize_t linelen; while((linelen = getline(&line,&linecap,fp)) != -1) { if (linelen && (line[linelen-1] == '\n' || line[linelen-1] == '\r')) line[--linelen] = '\0'; editorInsertRow(E.numrows,line,linelen); } free(line); fclose(fp); E.dirty = 0; return 0; }
/ Save the current file on disk. Return 0 on success, 1 on error. / int editorSave(void) { int len; char *buf = editorRowsToString(&len); int fd = open(E.filename,O_RDWR|O_CREAT,0644); if (fd == -1) goto writeerr;
/* Use truncate + a single write(2) call in order to make saving
* a bit safer, under the limits of what we can do in a small editor. */
if (ftruncate(fd,len) == -1) goto writeerr;
if (write(fd,buf,len) != len) goto writeerr;
close(fd);
free(buf);
E.dirty = 0;
editorSetStatusMessage("%d bytes written on disk", len);
return 0;
writeerr: free(buf); if (fd != -1) close(fd); editorSetStatusMessage("Can't save! I/O error: %s",strerror(errno)); return 1; }
/ ============================= Terminal update ============================ /
/* We define a very simple "append buffer" structure, that is an heap
void abAppend(struct abuf ab, const char s, int len) { char *new = realloc(ab->b,ab->len+len);
if (new == NULL) return;
memcpy(new+ab->len,s,len);
ab->b = new;
ab->len += len;
}
void abFree(struct abuf *ab) { free(ab->b); }
/* This function writes the whole screen using VT100 escape characters
starting from the logical state of the editor in the global state 'E'. / void editorRefreshScreen(void) { int y; erow r; char buf[32]; struct abuf ab = ABUF_INIT;
abAppend(&ab,"\x1b[?25l",6); / Hide cursor. / abAppend(&ab,"\x1b[H",3); / Go home. / for (y = 0; y < E.screenrows; y++) { int filerow = E.rowoff+y;
if (filerow >= E.numrows) {
if (E.numrows == 0 && y == E.screenrows/3) {
char welcome[80];
int welcomelen = snprintf(welcome,sizeof(welcome),
"Kilo editor -- verison %s\x1b[0K\r\n", KILO_VERSION);
int padding = (E.screencols-welcomelen)/2;
if (padding) {
abAppend(&ab,"~",1);
padding--;
}
while(padding--) abAppend(&ab," ",1);
abAppend(&ab,welcome,welcomelen);
} else {
abAppend(&ab,"~\x1b[0K\r\n",7);
}
continue;
}
r = &E.row[filerow];
int len = r->rsize - E.coloff;
int current_color = -1;
if (len > 0) {
if (len > E.screencols) len = E.screencols;
char *c = r->render+E.coloff;
unsigned char *hl = r->hl+E.coloff;
int j;
for (j = 0; j < len; j++) {
if (hl[j] == HL_NONPRINT) {
char sym;
abAppend(&ab,"\x1b[7m",4);
if (c[j] <= 26)
sym = '@'+c[j];
else
sym = '?';
abAppend(&ab,&sym,1);
abAppend(&ab,"\x1b[0m",4);
} else if (hl[j] == HL_NORMAL) {
if (current_color != -1) {
abAppend(&ab,"\x1b[39m",5);
current_color = -1;
}
abAppend(&ab,c+j,1);
} else {
int color = editorSyntaxToColor(hl[j]);
if (color != current_color) {
char buf[16];
int clen = snprintf(buf,sizeof(buf),"\x1b[%dm",color);
current_color = color;
abAppend(&ab,buf,clen);
}
abAppend(&ab,c+j,1);
}
}
}
abAppend(&ab,"\x1b[39m",5);
abAppend(&ab,"\x1b[0K",4);
abAppend(&ab,"\r\n",2);
}
/ Create a two rows status. First row: / abAppend(&ab,"\x1b[0K",4); abAppend(&ab,"\x1b[7m",4); char status[80], rstatus[80]; int len = snprintf(status, sizeof(status), "%.20s - %d lines %s", E.filename, E.numrows, E.dirty ? "(modified)" : ""); int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d",E.rowoff+E.cy+1,E.numrows); if (len > E.screencols) len = E.screencols; abAppend(&ab,status,len); while(len < E.screencols) { if (E.screencols - len == rlen) { abAppend(&ab,rstatus,rlen); break; } else { abAppend(&ab," ",1); len++; } } abAppend(&ab,"\x1b[0m\r\n",6);
/ Second row depends on E.statusmsg and the status message update time. / abAppend(&ab,"\x1b[0K",4); int msglen = strlen(E.statusmsg); if (msglen && time(NULL)-E.statusmsg_time < 5) abAppend(&ab,E.statusmsg,msglen <= E.screencols ? msglen : E.screencols);
/* Put cursor at its current position. Note that the horizontal position
/* Set an editor status message for the second line of the status, at the
/ =============================== Find mode ================================ /
void editorFind(int fd) { char query[KILO_QUERY_LEN+1] = {0}; int qlen = 0; int last_match = -1; / Last line where a match was found. -1 for none. / int find_next = 0; / if 1 search next, if -1 search prev. / int saved_hl_line = -1; / No saved HL / char *saved_hl = NULL;
if (saved_hl) { \
memcpy(E.row[saved_hl_line].hl,saved_hl, E.row[saved_hl_line].rsize); \
saved_hl = NULL; \
} \
} while (0)
/* Save the cursor position in order to restore it later. */
int saved_cx = E.cx, saved_cy = E.cy;
int saved_coloff = E.coloff, saved_rowoff = E.rowoff;
while(1) {
editorSetStatusMessage(
"Search: %s (Use ESC/Arrows/Enter)", query);
editorRefreshScreen();
int c = editorReadKey(fd);
if (c == DEL_KEY || c == CTRL_H || c == BACKSPACE) {
if (qlen != 0) query[--qlen] = '\0';
last_match = -1;
} else if (c == ESC || c == ENTER) {
if (c == ESC) {
E.cx = saved_cx; E.cy = saved_cy;
E.coloff = saved_coloff; E.rowoff = saved_rowoff;
}
FIND_RESTORE_HL;
editorSetStatusMessage("");
return;
} else if (c == ARROW_RIGHT || c == ARROW_DOWN) {
find_next = 1;
} else if (c == ARROW_LEFT || c == ARROW_UP) {
find_next = -1;
} else if (isprint(c)) {
if (qlen < KILO_QUERY_LEN) {
query[qlen++] = c;
query[qlen] = '\0';
last_match = -1;
}
}
/* Search occurrence. */
if (last_match == -1) find_next = 1;
if (find_next) {
char *match = NULL;
int match_offset = 0;
int i, current = last_match;
for (i = 0; i < E.numrows; i++) {
current += find_next;
if (current == -1) current = E.numrows-1;
else if (current == E.numrows) current = 0;
match = strstr(E.row[current].render,query);
if (match) {
match_offset = match-E.row[current].render;
break;
}
}
find_next = 0;
/* Highlight */
FIND_RESTORE_HL;
if (match) {
erow *row = &E.row[current];
last_match = current;
if (row->hl) {
saved_hl_line = current;
saved_hl = malloc(row->rsize);
memcpy(saved_hl,row->hl,row->rsize);
memset(row->hl+match_offset,HL_MATCH,qlen);
}
E.cy = 0;
E.cx = match_offset;
E.rowoff = current;
E.coloff = 0;
/* Scroll horizontally as needed. */
if (E.cx > E.screencols) {
int diff = E.cx - E.screencols;
E.cx -= diff;
E.coloff += diff;
}
}
}
}
}
/ ========================= Editor events handling ======================== /
/ Handle cursor position change because arrow keys were pressed. / void editorMoveCursor(int key) { int filerow = E.rowoff+E.cy; int filecol = E.coloff+E.cx; int rowlen; erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
switch(key) {
case ARROW_LEFT:
if (E.cx == 0) {
if (E.coloff) {
E.coloff--;
} else {
if (filerow > 0) {
E.cy--;
E.cx = E.row[filerow-1].size;
if (E.cx > E.screencols-1) {
E.coloff = E.cx-E.screencols+1;
E.cx = E.screencols-1;
}
}
}
} else {
E.cx -= 1;
}
break;
case ARROW_RIGHT:
if (row && filecol < row->size) {
if (E.cx == E.screencols-1) {
E.coloff++;
} else {
E.cx += 1;
}
} else if (row && filecol == row->size) {
E.cx = 0;
E.coloff = 0;
if (E.cy == E.screenrows-1) {
E.rowoff++;
} else {
E.cy += 1;
}
}
break;
case ARROW_UP:
if (E.cy == 0) {
if (E.rowoff) E.rowoff--;
} else {
E.cy -= 1;
}
break;
case ARROW_DOWN:
if (filerow < E.numrows) {
if (E.cy == E.screenrows-1) {
E.rowoff++;
} else {
E.cy += 1;
}
}
break;
}
/* Fix cx if the current line has not enough chars. */
filerow = E.rowoff+E.cy;
filecol = E.coloff+E.cx;
row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
rowlen = row ? row->size : 0;
if (filecol > rowlen) {
E.cx -= filecol-rowlen;
if (E.cx < 0) {
E.coloff += E.cx;
E.cx = 0;
}
}
}
/* Process events arriving from the standard input, which is, the user
is typing stuff on the terminal. */
void editorProcessKeypress(int fd) { /* When the file is modified, requires Ctrl-q to be pressed N times
int c = editorReadKey(fd); switch(c) { case ENTER: / Enter / editorInsertNewline(); break; case CTRL_C: / Ctrl-c / /* We ignore ctrl-c, it can't be so simple to lose the changes
case ARROW_UP: case ARROW_DOWN: case ARROW_LEFT: case ARROW_RIGHT: editorMoveCursor(c); break; case CTRL_L: / ctrl+l, clear screen / / Just refresht the line as side effect. / break; case ESC: / Nothing to do for ESC in this mode. / break; default: editorInsertChar(c); break; }
quit_times = KILO_QUIT_TIMES; / Reset it to the original value. / }
int editorFileWasModified(void) { return E.dirty; }
void initEditor(void) { E.cx = 0; E.cy = 0; E.rowoff = 0; E.coloff = 0; E.numrows = 0; E.row = NULL; E.dirty = 0; E.filename = NULL; E.syntax = NULL; if (getWindowSize(STDIN_FILENO,STDOUT_FILENO, &E.screenrows,&E.screencols) == -1) { perror("Unable to query the screen for size (columns / rows)"); exit(1); } E.screenrows -= 2; / Get room for status bar. / }
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr,"Usage: kilo
initEditor();
editorSelectSyntaxHighlight(argv[1]);
editorOpen(argv[1]);
enableRawMode(STDIN_FILENO);
editorSetStatusMessage(
"HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find");
while(1) {
editorRefreshScreen();
editorProcessKeypress(STDIN_FILENO);
}
return 0;
}
just for the records:
Fedora release 29
gcc (GCC) 8.2.1 20181215 (Red Hat 8.2.1-6)
In file included from /usr/include/termios.h:25, from kilo.c:40: /usr/include/features.h:184:3: warning: #warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-Wcpp]
warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"
^
~~ kilo.c: In function ‘editorRefreshScreen’: kilo.c:953:19: warning: implicit declaration of function ‘time’; did you mean ‘tee’? [-Wimplicit-function-declaration] if (msglen && time(NULL)-E.statusmsg_time < 5) ^~~~ tee