8 #define BUF_SIZE 1024*1024
12 static char g_memory[1024*1024];
13 static int g_memory_index = 0;
15 void * alloc(int num, int size) {
16 void * result = g_memory + g_memory_index;
17 for (int i = 0; i < num*size; i++)
18 g_memory[g_memory_index+i] = 0;
19 g_memory_index += num*size;
23 #define NEW(TYPE) ((TYPE *)alloc(1, sizeof(TYPE)))
24 #define NEWARR(TYPE, NUM) ((TYPE *)alloc(NUM, sizeof(TYPE)))
32 #include <sys/ioctl.h>
37 /* reads from keypress, doesn't echo */
40 struct termios oldattr, newattr;
42 tcgetattr( STDIN_FILENO, &oldattr );
44 newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
45 tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
47 tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
54 struct termios oldattr, newattr;
55 tcgetattr( STDIN_FILENO, &oldattr );
57 newattr.c_lflag &= ~( ICANON | ECHO );
58 tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
60 tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
75 void vt100Escape(const char * str, ...) {
79 printf("%c", ASCII_ESC);
83 void vt100ClearScreen() { vt100Escape("[2J"); }
84 void vt100CursorHome() { vt100Escape("[H"); }
85 void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
86 void vt100SaveCursor() { vt100Escape("7"); }
87 void vt100RestoreCursor() { vt100Escape("8"); }
88 void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); }
89 void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); }
90 void vt100EnableNegative() { vt100Escape("[7m"); }
91 void vt100DisableNegative() { vt100Escape("[27m"); }
92 void vt100ShowCursor() { vt100Escape("[?25h"); }
93 void vt100HideCursor() { vt100Escape("[?25l"); }
94 void vt100GetScreenSize(int * v, int * h) {
96 CONSOLE_SCREEN_BUFFER_INFO csbi;
97 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
98 *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
99 *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
102 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
118 typedef struct Node Node;
124 Node *next, *prev, *parent, *child;
127 Node *NodeGetChild(Node *n, unsigned int index) {
128 if (index >= n->childCount)
131 Node *result = n->child;
132 for (int i = 0; i < index; i++)
133 result = result->next;
137 void NodeAppend(Node *n1, Node *n2) {
138 if (n1->childCount == 0) {
142 Node *lastChild = NodeGetChild(n1, n1->childCount-1);
144 lastChild->next = n2;
145 n2->prev = lastChild;
152 void NodeInsert(Node *n1, Node *n2, unsigned int index) {
153 if (index >= n1->childCount-1) {
158 Node *insertAfter = NodeGetChild(n1, index);
159 Node *insertBefore = NodeGetChild(n1, index+1);
161 insertAfter->next = n2;
162 insertBefore->prev = n2;
163 n2->prev = insertAfter;
164 n2->next = insertBefore;
169 Node *NodeRemove(Node *n1, Node *n2) {
173 Node *prev = n2->prev;
174 Node *next = n2->next;
181 n2->prev = n2->next = n2->parent = NULL;
194 void NodeDraw(Node *n, Node *selected) {
195 static int indent = 0;
196 for (int i = 0; i < indent; i++)
199 if (n == selected) vt100EnableNegative();
202 case NK_Nul: printf("null\n"); break;
203 case NK_Arr: printf("(%d) [\n", n->childCount); for (int i = 0; i < n->childCount; i++) NodeDraw(NodeGetChild(n, i), selected); printf("]\n"); break;
204 case NK_Str: printf("'%.16s'\n", (char *)n->data); break;
207 if (n == selected) vt100DisableNegative();
213 #define KEY_BACKSPACE1 8
214 #define KEY_BACKSPACE2 127
241 case 'a': return IN_A;
242 case 's': return IN_S;
243 case 'd': return IN_D;
245 case 'h': return IN_H;
246 case 'j': return IN_J;
247 case 'k': return IN_K;
248 case 'l': return IN_L;
250 case ' ': return IN_SPACE;
252 case 'q': return IN_Quit;
257 typedef enum InputAction {
272 Node *GetNode(InputAction actions[NK_COUNT][IN_COUNT]) {
273 Node * result = NEW(Node);
274 result->kind = NK_Arr;
284 } mode = Mode_Normal;
291 if (mode == Mode_Editing) {
293 char *s = (char*)n->data;
294 int slen = strlen(s);
296 if (c == KEY_BACKSPACE1 || c == KEY_BACKSPACE2) {
302 else if (slen < STR_SIZE) {
306 else if (mode == Mode_Normal) {
312 action = actions[n->kind][in];
314 #define NODE_APPEND(KIND, DATA) Node *newNode = NEW(Node); newNode->kind = KIND; newNode->data = DATA; NodeAppend(n, newNode); n = newNode;
317 case IA_AppendArray: { NODE_APPEND(NK_Arr, 0); break; }
318 case IA_AppendString: { NODE_APPEND(NK_Str, NEWARR(char, STR_SIZE)); mode = Mode_Editing; break; }
319 case IA_StartEditing: { mode = Mode_Editing; break; }
320 case IA_Delete: { n = NodeRemove(n->parent, n); break; }
322 case IA_MoveLeft: { if (n->prev != NULL) n = n->prev; break; }
323 case IA_MoveDown: { if (n->child != NULL) n = n->child; break; }
324 case IA_MoveUp: { if (n->parent != NULL) n = n->parent; break; }
325 case IA_MoveRight: { if (n->next != NULL) n = n->next; break; }
338 InputAction actions[NK_COUNT][IN_COUNT];
340 actions[NK_Arr][IN_A] = IA_AppendArray;
341 actions[NK_Arr][IN_S] = IA_AppendString;
342 actions[NK_Arr][IN_D] = IA_Delete;
343 actions[NK_Arr][IN_H] = IA_MoveLeft;
344 actions[NK_Arr][IN_J] = IA_MoveDown;
345 actions[NK_Arr][IN_K] = IA_MoveUp;
346 actions[NK_Arr][IN_L] = IA_MoveRight;
348 actions[NK_Str][IN_SPACE] = IA_StartEditing;
349 actions[NK_Str][IN_D] = IA_Delete;
350 actions[NK_Str][IN_H] = IA_MoveLeft;
351 actions[NK_Str][IN_J] = IA_MoveDown;
352 actions[NK_Str][IN_K] = IA_MoveUp;
353 actions[NK_Str][IN_L] = IA_MoveRight;
356 vt100EnableAlternateBuffer();
359 Node *n = GetNode(actions);
361 vt100DisableAlternateBuffer();
365 vt100GetScreenSize(&v, &h);
366 printf("Screen Size: %d | %d\n", v, h);