@@ -95,6 +95,16 @@ int character_compare_array (char character, char * character_array) { // I didn | |||
return (FALSE); | |||
} | |||
int character_count (char * string, char character, int from, int to, char stop) { // This function seem trickier to understand, but it's nothing special if you think about it. | |||
int count; | |||
for (count = 0; (from != to) && (string [from] != stop); from += ((to < from) ? -1 : 1)) { // We want to know how many 'character's are in our 'string'. | |||
count += (int) ((string [from] == character) || (character == '\0')); // This covers searching forward and backward, depending on 'from' and 'to'. | |||
} | |||
return (count); // And we found our count! | |||
} | |||
/* | |||
You can see important information about some functions on manual pages in every Linux distro, with 'man ([optional] number) function_name', for example 'man 2 open', and I'll list | |||
few important ones down below with some copy & paste magic, but I'll keep it short. | |||
@@ -344,6 +344,8 @@ extern int character_is_hexadecimal (char character); | |||
extern int character_compare_array (char character, char * character_array); // This function is singled out, because it's different from those above, and we use it internally. | |||
extern int character_count (char * string, char character, int from, int to, char stop); // We'll use this to count characters in null-terminated strings. | |||
/* | |||
And here are also utility functions that handle files, most of them are reimplemented using "system calls" from <fcntl.h> and <unistd.h>, but you also have access to <stdio.h>, | |||
which is probably the most used header file in C language. It handles the 'FILE *' type, not a file descriptors which are 'int', and has functions that are prefixed with character | |||
@@ -344,7 +344,7 @@ void syntax_highlight_ada (void) { | |||
void program_curses_view_file (char * text_file, int x, int y) { | |||
char * text_data; // This local variable will hold our data. | |||
int reset_x, reset_y; // Since we're using curses, we want to reset the offset. | |||
int reset_x, reset_y, from, to; // Since we're using curses, we want to reset the offset. | |||
curses_configure (); // Curses configuration, aka printing ugly text. | |||
@@ -365,6 +365,8 @@ void program_curses_view_file (char * text_file, int x, int y) { | |||
reset_x = x; | |||
reset_y = y; | |||
from = 0; | |||
to = string_length (text_data); | |||
while (curses_active == TRUE) { // We enter our main subprogram loop. | |||
int offset, select, length; | |||
@@ -376,7 +378,13 @@ void program_curses_view_file (char * text_file, int x, int y) { | |||
select = syntax_count; // I intentionally set this to an invalid value. | |||
length = 0; | |||
for (offset = 0; offset < string_length (text_data); offset += length) { // And it's time to start rendering our file. | |||
if (curses_character == 'w') { // WORK IN PROGRESS | |||
from -= character_count (text_data, '\0', from, to, '\n'); | |||
} else if (curses_character == 's') { | |||
from += character_count (text_data, '\0', from, to, '\n') + 1; | |||
} | |||
for (offset = from; offset < to; offset += length) { // And it's time to start rendering our file. | |||
int suboffset, colour, effect; | |||
select = syntax_select (& text_data [offset], & length); // Here we're evaluating variables 'select' and 'length'. | |||
@@ -408,6 +416,10 @@ void program_curses_view_file (char * text_file, int x, int y) { | |||
x += 1; | |||
} | |||
} | |||
if (y >= curses_screen_height) { | |||
break; | |||
} | |||
} | |||
curses_synchronize (); // Lastly, we synchronize our terminal. | |||
@@ -58,6 +58,32 @@ which is dangerous in my opinion for one reason: They think they're always right | |||
own what I know, no one owns anyones' knowledge, but they weren't always right. So, if you don't have a CS degree, you can learn C easier, that's my point. | |||
C is good programming language to learn first because it shows you what can you create with very simple tools. Now, lets get to syntax highlighting: | |||
I'll say it as many times as I need, readability is the key to good software. If your code is readable, yet simple, without structure-hell or function-hell, but you don't have the | |||
knowledge to optimize it currently, if you share it under some permissive license and show it to other people who (probably) know more about optimizing the program than you, they | |||
might have less trouble "fixing" it. Again, this depends on more factors, how many global variables you have, because without them compiler will (maybe / probably) be able to | |||
optimize it for you. But the source code being readable is a good start. | |||
However, no matter how readable and nicely formatted it is, it would be harder to read if everything is printed in white text on black background (like it's with ed text editor). | |||
When you open your text editor of choice, as soon as you see certain colour, you know it's a keyword, not an identifier, you notice comments and probably ignore them, it's a good | |||
thing, right? So, there are more than one ways to parse a text file and determine what's a keyword, a number, a string, etc. I'm using simple approach from my older program, which | |||
was made to replace me constantly using '$ cat text_file.c' in terminal. | |||
Imagine this: | |||
This is an array of characters, in C type 'char', and only the last one is '\0', aka CHARACTER_NULL in our enumeration. | |||
[.................................................................................................................................................................................] | |||
This is how we parse it, determine where some syntax rule begins, where it ends, how long it is, without changing that array of characters, aka string. | |||
[.................................................................................................................................................................................] | |||
^ - at the start, we're pointing to first character, whose index is 0. | |||
^^^ - then we try to match (for example) first 3 characters, if there's a syntax rule like that, with strict comparison. | |||
^ - if we matched it, then we need to check if next character, 4th one (with index 3), an ending character or string. | |||
^ - if it is, we return index of that rule (with function 'syntax_select') and length is 3, without changing the offset. | |||
And we repeat that process until we reach the end of the string, that null termination, it's not a fast algorithm, but it's simple. Easy. | |||
*/ | |||
extern int syntax_define (int enrange, int derange, char * begin, char * end, char escape, int colour, int effect); // This must be called before 'syntax_select' function. | |||