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) {
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;
}
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;
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);
+ }
+ }
}
--- /dev/null
+this file\r
+uses\r
+dos\r
+line\r
+endings\r
/* 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 */
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);
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);
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;
}
}
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;
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;
}
}
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;
}
}
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;
}
}
}
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;
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;
}
}
@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 };
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) {