Creating a tui in c.
From the project's README:
foochr is a text-based user interface (TUI) program to help keep track of commands with flags, other TUI's and even allows for a bit of scripting.
It is basically just a fancier way for bash aliases. Instead of having an alias
for cha -MV or for bluetui, the user can just write those down, giving the
commands a name and then launch foochr to get a list of all those commands
My initial idea for this project came a while back, when I started using cli's and tui's more and more. My issue back then was, that i kept forgetting the names of especially those programs, that i did not use that often. For examle impala and bluetui.
Also I wanted to learn ncurses, as well as c. This is because i had another project that i wanted to code, that was larger and much more complicated than this. I thought, that this could be an easy introduction to those two components.
My first version was quickly written, thanks to the very useful guide for ncurses over at the tldp website. However, one might notice, that all of the applications were hard-coded inside of the binary, thus making adjustments to this "configuration" very painfully.
Because I did not have much knowledge about how to parse a config file, I asked my chatbot of choice, that he should create me such a feature. This has worked pretty well, however I wasnt really happy that I needed help from an ai for such a simple task.
I generally think that AI is not sustainable and that this technology should not be used. Thus, my decision was made, to rewrite this piece of software.
About a week ago, I started coding this new version, fully free of AI-slop.
Because parsing the config would be one of the first things that will be done
in the application, I also started with this step. It is actually not quite as
difficult as I thought. Reading the first line can be done pretty easily, as
well as getting an absolute path to the .config directory via getenv().
I noticed my lacking knowledge of the c standard library very quickly. I didn't
know that there was a function to "tokenize" a given input, etc. This however
did not prevent me from implementing the parser. (acutally even without the
strtok() function)
Okay now to the technicalities. A config file for foochr can look like this:
chawan=cha -MV
system monitor=btop
wifi=impala
For parsing the config, I mostly used the fgetch() function, which reads the
next character in a given stream and returns it. With this, it is possible to
just loop over the file and based on the character that gets returned, do
something differently. In my case, this looks something like this:
First there is a struct, where the config entries get stored.
// This struct stores the key and the value for a given entry.
struct KeyValue
{
char key[127]; // This stores the value that will be shown in the tui
char value[127]; // This stores the command that will be run
}
Next, some values that later will be used get initialized. config_values[] is
an array of the struct above. In this example, the maximum amount that a
configuration can have, is 15 lines. In the actual program, this memory will
be allocated and has not a fixed value. config_index is the current position
in the config_values[] array. This will be useful to determine, where the
next character should be inserted into.
is_value stores if the next characters should be inserted into the key[]
array or the value[] array.
struct KeyValue config_values[15];
config_index = 0;
bool is_value = false;
And lastly, there is a while block, that does multiple things. It checks if the
current character is a \n. If so, the config_index should be incremented.
This is because in the config file, each new-line indicates a new command that
should be displayed in the ui/executed using foochr.
If the current character is a =, the boolean is_value is switched, thus
allowing the next characters to flow into the value instead of the key.
while (true)
{
character = fgetch(fp);
if (character == '\n')
{
is_value = != is_value;
config_index++;
continue;
}
if (character == '=')
{
is_value != is_value;
}
if (is_value == true)
{
strcat(
config_values[config_index].value,
(char*)&character
)
}
else
{
strcat(
config_values[config_index].key,
(char*)&character
)
}
}
All of this above is just a very simple example. This is not how the code actually looks like. To see, what the code looks like; you can find it here.
The config-file parsing was the main part, that I did not know how to implement. With that out of the way, all that was left, were the ncurses things, which I already knew from the first version of foochr and some Makefile shenanigans for allowing the program to be packaged.
To be honest, not using AI in the whole process, from start to end, made me realize, how useless AI actually is. If you know the general concepts of programming and know how to search if you have an issue, you're probably better off without any LLM's.
Also some people say, that with LLM's you actually write the same code but faster. I do not think that this is true. Almost everybody I know, that uses AI either spends half the time waiting for the prompt to be processed or to be mad at the chatbot because it did not write the code that they wanted. This is especially true with low-level programming, but applies to general programming as well.
So; don't forget that just because some huge tech companies tell everybody how their product will replace you, that this statement is actually true. They most likey (as with almost all other companies) just want you to spend money.
Have a great day!
by ivanpollak