#include #include #include #include #include /* TODO - whitelist input on GetStr/GetInt */ // Memory #define NEW(TYPE) ((TYPE *)calloc(1, sizeof(TYPE))) #define NEWARR(TYPE, NUM) ((TYPE *)calloc(NUM, sizeof(TYPE))) // Util bool charInString(char c, const char * str) { for (int i = 0; i < strlen(str); i++) if (c == str[i]) return true; return false; } bool isNewline(char c) { return c == '\n' || c == '\r'; } bool isBackspace(char c) { return c == 8 || c == 127; } // Key defines #define KEY_CTRL_C 3 #define KEY_BACKSPACE1 8 #define KEY_BACKSPACE2 127 // getch #ifdef _WIN32 #include #include #else #include #include #include #include /* 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(); //ungetc(c, stdin); 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 vt100GetCursor(int * v, int * h) { // *v = *h = 0; // printf("\033[6n"); // getch(); getch(); // int c; // while ((c = getch()) != ';') // *v = (10*(*v)+(c-'0')); // while ((c = getch()) != 'R') // *h = (10*(*h)+(c-'0')); // } 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 } void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); } void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); } // JSON typedef enum { JSONNodeKind_Nul, JSONNodeKind_Int, JSONNodeKind_Str, JSONNodeKind_Obj, JSONNodeKind_Key, JSONNodeKind_Arr, JSONNodeKind_COUNT } JSONNodeKind; struct JSONNode; typedef struct JSONNode { JSONNodeKind kind; size_t data; struct JSONNode * parent; struct JSONNode * firstChild; int childCount; struct JSONNode * prev; struct JSONNode * next; } JSONNode; JSONNode * JSONNodeNew(JSONNodeKind kind) { JSONNode * result = NEW(JSONNode); result->kind = kind; return result; } JSONNode * JSONNodePush(JSONNode * this, JSONNode * that) { if (this->firstChild == NULL) { this->firstChild = that; } else { JSONNode * lastNode = this->firstChild; while (lastNode->next != NULL) lastNode = lastNode->next; lastNode->next = that; that->prev = lastNode; } this->childCount++; that->parent = this; return that; } JSONNode * JSONNodeRemove(JSONNode * node) { if (node->prev == NULL) { // first child node->parent->firstChild = node->next; if (node->next != NULL) node->next->prev = NULL; return node->parent; } else { // second child node->prev->next = node->next; if (node->next != NULL) node->next->prev = node->prev; return node->prev; } } bool JSONNodeEditable(JSONNode * node) { if (node == NULL) return false; else if (node->kind == JSONNodeKind_Int) return true; else if (node->kind == JSONNodeKind_Str) return true; return false; } void Indent(int indent) { for (int i = 0; i < indent; i++) printf(" "); } void JSONNodePrint(JSONNode * node, JSONNode * currNode) { if (node == NULL) return; static int indent; if (node->parent == NULL) indent = 0; if (currNode == node) { vt100SaveCursor(); } switch (node->kind) { case JSONNodeKind_Nul: { printf("null"); break; } case JSONNodeKind_Int: { char * str = (char *)node->data; printf("%s", (str == NULL || strlen(str) == 0) ? "0" : str); break; } case JSONNodeKind_Str: { char * str = (char *)node->data; printf("\"%s\"", str == NULL ? "" : str); break; } case JSONNodeKind_Obj: { printf("{\n"); JSONNode * ptr = node->firstChild; indent++; while (ptr != NULL) { Indent(indent); JSONNodePrint(ptr, currNode); JSONNodePrint(ptr->firstChild, currNode); if (ptr->next != NULL) printf(","); ptr = ptr->next; printf("\n"); } indent--; Indent(indent); printf("}"); break; } case JSONNodeKind_Key: { char * str = (char *)node->data; printf("\"%s\": ", str == NULL ? "" : str); break; } case JSONNodeKind_Arr: { printf("[\n"); JSONNode * ptr = node->firstChild; indent++; while (ptr != NULL) { Indent(indent); JSONNodePrint(ptr, currNode); if (ptr->next != NULL) printf(","); printf("\n"); ptr = ptr->next; } indent--; Indent(indent); printf("]"); break; } } } // Input JSONNode * g_DrawNode = NULL; JSONNode * g_CurrNode = NULL; void Draw(void) { vt100ClearScreen(); vt100CursorHome(); if (g_DrawNode != NULL) { JSONNodePrint(g_DrawNode, g_CurrNode); vt100RestoreCursor(); } } int GetChar() { Draw(); int c = getch(); return c; } int PeekChar() { Draw(); int c = peekch(); return c; } typedef bool(*CharPredicateFunc)(char, int); bool predStr(char c, int i) { return c >= 'a' && c <= 'z'; } bool predInt(char c, int i) { return c >= '0' && c <= '9'; } void GetInput(JSONNode * node, char c) { if (node->data == (size_t)NULL) { node->data = (size_t)NEWARR(char, 16); } char * str = (char *)node->data; int strLen = strlen(str); if (isBackspace(c)) { str[strLen-1] = '\0'; } else if (strLen < 16 - 1) { str[strLen] = c; str[strLen+1] = '\0'; } } JSONNode * GetNode() { JSONNode * result = NULL; JSONNode * node = NULL; int c; bool editingNode = false; while (true) { Draw(); c = getch(); if (c == KEY_CTRL_C) break; if (node == NULL) { /**/ if (c == 'i') { node = JSONNodeNew(JSONNodeKind_Int); editingNode = true; } else if (c == 's') { node = JSONNodeNew(JSONNodeKind_Str); editingNode = true; } else if (c == 'o') { node = JSONNodeNew(JSONNodeKind_Obj); editingNode = true; } else if (c == 'a') { node = JSONNodeNew(JSONNodeKind_Arr); editingNode = true; } g_DrawNode = g_CurrNode = result = node; } else if (node->kind ==JSONNodeKind_Int) { if (editingNode) { GetInput(node, c); } else { /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; } else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; } else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; } else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; } else if (c == 'h') { if (node->prev != NULL) g_CurrNode = node = node->prev; } else if (c == 'l') { if (node->next != NULL) g_CurrNode = node = node->next; } else if (c == 'k') { if (node->parent != NULL) g_CurrNode = node = node->parent; } else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; } else if (c == ' ') { editingNode = true; } else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); } g_CurrNode = node; } } else if (node->kind ==JSONNodeKind_Str) { if (editingNode) { GetInput(node, c); } else { /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; } else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; } else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; } else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; } else if (c == 'h') { if (node->prev != NULL) g_CurrNode = node = node->prev; } else if (c == 'l') { if (node->next != NULL) g_CurrNode = node = node->next; } else if (c == 'k') { if (node->parent != NULL) g_CurrNode = node = node->parent; } else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; } else if (c == ' ') { editingNode = true; } else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); } g_CurrNode = node; } } else if (node->kind ==JSONNodeKind_Obj) { if (editingNode) { GetInput(node, c); } else { /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; } else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; } else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; } else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; } else if (c == 'h') { if (node->prev != NULL) g_CurrNode = node = node->prev; } else if (c == 'l') { if (node->next != NULL) g_CurrNode = node = node->next; } else if (c == 'k') { if (node->parent != NULL) g_CurrNode = node = node->parent; } else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; } else if (c == ' ') { editingNode = true; } else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); } g_CurrNode = node; } } else if (node->kind ==JSONNodeKind_Key) { if (editingNode) { GetInput(node, c); } else { /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; } else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; } else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; } else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; } else if (c == 'h') { if (node->prev != NULL) g_CurrNode = node = node->prev; } else if (c == 'l') { if (node->next != NULL) g_CurrNode = node = node->next; } else if (c == 'k') { if (node->parent != NULL) g_CurrNode = node = node->parent; } else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; } else if (c == ' ') { editingNode = true; } else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); } g_CurrNode = node; } } else if (node->kind ==JSONNodeKind_Arr) { if (editingNode) { GetInput(node, c); } else { /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; } else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; } else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; } else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; } else if (c == 'h') { if (node->prev != NULL) g_CurrNode = node = node->prev; } else if (c == 'l') { if (node->next != NULL) g_CurrNode = node = node->next; } else if (c == 'k') { if (node->parent != NULL) g_CurrNode = node = node->parent; } else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; } else if (c == ' ') { editingNode = true; } else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); } g_CurrNode = node; } } } return result; } int main() { vt100EnableAlternateBuffer(); JSONNode * n = GetNode(); vt100DisableAlternateBuffer(); JSONNodePrint(n, NULL); // JSONFree(n); return 0; }