From 69b3ad89b631ca0cfae973088c8154e7ea9af778 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 16:36:35 +0100 Subject: [PATCH 01/17] Makefile: support user-provided C/LDFLAGS --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 13620cc1..a9a0b131 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ all: kilo kilo: kilo.c - $(CC) -o kilo kilo.c -Wall -W -pedantic -std=c99 + $(CC) $(CFLAGS) $(LDFLAGS) -o kilo kilo.c -Wall -W -pedantic -std=c99 clean: rm kilo From c97ca0ed79e2c1039967513f00ea0d2f53ea5c25 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 16:37:25 +0100 Subject: [PATCH 02/17] Makefile: optionally incude user-provided config.mak --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index a9a0b131..a08248bd 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +-include config.mak + all: kilo kilo: kilo.c From 939da83127a10f80f6fa69098016182778e50420 Mon Sep 17 00:00:00 2001 From: John Little Date: Mon, 8 Apr 2019 16:34:58 +0100 Subject: [PATCH 03/17] Handling of HOME and END --- kilo.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 406eb7be..55d14960 100644 --- a/kilo.c +++ b/kilo.c @@ -1167,6 +1167,17 @@ void editorMoveCursor(int key) { } } break; + case HOME_KEY: + E.cx = 0; + E.coloff = 0; + break; + case END_KEY: + E.cx = E.row[filerow].size; + if (E.cx > E.screencols-1) { + E.coloff = E.cx-E.screencols+1; + E.cx = E.screencols-1; + } + break; } /* Fix cx if the current line has not enough chars. */ filerow = E.rowoff+E.cy; @@ -1233,7 +1244,8 @@ void editorProcessKeypress(int fd) { ARROW_DOWN); } break; - + case HOME_KEY: + case END_KEY: case ARROW_UP: case ARROW_DOWN: case ARROW_LEFT: From f5b7cdae2937066948a5b40dd238fa9fd00a242a Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 17:13:08 +0100 Subject: [PATCH 04/17] add basic python syntax highlight support --- kilo.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 55d14960..f5d2739f 100644 --- a/kilo.c +++ b/kilo.c @@ -183,6 +183,18 @@ char *C_HL_keywords[] = { "void|","short|","auto|","const|","bool|",NULL }; + /* python */ +char *PY_HL_extensions[] = {".py","python",NULL}; +char *PY_HL_keywords[] = { + "def","if","while","for","break","return","continue","else","elif", + "import","try","except","in","and","or","is","not","with","as", + "True","False","None","class", + /* Python types */ + "int|","str|","unicode|","dict|","float|","repr|","long|","eval|", + "tuple|","list|","set|","frozenset|","chr|","unichr|","ord|","hex|", + NULL +}; + /* Here we define an array of syntax highlights by extensions, keywords, * comments delimiters and flags. */ struct editorSyntax HLDB[] = { @@ -192,7 +204,13 @@ struct editorSyntax HLDB[] = { C_HL_keywords, "//","/*","*/", HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_NUMBERS - } + }, + { + PY_HL_extensions, + PY_HL_keywords, + "#","\"\"\"", "\"\"\"", + HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_NUMBERS + }, }; #define HLDB_ENTRIES (sizeof(HLDB)/sizeof(HLDB[0])) From 2d408300f082674402fdb7564291bbf35917ea2f Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 17:13:16 +0100 Subject: [PATCH 05/17] recognize ':' as separator for improved python keyword recognition --- kilo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index f5d2739f..123b82c9 100644 --- a/kilo.c +++ b/kilo.c @@ -382,7 +382,7 @@ int getWindowSize(int ifd, int ofd, int *rows, int *cols) { /* ====================== Syntax highlight color scheme ==================== */ int is_separator(int c) { - return c == '\0' || isspace(c) || strchr(",.()+-/*=~%[];",c) != NULL; + return c == '\0' || isspace(c) || strchr(",.()+-/*=~%[];:",c) != NULL; } /* Return true if the specified row last char is part of a multi line comment From 48a0e1a09e01f33b8a9ff1da5d99e3042bc60404 Mon Sep 17 00:00:00 2001 From: dirkf Date: Sat, 19 Dec 2020 12:15:48 +0000 Subject: [PATCH 06/17] Write entire highlight string for a single-line comment Was writing `size` chars but the `hl` array was allocated as `rsize` chars. --- kilo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 123b82c9..79bc85f9 100644 --- a/kilo.c +++ b/kilo.c @@ -430,7 +430,7 @@ void editorUpdateSyntax(erow *row) { /* 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); + memset(row->hl+i,HL_COMMENT,row->rsize-i); return; } From 5e71a2e8686bef565b0e8dc16f663fe2d0408911 Mon Sep 17 00:00:00 2001 From: dirkf Date: Sat, 19 Dec 2020 12:31:02 +0000 Subject: [PATCH 07/17] Avoid stepping past line end in incomplete string when \ is last char With `'\` or `"...\` as the last characters on the line, `HL_STRING` could be written beyond the allocated size of the `hl` array, causing memory corruption and SEGV. --- kilo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 79bc85f9..42670719 100644 --- a/kilo.c +++ b/kilo.c @@ -460,7 +460,7 @@ void editorUpdateSyntax(erow *row) { /* Handle "" and '' */ if (in_string) { row->hl[i] = HL_STRING; - if (*p == '\\') { + if (*p == '\\' && *(p+1)) { row->hl[i+1] = HL_STRING; p += 2; i += 2; prev_sep = 0; From 216474682fb17f366468206a555c3022374bbdf5 Mon Sep 17 00:00:00 2001 From: dirkf Date: Sat, 19 Dec 2020 12:39:42 +0000 Subject: [PATCH 08/17] Avoid invalid memory access if rest of line is shorter than some keyword The test for a keyword would try to read the entire length of each keyword from the line position even if the rest of the line was too short to contain that keyword. A PR was already submitted for this but the author closed it before it could be merged. --- kilo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 42670719..9eb7a7c2 100644 --- a/kilo.c +++ b/kilo.c @@ -499,12 +499,13 @@ void editorUpdateSyntax(erow *row) { /* Handle keywords and lib calls */ if (prev_sep) { int j; + int ileft = row->rsize - i; 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) && + if (klen < ileft && !memcmp(p,keywords[j],klen) && is_separator(*(p+klen))) { /* Keyword */ From c4a4d4c8734d671724eb8c8bca3ce121b0bb79e1 Mon Sep 17 00:00:00 2001 From: dirkf Date: Sun, 20 Dec 2020 03:55:50 +0000 Subject: [PATCH 09/17] fix multiline comments The function `editorRowHasOpenComment()` used its own definition of a closing multiline comment and duplicated the `hl_oc` member of `struct erow`. Change to use the latter throughout and thus respect the selected syntax definition. --- kilo.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/kilo.c b/kilo.c index 9eb7a7c2..cd71bf45 100644 --- a/kilo.c +++ b/kilo.c @@ -385,16 +385,6 @@ 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 - * that starts at this row or at one before, and does not end at the end - * of the row but spawns to the next row. */ -int editorRowHasOpenComment(erow *row) { - if (row->hl && row->rsize && row->hl[row->rsize-1] == HL_MLCOMMENT && - (row->rsize < 2 || (row->render[row->rsize-2] != '*' || - row->render[row->rsize-1] != '/'))) return 1; - return 0; -} - /* 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) { @@ -423,8 +413,7 @@ void editorUpdateSyntax(erow *row) { /* If the previous line has an open comment, this line starts * with an open comment state. */ - if (row->idx > 0 && editorRowHasOpenComment(&E.row[row->idx-1])) - in_comment = 1; + if (row->idx > 0) in_comment = E.row[row->idx-1].hl_oc; while(*p) { /* Handle // comments. */ @@ -526,13 +515,15 @@ void editorUpdateSyntax(erow *row) { p++; i++; } - /* Propagate syntax change to the next row if the open commen + /* Propagate syntax change to the next row if the open comment * state changed. This may recursively affect all the following rows * in the file. */ - int oc = editorRowHasOpenComment(row); - if (row->hl_oc != oc && row->idx+1 < E.numrows) - editorUpdateSyntax(&E.row[row->idx+1]); - row->hl_oc = oc; + if (!!row->hl_oc != !!in_comment) { + row->hl_oc = in_comment; + if (row->idx+1 < E.numrows) + editorUpdateSyntax(&E.row[row->idx+1]); + } + } /* Maps syntax highlight token types to terminal colors. */ From 3797b2b5bf7a3cd6c4017b5df00e9b158334c811 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 18:56:41 +0100 Subject: [PATCH 10/17] fix comments in python syntax mode --- kilo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kilo.c b/kilo.c index cd71bf45..7b3cbd74 100644 --- a/kilo.c +++ b/kilo.c @@ -417,7 +417,7 @@ void editorUpdateSyntax(erow *row) { while(*p) { /* Handle // comments. */ - if (prev_sep && *p == scs[0] && *(p+1) == scs[1]) { + if (prev_sep && *p == scs[0] && (!scs[1] || *(p+1) == scs[1])) { /* From here to end is a comment */ memset(row->hl+i,HL_COMMENT,row->rsize-i); return; @@ -426,7 +426,7 @@ void editorUpdateSyntax(erow *row) { /* Handle multi line comments. */ if (in_comment) { row->hl[i] = HL_MLCOMMENT; - if (*p == mce[0] && *(p+1) == mce[1]) { + if (*p == mce[0] && *(p+1) == mce[1] && (!mce[2] || *(p+2) == mce[2])) { row->hl[i+1] = HL_MLCOMMENT; p += 2; i += 2; in_comment = 0; @@ -437,7 +437,7 @@ void editorUpdateSyntax(erow *row) { p++; i++; continue; } - } else if (*p == mcs[0] && *(p+1) == mcs[1]) { + } else if (*p == mcs[0] && *(p+1) == mcs[1] && (!mce[2] || *(p+2) == mce[2])) { row->hl[i] = HL_MLCOMMENT; row->hl[i+1] = HL_MLCOMMENT; p += 2; i += 2; From b4788736af3f912f224a7eed55d2e4e3f6c517be Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 19:00:04 +0100 Subject: [PATCH 11/17] if inside multi-line comment, ignore single-line comment --- kilo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 7b3cbd74..c6ddf092 100644 --- a/kilo.c +++ b/kilo.c @@ -417,7 +417,7 @@ void editorUpdateSyntax(erow *row) { while(*p) { /* Handle // comments. */ - if (prev_sep && *p == scs[0] && (!scs[1] || *(p+1) == scs[1])) { + if (!in_comment && prev_sep && *p == scs[0] && (!scs[1] || *(p+1) == scs[1])) { /* From here to end is a comment */ memset(row->hl+i,HL_COMMENT,row->rsize-i); return; From 3f29b6ac9edccca4b3d6d2a445ceeceef7bad7bf Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 19:40:50 +0100 Subject: [PATCH 12/17] implement proper handling of DEL key del key used to behave just like backspace. commit is based on https://github.com/d-e-h-i-o/kilo/commit/799c7437cb769c0d0853ac4f3b736035147878a6 but works on first char in file and doesnt crash program on last. --- kilo.c | 72 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/kilo.c b/kilo.c index c6ddf092..b577256b 100644 --- a/kilo.c +++ b/kilo.c @@ -768,36 +768,54 @@ void editorInsertNewline(void) { } /* Delete the char at the current prompt position. */ -void editorDelChar() { +void editorDelChar(int back) { 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; + if (filerow >= E.numrows) return; + + erow *row = &E.row[filerow]; + + if (back) { + if (filecol == 0 && filerow == 0) return; + if (back && 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--; } } else { - editorRowDelChar(row,filecol-1); - if (E.cx == 0 && E.coloff) - E.coloff--; - else - E.cx--; + /* not backspace */ + if (filerow == E.numrows-1 && filecol >= row->size) return; + + if (filecol == row->size) { + /* Handle the case of last column, we need to delete the newline on the end of line */ + erow *nextrow = (filerow + 1 >= E.numrows) ? NULL : &E.row[filerow + 1]; + editorRowAppendString(&E.row[filerow],nextrow->chars,nextrow->size); + editorDelRow(filerow + 1); + row = NULL; + } else { + editorRowDelChar(row,filecol); + } } + if (row) editorUpdateRow(row); E.dirty++; } @@ -1238,8 +1256,10 @@ void editorProcessKeypress(int fd) { break; case BACKSPACE: /* Backspace */ case CTRL_H: /* Ctrl-h */ + editorDelChar(1); + break; case DEL_KEY: - editorDelChar(); + editorDelChar(0); break; case PAGE_UP: case PAGE_DOWN: From 88adc95a9c8cc16441cfdccb637e1be289741bea Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 23:28:08 +0100 Subject: [PATCH 13/17] improve multiline start/end matching --- kilo.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kilo.c b/kilo.c index b577256b..6e3f727b 100644 --- a/kilo.c +++ b/kilo.c @@ -427,8 +427,8 @@ void editorUpdateSyntax(erow *row) { if (in_comment) { row->hl[i] = HL_MLCOMMENT; if (*p == mce[0] && *(p+1) == mce[1] && (!mce[2] || *(p+2) == mce[2])) { - row->hl[i+1] = HL_MLCOMMENT; - p += 2; i += 2; + for(++i,++p;mce[i];++i,++p) + row->hl[i] = HL_MLCOMMENT; in_comment = 0; prev_sep = 1; continue; @@ -438,9 +438,8 @@ void editorUpdateSyntax(erow *row) { continue; } } else if (*p == mcs[0] && *(p+1) == mcs[1] && (!mce[2] || *(p+2) == mce[2])) { - row->hl[i] = HL_MLCOMMENT; - row->hl[i+1] = HL_MLCOMMENT; - p += 2; i += 2; + for(;mce[i];++i,++p) + row->hl[i] = HL_MLCOMMENT; in_comment = 1; prev_sep = 0; continue; From 00de72ec3b81715a2ecf2c78e8d077fd12497278 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Apr 2021 23:30:20 +0100 Subject: [PATCH 14/17] remove python multiline comments since python multiline string/comments start and end with the same sequence, kilo is unable to figure out which is which once one removes either one of the start or end markers of the section. dealing with this would require a quite more elaborate engine than currently implement, or doing a new syntax scan over the entire file. --- kilo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kilo.c b/kilo.c index 6e3f727b..82e098ad 100644 --- a/kilo.c +++ b/kilo.c @@ -208,7 +208,7 @@ struct editorSyntax HLDB[] = { { PY_HL_extensions, PY_HL_keywords, - "#","\"\"\"", "\"\"\"", + "#","\0\0\0", "\0\0\0", HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_NUMBERS }, }; From a3844aac1b6501c5a0c13b7099a868ba926ec888 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Thu, 22 Apr 2021 16:13:35 +0100 Subject: [PATCH 15/17] fix ub parsing multiline comments --- kilo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kilo.c b/kilo.c index 82e098ad..692ddec6 100644 --- a/kilo.c +++ b/kilo.c @@ -427,7 +427,7 @@ void editorUpdateSyntax(erow *row) { if (in_comment) { row->hl[i] = HL_MLCOMMENT; if (*p == mce[0] && *(p+1) == mce[1] && (!mce[2] || *(p+2) == mce[2])) { - for(++i,++p;mce[i];++i,++p) + for(++i,++p;irsize&&mce[i];++i,++p) row->hl[i] = HL_MLCOMMENT; in_comment = 0; prev_sep = 1; @@ -438,7 +438,7 @@ void editorUpdateSyntax(erow *row) { continue; } } else if (*p == mcs[0] && *(p+1) == mcs[1] && (!mce[2] || *(p+2) == mce[2])) { - for(;mce[i];++i,++p) + for(;irsize&&mce[i];++i,++p) row->hl[i] = HL_MLCOMMENT; in_comment = 1; prev_sep = 0; From 6328119697d30baf585c6e689ee711c3312bfdca Mon Sep 17 00:00:00 2001 From: rofl0r Date: Thu, 22 Apr 2021 16:14:17 +0100 Subject: [PATCH 16/17] don't redraw entire screen if we move cursor within visible area for a cursor move that doesnt result in any scrolling, we now simply update cursor position (and col/row in status bar) to remove the nasty flickering caused by kilo on xterm when redrawing the entire screen everytime a cursor is moved. there's still a bug when moving cursor horizontally inside a long line, in that it's not detected that the screen needs redraw. i'll leave the fix to someone else as i'm done with this buggy editor. --- kilo.c | 138 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 51 deletions(-) diff --git a/kilo.c b/kilo.c index 692ddec6..4b75c882 100644 --- a/kilo.c +++ b/kilo.c @@ -904,16 +904,75 @@ void abFree(struct abuf *ab) { free(ab->b); } +static void hideCursor(struct abuf *ab) { + abAppend(ab,"\x1b[?25l",6); /* Hide cursor. */ + abAppend(ab,"\x1b[H",3); /* Go home. */ +} + +static void setCursor(struct abuf *ab) { + /* Put cursor at its current position. Note that the horizontal position + * at which the cursor is displayed may be different compared to 'E.cx' + * because of TABs. */ + int j; + int cx = 1; + int filerow = E.rowoff+E.cy; + char buf[32]; + + erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; + if (row) { + for (j = E.coloff; j < (E.cx+E.coloff); j++) { + if (j < row->size && row->chars[j] == TAB) cx += 7-((cx)%8); + cx++; + } + } + snprintf(buf,sizeof(buf),"\x1b[%d;%dH",E.cy+1,cx); + abAppend(ab,buf,strlen(buf)); + abAppend(ab,"\x1b[?25h",6); /* Show cursor. */ +} + +static void setStatus(struct abuf *ab, int putcursor) { + if(putcursor) { + char buf[32]; + snprintf(buf,sizeof(buf),"\x1b[%d;%dH",E.screenrows+1,0); + abAppend(ab,buf,strlen(buf)); + } + /* 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); +} + /* 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. */ + hideCursor(&ab); + for (y = 0; y < E.screenrows; y++) { int filerow = E.rowoff+y; @@ -977,49 +1036,8 @@ void editorRefreshScreen(void) { 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 - * at which the cursor is displayed may be different compared to 'E.cx' - * because of TABs. */ - int j; - int cx = 1; - int filerow = E.rowoff+E.cy; - erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; - if (row) { - for (j = E.coloff; j < (E.cx+E.coloff); j++) { - if (j < row->size && row->chars[j] == TAB) cx += 7-((cx)%8); - cx++; - } - } - snprintf(buf,sizeof(buf),"\x1b[%d;%dH",E.cy+1,cx); - abAppend(&ab,buf,strlen(buf)); - abAppend(&ab,"\x1b[?25h",6); /* Show cursor. */ + setStatus(&ab,0); + setCursor(&ab); write(STDOUT_FILENO,ab.b,ab.len); abFree(&ab); } @@ -1221,12 +1239,16 @@ void editorMoveCursor(int key) { } /* Process events arriving from the standard input, which is, the user - * is typing stuff on the terminal. */ + * is typing stuff on the terminal. + * If return value is 0, only cursor position needs to be updated, + * else the entire screen. + */ #define KILO_QUIT_TIMES 3 -void editorProcessKeypress(int fd) { +int editorProcessKeypress(int fd) { /* When the file is modified, requires Ctrl-q to be pressed N times * before actually quitting. */ static int quit_times = KILO_QUIT_TIMES; + int ret = 1; int c = editorReadKey(fd); switch(c) { @@ -1243,7 +1265,7 @@ void editorProcessKeypress(int fd) { editorSetStatusMessage("WARNING!!! File has unsaved changes. " "Press Ctrl-Q %d more times to quit.", quit_times); quit_times--; - return; + return ret; } exit(0); break; @@ -1279,7 +1301,10 @@ void editorProcessKeypress(int fd) { case ARROW_DOWN: case ARROW_LEFT: case ARROW_RIGHT: + ret = E.rowoff; editorMoveCursor(c); + ret = (ret != E.rowoff); + if(!ret) ret = (E.coloff >= E.screencols); break; case CTRL_L: /* ctrl+l, clear screen */ /* Just refresht the line as side effect. */ @@ -1293,6 +1318,7 @@ void editorProcessKeypress(int fd) { } quit_times = KILO_QUIT_TIMES; /* Reset it to the original value. */ + return ret; } int editorFileWasModified(void) { @@ -1341,9 +1367,19 @@ int main(int argc, char **argv) { enableRawMode(STDIN_FILENO); editorSetStatusMessage( "HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find"); + + editorRefreshScreen(); while(1) { - editorRefreshScreen(); - editorProcessKeypress(STDIN_FILENO); + if(!editorProcessKeypress(STDIN_FILENO)) { + /* only cursor moved, no need to repain entire screen */ + struct abuf ab = ABUF_INIT; + hideCursor(&ab); + setStatus(&ab,1); + setCursor(&ab); + write(STDOUT_FILENO,ab.b,ab.len); + abFree(&ab); + } else + editorRefreshScreen(); } return 0; } From 92b6032d6f2f7d19306ad1f0383ae981aefd51a3 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Thu, 22 Apr 2021 16:18:35 +0100 Subject: [PATCH 17/17] add BUGS --- BUGS | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 BUGS diff --git a/BUGS b/BUGS new file mode 100644 index 00000000..3edbc560 --- /dev/null +++ b/BUGS @@ -0,0 +1,7 @@ +- long lines with tabs in them aren't correctly rendered when editing the part + outside of the boundaries of the editor windows (i.e. when scrolled to the right.) + a patch of dirkf exists, however it's way too intrusive, and actually doesn't even + work correctly. +- if cursor is moved outside the visible bounds of a long line, the new code + to optimize screen redraw doesn't properly detect that the screen needs redraw +