]> gitweb.ps.run Git - iftint/blob - main2.c
object editing, press space to edit existing primitive node
[iftint] / main2.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdbool.h>
6
7 /* TODO
8 - whitelist input on GetStr/GetInt
9 */
10
11 // Memory
12
13 #define NEW(TYPE) ((TYPE *)calloc(1, sizeof(TYPE)))
14 #define NEWARR(TYPE, NUM) ((TYPE *)calloc(NUM, sizeof(TYPE)))
15
16
17 // Util
18
19 bool
20 charInString(char c, const char * str) {
21     for (int i = 0; i < strlen(str); i++)
22         if (c == str[i])
23             return true;
24     return false;
25 }
26
27 bool
28 isNewline(char c) {
29     return c == '\n' || c == '\r';
30 }
31 bool
32 isBackspace(char c) {
33     return c == 8 || c == 127;
34 }
35
36
37 // Key defines
38
39 #define KEY_CTRL_C 3
40 #define KEY_BACKSPACE1 8
41 #define KEY_BACKSPACE2 127
42
43
44 // getch
45
46 #ifdef _WIN32
47 #include <windows.h>
48 #include <conio.h>
49 #else
50 #include <sys/ioctl.h>
51 #include <termios.h>
52 #include <unistd.h>
53 #include <stdio.h>
54
55 /* reads from keypress, doesn't echo */
56 int getch(void)
57 {
58     struct termios oldattr, newattr;
59     int ch;
60     tcgetattr( STDIN_FILENO, &oldattr );
61     newattr = oldattr;
62     newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
63     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
64     ch = getchar();
65     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
66     return ch;
67 }
68
69 /* ungets keypress */
70 void ungetch(int ch)
71 {
72     struct termios oldattr, newattr;
73     tcgetattr( STDIN_FILENO, &oldattr );
74     newattr = oldattr;
75     newattr.c_lflag &= ~( ICANON | ECHO );
76     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
77     ungetc(ch, stdin);
78     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
79 }
80 #endif
81
82 int
83 peekch() {
84     int c = getch();
85     //ungetc(c, stdin);
86     ungetch(c);
87     return c;
88 }
89
90
91 // VT100
92
93 #define ASCII_ESC 27
94
95 void vt100Escape(const char * str, ...) {
96     va_list args;
97     va_start(args, str);
98
99     printf("%c", ASCII_ESC);
100     vprintf(str, args);
101 }
102
103 void vt100ClearScreen() { vt100Escape("[2J"); }
104 void vt100CursorHome() { vt100Escape("[H"); }
105 void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
106 void vt100SaveCursor() { vt100Escape("7"); }
107 void vt100RestoreCursor() { vt100Escape("8"); }
108 // void vt100GetCursor(int * v, int * h) {
109 //     *v = *h = 0;
110 //     printf("\033[6n");
111 //     getch(); getch();
112 //     int c;
113 //     while ((c = getch()) != ';')
114 //         *v = (10*(*v)+(c-'0'));
115 //     while ((c = getch()) != 'R')
116 //         *h = (10*(*h)+(c-'0'));
117 // }
118 void vt100GetScreenSize(int * v, int * h) {
119 #ifdef _WIN32
120     CONSOLE_SCREEN_BUFFER_INFO csbi;
121     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
122     *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
123     *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
124 #else
125     struct winsize w;
126     ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
127     *h = w.ws_row;
128     *v = w.ws_col;
129 #endif
130 }
131 void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); }
132 void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); }
133
134
135 // JSON
136
137 typedef enum {
138     JSONNodeKind_Nul,
139     JSONNodeKind_Int,
140     JSONNodeKind_Str,
141     JSONNodeKind_Obj,
142     JSONNodeKind_Arr,
143     JSONNodeKind_COUNT
144 } JSONNodeKind;
145
146 struct JSONNode;
147 typedef struct JSONNode {
148     JSONNodeKind kind;
149     size_t data;
150     struct JSONNode * parent;
151     struct JSONNode * firstChild;
152     int childCount;
153     struct JSONNode * prev;
154     struct JSONNode * next;
155 } JSONNode;
156
157 JSONNode *
158 JSONNodeNew(JSONNodeKind kind) {
159     JSONNode * result = NEW(JSONNode);
160     result->kind = kind;
161     return result;
162 }
163
164 JSONNode *
165 JSONNodePush(JSONNode * this, JSONNode * that) {
166     if (this->firstChild == NULL) {
167         this->firstChild = that;
168     }
169     else {
170         JSONNode * lastNode = this->firstChild;
171         while (lastNode->next != NULL)
172             lastNode = lastNode->next;
173         lastNode->next = that;
174         that->prev = lastNode;
175     }
176     this->childCount++;
177     that->parent = this;
178     
179     return that;
180 }
181
182 JSONNode *
183 JSONNodeRemove(JSONNode * node) {
184     if (node->prev == NULL) { // first child
185         node->parent->firstChild = node->next;
186         if (node->next != NULL)
187             node->next->prev = NULL;
188         return node->parent;
189     }
190     else { // second child
191         node->prev->next = node->next;
192         if (node->next != NULL)
193             node->next->prev = node->prev;
194         return node->prev;
195     }
196 }
197
198 bool
199 JSONNodeEditable(JSONNode * node) {
200     if (node == NULL) return false;
201     else if (node->kind == JSONNodeKind_Int) return true;
202     else if (node->kind == JSONNodeKind_Str) return true;
203     return false;
204 }
205
206 void
207 Indent(int indent) {
208     for (int i = 0; i < indent; i++)
209         printf("  ");
210 }
211
212 void
213 JSONNodePrint(JSONNode * node, JSONNode * currNode) {
214     if (node == NULL)
215         return;
216     
217     static int indent;
218     if (node->parent == NULL)
219         indent = 0;
220
221     if (currNode == node) {
222         vt100SaveCursor();
223     }
224
225     switch (node->kind) {
226     case JSONNodeKind_Nul: {
227         printf("null");
228         break;
229     }
230     case JSONNodeKind_Int: {
231         char * str = (char *)node->data;
232         printf("%s", (str == NULL || strlen(str) == 0) ? "0" : str);
233         break;
234     }
235     case JSONNodeKind_Str: {
236         char * str = (char *)node->data;
237         printf("\"%s\"", str == NULL ? "" : str);
238         break;
239     }
240     case JSONNodeKind_Obj: {
241         printf("{\n");
242         JSONNode * ptr = node->firstChild;
243         indent++;
244         while (ptr != NULL) {
245             Indent(indent);
246             JSONNodePrint(ptr, currNode);
247             printf(": ");
248             JSONNodePrint(ptr->firstChild, currNode);
249             if (ptr->next != NULL)
250                 printf(",");
251             ptr = ptr->next;
252             printf("\n");
253         }
254         indent--;
255         Indent(indent);
256         printf("}");
257         break;
258     }
259     case JSONNodeKind_Arr: {
260         printf("[\n");
261         JSONNode * ptr = node->firstChild;
262         indent++;
263         while (ptr != NULL) {
264             Indent(indent);
265             JSONNodePrint(ptr, currNode);
266             if (ptr->next != NULL)
267                 printf(",");
268             printf("\n");
269             ptr = ptr->next;
270         }
271         indent--;
272         Indent(indent);
273         printf("]");
274         break;
275     }
276     }
277 }
278
279
280 // Input
281
282 JSONNode * g_DrawNode = NULL;
283 JSONNode * g_CurrNode = NULL;
284
285 void
286 Draw(void) {
287     vt100ClearScreen();
288     vt100CursorHome();
289     
290     if (g_DrawNode != NULL) {
291         JSONNodePrint(g_DrawNode, g_CurrNode);
292         vt100RestoreCursor();
293     }
294 }
295
296 int
297 GetChar() {
298     Draw();
299     int c = getch();
300     return c;
301 }
302
303 int
304 PeekChar() {
305     Draw();
306     int c = peekch();
307     return c;
308 }
309
310 typedef bool(*CharPredicateFunc)(char, int);
311
312 bool predStr(char c, int i) { return c >= 'a' && c <= 'z'; }
313 bool predInt(char c, int i) { return c >= '0' && c <= '9'; }
314
315 JSONNode *
316 GetNode() {
317     JSONNode * result = NULL;
318     JSONNode * node = NULL;
319     int c;
320     int strLen = 0;
321
322     typedef enum {
323         InputState_Initial,
324         InputState_Primitive,
325         InputState_Object,
326         InputState_KeyValue,
327         InputState_Array,
328     } InputState;
329     InputState inputState;
330
331     bool editingNode = false;
332
333     while (true) {
334         c = GetChar();
335
336         if (c == KEY_CTRL_C)
337             break;
338
339         if (isNewline(c)) {
340             if (node == NULL || node->parent == NULL)
341                 break;
342
343             if (node->parent->kind == JSONNodeKind_Obj) // editing obj key
344                 g_CurrNode = node = node->firstChild;
345             else if (node->parent->kind == JSONNodeKind_Str) // editing obj value
346                 g_CurrNode = node = node->parent->parent;
347             else
348                 g_CurrNode = node = node->parent;
349             
350             editingNode = JSONNodeEditable(node);
351             
352             continue;
353         }
354
355         if (JSONNodeEditable(node) && editingNode) {
356             if (node->data == (size_t)NULL) {
357                 node->data = (size_t)NEWARR(char, 16);
358                 strLen = 0;
359             }
360             char * str = (char *)node->data;
361
362             if (isBackspace(c)) {
363                 str[strLen-1] = '\0';
364                 strLen--;
365             }
366             else if (strLen < 16 - 1) {
367                 str[strLen] = c;
368                 str[strLen+1] = '\0';
369                 strLen++;
370             }
371         }
372         else {
373             JSONNode * old = node;
374
375             /**/ if (c == 'i') { node = JSONNodeNew(JSONNodeKind_Int); editingNode = true; }
376             else if (c == 's') { node = JSONNodeNew(JSONNodeKind_Str); editingNode = true; }
377             else if (c == 'o') { node = JSONNodeNew(JSONNodeKind_Obj); }
378             else if (c == 'a') { node = JSONNodeNew(JSONNodeKind_Arr); }
379             else if (c == 'h') { if (node->prev != NULL) g_CurrNode = node = node->prev; continue; }
380             else if (c == 'l') { if (node->next != NULL) g_CurrNode = node = node->next; continue; }
381             else if (c == 'k') { if (node->parent != NULL) g_CurrNode = node = node->parent; continue; }
382             else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; continue; }
383             else if (c == ' ') { if (JSONNodeEditable(node)) editingNode = true; continue; }
384             else if (isBackspace(c) && node != NULL) { g_CurrNode = node = JSONNodeRemove(node); continue; }
385             else { continue; }
386
387             if (old != NULL) {
388                 // new node was added to an object
389                 if (old->kind == JSONNodeKind_Obj) {
390                     JSONNode * keyNode = JSONNodeNew(JSONNodeKind_Str);
391                     JSONNodePush(keyNode, node);
392                     node = keyNode;
393                     editingNode = true;
394                 }
395                 JSONNodePush(old, node);
396             }
397             else {
398                 g_DrawNode = result = node;
399             }
400
401             g_CurrNode = node;
402         }
403     }
404
405     return result;
406 }
407
408
409
410
411 int main() {
412     vt100EnableAlternateBuffer();
413
414     JSONNode * n = GetNode();
415     
416     vt100DisableAlternateBuffer();
417
418     JSONNodePrint(n, NULL);
419
420     // JSONFree(n);
421
422     return 0;
423 }