From b78f00ecf1699925b7011fc5512d3e0ec90e06a1 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Mon, 17 Oct 2016 21:41:03 -0400 Subject: [PATCH] Implemented CRLF handling --- buf.c | 16 +++++++++---- charset.c | 11 +++++++-- docs/crlf.txt | 5 ++++ edit.h | 12 ++++++---- keyboard.c | 63 +++++++++++++++++++++++++++++++++------------------ screen.c | 6 ++--- utf8.c | 12 ++++++++-- 7 files changed, 87 insertions(+), 38 deletions(-) create mode 100644 docs/crlf.txt diff --git a/buf.c b/buf.c index b9b573c..8bd9752 100644 --- 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; diff --git a/charset.c b/charset.c index 0900bc3..7a475ff 100644 --- 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 index 0000000..dab8c54 --- /dev/null +++ b/docs/crlf.txt @@ -0,0 +1,5 @@ +this file +uses +dos +line +endings diff --git a/edit.h b/edit.h index 50c7d4d..2570b12 100644 --- 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); diff --git a/keyboard.c b/keyboard.c index e63d543..16cf0e7 100644 --- a/keyboard.c +++ b/keyboard.c @@ -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; } } diff --git a/screen.c b/screen.c index 9d5b90d..92f61b2 100644 --- 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 99ae9d2..8541b4e 100644 --- a/utf8.c +++ b/utf8.c @@ -4,6 +4,7 @@ @license BSD 2-clause License */ #include "edit.h" +#include 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) { -- 2.49.0