]> git.mdlowis.com Git - projs/tide.git/commitdiff
Added basic editing capabilties and mode toggling
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 4 Oct 2016 00:43:11 +0000 (20:43 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 4 Oct 2016 00:43:11 +0000 (20:43 -0400)
Makefile
edit.h
utf8.c [new file with mode: 0644]
xedit.c

index 702fb2e4348aabde88adc35d1c234daa0dd6ed85..840f74b7c6c6bf14396dd8b721423d4e9a270c19 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 LDFLAGS  = -L/opt/X11/lib -lX11 -lXft
 CFLAGS   = --std=c99 -Wall -Wextra -I. -I/opt/X11/include -I/opt/local/include/freetype2 -I/usr/include/freetype2
-SRCS     = xedit.c buf.c screen.c
+SRCS     = xedit.c buf.c screen.c utf8.c
 OBJS     = $(SRCS:.c=.o)
 TESTSRCS = tests/tests.c tests/buf.c
 TESTOBJS = $(TESTSRCS:.c=.o)
diff --git a/edit.h b/edit.h
index b38f798f6071599fb75d73b3bb233430143fc3f2..3173a73aad77cb2c8d60badd5f594a7b626a811a 100644 (file)
--- a/edit.h
+++ b/edit.h
@@ -72,13 +72,25 @@ Rune screen_getcell(unsigned row, unsigned col);
  *****************************************************************************/
 void die(char* msg);
 
+/* UTF-8 Handling
+ *****************************************************************************/
+#define UTF_MAX   6u
+#define RUNE_SELF ((Rune)0x80)
+#define RUNE_ERR  ((Rune)0xFFFD)
+#define RUNE_MAX  ((Rune)0x10FFFF)
+#define RUNE_EOF  ((Rune)EOF)
+
+size_t utf8encode(char str[UTF_MAX], Rune rune);
+bool utf8decode(Rune* rune, size_t* length, int byte);
+
 /* Configuration
  *****************************************************************************/
 enum {
-    Width     = 640,
-    Height    = 480,
-    TabWidth  = 4,
-    BufSize   = 8192,
+    Width       = 640,
+    Height      = 480,
+    TabWidth    = 4,
+    ScrollLines = 1,
+    BufSize     = 8192,
 };
 
 static enum { DARK = 0, LIGHT = 1 } ColorBase = DARK;
diff --git a/utf8.c b/utf8.c
new file mode 100644 (file)
index 0000000..02074a2
--- /dev/null
+++ b/utf8.c
@@ -0,0 +1,96 @@
+/**
+  @brief Simple UTF-8 encoding and decoding routines.
+  @author Michael D. Lowis
+  @license BSD 2-clause License
+*/
+#include "edit.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 };
+const uint8_t UTF8_SeqLens[] = { 0x01u, 0x00u, 0x02u, 0x03u, 0x04u, 0x05u, 0x06u, 0x00u };
+
+bool runevalid(Rune val) {
+    return (val <= RUNE_MAX)
+        && ((val & 0xFFFEu) != 0xFFFEu)
+        && ((val < 0xD800u) || (val > 0xDFFFu))
+        && ((val < 0xFDD0u) || (val > 0xFDEFu));
+}
+
+size_t runelen(Rune rune) {
+    if(!runevalid(rune))
+        return 0;
+    else if(rune <= 0x7F)
+        return 1;
+    else if(rune <= 0x07FF)
+        return 2;
+    else if(rune <= 0xFFFF)
+        return 3;
+    else
+        return 4;
+}
+
+uint8_t utfseq(uint8_t byte) {
+    for (int i = 1; i < 8; i++)
+        if ((byte & UTF8_SeqBits[i]) == UTF8_SeqBits[i-1])
+            return UTF8_SeqLens[i-1];
+    return 0;
+}
+
+size_t utf8encode(char str[UTF_MAX], Rune rune) {
+    size_t len = runelen(rune);
+    str[0] = (len == 1 ? 0x00 : UTF8_SeqBits[len])
+           | (UTF8_SeqMask[len] & (rune >> (6 * (len-1))));
+    for (size_t i = 1; i < len; i++)
+        str[i] = 0x80u | (0x3Fu & (rune >> (6 * (len-i-1))));
+    return len;
+}
+
+bool utf8decode(Rune* rune, size_t* length, int byte) {
+    /* Handle the start of a new rune */
+    if (*length == 0) {
+        /* If we were fed in an EOF as a start byte, handle it here */
+        if (byte == EOF) {
+            *rune = RUNE_EOF;
+        } else {
+            /* Otherwise, decode the first byte of the rune */
+            *length = utfseq(byte);
+            *rune   = (*length == 0) ? RUNE_ERR : (byte & UTF8_SeqMask[*length]);
+            (*length)--;
+        }
+    /* Handle continuation bytes */
+    } else if ((byte & 0xC0) == 0x80) {
+        /* add bits from continuation byte to rune value
+         * cannot overflow: 6 byte sequences contain 31 bits */
+        *rune = (*rune << 6) | (byte & 0x3F); /* 10xxxxxx */
+        (*length)--;
+        /* Sanity check the final rune value before finishing */
+        if ((*length == 0) && !runevalid(*rune))
+            *rune = RUNE_ERR;
+    /* Didn't get the continuation byte we expected */
+    } else {
+        *rune = RUNE_ERR;
+    }
+    /* Tell the caller whether we finished or not */
+    return ((*length == 0) || (*rune == RUNE_ERR));
+}
+
+size_t utflen(const char* s) {
+    size_t len = 0;
+    Rune rune = 0;
+    while (*s && !utf8decode(&rune, &len, *(s++)))
+        len++;
+    return len;
+}
+
+Rune fgetrune(FILE* f) {
+    Rune rune = 0;
+    size_t length = 0;
+    while (!utf8decode(&rune, &length, fgetc(f)));
+    return rune;
+}
+
+void fputrune(Rune rune, FILE* f) {
+    char utf[UTF_MAX] = {0};
+    utf8encode(utf, rune);
+    fprintf(f, "%s", utf);
+}
diff --git a/xedit.c b/xedit.c
index 08992ba9576fd6377b2131c219b5af6518d0bc17..77145f7ff81d27055f04e898e5885c4f4995e76d 100644 (file)
--- a/xedit.c
+++ b/xedit.c
@@ -138,6 +138,28 @@ static void handle_key(XEvent* e) {
         case XK_Up:
             CursorPos = buf_byline(&Buffer, CursorPos, -1);
             break;
+
+        case XK_Escape:
+            InsertMode = false;
+            break;
+
+        case XK_BackSpace:
+            if (InsertMode)
+                buf_del(&Buffer, --CursorPos);
+            break;
+
+        default:
+            if (len > 0) {
+                Rune r;
+                size_t len = 0;
+                if (buf[0] == '\r')
+                    buf[0] = '\n';
+                for(int i = 0; i < 8 && !utf8decode(&r, &len, buf[i]); i++);
+                printf("Rune: '%c'\n", (char)r);
+                if (InsertMode)
+                    buf_ins(&Buffer, CursorPos++, r);
+            }
+            break;
     }
 }
 
@@ -150,8 +172,10 @@ static void handle_mousebtn(XEvent* e) {
         case Button3: /* Right Button */
             break;
         case Button4: /* Wheel Up */
+            CursorPos = buf_byline(&Buffer, CursorPos, -ScrollLines);
             break;
         case Button5: /* Wheel Down */
+            CursorPos = buf_byline(&Buffer, CursorPos, ScrollLines);
             break;
     }
 }
@@ -222,9 +246,15 @@ static void redraw(void) {
             if (CursorPos == pos)
                 csrx = x, csry = y;
             Rune r = buf_get(&Buffer, pos++);
-            if (r == '\n') { break; }
-            if (r == '\t') { x += 4; break; }
-            screen_setcell(y,x,r);
+            if (r == '\n') {
+                screen_setcell(y,x,' ');
+                break;
+            } else if (r == '\t') {
+                screen_setcell(y,x,' ');
+                x += TabWidth - (x % TabWidth) - 1;
+            } else {
+                screen_setcell(y,x,r);
+            }
         }
     }
     EndPos = pos-1;