]> git.mdlowis.com Git - projs/tide.git/commitdiff
Implemented CRLF handling
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 18 Oct 2016 01:41:03 +0000 (21:41 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 18 Oct 2016 01:41:03 +0000 (21:41 -0400)
buf.c
charset.c
docs/crlf.txt [new file with mode: 0644]
edit.h
keyboard.c
screen.c
utf8.c

diff --git a/buf.c b/buf.c
index b9b573cc6f101e62b4d6971ebb10b24a836dc4f2..8bd9752ee653a5bea71e0984e68a745478dc3e25 100644 (file)
--- a/buf.c
+++ b/buf.c
@@ -105,7 +105,10 @@ void buf_ins(Buf* buf, unsigned off, Rune rune) {
     if (!buf->insert_mode) { return; }
     buf->modified = true;
     syncgap(buf, off);
-    *(buf->gapstart++) = rune;
+    if (rune == '\n' && buf_get(buf, off-1) == '\r')
+        *(buf->gapstart-1) = RUNE_CRLF;
+    else
+        *(buf->gapstart++) = rune;
 }
 
 Rune buf_get(Buf* buf, unsigned off) {
@@ -117,13 +120,18 @@ Rune buf_get(Buf* buf, unsigned off) {
         return *(buf->gapend + (off - bsz));
 }
 
+bool buf_iseol(Buf* buf, unsigned off) {
+    Rune r = buf_get(buf, off);
+    return (r == '\n' || r == RUNE_CRLF);
+}
+
 unsigned buf_bol(Buf* buf, unsigned off) {
-    for (Rune r; (r = buf_get(buf, off-1)) != '\n'; off--);
+    for (; !buf_iseol(buf, off-1); off--);
     return off;
 }
 
 unsigned buf_eol(Buf* buf, unsigned off) {
-    for (Rune r; (r = buf_get(buf, off)) != '\n'; off++);
+    for (; !buf_iseol(buf, off); off++);
     return off;
 }
 
@@ -175,7 +183,7 @@ unsigned buf_setcol(Buf* buf, unsigned pos, unsigned col) {
     unsigned len  = 0;
     unsigned i    = 0;
     /* determine the length of the line in columns */
-    for (; buf_get(buf, curr) != '\n'; curr = buf_byrune(buf, curr, 1))
+    for (; !buf_iseol(buf, curr); curr++)
         len += runewidth(len, buf_get(buf, curr));
     /* iterate over the runes until we reach the target column */
     curr = bol, i = 0;
index 0900bc3c32560bcce5398d8ecbcc8ca59fa4411d..7a475ff31f670a42a7221571665d8f37587dd6e1 100644 (file)
--- a/charset.c
+++ b/charset.c
@@ -52,6 +52,13 @@ void binload(Buf* buf, FMap file) {
 
 void binsave(Buf* buf, FILE* file) {
     unsigned end = buf_end(buf);
-    for (unsigned i = 0; i < end; i++)
-        fputc((int)buf_get(buf, i), file);
+    for (unsigned i = 0; i < end; i++) {
+        Rune r = buf_get(buf, i);
+        if (r == RUNE_CRLF) {
+            fputc('\r', file);
+            fputc('\n', file);
+        } else {
+            fputc((int)r, file);
+        }
+    }
 }
diff --git a/docs/crlf.txt b/docs/crlf.txt
new file mode 100644 (file)
index 0000000..dab8c54
--- /dev/null
@@ -0,0 +1,5 @@
+this file\r
+uses\r
+dos\r
+line\r
+endings\r
diff --git a/edit.h b/edit.h
index 50c7d4d9a1b872e289e35e33010e9d20782dedf4..2570b121de3c82546d655185fbb198f466269ab5 100644 (file)
--- a/edit.h
+++ b/edit.h
@@ -20,11 +20,12 @@ uint32_t getmillis(void);
 /* Unicode Handling
  *****************************************************************************/
 enum {
-    UTF_MAX   = 6u,        /* maximum number of bytes that make up a rune */
-    RUNE_SELF = 0x80,      /* byte values larger than this are *not* ascii */
-    RUNE_ERR  = 0xFFFD,    /* rune value representing an error */
-    RUNE_MAX  = 0x10FFFF,  /* Maximum decodable rune value */
-    RUNE_EOF  = UINT32_MAX /* rune value representing end of file */
+    UTF_MAX   = 6u,          /* maximum number of bytes that make up a rune */
+    RUNE_SELF = 0x80,        /* byte values larger than this are *not* ascii */
+    RUNE_ERR  = 0xFFFD,      /* rune value representing an error */
+    RUNE_MAX  = 0x10FFFF,    /* Maximum decodable rune value */
+    RUNE_EOF  = UINT32_MAX,  /* rune value representing end of file */
+    RUNE_CRLF = UINT32_MAX-1 /* rune value representing a \r\n sequence */
 };
 
 /* Represents a unicode code point */
@@ -58,6 +59,7 @@ void buf_clr(Buf* buf);
 void buf_del(Buf* buf, unsigned pos);
 void buf_ins(Buf* buf, unsigned pos, Rune);
 Rune buf_get(Buf* buf, unsigned pos);
+bool buf_iseol(Buf* buf, unsigned pos);
 unsigned buf_bol(Buf* buf, unsigned pos);
 unsigned buf_eol(Buf* buf, unsigned pos);
 unsigned buf_end(Buf* buf);
index e63d543df41800b49e79d0ff1538a31274c02200..16cf0e7a5abc21153df2bf3c412a0fc2aa100875 100644 (file)
@@ -4,6 +4,14 @@ static void special_keys(Rune key);
 static void control_keys(Rune key);
 static void vi_keys(Rune key);
 
+static void toggle_mode(void) {
+    Buffer.insert_mode = !Buffer.insert_mode;
+}
+
+static void toggle_colors(void) {
+    ColorBase = !ColorBase;
+}
+
 static void cursor_up(void) {
     CursorPos = buf_byline(&Buffer, CursorPos, -1);
     CursorPos = buf_setcol(&Buffer, CursorPos, TargetCol);
@@ -24,12 +32,12 @@ static void cursor_right(void) {
     TargetCol = buf_getcol(&Buffer, CursorPos);
 }
 
-static void cursor_home(void) {
+static void cursor_bol(void) {
     CursorPos = buf_bol(&Buffer, CursorPos);
     TargetCol = 0;
 }
 
-static void cursor_end(void) {
+static void cursor_eol(void) {
     CursorPos = buf_eol(&Buffer, CursorPos);
     TargetCol = (unsigned)-1;
 }
@@ -41,11 +49,22 @@ static void backspace(void) {
 }
 
 static void insert(Rune r) {
-    if (r == '\n' && Buffer.crlf)
-        buf_ins(&Buffer, CursorPos++, '\r');
     buf_ins(&Buffer, CursorPos++, r);
 }
 
+static void delete(void) {
+    buf_del(&Buffer, CursorPos);
+}
+
+static void insert_before(void) {
+    Buffer.insert_mode = true;
+}
+
+static void insert_after(void) {
+    CursorPos++;
+    Buffer.insert_mode = true;
+}
+
 void handle_key(Rune key) {
     /* ignore invalid keys */
     if (key == RUNE_ERR) return;
@@ -64,16 +83,16 @@ void handle_key(Rune key) {
 
 static void special_keys(Rune key) {
     switch (key) {
-        case KEY_F6:     ColorBase = !ColorBase;                   break;
-        case KEY_UP:     cursor_up();                              break;
-        case KEY_DOWN:   cursor_dn();                              break;
-        case KEY_LEFT:   cursor_left();                            break;
-        case KEY_RIGHT:  cursor_right();                           break;
-        case KEY_INSERT: Buffer.insert_mode = !Buffer.insert_mode; break;
-        case KEY_F1:     Buffer.insert_mode = !Buffer.insert_mode; break;
-        case KEY_DELETE: buf_del(&Buffer, CursorPos);              break;
-        case KEY_HOME:   cursor_home();                            break;
-        case KEY_END:    cursor_end();                             break;
+        case KEY_F6:     toggle_colors(); break;
+        case KEY_UP:     cursor_up();     break;
+        case KEY_DOWN:   cursor_dn();     break;
+        case KEY_LEFT:   cursor_left();   break;
+        case KEY_RIGHT:  cursor_right();  break;
+        case KEY_INSERT: toggle_mode();   break;
+        case KEY_F1:     toggle_mode();   break;
+        case KEY_DELETE: delete();        break;
+        case KEY_HOME:   cursor_bol();    break;
+        case KEY_END:    cursor_eol();    break;
     }
 }
 
@@ -89,13 +108,13 @@ static void control_keys(Rune key) {
 
 static void vi_keys(Rune key) {
     switch (key) {
-        case 'a': CursorPos++;
-        case 'i': Buffer.insert_mode = true; break;
-        case 'k': cursor_up();               break;
-        case 'j': cursor_dn();               break;
-        case 'h': cursor_left();             break;
-        case 'l': cursor_right();            break;
-        case '^': cursor_home();             break;
-        case '$': cursor_end();              break;
+        case 'a': insert_after();  break;
+        case 'i': insert_before(); break;
+        case 'k': cursor_up();     break;
+        case 'j': cursor_dn();     break;
+        case 'h': cursor_left();   break;
+        case 'l': cursor_right();  break;
+        case '0': cursor_bol();    break;
+        case '$': cursor_eol();    break;
     }
 }
index 9d5b90ddcc3de182f03f7a714e171e7052e58123..92f61b2b1389020898076418d62e019ebe42b9e7 100644 (file)
--- a/screen.c
+++ b/screen.c
@@ -12,7 +12,7 @@ static void screen_reflow(Buf* buf) {
         for (unsigned x = 0; x < NumCols;) {
             Rune r = buf_get(buf, pos++);
             x += screen_setcell(y,x,r);
-            if (r == '\n') break;
+            if (buf_iseol(buf, pos-1)) break;
         }
     }
 }
@@ -77,7 +77,7 @@ unsigned screen_setcell(unsigned row, unsigned col, Rune r) {
     Row* scrrow = screen_getrow(row);
     int ncols = runewidth(col, r);
     /* write the rune to the screen buf */
-    if (r == '\t' || r == '\n' || r == '\r')
+    if (r == '\t' || r == '\n' || r == RUNE_CRLF)
         scrrow->cols[col].rune = ' ';
     else
         scrrow->cols[col].rune = r;
@@ -105,7 +105,7 @@ static void fill_row(Buf* buf, unsigned row, unsigned pos) {
     for (unsigned x = 0; x < NumCols;) {
         Rune r = buf_get(buf, pos++);
         x += screen_setcell(row, x, r);
-        if (r == '\n') break;
+        if (buf_iseol(buf, pos-1)) break;
     }
 }
 
diff --git a/utf8.c b/utf8.c
index 99ae9d213d3fa786338edb91d279b36ab18b50d6..8541b4e6367a564780631ea3e8fad99c122f2393 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -4,6 +4,7 @@
   @license BSD 2-clause License
 */
 #include "edit.h"
+#include <wchar.h>
 
 const uint8_t UTF8_SeqBits[] = { 0x00u, 0x80u, 0xC0u, 0xE0u, 0xF0u, 0xF8u, 0xFCu, 0xFEu };
 const uint8_t UTF8_SeqMask[] = { 0x00u, 0xFFu, 0x1Fu, 0x0Fu, 0x07u, 0x03u, 0x01u, 0x00u };
@@ -98,8 +99,15 @@ void utf8load(Buf* buf, FMap file) {
 
 void utf8save(Buf* buf, FILE* file) {
     unsigned end = buf_end(buf);
-    for (unsigned i = 0; i < end; i++)
-        fputrune(buf_get(buf, i), file);
+    for (unsigned i = 0; i < end; i++) {
+        Rune r = buf_get(buf, i);
+        if (r == RUNE_CRLF) {
+            fputrune('\r', file);
+            fputrune('\n', file);
+        } else {
+            fputrune(r, file);
+        }
+    }
 }
 
 int runewidth(unsigned col, Rune r) {