Subversion Repositories Kolibri OS

Rev

Rev 8116 | Rev 8127 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7413 siemargl 1
/*
2
*   Copyright (C) 2017 Daniel Morales
3
*
4
*   This program is free software: you can redistribute it and/or modify
5
*   it under the terms of the GNU General Public License as published by
6
*   the Free Software Foundation, either version 3 of the License, or
7
*   any later version.
8
*
9
*   This program is distributed in the hope that it will be useful,
10
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
*   GNU General Public License for more details.
13
*
14
*   You should have received a copy of the GNU General Public License
15
*   along with this program.  If not, see .
16
*/
8116 maxcodehac 17
/* Kolibri port by Siemargl 2018 and update by maxcodehack 2020
7419 siemargl 18
 * my fixes mostly commented with triple comment ///
19
 * */
7413 siemargl 20
 
21
/*** Include section ***/
22
 
23
// We add them above our includes, because the header
24
// files we are including use the macros to decide what
25
// features to expose. These macros remove some compilation
26
// warnings. See
27
// https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
28
// for more info.
29
#define _DEFAULT_SOURCE
30
#define _BSD_SOURCE
31
#define _GNU_SOURCE
32
 
33
#include 
34
#include 
7414 siemargl 35
///#include 
36
///#include 
7413 siemargl 37
#include 
38
#include 
39
#include 
40
#include 
7414 siemargl 41
///#include 
42
///#include 
43
///#include 
7413 siemargl 44
#include 
7414 siemargl 45
///#include 
46
#include 
7419 siemargl 47
 
48
 
49
 
7413 siemargl 50
/*** Define section ***/
51
 
52
// This mimics the Ctrl + whatever behavior, setting the
53
// 3 upper bits of the character pressed to 0.
7414 siemargl 54
///#define CTRL_KEY(k) ((k) & 0x1f)
55
// Siemargl - set top 4 bits
56
#define CTRL_KEY(k) ((k) | 0xf000)
7413 siemargl 57
// Empty buffer
58
#define ABUF_INIT {NULL, 0}
59
// Version code
60
#define TTE_VERSION "0.0.5"
61
// Length of a tab stop
62
#define TTE_TAB_STOP 4
63
// Times to press Ctrl-Q before exiting
64
#define TTE_QUIT_TIMES 2
65
// Highlight flags
66
#define HL_HIGHLIGHT_NUMBERS (1 << 0)
67
#define HL_HIGHLIGHT_STRINGS (1 << 1)
68
 
69
/*** Data section ***/
70
 
7414 siemargl 71
// Kolibri defaults
72
int con_def_wnd_width   =    80;
73
int	con_def_wnd_height  =    25;
7419 siemargl 74
/// winFile support
75
int	fileIsOd0a;
7414 siemargl 76
 
7413 siemargl 77
typedef struct editor_row {
78
    int idx; // Row own index within the file.
79
    int size; // Size of the content (excluding NULL term)
80
    int render_size; // Size of the rendered content
81
    char* chars; // Row content
82
    char* render; // Row content "rendered" for screen (for TABs).
83
    unsigned char* highlight; // This will tell you if a character is part of a string, comment, number...
84
    int hl_open_comment; // True if the line is part of a ML comment.
85
} editor_row;
86
 
87
struct editor_syntax {
88
    // file_type field is the name of the filetype that will be displayed
89
    // to the user in the status bar.
90
    char* file_type;
91
    // file_match is an array of strings, where each string contains a
92
    // pattern to match a filename against. If the filename matches,
93
    // then the file will be recognized as having that filetype.
94
    char** file_match;
95
    // This will be a NULL-terminated array of strings, each string containing
96
    // a keyword. To differentiate between the two types of keywords,
8121 maxcodehac 97
    // we'll terminate the second type of keywords with a pipe (|)
7413 siemargl 98
    // character (also known as a vertical bar).
99
    char** keywords;
100
    // We let each language specify its own single-line comment pattern.
101
    char* singleline_comment_start;
102
    // flags is a bit field that will contain flags for whether to
103
    // highlight numbers and whether to highlight strings for that
104
    // filetype.
105
    char* multiline_comment_start;
106
    char* multiline_comment_end;
107
    int flags;
108
};
109
 
110
struct editor_config {
111
    int cursor_x;
112
    int cursor_y;
113
    int render_x;
114
    int row_offset; // Offset of row displayed.
115
    int col_offset; // Offset of col displayed.
116
    int screen_rows; // Number of rows that we can show
117
    int screen_cols; // Number of cols that we can show
118
    int num_rows; // Number of rows
119
    editor_row* row;
120
    int dirty; // To know if a file has been modified since opening.
121
    char* file_name;
122
    char status_msg[80];
123
    time_t status_msg_time;
124
    char* copied_char_buffer;
125
    struct editor_syntax* syntax;
7414 siemargl 126
///    struct termios orig_termios;
7413 siemargl 127
} ec;
128
 
129
// Having a dynamic buffer will allow us to write only one
130
// time once the screen is refreshing, instead of doing
131
// a lot of write's.
132
struct a_buf {
133
    char* buf;
134
    int len;
135
};
136
 
137
enum editor_key {
7414 siemargl 138
///    BACKSPACE = 0x7f, // 127
139
    BACKSPACE = 0x3e7, // fixed russian letter
7413 siemargl 140
    ARROW_LEFT = 0x3e8, // 1000, large value out of the range of a char.
141
    ARROW_RIGHT,
142
    ARROW_UP,
143
    ARROW_DOWN,
144
    PAGE_UP,
145
    PAGE_DOWN,
146
    HOME_KEY,
147
    END_KEY,
148
    DEL_KEY
149
};
150
 
151
enum editor_highlight {
152
    HL_NORMAL = 0,
153
    HL_SL_COMMENT,
154
    HL_ML_COMMENT,
155
    HL_KEYWORD_1,
156
    HL_KEYWORD_2,
157
    HL_STRING,
158
    HL_NUMBER,
159
    HL_MATCH
160
};
161
 
162
/*** Filetypes ***/
163
 
164
char* C_HL_extensions[] = {".c", ".h", ".cpp", ".hpp", ".cc", NULL}; // Array must be terminated with NULL.
165
char* JAVA_HL_extensions[] = {".java", NULL};
166
char* PYTHON_HL_extensions[] = {".py", NULL};
167
char* BASH_HL_extensions[] = {".sh", NULL};
168
char* JS_HL_extensions[] = {".js", ".jsx", NULL};
169
char* PHP_HL_extensions[] = {".php", NULL};
170
char* JSON_HL_extensions[] = {".json", ".jsonp", NULL};
171
char* XML_HL_extensions[] = {".xml", NULL};
172
char* SQL_HL_extensions[] = {".sql", NULL};
173
char* RUBY_HL_extensions[] = {".rb", NULL};
174
 
175
char* C_HL_keywords[] = {
176
    "switch", "if", "while", "for", "break", "continue", "return", "else",
177
    "struct", "union", "typedef", "static", "enum", "class", "case", "#include",
178
    "volatile", "register", "sizeof", "typedef", "union", "goto", "const", "auto",
179
    "#define", "#if", "#endif", "#error", "#ifdef", "#ifndef", "#undef",
180
 
181
    "int|", "long|", "double|", "float|", "char|", "unsigned|", "signed|",
182
    "void|", "bool|", NULL
183
};
184
 
185
char* JAVA_HL_keywords[] = {
186
    "switch", "if", "while", "for", "break", "continue", "return", "else",
187
    "in", "public", "private", "protected", "static", "final", "abstract",
188
    "enum", "class", "case", "try", "catch", "do", "extends", "implements",
189
    "finally", "import", "instanceof", "interface", "new", "package", "super",
190
    "native", "strictfp",
191
    "synchronized", "this", "throw", "throws", "transient", "volatile",
192
 
193
    "byte|", "char|", "double|", "float|", "int|", "long|", "short|",
194
    "boolean|", NULL
195
};
196
 
197
char* PYTHON_HL_keywords[] = {
198
    "and", "as", "assert", "break", "class", "continue", "def", "del", "elif",
199
    "else", "except", "exec", "finally", "for", "from", "global", "if", "import",
200
    "in", "is", "lambda", "not", "or", "pass", "print", "raise", "return", "try",
201
    "while", "with", "yield",
202
 
203
    "buffer|", "bytearray|", "complex|", "False|", "float|", "frozenset|", "int|",
204
    "list|", "long|", "None|", "set|", "str|", "tuple|", "True|", "type|",
205
    "unicode|", "xrange|", NULL
206
};
207
 
208
char* BASH_HL_keywords[] = {
209
    "case", "do", "done", "elif", "else", "esac", "fi", "for", "function", "if",
210
    "in", "select", "then", "time", "until", "while", "alias", "bg", "bind", "break",
211
    "builtin", "cd", "command", "continue", "declare", "dirs", "disown", "echo",
212
    "enable", "eval", "exec", "exit", "export", "fc", "fg", "getopts", "hash", "help",
213
    "history", "jobs", "kill", "let", "local", "logout", "popd", "pushd", "pwd", "read",
214
    "readonly", "return", "set", "shift", "suspend", "test", "times", "trap", "type",
215
    "typeset", "ulimit", "umask", "unalias", "unset", "wait", "printf", NULL
216
};
217
 
218
char* JS_HL_keywords[] = {
219
    "break", "case", "catch", "class", "const", "continue", "debugger", "default",
220
    "delete", "do", "else", "enum", "export", "extends", "finally", "for", "function",
221
    "if", "implements", "import", "in", "instanceof", "interface", "let", "new",
222
    "package", "private", "protected", "public", "return", "static", "super", "switch",
223
    "this", "throw", "try", "typeof", "var", "void", "while", "with", "yield", "true",
224
    "false", "null", "NaN", "global", "window", "prototype", "constructor", "document",
225
    "isNaN", "arguments", "undefined",
226
 
227
    "Infinity|", "Array|", "Object|", "Number|", "String|", "Boolean|", "Function|",
228
    "ArrayBuffer|", "DataView|", "Float32Array|", "Float64Array|", "Int8Array|",
229
    "Int16Array|", "Int32Array|", "Uint8Array|", "Uint8ClampedArray|", "Uint32Array|",
230
    "Date|", "Error|", "Map|", "RegExp|", "Symbol|", "WeakMap|", "WeakSet|", "Set|", NULL
231
};
232
 
233
char* PHP_HL_keywords[] = {
234
    "__halt_compiler", "break", "clone", "die", "empty", "endswitch", "final", "global",
235
    "include_once", "list", "private", "return", "try", "xor", "abstract", "callable",
236
    "const", "do", "enddeclare", "endwhile", "finally", "goto", "instanceof", "namespace",
237
    "protected", "static", "unset", "yield", "and", "case", "continue", "echo", "endfor",
238
    "eval", "for", "if", "insteadof", "new", "public", "switch", "use", "array", "catch",
239
    "declare", "else", "endforeach", "exit", "foreach", "implements", "interface", "or",
240
    "require", "throw", "var", "as", "class", "default", "elseif", "endif", "extends",
241
    "function", "include", "isset", "print", "require_once", "trait", "while", NULL
242
};
243
 
244
char* JSON_HL_keywords[] = {
245
    NULL
246
};
247
 
248
char* XML_HL_keywords[] = {
249
    NULL
250
};
251
 
252
char* SQL_HL_keywords[] = {
253
    "SELECT", "FROM", "DROP", "CREATE", "TABLE", "DEFAULT", "FOREIGN", "UPDATE", "LOCK",
254
    "INSERT", "INTO", "VALUES", "LOCK", "UNLOCK", "WHERE", "DINSTINCT", "BETWEEN", "NOT",
255
    "NULL", "TO", "ON", "ORDER", "GROUP", "IF", "BY", "HAVING", "USING", "UNION", "UNIQUE",
256
    "AUTO_INCREMENT", "LIKE", "WITH", "INNER", "OUTER", "JOIN", "COLUMN", "DATABASE", "EXISTS",
257
    "NATURAL", "LIMIT", "UNSIGNED", "MAX", "MIN", "PRECISION", "ALTER", "DELETE", "CASCADE",
258
    "PRIMARY", "KEY", "CONSTRAINT", "ENGINE", "CHARSET", "REFERENCES", "WRITE",
259
 
260
    "BIT|", "TINYINT|", "BOOL|", "BOOLEAN|", "SMALLINT|", "MEDIUMINT|", "INT|", "INTEGER|",
261
    "BIGINT|", "DOUBLE|", "DECIMAL|", "DEC|" "FLOAT|", "DATE|", "DATETIME|", "TIMESTAMP|",
262
    "TIME|", "YEAR|", "CHAR|", "VARCHAR|", "TEXT|", "ENUM|", "SET|", "BLOB|", "VARBINARY|",
263
    "TINYBLOB|", "TINYTEXT|", "MEDIUMBLOB|", "MEDIUMTEXT|", "LONGTEXT|",
264
 
265
    "select", "from", "drop", "create", "table", "default", "foreign", "update", "lock",
266
    "insert", "into", "values", "lock", "unlock", "where", "dinstinct", "between", "not",
267
    "null", "to", "on", "order", "group", "if", "by", "having", "using", "union", "unique",
268
    "auto_increment", "like", "with", "inner", "outer", "join", "column", "database", "exists",
269
    "natural", "limit", "unsigned", "max", "min", "precision", "alter", "delete", "cascade",
270
    "primary", "key", "constraint", "engine", "charset", "references", "write",
271
 
272
    "bit|", "tinyint|", "bool|", "boolean|", "smallint|", "mediumint|", "int|", "integer|",
273
    "bigint|", "double|", "decimal|", "dec|" "float|", "date|", "datetime|", "timestamp|",
274
    "time|", "year|", "char|", "varchar|", "text|", "enum|", "set|", "blob|", "varbinary|",
275
    "tinyblob|", "tinytext|", "mediumblob|", "mediumtext|", "longtext|", NULL
276
};
277
 
278
char* RUBY_HL_keywords[] = {
279
    "__ENCODING__", "__LINE__", "__FILE__", "BEGIN", "END", "alias", "and", "begin", "break",
280
    "case", "class", "def", "defined?", "do", "else", "elsif", "end", "ensure", "for", "if",
281
    "in", "module", "next", "not", "or", "redo", "rescue", "retry", "return", "self", "super",
282
    "then", "undef", "unless", "until", "when", "while", "yield", NULL
283
};
284
 
285
struct editor_syntax HL_DB[] = {
286
    {
287
        "c",
288
        C_HL_extensions,
289
        C_HL_keywords,
290
        "//",
291
        "/*",
292
        "*/",
293
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
294
    },
295
    {
296
        "java",
297
        JAVA_HL_extensions,
298
        JAVA_HL_keywords,
299
        "//",
300
        "/*",
301
        "*/",
302
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
303
    },
304
    {
305
        "python",
306
        PYTHON_HL_extensions,
307
        PYTHON_HL_keywords,
308
        "#",
309
        "'''",
310
        "'''",
311
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
312
    },
313
    {
314
        "bash",
315
        BASH_HL_extensions,
316
        BASH_HL_keywords,
317
        "#",
318
        NULL,
319
        NULL,
320
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
321
    },
322
    {
323
        "js",
324
        JS_HL_extensions,
325
        JS_HL_keywords,
326
        "//",
327
        "/*",
328
        "*/",
329
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
330
    },
331
    {
332
        "php",
333
        PHP_HL_extensions,
334
        PHP_HL_keywords,
335
        "//",
336
        "/*",
337
        "*/",
338
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
339
    },
340
    {
341
        "json",
342
        JSON_HL_extensions,
343
        JSON_HL_keywords,
344
        NULL,
345
        NULL,
346
        NULL,
347
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
348
    },
349
    {
350
        "xml",
351
        XML_HL_extensions,
352
        XML_HL_keywords,
353
        NULL,
354
        NULL,
355
        NULL,
356
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
357
    },
358
    {
359
        "sql",
360
        SQL_HL_extensions,
361
        SQL_HL_keywords,
362
        "--",
363
        "/*",
364
        "*/",
365
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
366
    },
367
    {
368
        "ruby",
369
        RUBY_HL_extensions,
370
        RUBY_HL_keywords,
371
        "#",
372
        "=begin",
373
        "=end",
374
        HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
375
    }
376
};
377
 
378
// Size of the "Hightlight Database" (HL_DB).
379
#define HL_DB_ENTRIES (sizeof(HL_DB) / sizeof(HL_DB[0]))
380
 
381
/*** Declarations section ***/
382
 
383
void editorClearScreen();
384
 
385
void editorRefreshScreen();
386
 
387
void editorSetStatusMessage(const char* msg, ...);
388
 
389
void consoleBufferOpen();
390
 
391
void abufFree();
392
 
393
void abufAppend();
394
 
395
char *editorPrompt(char* prompt, void (*callback)(char*, int));
396
 
397
void editorRowAppendString(editor_row* row, char* s, size_t len);
398
 
399
void editorInsertNewline();
400
 
401
/*** Terminal section ***/
402
 
403
void die(const char* s) {
404
    editorClearScreen();
405
    // perror looks for global errno variable and then prints
406
    // a descriptive error mesage for it.
407
    perror(s);
408
    printf("\r\n");
7419 siemargl 409
    con_exit(0); /// KOS console
7413 siemargl 410
    exit(1);
411
}
412
 
413
void disableRawMode() {
7414 siemargl 414
///    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &ec.orig_termios) == -1)
415
///        die("Failed to disable raw mode");
7413 siemargl 416
}
417
 
418
void enableRawMode() {
419
    // Save original terminal state into orig_termios.
7414 siemargl 420
///    if (tcgetattr(STDIN_FILENO, &ec.orig_termios) == -1)
421
///        die("Failed to get current terminal state");
7413 siemargl 422
    // At exit, restore the original state.
7414 siemargl 423
///    atexit(disableRawMode);
424
///
425
/*
7413 siemargl 426
    // Modify the original state to enter in raw mode.
427
    struct termios raw = ec.orig_termios;
428
    // This disables Ctrl-M, Ctrl-S and Ctrl-Q commands.
429
    // (BRKINT, INPCK and ISTRIP are not estrictly mandatory,
430
    // but it is recommended to turn them off in case any
431
    // system needs it).
432
    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
433
    // Turning off all output processing (\r\n).
434
    raw.c_oflag &= ~(OPOST);
435
    // Setting character size to 8 bits per byte (it should be
436
    // like that on most systems, but whatever).
437
    raw.c_cflag |= (CS8);
438
    // Using NOT operator on ECHO | ICANON | IEXTEN | ISIG and
439
    // then bitwise-AND them with flags field in order to
440
    // force c_lflag 4th bit to become 0. This disables
441
    // chars being printed (ECHO) and let us turn off
442
    // canonical mode in order to read input byte-by-byte
443
    // instead of line-by-line (ICANON), ISIG disables
444
    // Ctrl-C command and IEXTEN the Ctrl-V one.
445
    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
446
    // read() function now returns as soon as there is any
447
    // input to be read.
448
    raw.c_cc[VMIN] = 0;
449
    // Forcing read() function to return every 1/10 of a
450
    // second if there is nothing to read.
451
    raw.c_cc[VTIME] = 1;
7414 siemargl 452
*/
7413 siemargl 453
    consoleBufferOpen();
454
 
7414 siemargl 455
///    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1)
456
///        die("Failed to set raw mode");
7413 siemargl 457
}
458
 
7414 siemargl 459
 
7413 siemargl 460
 
7414 siemargl 461
/// by Siemargl rewritten, still Ctrl+ combination works only in english locale, so need analyze scancode
462
int editorReadKey() {
463
    int key = con_getch2();
464
    if (key == 0)
7419 siemargl 465
		die("Window closed by moused X-button");
7413 siemargl 466
 
7414 siemargl 467
	if (0 != (key & 0xff)) {
468
		key &= 0xff;
469
		switch (key) {
470
			case 27: // ESC
471
				return '\x1b';
472
 
473
			case 13: // ENTER
474
				return '\r';
475
 
476
			case 8: // BACKSPACE
477
				return BACKSPACE;
478
 
479
			case 9: // TAB
480
				return	key;
481
 
482
			case 22: // Ctrl+V
483
				return CTRL_KEY('v');
484
 
485
			case 3: // Ctrl+C
486
				return CTRL_KEY('c');
487
 
488
			case 12: // Ctrl+L
489
				return CTRL_KEY('l');
490
 
491
			case 17: // Ctrl+Q
7419 siemargl 492
			case 26: // Ctrl+Z
7414 siemargl 493
				return CTRL_KEY('q');
494
 
495
			case 19: // Ctrl+S
496
				return CTRL_KEY('s');
497
 
498
			case 5: // Ctrl+E
499
				return CTRL_KEY('e');
500
 
501
			case 4: // Ctrl+D
502
				return CTRL_KEY('d');
503
 
504
			case 6: // Ctrl+F
505
				return CTRL_KEY('f');
506
 
507
			case 8: // Ctrl+H
508
				return CTRL_KEY('h');
509
 
510
			case 24: // Ctrl+X
511
				return CTRL_KEY('x');
512
 
513
			default:
514
				return	key;
515
 
516
		}
517
	} else {
518
		key = (key >> 8) & 0xff;
519
		switch (key) {
520
			case 83: // Del
521
				return DEL_KEY;
522
 
523
			case 75: // Left
524
				return ARROW_LEFT;
525
 
526
			case 77: // Right
527
				return ARROW_RIGHT;
528
 
529
			case 72: // Up
530
				return ARROW_UP;
531
 
532
			case 80: // Down
533
				return ARROW_DOWN;
534
 
535
			case 81: // PgDn
536
				return PAGE_DOWN;
537
 
538
			case 73: // PgUp
539
				return PAGE_UP;
540
 
541
			case 71: // Home
542
				return HOME_KEY;
543
 
544
			case 79: // End
545
				return END_KEY;
546
 
547
			default:
548
				return	0;
549
		}
550
	}
551
	return	0;
552
}
553
 
554
 
555
 
556
 
557
 
7413 siemargl 558
int getWindowSize(int* screen_rows, int* screen_cols) {
7414 siemargl 559
///    struct winsize ws;
7413 siemargl 560
 
561
    // Getting window size thanks to ioctl into the given
562
    // winsize struct.
7414 siemargl 563
    /*
7413 siemargl 564
    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
565
        return -1;
566
    } else {
567
        *screen_cols = ws.ws_col;
568
        *screen_rows = ws.ws_row;
569
        return 0;
570
    }
7414 siemargl 571
    */
572
    *screen_cols = con_def_wnd_width;
573
    *screen_rows = con_def_wnd_height;
7413 siemargl 574
}
575
 
576
void editorUpdateWindowSize() {
577
    if (getWindowSize(&ec.screen_rows, &ec.screen_cols) == -1)
578
        die("Failed to get window size");
579
    ec.screen_rows -= 2; // Room for the status bar.
580
}
581
 
582
void editorHandleSigwinch() {
583
    editorUpdateWindowSize();
584
    if (ec.cursor_y > ec.screen_rows)
585
        ec.cursor_y = ec.screen_rows - 1;
586
    if (ec.cursor_x > ec.screen_cols)
587
        ec.cursor_x = ec.screen_cols - 1;
588
    editorRefreshScreen();
589
}
590
 
591
void editorHandleSigcont() {
592
    disableRawMode();
593
    consoleBufferOpen();
594
    enableRawMode();
595
    editorRefreshScreen();
596
}
597
 
598
void consoleBufferOpen() {
599
    // Switch to another terminal buffer in order to be able to restore state at exit
600
    // by calling consoleBufferClose().
7414 siemargl 601
///    if (write(STDOUT_FILENO, "\x1b[?47h", 6) == -1)
602
///        die("Error changing terminal buffer");
7413 siemargl 603
}
604
 
605
void consoleBufferClose() {
606
    // Restore console to the state tte opened.
7414 siemargl 607
///    if (write(STDOUT_FILENO, "\x1b[?9l", 5) == -1 ||
608
///        write(STDOUT_FILENO, "\x1b[?47l", 6) == -1)
609
///        die("Error restoring buffer state");
7413 siemargl 610
 
611
    /*struct a_buf ab = {.buf = NULL, .len = 0};
612
    char* buf = NULL;
613
    if (asprintf(&buf, "\x1b[%d;%dH\r\n", ec.screen_rows + 1, 1) == -1)
614
        die("Error restoring buffer state");
615
    abufAppend(&ab, buf, strlen(buf));
616
    free(buf);
617
 
618
    if (write(STDOUT_FILENO, ab.buf, ab.len) == -1)
619
        die("Error restoring buffer state");
620
    abufFree(&ab);*/
621
 
622
    editorClearScreen();
623
}
624
 
625
/*** Syntax highlighting ***/
626
 
627
int isSeparator(int c) {
628
    // strchr() looks to see if any one of the characters in the first string
629
    // appear in the second string. If so, it returns a pointer to the
630
    // character in the second string that matched. Otherwise, it
631
    // returns NULL.
632
    return isspace(c) || c == '\0' || strchr(",.()+-/*=~%<>[]:;", c) != NULL;
633
}
634
 
635
int isAlsoNumber(int c) {
636
    return c == '.' || c == 'x' || c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f';
637
}
638
 
639
void editorUpdateSyntax(editor_row* row) {
640
    row -> highlight = realloc(row -> highlight, row -> render_size);
641
    // void * memset ( void * ptr, int value, size_t num );
642
    // Sets the first num bytes of the block of memory pointed by ptr to
643
    // the specified value. With this we set all characters to HL_NORMAL.
644
    memset(row -> highlight, HL_NORMAL, row -> render_size);
645
 
646
    if (ec.syntax == NULL)
647
        return;
648
 
649
    char** keywords = ec.syntax -> keywords;
650
 
651
    char* scs = ec.syntax -> singleline_comment_start;
652
    char* mcs = ec.syntax -> multiline_comment_start;
653
    char* mce = ec.syntax -> multiline_comment_end;
654
 
655
    int scs_len = scs ? strlen(scs) : 0;
656
    int mcs_len = mcs ? strlen(mcs) : 0;
657
    int mce_len = mce ? strlen(mce) : 0;
658
 
659
    int prev_sep = 1; // True (1) if the previous char is a separator, false otherwise.
660
    int in_string = 0; // If != 0, inside a string. We also keep track if it's ' or "
661
    int in_comment = (row -> idx > 0 && ec.row[row -> idx - 1].hl_open_comment); // This is ONLY used on ML comments.
662
 
663
    int i = 0;
664
    while (i < row -> render_size) {
665
        char c = row -> render[i];
666
        // Highlight type of the previous character.
667
        unsigned char prev_highlight = (i > 0) ? row -> highlight[i - 1] : HL_NORMAL;
668
 
669
        if (scs_len && !in_string && !in_comment) {
670
            // int strncmp ( const char * str1, const char * str2, size_t num );
671
            // Compares up to num characters of the C string str1 to those of the C string str2.
672
            // This function starts comparing the first character of each string. If they are
673
            // equal to each other, it continues with the following pairs until the characters
674
            // differ, until a terminating null-character is reached, or until num characters
675
            // match in both strings, whichever happens first.
676
            if (!strncmp(&row -> render[i], scs, scs_len)) {
677
                memset(&row -> highlight[i], HL_SL_COMMENT, row -> render_size - i);
678
                break;
679
            }
680
        }
681
 
682
        if (mcs_len && mce_len && !in_string) {
683
            if (in_comment) {
684
                row -> highlight[i] = HL_ML_COMMENT;
685
                if (!strncmp(&row -> render[i], mce, mce_len)) {
686
                    memset(&row -> highlight[i], HL_ML_COMMENT, mce_len);
687
                    i += mce_len;
688
                    in_comment = 0;
689
                    prev_sep = 1;
690
                    continue;
691
                } else {
692
                    i++;
693
                    continue;
694
                }
695
            } else if (!strncmp(&row -> render[i], mcs, mcs_len)) {
696
                memset(&row -> highlight[i], HL_ML_COMMENT, mcs_len);
697
                i += mcs_len;
698
                in_comment = 1;
699
                continue;
700
            }
701
 
702
        }
703
 
704
        if (ec.syntax -> flags & HL_HIGHLIGHT_STRINGS) {
705
            if (in_string) {
706
                row -> highlight[i] = HL_STRING;
707
                // If we’re in a string and the current character is a backslash (\),
708
                // and there’s at least one more character in that line that comes
709
                // after the backslash, then we highlight the character that comes
710
                // after the backslash with HL_STRING and consume it. We increment
711
                // i by 2 to consume both characters at once.
712
                if (c == '\\' && i + 1 < row -> render_size) {
713
                    row -> highlight[i + 1] = HL_STRING;
714
                    i += 2;
715
                    continue;
716
                }
717
 
718
                if (c == in_string)
719
                    in_string = 0;
720
                i++;
721
                prev_sep = 1;
722
                continue;
723
            } else {
724
                if (c == '"' || c == '\'') {
725
                    in_string = c;
726
                    row -> highlight[i] = HL_STRING;
727
                    i++;
728
                    continue;
729
                }
730
            }
731
        }
732
 
733
        if (ec.syntax -> flags & HL_HIGHLIGHT_NUMBERS) {
734
            if ((isdigit(c) && (prev_sep || prev_highlight == HL_NUMBER)) ||
735
                (isAlsoNumber(c) && prev_highlight == HL_NUMBER)) {
736
                row -> highlight[i] = HL_NUMBER;
737
                i++;
738
                prev_sep = 0;
739
                continue;
740
            }
741
        }
742
 
743
        if (prev_sep) {
744
            int j;
745
            for (j = 0; keywords[j]; j++) {
746
                int kw_len = strlen(keywords[j]);
747
                int kw_2 = keywords[j][kw_len - 1] == '|';
748
                if (kw_2)
749
                    kw_len--;
750
 
751
                // Keywords require a separator both before and after the keyword.
752
                if (!strncmp(&row -> render[i], keywords[j], kw_len) &&
753
                    isSeparator(row -> render[i + kw_len])) {
754
                    memset(&row -> highlight[i], kw_2 ? HL_KEYWORD_2 : HL_KEYWORD_1, kw_len);
755
                    i += kw_len;
756
                    break;
757
                }
758
            }
759
            if (keywords[j] != NULL) {
760
                prev_sep = 0;
761
                continue;
762
            }
763
        }
764
 
765
        prev_sep = isSeparator(c);
766
        i++;
767
    }
768
 
769
    int changed = (row -> hl_open_comment != in_comment);
770
    // This tells us whether the row ended as an unclosed multi-line
771
    // comment or not.
772
    row -> hl_open_comment = in_comment;
773
    // A user could comment out an entire file just by changing one line.
774
    // So it seems like we need to update the syntax of all the lines
775
    // following the current line. However, we know the highlighting
776
    // of the next line will not change if the value of this line’s
777
    // // // hl_open_comment did not change. So we check if it changed, and
778
    // // only call editorUpdateSyntax() on the next line if
779
    // hl_open_comment changed (and if there is a next line in the file).
780
    // Because editorUpdateSyntax() keeps calling itself with the next
781
    // line, the change will continue to propagate to more and more lines
782
    // until one of them is unchanged, at which point we know that all
783
    // the lines after that one must be unchanged as well.
784
    if (changed && row -> idx + 1 < ec.num_rows)
785
        editorUpdateSyntax(&ec.row[row -> idx + 1]);
786
}
787
 
788
int editorSyntaxToColor(int highlight) {
789
    // We return ANSI codes for colors.
790
    // See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
791
    // for a list of them.
792
    switch (highlight) {
793
        case HL_SL_COMMENT:
794
        case HL_ML_COMMENT: return 36;
795
        case HL_KEYWORD_1: return 31;
796
        case HL_KEYWORD_2: return 32;
797
        case HL_STRING: return 33;
798
        case HL_NUMBER: return 35;
799
        case HL_MATCH: return 34;
800
        default: return 37;
801
    }
802
}
803
 
804
void editorSelectSyntaxHighlight() {
805
    ec.syntax = NULL;
806
    if (ec.file_name == NULL)
807
        return;
808
 
809
    for (unsigned int j = 0; j < HL_DB_ENTRIES; j++) {
810
        struct editor_syntax* es = &HL_DB[j];
811
        unsigned int i = 0;
812
 
813
        while (es -> file_match[i]) {
814
            char* p = strstr(ec.file_name, es -> file_match[i]);
815
            if (p != NULL) {
816
                // Returns a pointer to the first occurrence of str2 in str1,
817
                // or a null pointer if str2 is not part of str1.
818
                int pat_len = strlen(es -> file_match[i]);
819
                if (es -> file_match[i][0] != '.' || p[pat_len] == '\0') {
820
                    ec.syntax = es;
821
 
822
                    int file_row;
823
                    for (file_row = 0; file_row < ec.num_rows; file_row++) {
824
                        editorUpdateSyntax(&ec.row[file_row]);
825
                    }
826
 
827
                    return;
828
                }
829
            }
830
            i++;
831
        }
832
    }
833
}
834
 
835
/*** Row operations ***/
836
 
837
int editorRowCursorXToRenderX(editor_row* row, int cursor_x) {
838
    int render_x = 0;
839
    int j;
840
    // For each character, if its a tab we use rx % TTE_TAB_STOP
841
    // to find out how many columns we are to the right of the last
842
    // tab stop, and then subtract that from TTE_TAB_STOP - 1 to
843
    // find out how many columns we are to the left of the next tab
844
    // stop. We add that amount to rx to get just to the left of the
845
    // next tab stop, and then the unconditional rx++ statement gets
846
    // us right on the next tab stop. Notice how this works even if
847
    // we are currently on a tab stop.
848
    for (j = 0; j < cursor_x; j++) {
849
        if (row -> chars[j] == '\t')
850
            render_x += (TTE_TAB_STOP - 1) - (render_x % TTE_TAB_STOP);
851
        render_x++;
852
    }
853
    return render_x;
854
}
855
 
856
int editorRowRenderXToCursorX(editor_row* row, int render_x) {
857
    int cur_render_x = 0;
858
    int cursor_x;
859
    for (cursor_x = 0; cursor_x < row -> size; cursor_x++) {
860
        if (row -> chars[cursor_x] == '\t')
861
            cur_render_x += (TTE_TAB_STOP - 1) - (cur_render_x % TTE_TAB_STOP);
862
        cur_render_x++;
863
 
864
        if (cur_render_x > render_x)
865
            return cursor_x;
866
    }
867
    return cursor_x;
868
}
869
 
870
void editorUpdateRow(editor_row* row) {
871
    // First, we have to loop through the chars of the row
872
    // and count the tabs in order to know how much memory
873
    // to allocate for render. The maximum number of characters
874
    // needed for each tab is 8. row->size already counts 1 for
875
    // each tab, so we multiply the number of tabs by 7 and add
876
    // that to row->size to get the maximum amount of memory we'll
877
    // need for the rendered row.
878
    int tabs = 0;
879
    int j;
880
    for (j = 0; j < row -> size; j++) {
881
        if (row -> chars[j] == '\t')
882
            tabs++;
883
    }
884
    free(row -> render);
885
    row -> render = malloc(row -> size + tabs * (TTE_TAB_STOP - 1) + 1);
886
 
887
    // After allocating the memory, we check whether the current character
888
    // is a tab. If it is, we append one space (because each tab must
889
    // advance the cursor forward at least one column), and then append
890
    // spaces until we get to a tab stop, which is a column that is
891
    // divisible by 8
892
    int idx = 0;
893
    for (j = 0; j < row -> size; j++) {
894
        if (row -> chars[j] == '\t') {
895
            row -> render[idx++] = ' ';
896
            while (idx % TTE_TAB_STOP != 0)
897
                row -> render[idx++] = ' ';
898
        } else
899
            row -> render[idx++] = row -> chars[j];
900
    }
901
    row -> render[idx] = '\0';
902
    row -> render_size = idx;
903
 
904
    editorUpdateSyntax(row);
905
}
906
 
907
void editorInsertRow(int at, char* s, size_t line_len) {
908
    if (at < 0 || at > ec.num_rows)
909
        return;
910
 
911
    ec.row = realloc(ec.row, sizeof(editor_row) * (ec.num_rows + 1));
912
    memmove(&ec.row[at + 1], &ec.row[at], sizeof(editor_row) * (ec.num_rows - at));
913
 
914
    for (int j = at + 1; j <= ec.num_rows; j++) {
915
        ec.row[j].idx++;
916
    }
917
 
918
    ec.row[at].idx = at;
919
 
920
    ec.row[at].size = line_len;
921
    ec.row[at].chars = malloc(line_len + 1); // We want to add terminator char '\0' at the end
922
    memcpy(ec.row[at].chars, s, line_len);
923
    ec.row[at].chars[line_len] = '\0';
924
 
925
    ec.row[at].render_size = 0;
926
    ec.row[at].render = NULL;
927
    ec.row[at].highlight = NULL;
928
    ec.row[at].hl_open_comment = 0;
929
    editorUpdateRow(&ec.row[at]);
930
 
931
    ec.num_rows++;
932
    ec.dirty++;
933
}
934
 
935
void editorFreeRow(editor_row* row) {
936
    free(row -> render);
937
    free(row -> chars);
938
    free(row -> highlight);
939
}
940
 
941
void editorDelRow(int at) {
942
    if (at < 0 || at >= ec.num_rows)
943
        return;
944
    editorFreeRow(&ec.row[at]);
945
    memmove(&ec.row[at], &ec.row[at + 1], sizeof(editor_row) * (ec.num_rows - at - 1));
946
 
947
    for (int j = at; j < ec.num_rows - 1; j++) {
948
        ec.row[j].idx--;
949
    }
950
 
951
    ec.num_rows--;
952
    ec.dirty++;
953
}
954
 
955
// -1 down, 1 up
956
void editorFlipRow(int dir) {
957
    editor_row c_row = ec.row[ec.cursor_y];
958
    ec.row[ec.cursor_y] = ec.row[ec.cursor_y - dir];
959
    ec.row[ec.cursor_y - dir] = c_row;
960
 
961
    ec.row[ec.cursor_y].idx += dir;
962
    ec.row[ec.cursor_y - dir].idx -= dir;
963
 
964
    int first = (dir == 1) ? ec.cursor_y - 1 : ec.cursor_y;
965
    editorUpdateSyntax(&ec.row[first]);
966
    editorUpdateSyntax(&ec.row[first] + 1);
967
    if (ec.num_rows - ec.cursor_y > 2)
968
      editorUpdateSyntax(&ec.row[first] + 2);
969
 
970
    ec.cursor_y -= dir;
971
    ec.dirty++;
972
}
973
 
974
void editorCopy(int cut) {
975
    ec.copied_char_buffer = realloc(ec.copied_char_buffer, strlen(ec.row[ec.cursor_y].chars) + 1);
976
    strcpy(ec.copied_char_buffer, ec.row[ec.cursor_y].chars);
977
    editorSetStatusMessage(cut ? "Content cut" : "Content copied");
978
}
979
 
980
void editorCut() {
981
    editorCopy(-1);
982
    editorDelRow(ec.cursor_y);
983
    if (ec.num_rows - ec.cursor_y > 0)
984
      editorUpdateSyntax(&ec.row[ec.cursor_y]);
985
    if (ec.num_rows - ec.cursor_y > 1)
986
      editorUpdateSyntax(&ec.row[ec.cursor_y + 1]);
987
    ec.cursor_x = ec.cursor_y == ec.num_rows ? 0 : ec.row[ec.cursor_y].size;
988
}
989
 
990
void editorPaste() {
991
    if (ec.copied_char_buffer == NULL)
992
      return;
993
 
994
    if (ec.cursor_y == ec.num_rows)
995
      editorInsertRow(ec.cursor_y, ec.copied_char_buffer, strlen(ec.copied_char_buffer));
996
    else
997
      editorRowAppendString(&ec.row[ec.cursor_y], ec.copied_char_buffer, strlen(ec.copied_char_buffer));
998
    ec.cursor_x += strlen(ec.copied_char_buffer);
999
}
1000
 
1001
void editorRowInsertChar(editor_row* row, int at, int c) {
1002
    if (at < 0 || at > row -> size)
1003
        at = row -> size;
1004
    // We need to allocate 2 bytes because we also have to make room for
1005
    // the null byte.
1006
    row -> chars = realloc(row -> chars, row -> size + 2);
1007
    // memmove it's like memcpy(), but is safe to use when the source and
1008
    // destination arrays overlap
1009
    memmove(&row -> chars[at + 1], &row -> chars[at], row -> size - at + 1);
1010
    row -> size++;
1011
    row -> chars[at] = c;
1012
    editorUpdateRow(row);
1013
    ec.dirty++; // This way we can see "how dirty" a file is.
1014
}
1015
 
1016
void editorInsertNewline() {
1017
    // If we're at the beginning of a line, all we have to do is insert
1018
    // a new blank row before the line we're on.
1019
    if (ec.cursor_x == 0) {
1020
        editorInsertRow(ec.cursor_y, "", 0);
1021
    // Otherwise, we have to split the line we're on into two rows.
1022
    } else {
1023
        editor_row* row = &ec.row[ec.cursor_y];
1024
        editorInsertRow(ec.cursor_y + 1, &row -> chars[ec.cursor_x], row -> size - ec.cursor_x);
1025
        row = &ec.row[ec.cursor_y];
1026
        row -> size = ec.cursor_x;
1027
        row -> chars[row -> size] = '\0';
1028
        editorUpdateRow(row);
1029
    }
1030
    ec.cursor_y++;
1031
    ec.cursor_x = 0;
1032
}
1033
 
1034
void editorRowAppendString(editor_row* row, char* s, size_t len) {
1035
    row -> chars = realloc(row -> chars, row -> size + len + 1);
1036
    memcpy(&row -> chars[row -> size], s, len);
1037
    row -> size += len;
1038
    row -> chars[row -> size] = '\0';
1039
    editorUpdateRow(row);
1040
    ec.dirty++;
1041
}
1042
 
1043
void editorRowDelChar(editor_row* row, int at) {
1044
    if (at < 0 || at >= row -> size)
1045
        return;
1046
    // Overwriting the deleted character with the characters that come
1047
    // after it.
1048
    memmove(&row -> chars[at], &row -> chars[at + 1], row -> size - at);
1049
    row -> size--;
1050
    editorUpdateRow(row);
1051
    ec.dirty++;
1052
}
1053
 
1054
/*** Editor operations ***/
1055
 
1056
void editorInsertChar(int c) {
1057
    // If this is true, the cursor is on the tilde line after the end of
1058
    // the file, so we need to append a new row to the file before inserting
1059
    // a character there.
1060
    if (ec.cursor_y == ec.num_rows)
1061
        editorInsertRow(ec.num_rows, "", 0);
1062
    editorRowInsertChar(&ec.row[ec.cursor_y], ec.cursor_x, c);
1063
    ec.cursor_x++; // This way we can see "how dirty" a file is.
1064
}
1065
 
1066
void editorDelChar() {
1067
    // If the cursor is past the end of the file, there's nothing to delete.
1068
    if (ec.cursor_y == ec.num_rows)
1069
        return;
1070
    // Cursor is at the beginning of a file, there's nothing to delete.
1071
    if (ec.cursor_x == 0 && ec.cursor_y == 0)
1072
        return;
1073
 
1074
    editor_row* row = &ec.row[ec.cursor_y];
1075
    if (ec.cursor_x > 0) {
1076
        editorRowDelChar(row, ec.cursor_x - 1);
1077
        ec.cursor_x--;
1078
    // Deleting a line and moving up all the content.
1079
    } else {
1080
        ec.cursor_x = ec.row[ec.cursor_y - 1].size;
1081
        editorRowAppendString(&ec.row[ec.cursor_y -1], row -> chars, row -> size);
1082
        editorDelRow(ec.cursor_y);
1083
        ec.cursor_y--;
1084
    }
1085
}
1086
 
1087
/*** File I/O ***/
1088
 
1089
char* editorRowsToString(int* buf_len) {
1090
    int total_len = 0;
1091
    int j;
1092
    // Adding up the lengths of each row of text, adding 1
1093
    // to each one for the newline character we'll add to
1094
    // the end of each line.
1095
    for (j = 0; j < ec.num_rows; j++) {
7419 siemargl 1096
        total_len += ec.row[j].size + 1
1097
							+ (fileIsOd0a ? 1:0); /// winFile suppor
7413 siemargl 1098
    }
1099
    *buf_len = total_len;
1100
 
1101
    char* buf = malloc(total_len);
1102
    char* p = buf;
1103
    // Copying the contents of each row to the end of the
1104
    // buffer, appending a newline character after each
1105
    // row.
1106
    for (j = 0; j < ec.num_rows; j++) {
1107
        memcpy(p, ec.row[j].chars, ec.row[j].size);
1108
        p += ec.row[j].size;
7419 siemargl 1109
        /// winFile support
1110
        if (fileIsOd0a) *p++ = '\r';
7413 siemargl 1111
        *p = '\n';
1112
        p++;
1113
    }
1114
 
1115
    return buf;
1116
}
1117
 
7414 siemargl 1118
extern int getline(char **buf, size_t *bufsiz, FILE *fp);
1119
 
7413 siemargl 1120
void editorOpen(char* file_name) {
1121
    free(ec.file_name);
1122
    ec.file_name = strdup(file_name);
1123
 
1124
    editorSelectSyntaxHighlight();
1125
 
1126
    FILE* file = fopen(file_name, "r+");
1127
    if (!file)
1128
        die("Failed to open the file");
1129
 
1130
    char* line = NULL;
1131
    // Unsigned int of at least 16 bit.
1132
    size_t line_cap = 0;
1133
    // Bigger than int
7414 siemargl 1134
    int line_len;  ///was ssize_t
7419 siemargl 1135
    fileIsOd0a = 0; /// winFile support
1136
 
7413 siemargl 1137
    while ((line_len = getline(&line, &line_cap, file)) != -1) {
1138
        // We already know each row represents one line of text, there's no need
1139
        // to keep carriage return and newline characters.
1140
        if (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
1141
            line_len--;
7419 siemargl 1142
/// Siemargl fix 0d0a windows file, save format flag
1143
         if (line_len > 0 && line[line_len - 1] == '\r')
1144
         {
1145
            line_len--;
1146
            fileIsOd0a = 1;
1147
		 }
1148
       editorInsertRow(ec.num_rows, line, line_len);
7413 siemargl 1149
    }
1150
    free(line);
1151
    fclose(file);
1152
    ec.dirty = 0;
1153
}
1154
 
1155
void editorSave() {
1156
    if (ec.file_name == NULL) {
1157
        ec.file_name = editorPrompt("Save as: %s (ESC to cancel)", NULL);
1158
        if (ec.file_name == NULL) {
1159
            editorSetStatusMessage("Save aborted");
1160
            return;
1161
        }
1162
        editorSelectSyntaxHighlight();
1163
    }
1164
 
1165
    int len;
1166
    char* buf = editorRowsToString(&len);
7419 siemargl 1167
 
1168
/// siemargl rewrite using standard FILE stream
7414 siemargl 1169
	FILE *fd = fopen(ec.file_name,"w+b");
7419 siemargl 1170
	int rc = -1;
7414 siemargl 1171
	if (fd) {
7419 siemargl 1172
		if ((rc = fwrite(buf, 1, len, fd)) == len) {
7414 siemargl 1173
			fclose(fd);
1174
			free(buf);
1175
			ec.dirty = 0;
1176
			editorSetStatusMessage("%d bytes written to disk", len);
1177
			return;
1178
		}
1179
        fclose(fd);
1180
	}
7413 siemargl 1181
 
1182
    free(buf);
1183
    editorSetStatusMessage("Cant's save file. Error occurred: %s", strerror(errno));
1184
}
1185
 
1186
/*** Search section ***/
1187
 
1188
void editorSearchCallback(char* query, int key) {
1189
    // Index of the row that the last match was on, -1 if there was
1190
    // no last match.
1191
    static int last_match = -1;
1192
    // 1 for searching forward and -1 for searching backwards.
1193
    static int direction = 1;
1194
 
1195
    static int saved_highlight_line;
1196
    static char* saved_hightlight = NULL;
1197
 
1198
    if (saved_hightlight) {
1199
        memcpy(ec.row[saved_highlight_line].highlight, saved_hightlight, ec.row[saved_highlight_line].render_size);
1200
        free(saved_hightlight);
1201
        saved_hightlight = NULL;
1202
    }
1203
 
1204
    // Checking if the user pressed Enter or Escape, in which case
1205
    // they are leaving search mode so we return immediately.
1206
    if (key == '\r' || key == '\x1b') {
1207
        last_match = -1;
1208
        direction = 1;
1209
        return;
1210
    } else if (key == ARROW_RIGHT || key == ARROW_DOWN) {
1211
        direction = 1;
1212
    } else if (key == ARROW_LEFT || key == ARROW_UP) {
1213
        if (last_match == -1) {
1214
            // If nothing matched and the left or up arrow key was pressed
1215
            return;
1216
        }
1217
        direction = -1;
1218
    } else {
1219
        last_match = -1;
1220
        direction = 1;
1221
    }
1222
 
1223
    int current = last_match;
1224
    int i;
1225
    for (i = 0; i < ec.num_rows; i++) {
1226
        current += direction;
1227
        if (current == -1)
1228
            current = ec.num_rows - 1;
1229
        else if (current == ec.num_rows)
1230
            current = 0;
1231
 
1232
        editor_row* row = &ec.row[current];
1233
        // We use strstr to check if query is a substring of the
1234
        // current row. It returns NULL if there is no match,
1235
        // oterwhise it returns a pointer to the matching substring.
1236
        char* match = strstr(row -> render, query);
1237
        if (match) {
1238
            last_match = current;
1239
            ec.cursor_y = current;
1240
            ec.cursor_x = editorRowRenderXToCursorX(row, match - row -> render);
1241
            // We set this like so to scroll to the bottom of the file so
1242
            // that the next screen refresh will cause the matching line to
1243
            // be at the very top of the screen.
1244
            ec.row_offset = ec.num_rows;
1245
 
1246
            saved_highlight_line = current;
1247
            saved_hightlight = malloc(row -> render_size);
1248
            memcpy(saved_hightlight, row -> highlight, row -> render_size);
1249
            memset(&row -> highlight[match - row -> render], HL_MATCH, strlen(query));
1250
            break;
1251
        }
1252
    }
1253
}
1254
 
1255
void editorSearch() {
1256
    int saved_cursor_x = ec.cursor_x;
1257
    int saved_cursor_y = ec.cursor_y;
1258
    int saved_col_offset = ec.col_offset;
1259
    int saved_row_offset = ec.row_offset;
1260
 
1261
    char* query = editorPrompt("Search: %s (Use ESC / Enter / Arrows)", editorSearchCallback);
1262
 
1263
    if (query) {
1264
        free(query);
1265
    // If query is NULL, that means they pressed Escape, so in that case we
1266
    // restore the cursor previous position.
1267
    } else {
1268
        ec.cursor_x = saved_cursor_x;
1269
        ec.cursor_y = saved_cursor_y;
1270
        ec.col_offset = saved_col_offset;
1271
        ec.row_offset = saved_row_offset;
1272
    }
1273
}
1274
 
1275
/*** Append buffer section **/
1276
 
1277
void abufAppend(struct a_buf* ab, const char* s, int len) {
1278
    // Using realloc to get a block of free memory that is
1279
    // the size of the current string + the size of the string
1280
    // to be appended.
1281
    char* new = realloc(ab -> buf, ab -> len + len);
1282
 
1283
    if (new == NULL)
1284
        return;
1285
 
1286
    // Copying the string s at the end of the current data in
1287
    // the buffer.
1288
    memcpy(&new[ab -> len], s, len);
1289
    ab -> buf = new;
1290
    ab -> len += len;
1291
}
1292
 
1293
void abufFree(struct a_buf* ab) {
1294
    // Deallocating buffer.
1295
    free(ab -> buf);
1296
}
1297
 
1298
/*** Output section ***/
1299
 
1300
void editorScroll() {
1301
    ec.render_x = 0;
1302
    if (ec.cursor_y < ec.num_rows)
1303
        ec.render_x = editorRowCursorXToRenderX(&ec.row[ec.cursor_y], ec.cursor_x);
1304
    // The first if statement checks if the cursor is above the visible window,
1305
    // and if so, scrolls up to where the cursor is. The second if statement checks
1306
    // if the cursor is past the bottom of the visible window, and contains slightly
1307
    // more complicated arithmetic because ec.row_offset refers to what's at the top
1308
    // of the screen, and we have to get ec.screen_rows involved to talk about what's
1309
    // at the bottom of the screen.
1310
    if (ec.cursor_y < ec.row_offset)
1311
        ec.row_offset = ec.cursor_y;
1312
    if (ec.cursor_y >= ec.row_offset + ec.screen_rows)
1313
        ec.row_offset = ec.cursor_y - ec.screen_rows + 1;
1314
 
1315
    if (ec.render_x < ec.col_offset)
1316
        ec.col_offset = ec.render_x;
1317
    if (ec.render_x >= ec.col_offset + ec.screen_cols)
1318
        ec.col_offset = ec.render_x - ec.screen_cols + 1;
1319
}
1320
 
1321
void editorDrawStatusBar(struct a_buf* ab) {
1322
    // This switches to inverted colors.
1323
    // NOTE:
1324
    // The m command (Select Graphic Rendition) causes the text printed
1325
    // after it to be printed with various possible attributes including
1326
    // bold (1), underscore (4), blink (5), and inverted colors (7). An
1327
    // argument of 0 clears all attributes (the default one). See
1328
    // http://vt100.net/docs/vt100-ug/chapter3.html#SGR for more info.
1329
    abufAppend(ab, "\x1b[7m", 4);
1330
 
1331
    char status[80], r_status[80];
1332
    // Showing up to 20 characters of the filename, followed by the number of lines.
1333
    int len = snprintf(status, sizeof(status), " Editing: %.20s %s", ec.file_name ? ec.file_name : "New file", ec.dirty ? "(modified)" : "");
1334
    int col_size = ec.row && ec.cursor_y <= ec.num_rows - 1 ? col_size = ec.row[ec.cursor_y].size : 0;
1335
    int r_len = snprintf(r_status, sizeof(r_status), "%d/%d lines  %d/%d cols ", ec.cursor_y + 1 > ec.num_rows ? ec.num_rows : ec.cursor_y + 1, ec.num_rows,
1336
        ec.cursor_x + 1 > col_size ? col_size : ec.cursor_x + 1, col_size);
1337
    if (len > ec.screen_cols)
1338
        len = ec.screen_cols;
1339
    abufAppend(ab, status, len);
1340
    while (len < ec.screen_cols) {
1341
        if (ec.screen_cols - len == r_len) {
1342
            abufAppend(ab, r_status, r_len);
1343
            break;
1344
        } else {
1345
            abufAppend(ab, " ", 1);
1346
            len++;
1347
        }
1348
    }
1349
    // This switches back to normal colors.
1350
    abufAppend(ab, "\x1b[m", 3);
1351
 
1352
    abufAppend(ab, "\r\n", 2);
1353
}
1354
 
1355
void editorDrawMessageBar(struct a_buf *ab) {
1356
    // Clearing the message bar.
7419 siemargl 1357
///    abufAppend(ab, "\x1b[K", 3);	/// not work in Kolibri
7413 siemargl 1358
    int msg_len = strlen(ec.status_msg);
1359
    if (msg_len > ec.screen_cols)
1360
        msg_len = ec.screen_cols;
1361
    // We only show the message if its less than 5 secons old, but
1362
    // remember the screen is only being refreshed after each keypress.
1363
    if (msg_len && time(NULL) - ec.status_msg_time < 5)
1364
        abufAppend(ab, ec.status_msg, msg_len);
1365
}
1366
 
1367
void editorDrawWelcomeMessage(struct a_buf* ab) {
1368
    char welcome[80];
1369
    // Using snprintf to truncate message in case the terminal
1370
    // is too tiny to handle the entire string.
1371
    int welcome_len = snprintf(welcome, sizeof(welcome),
8116 maxcodehac 1372
        "TinyTextEditor %s", TTE_VERSION);
7413 siemargl 1373
    if (welcome_len > ec.screen_cols)
1374
        welcome_len = ec.screen_cols;
1375
    // Centering the message.
1376
    int padding = (ec.screen_cols - welcome_len) / 2;
1377
    // Remember that everything != 0 is true.
1378
    if (padding) {
1379
        abufAppend(ab, "~", 1);
1380
        padding--;
1381
    }
1382
    while (padding--)
1383
        abufAppend(ab, " ", 1);
1384
    abufAppend(ab, welcome, welcome_len);
1385
}
1386
 
1387
// The ... argument makes editorSetStatusMessage() a variadic function,
1388
// meaning it can take any number of arguments. C's way of dealing with
1389
// these arguments is by having you call va_start() and va_end() on a
1390
// // value of type va_list. The last argument before the ... (in this
1391
// case, msg) must be passed to va_start(), so that the address of
1392
// the next arguments is known. Then, between the va_start() and
1393
// va_end() calls, you would call va_arg() and pass it the type of
1394
// the next argument (which you usually get from the given format
1395
// string) and it would return the value of that argument. In
1396
// this case, we pass msg and args to vsnprintf() and it takes care
1397
// of reading the format string and calling va_arg() to get each
1398
// argument.
1399
void editorSetStatusMessage(const char* msg, ...) {
1400
    va_list args;
1401
    va_start(args, msg);
1402
    vsnprintf(ec.status_msg, sizeof(ec.status_msg), msg, args);
1403
    va_end(args);
1404
    ec.status_msg_time = time(NULL);
1405
}
1406
 
1407
void editorDrawRows(struct a_buf* ab) {
1408
    int y;
1409
    for (y = 0; y < ec.screen_rows; y++) {
1410
        int file_row = y + ec.row_offset;
1411
        if(file_row >= ec.num_rows) {
1412
            if (ec.num_rows == 0 && y == ec.screen_rows / 3)
1413
                editorDrawWelcomeMessage(ab);
1414
            else
1415
                abufAppend(ab, "~", 1);
1416
        } else {
1417
            int len = ec.row[file_row].render_size - ec.col_offset;
1418
            // len can be a negative number, meaning the user scrolled
1419
            // horizontally past the end of the line. In that case, we set
1420
            // len to 0 so that nothing is displayed on that line.
1421
            if (len < 0)
1422
                len = 0;
1423
            if (len > ec.screen_cols)
1424
                len = ec.screen_cols;
1425
 
1426
            char* c = &ec.row[file_row].render[ec.col_offset];
1427
            unsigned char* highlight = &ec.row[file_row].highlight[ec.col_offset];
1428
            int current_color = -1;
1429
            int j;
1430
            for (j = 0; j < len; j++) {
1431
                // Displaying nonprintable characters as (A-Z, @, and ?).
1432
                if (iscntrl(c[j])) {
1433
                    char sym = (c[j] <= 26) ? '@' + c[j] : '?';
1434
                    abufAppend(ab, "\x1b[7m", 4);
1435
                    abufAppend(ab, &sym, 1);
1436
                    abufAppend(ab, "\x1b[m", 3);
1437
                    if (current_color != -1) {
1438
                        char buf[16];
1439
                        int c_len = snprintf(buf, sizeof(buf), "\x1b[%dm", current_color);
1440
                        abufAppend(ab, buf, c_len);
1441
                    }
1442
                } else if (highlight[j] == HL_NORMAL) {
1443
                    if (current_color != -1) {
7419 siemargl 1444
                        abufAppend(ab, "\x1b[m", 3);  /// was [39, 5
7413 siemargl 1445
                        current_color = -1;
1446
                    }
1447
                    abufAppend(ab, &c[j], 1);
1448
                } else {
1449
                    int color = editorSyntaxToColor(highlight[j]);
1450
                    // We only use escape sequence if the new color is different
1451
                    // from the last character's color.
1452
                    if (color != current_color) {
1453
                        current_color = color;
1454
                        char buf[16];
1455
                        int c_len = snprintf(buf, sizeof(buf), "\x1b[%dm", color);
1456
                        abufAppend(ab, buf, c_len);
1457
                    }
1458
 
1459
                    abufAppend(ab, &c[j], 1);
1460
                }
1461
            }
7419 siemargl 1462
            abufAppend(ab, "\x1b[m", 3);  /// was [39, 5
7413 siemargl 1463
        }
1464
 
1465
        // Redrawing each line instead of the whole screen.
7419 siemargl 1466
///        abufAppend(ab, "\x1b[K", 3);  /// not work in Kolibri
7413 siemargl 1467
        // Addind a new line
1468
        abufAppend(ab, "\r\n", 2);
1469
    }
1470
}
1471
 
1472
void editorRefreshScreen() {
1473
    editorScroll();
1474
 
1475
    struct a_buf ab = ABUF_INIT;
1476
 
1477
    // Hiding the cursor while the screen is refreshing.
1478
    // See http://vt100.net/docs/vt100-ug/chapter3.html#S3.3.4
1479
    // for more info.
7419 siemargl 1480
///    abufAppend(&ab, "\x1b[?25l", 6);
7413 siemargl 1481
    abufAppend(&ab, "\x1b[H", 3);
1482
 
7419 siemargl 1483
/// full clear because "\x1b[K" not work in Kolibri
1484
    abufAppend(&ab, "\x1b[2J", 4);
1485
 
7413 siemargl 1486
    editorDrawRows(&ab);
1487
    editorDrawStatusBar(&ab);
1488
    editorDrawMessageBar(&ab);
1489
 
1490
    // Moving the cursor where it should be.
1491
    char buf[32];
7419 siemargl 1492
///    snprintf(buf, sizeof(buf), "\x1b[%d;%dH", (ec.cursor_y - ec.row_offset) + 1, (ec.render_x - ec.col_offset) + 1);
1493
/// a bit different in Kolibri
1494
    snprintf(buf, sizeof(buf), "\x1b[%d;%dH", (ec.render_x - ec.col_offset), (ec.cursor_y - ec.row_offset));
1495
       abufAppend(&ab, buf, strlen(buf));
7413 siemargl 1496
 
1497
    // Showing again the cursor.
7419 siemargl 1498
///    abufAppend(&ab, "\x1b[?25h", 6);
7413 siemargl 1499
 
1500
    // Writing all content at once
7414 siemargl 1501
///    write(STDOUT_FILENO, ab.buf, ab.len);
1502
	con_write_string(ab.buf, ab.len);
7413 siemargl 1503
    abufFree(&ab);
1504
}
1505
 
1506
void editorClearScreen() {
1507
    // Writing 4 bytes out to the terminal:
1508
    // - (1 byte) \x1b : escape character
1509
    // - (3 bytes) [2J : Clears the entire screen, see
1510
    // http://vt100.net/docs/vt100-ug/chapter3.html#ED
1511
    // for more info.
7414 siemargl 1512
///    write(STDOUT_FILENO, "\x1b[2J", 4);
1513
	con_write_string("\x1b[2J", 4);
1514
 
7413 siemargl 1515
    // Writing 3 bytes to reposition the cursor back at
1516
    // the top-left corner, see
1517
    // http://vt100.net/docs/vt100-ug/chapter3.html#CUP
1518
    // for more info.
7414 siemargl 1519
///    write(STDOUT_FILENO, "\x1b[H", 3);
1520
	con_write_string("\x1b[H", 3);
7413 siemargl 1521
}
1522
 
1523
/*** Input section ***/
1524
 
1525
char* editorPrompt(char* prompt, void (*callback)(char*, int)) {
1526
    size_t buf_size = 128;
1527
    char* buf = malloc(buf_size);
1528
 
1529
    size_t buf_len = 0;
1530
    buf[0] = '\0';
1531
 
1532
    while (1) {
1533
        editorSetStatusMessage(prompt, buf);
1534
        editorRefreshScreen();
1535
 
1536
        int c = editorReadKey();
1537
        if (c == DEL_KEY || c == CTRL_KEY('h') || c == BACKSPACE) {
1538
            if (buf_len != 0)
1539
                buf[--buf_len] = '\0';
1540
        } else if (c == '\x1b') {
1541
            editorSetStatusMessage("");
1542
            if (callback)
1543
                callback(buf, c);
1544
            free(buf);
1545
            return NULL;
1546
        } else if (c == '\r') {
1547
            if (buf_len != 0) {
1548
                editorSetStatusMessage("");
1549
                if (callback)
1550
                    callback(buf, c);
1551
                return buf;
1552
            }
1553
        } else if (!iscntrl(c) && isprint(c)) {
1554
            if (buf_len == buf_size - 1) {
1555
                buf_size *= 2;
1556
                buf = realloc(buf, buf_size);
1557
            }
1558
            buf[buf_len++] = c;
1559
            buf[buf_len] = '\0';
1560
        }
1561
 
1562
        if (callback)
1563
            callback(buf, c);
1564
    }
1565
}
1566
 
1567
void editorMoveCursor(int key) {
1568
    editor_row* row = (ec.cursor_y >= ec.num_rows) ? NULL : &ec.row[ec.cursor_y];
1569
 
1570
    switch (key) {
1571
        case ARROW_LEFT:
1572
            if (ec.cursor_x != 0)
1573
                ec.cursor_x--;
1574
            // If <- is pressed, move to the end of the previous line
1575
            else if (ec.cursor_y > 0) {
1576
                ec.cursor_y--;
1577
                ec.cursor_x = ec.row[ec.cursor_y].size;
1578
            }
1579
            break;
1580
        case ARROW_RIGHT:
1581
            if (row && ec.cursor_x < row -> size)
1582
                ec.cursor_x++;
1583
            // If -> is pressed, move to the start of the next line
1584
            else if (row && ec.cursor_x == row -> size) {
1585
                ec.cursor_y++;
1586
                ec.cursor_x = 0;
1587
            }
1588
            break;
1589
        case ARROW_UP:
1590
            if (ec.cursor_y != 0)
1591
                ec.cursor_y--;
1592
            break;
1593
        case ARROW_DOWN:
1594
            if (ec.cursor_y < ec.num_rows)
1595
                ec.cursor_y++;
1596
            break;
1597
    }
1598
 
1599
    // Move cursor_x if it ends up past the end of the line it's on
1600
    row = (ec.cursor_y >= ec.num_rows) ? NULL : &ec.row[ec.cursor_y];
1601
    int row_len = row ? row -> size : 0;
1602
    if (ec.cursor_x > row_len)
1603
        ec.cursor_x = row_len;
1604
}
1605
 
1606
void editorProcessKeypress() {
1607
    static int quit_times = TTE_QUIT_TIMES;
1608
 
1609
    int c = editorReadKey();
1610
 
1611
    switch (c) {
1612
        case '\r': // Enter key
1613
            editorInsertNewline();
1614
            break;
1615
        case CTRL_KEY('q'):
1616
            if (ec.dirty && quit_times > 0) {
7419 siemargl 1617
                editorSetStatusMessage("Warning! File has unsaved changes. Press Ctrl-Q or ^Z %d more time%s to quit", quit_times, quit_times > 1 ? "s" : "");
7413 siemargl 1618
                quit_times--;
1619
                return;
1620
            }
1621
            editorClearScreen();
1622
            consoleBufferClose();
7419 siemargl 1623
            con_exit(1); /// KOS console
7413 siemargl 1624
            exit(0);
1625
            break;
1626
        case CTRL_KEY('s'):
1627
            editorSave();
1628
            break;
1629
        case CTRL_KEY('e'):
1630
            if (ec.cursor_y > 0 && ec.cursor_y <= ec.num_rows - 1)
1631
                editorFlipRow(1);
1632
            break;
1633
        case CTRL_KEY('d'):
1634
            if (ec.cursor_y < ec.num_rows - 1)
1635
            editorFlipRow(-1);
1636
            break;
1637
        case CTRL_KEY('x'):
1638
            if (ec.cursor_y < ec.num_rows)
1639
            editorCut();
1640
            break;
1641
        case CTRL_KEY('c'):
1642
            if (ec.cursor_y < ec.num_rows)
1643
            editorCopy(0);
1644
            break;
1645
        case CTRL_KEY('v'):
1646
            editorPaste();
1647
            break;
7414 siemargl 1648
///        case CTRL_KEY('p'):
1649
///            consoleBufferClose();
1650
///            kill(0, SIGTSTP);
7413 siemargl 1651
        case ARROW_UP:
1652
        case ARROW_DOWN:
1653
        case ARROW_LEFT:
1654
        case ARROW_RIGHT:
1655
            editorMoveCursor(c);
1656
            break;
1657
        case PAGE_UP:
1658
        case PAGE_DOWN:
1659
            { // You can't declare variables directly inside a switch statement.
1660
                if (c == PAGE_UP)
1661
                    ec.cursor_y = ec.row_offset;
1662
                else if (c == PAGE_DOWN)
1663
                    ec.cursor_y = ec.row_offset + ec.screen_rows - 1;
1664
 
1665
                int times = ec.screen_rows;
1666
                while (times--)
1667
                    editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
1668
            }
1669
            break;
1670
        case HOME_KEY:
1671
            ec.cursor_x = 0;
1672
            break;
1673
        case END_KEY:
1674
            if (ec.cursor_y < ec.num_rows)
1675
                ec.cursor_x = ec.row[ec.cursor_y].size;
1676
            break;
1677
        case CTRL_KEY('f'):
1678
            editorSearch();
1679
            break;
1680
        case BACKSPACE:
1681
        case CTRL_KEY('h'):
1682
        case DEL_KEY:
1683
            if (c == DEL_KEY)
1684
                editorMoveCursor(ARROW_RIGHT);
1685
            editorDelChar();
1686
            break;
1687
        case CTRL_KEY('l'):
1688
        case '\x1b': // Escape key
1689
            break;
1690
        default:
1691
            editorInsertChar(c);
1692
            break;
1693
    }
1694
 
1695
    quit_times = TTE_QUIT_TIMES;
1696
}
1697
 
1698
/*** Init section ***/
1699
 
1700
void initEditor() {
1701
    ec.cursor_x = 0;
1702
    ec.cursor_y = 0;
1703
    ec.render_x = 0;
1704
    ec.row_offset = 0;
1705
    ec.col_offset = 0;
1706
    ec.num_rows = 0;
1707
    ec.row = NULL;
1708
    ec.dirty = 0;
1709
    ec.file_name = NULL;
1710
    ec.status_msg[0] = '\0';
1711
    ec.status_msg_time = 0;
1712
    ec.copied_char_buffer = NULL;
1713
    ec.syntax = NULL;
1714
 
1715
    editorUpdateWindowSize();
1716
    // The SIGWINCH signal is sent to a process when its controlling
1717
    // terminal changes its size (a window change).
7414 siemargl 1718
///    signal(SIGWINCH, editorHandleSigwinch);
7413 siemargl 1719
    // The SIGCONT signal instructs the operating system to continue
1720
    // (restart) a process previously paused by the SIGSTOP or SIGTSTP
1721
    // signal.
7414 siemargl 1722
///    signal(SIGCONT, editorHandleSigcont);
7413 siemargl 1723
}
1724
 
1725
void printHelp() {
1726
    printf("Usage: tte [OPTIONS] [FILE]\n\n");
1727
    printf("\nKEYBINDINGS\n-----------\n\n");
1728
    printf("Keybinding\t\tAction\n\n");
7419 siemargl 1729
    printf("Ctrl-Q,^Z \t\tExit\n");
7413 siemargl 1730
    printf("Ctrl-S    \t\tSave\n");
1731
    printf("Ctrl-F    \t\tSearch. Esc, enter and arrows to interact once searching\n");
1732
    printf("Ctrl-E    \t\tFlip line upwards\n");
1733
    printf("Ctrl-D    \t\tFlip line downwards\n");
1734
    printf("Ctrl-C    \t\tCopy line\n");
1735
    printf("Ctrl-X    \t\tCut line\n");
1736
    printf("Ctrl-V    \t\tPaste line\n");
7414 siemargl 1737
 ///   printf("Ctrl-P    \t\tPause tte (type \"fg\" to resume)\n");
7413 siemargl 1738
 
1739
    printf("\n\nOPTIONS\n-------\n\n");
1740
    printf("Option        \t\tAction\n\n");
1741
    printf("-h | --help   \t\tPrints the help\n");
1742
    printf("-v | --version\t\tPrints the version of tte\n");
1743
 
1744
    printf("\n\nFor now, usage of ISO 8859-1 is recommended.\n");
1745
}
1746
 
1747
// 1 if editor should open, 0 otherwise, -1 if the program should exit
1748
int handleArgs(int argc, char* argv[]) {
1749
    if (argc == 1)
1750
        return 0;
1751
 
1752
    if (argc >= 2) {
1753
        if (strncmp("-h", argv[1], 2) == 0 || strncmp("--help", argv[1], 6) == 0) {
1754
            printHelp();
1755
            return -1;
1756
        } else if(strncmp("-v", argv[1], 2) == 0 || strncmp("--version", argv[1], 9) == 0) {
1757
            printf("tte - version %s\n", TTE_VERSION);
1758
            return -1;
1759
        }
1760
    }
1761
 
1762
    return 1;
1763
}
1764
 
1765
int main(int argc, char* argv[]) {
8121 maxcodehac 1766
	con_init_console_dll_param(con_def_wnd_width, con_def_wnd_height, con_def_wnd_width, con_def_wnd_height, "TinyTextEditor");
7413 siemargl 1767
    initEditor();
1768
    int arg_response = handleArgs(argc, argv);
8116 maxcodehac 1769
    if (arg_response == 1) {
1770
		editorOpen(argv[1]);
1771
		char* title = argv[1];
1772
		strcat(title, " - TinyTextEditor");
1773
		con_set_title(title);
1774
	}
7413 siemargl 1775
    else if (arg_response == -1)
1776
        return 0;
1777
    enableRawMode();
7419 siemargl 1778
    editorSetStatusMessage(" Ctrl-Q, ^Z to quit | Ctrl-S to save | (tte -h | --help for more info)");
7413 siemargl 1779
 
1780
    while (1) {
1781
        editorRefreshScreen();
1782
        editorProcessKeypress();
1783
    }
1784
 
7419 siemargl 1785
	con_exit(1);
7413 siemargl 1786
    return 0;
1787
}