]> gitweb.ps.run Git - iftint/commitdiff
main3: basic functionality, array and string
authorPatrick <patrick.schoenberger@posteo.de>
Sat, 23 Sep 2023 21:59:39 +0000 (23:59 +0200)
committerPatrick <patrick.schoenberger@posteo.de>
Sat, 23 Sep 2023 21:59:39 +0000 (23:59 +0200)
main3.c [new file with mode: 0644]

diff --git a/main3.c b/main3.c
new file mode 100644 (file)
index 0000000..b7f1344
--- /dev/null
+++ b/main3.c
@@ -0,0 +1,371 @@
+#include<stdint.h>
+#include<stdbool.h>
+#include<stdio.h>
+
+// Global defines
+
+#define STR_SIZE 128
+#define BUF_SIZE 1024*1024
+
+// Memory
+
+static char g_memory[1024*1024];
+static int g_memory_index = 0;
+
+void * alloc(int num, int size) {
+    void * result = g_memory + g_memory_index;
+    for (int i = 0; i < num*size; i++)
+        g_memory[g_memory_index+i] = 0;
+    g_memory_index += num*size;
+    return result;
+}
+
+#define NEW(TYPE) ((TYPE *)alloc(1, sizeof(TYPE)))
+#define NEWARR(TYPE, NUM) ((TYPE *)alloc(NUM, sizeof(TYPE)))
+
+// getch
+
+#ifdef _WIN32
+#include <windows.h>
+#include <conio.h>
+#else
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* reads from keypress, doesn't echo */
+int getch(void)
+{
+    struct termios oldattr, newattr;
+    int ch;
+    tcgetattr( STDIN_FILENO, &oldattr );
+    newattr = oldattr;
+    newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
+    tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
+    ch = getchar();
+    tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
+    return ch;
+}
+
+/* ungets keypress */
+void ungetch(int ch)
+{
+    struct termios oldattr, newattr;
+    tcgetattr( STDIN_FILENO, &oldattr );
+    newattr = oldattr;
+    newattr.c_lflag &= ~( ICANON | ECHO );
+    tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
+    ungetc(ch, stdin);
+    tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
+}
+#endif
+
+int
+peekch() {
+    int c = getch();
+    ungetch(c);
+    return c;
+}
+
+// VT100
+
+#define ASCII_ESC 27
+
+void vt100Escape(const char * str, ...) {
+    va_list args;
+    va_start(args, str);
+
+    printf("%c", ASCII_ESC);
+    vprintf(str, args);
+}
+
+void vt100ClearScreen() { vt100Escape("[2J"); }
+void vt100CursorHome() { vt100Escape("[H"); }
+void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
+void vt100SaveCursor() { vt100Escape("7"); }
+void vt100RestoreCursor() { vt100Escape("8"); }
+void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); }
+void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); }
+void vt100EnableNegative() { vt100Escape("[7m"); }
+void vt100DisableNegative() { vt100Escape("[27m"); }
+void vt100ShowCursor() { vt100Escape("[?25h"); }
+void vt100HideCursor() { vt100Escape("[?25l"); }
+void vt100GetScreenSize(int * v, int * h) {
+#ifdef _WIN32
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+    *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+    *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+#else
+    struct winsize w;
+    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
+    *h = w.ws_row;
+    *v = w.ws_col;
+#endif
+}
+
+// Node
+
+typedef enum {
+    NK_Nul,
+    NK_Arr,
+    NK_Str,
+
+    NK_COUNT
+} NodeKind;
+
+typedef struct Node Node;
+struct Node {
+    NodeKind kind;
+    void * data;
+
+    int childCount;
+    Node *next, *prev, *parent, *child;
+};
+
+Node *NodeGetChild(Node *n, unsigned int index) {
+    if (index >= n->childCount)
+        return NULL;
+    
+    Node *result = n->child;
+    for (int i = 0; i < index; i++)
+        result = result->next;
+    return result;
+}
+
+void NodeAppend(Node *n1, Node *n2) {
+    if (n1->childCount == 0) {
+        n1->child = n2;
+    }
+    else {
+        Node *lastChild = NodeGetChild(n1, n1->childCount-1);
+
+        lastChild->next = n2;
+        n2->prev = lastChild;
+        n2->next = NULL;
+    }
+    n2->parent = n1;
+    n1->childCount += 1;
+}
+
+void NodeInsert(Node *n1, Node *n2, unsigned int index) {
+    if (index >= n1->childCount-1) {
+        NodeAppend(n1, n2);
+        return;
+    }
+
+    Node *insertAfter = NodeGetChild(n1, index);
+    Node *insertBefore = NodeGetChild(n1, index+1);
+
+    insertAfter->next = n2;
+    insertBefore->prev = n2;
+    n2->prev = insertAfter;
+    n2->next = insertBefore;
+
+    n1->childCount += 1;
+}
+
+Node *NodeRemove(Node *n1, Node *n2) {
+    if (n1 == NULL)
+        return n2;
+    
+    Node *prev = n2->prev;
+    Node *next = n2->next;
+
+    if (prev != NULL)
+        prev->next = next;
+    if (next != NULL)
+        next->prev = prev;
+    
+    n2->prev = n2->next = n2->parent = NULL;
+
+    if (n2 == n1->child)
+        n1->child = next;
+
+    n1->childCount -= 1;
+    
+    if (prev == NULL)
+        return n1;
+    else
+        return prev;
+}
+
+void NodeDraw(Node *n, Node *selected) {
+    static int indent = 0;
+    for (int i = 0; i < indent; i++)
+        printf("  ");
+    
+    if (n == selected) vt100EnableNegative();
+    
+    switch (n->kind) {
+    case NK_Nul: printf("null\n"); break;
+    case NK_Arr: printf("(%d) [\n", n->childCount); for (int i = 0; i < n->childCount; i++) NodeDraw(NodeGetChild(n, i), selected); printf("]\n"); break;
+    case NK_Str: printf("'%.16s'\n", (char *)n->data); break;
+    }
+
+    if (n == selected) vt100DisableNegative();
+}
+
+// Input
+
+#define KEY_CTRL_C 3
+#define KEY_BACKSPACE1 8
+#define KEY_BACKSPACE2 127
+
+typedef enum Input {
+    IN_None,
+
+    IN_A,
+    IN_S,
+    IN_D,
+
+    IN_H,
+    IN_J,
+    IN_K,
+    IN_L,
+
+    IN_SPACE,
+
+    IN_Quit,
+
+    IN_COUNT
+} Input;
+
+Input InputGet() {
+    int c;
+
+    while (true) {
+        c = getch();
+        switch (c) {
+            case 'a': return IN_A;
+            case 's': return IN_S;
+            case 'd': return IN_D;
+            
+            case 'h': return IN_H;
+            case 'j': return IN_J;
+            case 'k': return IN_K;
+            case 'l': return IN_L;
+
+            case ' ': return IN_SPACE;
+
+            case 'q': return IN_Quit;
+        }
+    }
+}
+
+typedef enum InputAction {
+    IA_None,
+    IA_AppendArray,
+    IA_AppendString,
+    IA_StartEditing,
+    IA_Delete,
+
+    IA_MoveLeft,
+    IA_MoveDown,
+    IA_MoveUp,
+    IA_MoveRight,
+
+    IA_COUNT
+} InputAction;
+
+Node *GetNode(InputAction actions[NK_COUNT][IN_COUNT]) {
+    Node * result = NEW(Node);
+    result->kind = NK_Arr;
+
+    Node * n = result;
+
+    Input in;
+    InputAction action;
+
+    enum {
+        Mode_Normal,
+        Mode_Editing,
+    } mode = Mode_Normal;
+
+    while (true) {
+        vt100ClearScreen();
+        vt100CursorHome();
+        NodeDraw(result, n);
+
+        if (mode == Mode_Editing) {
+            int c = getch();
+            char *s = (char*)n->data;
+            int slen = strlen(s);
+            
+            if (c == KEY_BACKSPACE1 || c == KEY_BACKSPACE2) {
+                s[slen-1] = '\0';
+            }
+            else if (c == 13) {
+                mode = Mode_Normal;
+            }
+            else if (slen < STR_SIZE) {
+                s[slen++] = (char)c;
+            }
+        }
+        else if (mode == Mode_Normal) {
+            in = InputGet();
+
+            if (in == IN_Quit)
+                break;
+
+            action = actions[n->kind][in];
+
+            #define NODE_APPEND(KIND, DATA) Node *newNode = NEW(Node); newNode->kind = KIND; newNode->data = DATA; NodeAppend(n, newNode); n = newNode;
+
+            switch (action) {
+            case IA_AppendArray: { NODE_APPEND(NK_Arr, 0); break; }
+            case IA_AppendString: { NODE_APPEND(NK_Str, NEWARR(char, STR_SIZE)); mode = Mode_Editing; break; }
+            case IA_StartEditing: { mode = Mode_Editing; break; }
+            case IA_Delete: { n = NodeRemove(n->parent, n); break; }
+
+            case IA_MoveLeft: { if (n->prev != NULL) n = n->prev; break; }
+            case IA_MoveDown: { if (n->child != NULL) n = n->child; break; }
+            case IA_MoveUp: { if (n->parent != NULL) n = n->parent; break; }
+            case IA_MoveRight: { if (n->next != NULL) n = n->next; break; }
+            }
+
+            #undef NODE_APPEND
+        }
+    }
+
+    return result;
+}
+
+
+int main() {
+    // Setup
+    InputAction actions[NK_COUNT][IN_COUNT];
+
+    actions[NK_Arr][IN_A] = IA_AppendArray;
+    actions[NK_Arr][IN_S] = IA_AppendString;
+    actions[NK_Arr][IN_D] = IA_Delete;
+    actions[NK_Arr][IN_H] = IA_MoveLeft;
+    actions[NK_Arr][IN_J] = IA_MoveDown;
+    actions[NK_Arr][IN_K] = IA_MoveUp;
+    actions[NK_Arr][IN_L] = IA_MoveRight;
+
+    actions[NK_Str][IN_SPACE] = IA_StartEditing;
+    actions[NK_Str][IN_D] = IA_Delete;
+    actions[NK_Str][IN_H] = IA_MoveLeft;
+    actions[NK_Str][IN_J] = IA_MoveDown;
+    actions[NK_Str][IN_K] = IA_MoveUp;
+    actions[NK_Str][IN_L] = IA_MoveRight;
+
+    // Main
+    vt100EnableAlternateBuffer();
+    vt100HideCursor();
+
+    Node *n = GetNode(actions);
+
+    vt100DisableAlternateBuffer();
+    vt100ShowCursor();
+
+    int v, h;
+    vt100GetScreenSize(&v, &h);
+    printf("Screen Size: %d | %d\n", v, h);
+
+    NodeDraw(n, NULL);
+
+    return 0;
+}