diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/auth.h b/auth.h old mode 100644 new mode 100755 diff --git a/browse.c b/browse.c old mode 100644 new mode 100755 diff --git a/browse.h b/browse.h old mode 100644 new mode 100755 diff --git a/chat.h b/chat.h index 11d42ee..8e2a2a8 100644 --- a/chat.h +++ b/chat.h @@ -51,8 +51,8 @@ char *chat_json(const char *role, const char *message) { if (role != NULL && message != NULL) { message_add(role, message); - if(use_tools()){ - json_object_object_add(root_object, "tools", tools_descriptions()); + if (use_tools()) { + json_object_object_add(root_object, "tools", tools_descriptions()); } } diff --git a/cmd.sh b/cmd.sh old mode 100644 new mode 100755 diff --git a/compose.yml b/compose.yml old mode 100644 new mode 100755 diff --git a/database.db b/database.db old mode 100644 new mode 100755 diff --git a/db_utils.c b/db_utils.c old mode 100644 new mode 100755 diff --git a/db_utils.h b/db_utils.h old mode 100644 new mode 100755 diff --git a/http_curl.h b/http_curl.h index 95862c9..8111fa8 100644 --- a/http_curl.h +++ b/http_curl.h @@ -68,7 +68,8 @@ char *curl_post(const char *url, const char *data) { curl_easy_setopt(curl, CURLOPT_URL, url); headers = curl_slist_append(headers, "Content-Type: application/json"); char bearer_header[1337]; - snprintf(bearer_header, sizeof(bearer_header), "Authorization: Bearer %s", resolve_api_key()); + snprintf(bearer_header, sizeof(bearer_header), "Authorization: Bearer %s", + resolve_api_key()); headers = curl_slist_append(headers, bearer_header); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); @@ -102,7 +103,8 @@ char *curl_get(const char *url) { curl_easy_setopt(curl, CURLOPT_URL, url); headers = curl_slist_append(headers, "Content-Type: application/json"); char bearer_header[1337]; - snprintf(bearer_header, sizeof(bearer_header), "Authorization: Bearer %s", resolve_api_key()); + snprintf(bearer_header, sizeof(bearer_header), "Authorization: Bearer %s", + resolve_api_key()); headers = curl_slist_append(headers, bearer_header); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); diff --git a/indexer.h b/indexer.h old mode 100644 new mode 100755 diff --git a/line.h b/line.h old mode 100644 new mode 100755 diff --git a/main.c b/main.c index cdc62cb..942c705 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,8 @@ -#include "r.h" #include "db_utils.h" #include "line.h" #include "markdown.h" #include "openai.h" +#include "r.h" #include "tools.h" #include "utils.h" @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include volatile sig_atomic_t sigint_count = 0; time_t first_sigint_time = 0; @@ -29,259 +29,263 @@ static void repl(void); static void init(void); static void handle_sigint(int sig); -char * get_env_string(){ - FILE *fp = popen("env", "r"); - if (fp == NULL) { - perror("popen failed"); - return NULL; - } +char *get_env_string() { + FILE *fp = popen("env", "r"); + if (fp == NULL) { + perror("popen failed"); + return NULL; + } - size_t buffer_size = 1024; - size_t total_size = 0; - char *output = malloc(buffer_size); - if (output == NULL) { - perror("malloc failed"); + size_t buffer_size = 1024; + size_t total_size = 0; + char *output = malloc(buffer_size); + if (output == NULL) { + perror("malloc failed"); + pclose(fp); + return NULL; + } + + size_t bytes_read; + while ((bytes_read = fread(output + total_size, 1, buffer_size - total_size, + fp)) > 0) { + total_size += bytes_read; + if (total_size >= buffer_size) { + buffer_size *= 2; + char *temp = realloc(output, buffer_size); + if (temp == NULL) { + perror("realloc failed"); + free(output); pclose(fp); return NULL; + } + output = temp; } + } - size_t bytes_read; - while ((bytes_read = fread(output + total_size, 1, buffer_size - total_size, fp)) > 0) { - total_size += bytes_read; - if (total_size >= buffer_size) { - buffer_size *= 2; - char *temp = realloc(output, buffer_size); - if (temp == NULL) { - perror("realloc failed"); - free(output); - pclose(fp); - return NULL; - } - output = temp; - } - } + // Null-terminate the output + output[total_size] = '\0'; - // Null-terminate the output - output[total_size] = '\0'; - - - pclose(fp); - return output; + pclose(fp); + return output; } static char *get_prompt_from_stdin(char *prompt) { - int index = 0; - int c; - while ((c = getchar()) != EOF) { - prompt[index++] = (char)c; - } - prompt[index] = '\0'; - return prompt; + int index = 0; + int c; + while ((c = getchar()) != EOF) { + prompt[index++] = (char)c; + } + prompt[index] = '\0'; + return prompt; } static char *get_prompt_from_args(int argc, char **argv) { - char *prompt = malloc(10 * 1024 * 1024 + 1); - char *system = malloc(1024 * 1024); - if (!prompt || !system) { - fprintf(stderr, "Error: Memory allocation failed.\n"); - free(prompt); - free(system); - return NULL; - } + char *prompt = malloc(10 * 1024 * 1024 + 1); + char *system = malloc(1024 * 1024); + if (!prompt || !system) { + fprintf(stderr, "Error: Memory allocation failed.\n"); + free(prompt); + free(system); + return NULL; + } - bool get_from_std_in = false; + bool get_from_std_in = false; - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--stdin") == 0) { - fprintf(stderr, "Reading from stdin.\n"); - get_from_std_in = true; - } else if (strcmp(argv[i], "--verbose") == 0) { - is_verbose = true; - } else if (strcmp(argv[i], "--py") == 0 && i + 1 < argc) { - char *py_file_path = expand_home_directory(argv[++i]); - fprintf(stderr, "Including \"%s\".\n", py_file_path); - openai_include(py_file_path); - free(py_file_path); - } else if (strcmp(argv[i], "--free") == 0) { - auth_free(); - } else if (strcmp(argv[i], "--context") == 0 && i + 1 < argc) { - char *context_file_path = argv[++i]; - fprintf(stderr, "Including \"%s\".\n", context_file_path); - openai_include(context_file_path); - } else if (strcmp(argv[i], "--api") == 0) { - API_MODE = true; - } else if (strcmp(argv[i], "--nh") == 0) { - SYNTAX_HIGHLIGHT_ENABLED = false; - fprintf(stderr, "Syntax highlighting disabled.\n"); - } else { - strcat(system, argv[i]); - strcat(system, (i < argc - 1) ? " " : "."); - } - } - - if (get_from_std_in) { - if (*system) - openai_system(system); - prompt = get_prompt_from_stdin(prompt); + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--stdin") == 0) { + fprintf(stderr, "Reading from stdin.\n"); + get_from_std_in = true; + } else if (strcmp(argv[i], "--verbose") == 0) { + is_verbose = true; + } else if (strcmp(argv[i], "--py") == 0 && i + 1 < argc) { + char *py_file_path = expand_home_directory(argv[++i]); + fprintf(stderr, "Including \"%s\".\n", py_file_path); + openai_include(py_file_path); + free(py_file_path); + } else if (strcmp(argv[i], "--free") == 0) { + auth_free(); + } else if (strcmp(argv[i], "--context") == 0 && i + 1 < argc) { + char *context_file_path = argv[++i]; + fprintf(stderr, "Including \"%s\".\n", context_file_path); + openai_include(context_file_path); + } else if (strcmp(argv[i], "--api") == 0) { + API_MODE = true; + } else if (strcmp(argv[i], "--nh") == 0) { + SYNTAX_HIGHLIGHT_ENABLED = false; + fprintf(stderr, "Syntax highlighting disabled.\n"); } else { - free(prompt); - prompt = system; + strcat(system, argv[i]); + strcat(system, (i < argc - 1) ? " " : "."); } + } - if (!*prompt) { - free(prompt); - return NULL; - } - return prompt; + if (get_from_std_in) { + if (*system) + openai_system(system); + prompt = get_prompt_from_stdin(prompt); + } else { + free(prompt); + prompt = system; + } + + if (!*prompt) { + free(prompt); + return NULL; + } + return prompt; } static bool try_prompt(int argc, char *argv[]) { - char *prompt = get_prompt_from_args(argc, argv); - if (prompt) { - char *response = openai_chat("user", prompt); - if (!response) { - printf("Could not get response from server\n"); - free(prompt); - return false; - } - render(response); - free(response); - free(prompt); - return true; + char *prompt = get_prompt_from_args(argc, argv); + if (prompt) { + char *response = openai_chat("user", prompt); + if (!response) { + printf("Could not get response from server\n"); + free(prompt); + return false; } - return false; + render(response); + free(response); + free(prompt); + return true; + } + return false; } static bool openai_include(const char *path) { - char *file_content = read_file(path); - if (!file_content) - return false; + char *file_content = read_file(path); + if (!file_content) + return false; - openai_system(file_content); - free(file_content); - return true; + openai_system(file_content); + free(file_content); + return true; } static void render(const char *content) { - if (SYNTAX_HIGHLIGHT_ENABLED) { - parse_markdown_to_ansi(content); - } else { - printf("%s", content); - } + if (SYNTAX_HIGHLIGHT_ENABLED) { + parse_markdown_to_ansi(content); + } else { + printf("%s", content); + } } static void repl(void) { - line_init(); - char *line = NULL; + line_init(); + char *line = NULL; - while (true) { - line = line_read("> "); - if (!line || !*line) - continue; + while (true) { + line = line_read("> "); + if (!line || !*line) + continue; - if (!strncmp(line, "!dump", 5)) { - printf("%s\n", message_json()); - continue; - } - if (!strncmp(line, "!verbose", 8)) { - is_verbose = !is_verbose; - fprintf(stderr, "%s\n", is_verbose ? "Verbose mode enabled" : "Verbose mode disabled"); - continue; - } - if (line && *line != '\n') - line_add_history(line); - if (!strncmp(line, "!tools", 6)) { - printf("Available tools: %s\n", json_object_to_json_string(tools_descriptions())); - continue; - } - if (!strncmp(line, "!models", 7)) { - printf("Current model: %s\n", openai_fetch_models()); - continue; - } - if (!strncmp(line, "!model", 6)) { - if (line[6] == ' ') { - set_prompt_model(line + 7); - } - printf("Current model: %s\n", get_prompt_model()); - continue; - } - if (!strncmp(line, "exit", 4)) - exit(0); - - while (line && *line != '\n') { - char *response = openai_chat("user", line); - if (response) { - render(response); - printf("\n"); - if (strstr(response, "_STEP_")) { - line = "continue"; - } else { - line = NULL; - } - free(response); - } else { - exit(0); - } - } + if (!strncmp(line, "!dump", 5)) { + printf("%s\n", message_json()); + continue; } + if (!strncmp(line, "!verbose", 8)) { + is_verbose = !is_verbose; + fprintf(stderr, "%s\n", + is_verbose ? "Verbose mode enabled" : "Verbose mode disabled"); + continue; + } + if (line && *line != '\n') + line_add_history(line); + if (!strncmp(line, "!tools", 6)) { + printf("Available tools: %s\n", + json_object_to_json_string(tools_descriptions())); + continue; + } + if (!strncmp(line, "!models", 7)) { + printf("Current model: %s\n", openai_fetch_models()); + continue; + } + if (!strncmp(line, "!model", 6)) { + if (line[6] == ' ') { + set_prompt_model(line + 7); + } + printf("Current model: %s\n", get_prompt_model()); + continue; + } + if (!strncmp(line, "exit", 4)) + exit(0); + + while (line && *line != '\n') { + char *response = openai_chat("user", line); + if (response) { + render(response); + printf("\n"); + if (strstr(response, "_STEP_")) { + line = "continue"; + } else { + line = NULL; + } + free(response); + } else { + exit(0); + } + } + } } static void init(void) { - setbuf(stdout, NULL); - line_init(); - auth_init(); - db_initialize(); - char *schema = db_get_schema(); - char payload[1024 * 1024] = {0}; - snprintf(payload, sizeof(payload), - "# LOCAL DATABASE" - "Your have a local database that you can mutate using the query tool and " - "the get and set tool." - "If you set a value using the tool, make sure that the key is stemmed and lowercased to prevent double entries." - "Dialect is sqlite. This is the schema in json format: %s. ", - schema); - free(schema); - fprintf(stderr, "Loading... 📨"); - openai_system(payload); - char * env_system_message = get_env_system_message(); - if(env_system_message && *env_system_message){ - openai_system(env_system_message); - free(env_system_message); - } - if (!openai_include(".rcontext.txt")) { - openai_include("~/.rcontext.txt"); - } - fprintf(stderr, "\r \r"); + setbuf(stdout, NULL); + line_init(); + auth_init(); + db_initialize(); + char *schema = db_get_schema(); + char payload[1024 * 1024] = {0}; + snprintf( + payload, sizeof(payload), + "# LOCAL DATABASE" + "Your have a local database that you can mutate using the query tool and " + "the get and set tool." + "If you set a value using the tool, make sure that the key is stemmed " + "and lowercased to prevent double entries." + "Dialect is sqlite. This is the schema in json format: %s. ", + schema); + free(schema); + fprintf(stderr, "Loading... 📨"); + openai_system(payload); + char *env_system_message = get_env_system_message(); + if (env_system_message && *env_system_message) { + openai_system(env_system_message); + free(env_system_message); + } + if (!openai_include(".rcontext.txt")) { + openai_include("~/.rcontext.txt"); + } + fprintf(stderr, "\r \r"); } static void handle_sigint(int sig) { - time_t current_time = time(NULL); - printf("\n"); - if (sigint_count == 0) { - first_sigint_time = current_time; - sigint_count++; + time_t current_time = time(NULL); + printf("\n"); + if (sigint_count == 0) { + first_sigint_time = current_time; + sigint_count++; + } else { + if (difftime(current_time, first_sigint_time) <= 1) { + exit(0); } else { - if (difftime(current_time, first_sigint_time) <= 1) { - exit(0); - } else { - sigint_count = 1; - first_sigint_time = current_time; - } + sigint_count = 1; + first_sigint_time = current_time; } + } } int main(int argc, char *argv[]) { - signal(SIGINT, handle_sigint); + signal(SIGINT, handle_sigint); - init(); - char * env_string = get_env_string(); - if(env_string && *env_string){ - openai_system(env_string); - free(env_string); - } - if (try_prompt(argc, argv)) - return 0; - - repl(); + init(); + char *env_string = get_env_string(); + if (env_string && *env_string) { + openai_system(env_string); + free(env_string); + } + if (try_prompt(argc, argv)) return 0; + + repl(); + return 0; } diff --git a/markdown.h b/markdown.h index 97709f9..46ec120 100644 --- a/markdown.h +++ b/markdown.h @@ -1,45 +1,30 @@ -// Written by retoor@molodetz.nl - -// This program provides functionality to highlight the keywords in source code -// using ANSI color formatting and convert Markdown syntax into ANSI-colored -// text output. - -// Uses standard C libraries: , . Also utilizes ANSI escape -// codes for text formatting. - -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - +#include #include #include #include +// --- ANSI Escape Codes --- #define RESET "\033[0m" #define BOLD "\033[1m" #define ITALIC "\033[3m" +#define STRIKETHROUGH "\033[9m" + #define FG_YELLOW "\033[33m" #define FG_BLUE "\033[34m" #define FG_CYAN "\033[36m" +#define FG_MAGENTA "\033[35m" +#define BG_YELLOW_FG_BLACK "\033[43;30m" + +/** + * @brief Checks if a given word is a programming language keyword. + * * @param word The word to check. + * @return int 1 if it's a keyword, 0 otherwise. + */ int is_keyword(const char *word) { - + // A comprehensive list of keywords from various popular languages. const char *keywords[] = { + // C keywords "int", "float", "double", "char", "void", "if", "else", "while", "for", "return", "struct", "printf", // Rust keywords @@ -75,33 +60,38 @@ int is_keyword(const char *word) { return 0; } +/** + * @brief Applies basic syntax highlighting to a string of code. + * * @param code The code string to highlight. + */ void highlight_code(const char *code) { const char *ptr = code; char buffer[4096]; size_t index = 0; while (*ptr) { - if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || - (*ptr == '_')) { - while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || - (*ptr >= '0' && *ptr <= '9') || (*ptr == '_')) { + // Highlight keywords + if (isalpha((unsigned char)*ptr) || *ptr == '_') { + while (isalnum((unsigned char)*ptr) || *ptr == '_') { buffer[index++] = *ptr++; } - buffer[index] = 0; + buffer[index] = '\0'; if (is_keyword(buffer)) { - printf(FG_BLUE "%s" RESET, buffer); + printf(FG_BLUE "%s" RESET FG_YELLOW, buffer); } else { printf("%s", buffer); } index = 0; - } else if (*ptr >= '0' && *ptr <= '9') { - while (*ptr >= '0' && *ptr <= '9') { + // Highlight numbers + } else if (isdigit((unsigned char)*ptr)) { + while (isdigit((unsigned char)*ptr)) { buffer[index++] = *ptr++; } - buffer[index] = 0; - printf(FG_CYAN "%s" RESET, buffer); + buffer[index] = '\0'; + printf(FG_CYAN "%s" RESET FG_YELLOW, buffer); index = 0; + // Print other characters as-is } else { putchar(*ptr); ptr++; @@ -109,93 +99,253 @@ void highlight_code(const char *code) { } } +/** + * @brief Parses a Markdown string and prints it to the console with ANSI color + * codes. + * + * This version supports a wide range of Markdown features, including: + * - Headers (H1-H6) + * - Bold (**, __) and Italic (*, _) text + * - Strikethrough (~~) and Highlight (==) + * - Blockquotes (>), Nested Ordered (1.) and Unordered lists (*, -, +) + * - Inline code (`) and full code blocks (```) with syntax highlighting + * - Links ([text](url)) and Horizontal rules (---, ***) + * * @param markdown The raw Markdown string to parse. + */ void parse_markdown_to_ansi(const char *markdown) { const char *ptr = markdown; - bool inside_code = false; + bool is_start_of_line = true; while (*ptr) { - if (*ptr == '`' && *(ptr + 1) != '`') { - inside_code = !inside_code; - if (inside_code) { + // --- Code Blocks (```) --- + if (is_start_of_line && strncmp(ptr, "```", 3) == 0) { + ptr += 3; + while (*ptr && *ptr != '\n') + ptr++; + if (*ptr) + ptr++; + + const char *code_start = ptr; + const char *code_end = strstr(code_start, "```"); + + if (code_end) { + char block_buffer[code_end - code_start + 1]; + strncpy(block_buffer, code_start, code_end - code_start); + block_buffer[code_end - code_start] = '\0'; + printf(FG_YELLOW); - } else { + highlight_code(block_buffer); printf(RESET); - } - ptr++; - continue; - } else if (!strncmp(ptr, "```", 3)) { - inside_code = !inside_code; - if (inside_code) { - ptr = strstr(ptr, "\n") + 1; + + ptr = code_end + 3; + if (*ptr == '\n') + ptr++; + is_start_of_line = true; + continue; } else { - ptr += 3; - } - if (*ptr == '\0') { + printf(FG_YELLOW); + highlight_code(code_start); + printf(RESET); break; } } - if (inside_code) { - char code_buffer[1024 * 1024] = {0}; - ; - size_t index = 0; - - while (*ptr && *ptr != '`') { - code_buffer[index++] = *ptr++; - if (*ptr == '\n' || *ptr == ' ' || *ptr == '\t' || *ptr == '.') { - code_buffer[index++] = 0; - highlight_code(code_buffer); - index = 0; - } - } - code_buffer[index] = 0; - if (index) { - highlight_code(code_buffer); - } - } else { - if (strncmp(ptr, "**", 2) == 0) { - printf(BOLD); - ptr += 2; - while (*ptr && strncmp(ptr, "**", 2) != 0) { - putchar(*ptr++); - } - if (*ptr == '*' && *(ptr + 1) == '*') - ptr += 2; - printf(RESET); - } else if (*ptr == '*' && (ptr == markdown || *(ptr - 1) != '*')) { - printf(ITALIC); + // --- Block-level Elements (checked at the start of a line) --- + if (is_start_of_line) { + const char *line_start_ptr = ptr; + int indent_level = 0; + while (*ptr == ' ') { + indent_level++; ptr++; - while (*ptr && *ptr != '*') { - putchar(*ptr++); - } - if (*ptr == '*') - ptr++; - printf(RESET); + } + + bool block_processed = true; + if (strncmp(ptr, "###### ", 7) == 0) { + printf(BOLD FG_YELLOW); + ptr += 7; + } else if (strncmp(ptr, "##### ", 6) == 0) { + printf(BOLD FG_YELLOW); + ptr += 6; + } else if (strncmp(ptr, "#### ", 5) == 0) { + printf(BOLD FG_YELLOW); + ptr += 5; } else if (strncmp(ptr, "### ", 4) == 0) { printf(BOLD FG_YELLOW); ptr += 4; - while (*ptr && *ptr != '\n') { - putchar(*ptr++); - } - printf(RESET "\n"); } else if (strncmp(ptr, "## ", 3) == 0) { printf(BOLD FG_YELLOW); ptr += 3; - while (*ptr && *ptr != '\n') { - putchar(*ptr++); - } - printf(RESET "\n"); } else if (strncmp(ptr, "# ", 2) == 0) { printf(BOLD FG_YELLOW); ptr += 2; - while (*ptr && *ptr != '\n') { - putchar(*ptr++); - } - printf(RESET "\n"); + } else if ((strncmp(ptr, "---", 3) == 0 || strncmp(ptr, "***", 3) == 0) && + (*(ptr + 3) == '\n' || *(ptr + 3) == '\0')) { + printf(FG_CYAN "───────────────────────────────────────────────────────" + "──────────" RESET "\n"); + ptr += 3; + if (*ptr == '\n') + ptr++; + is_start_of_line = true; + continue; + } else if (strncmp(ptr, "> ", 2) == 0) { + for (int i = 0; i < indent_level; i++) + putchar(' '); + printf(ITALIC FG_CYAN "▎ " RESET); + ptr += 2; + is_start_of_line = false; + continue; + } else if ((*ptr == '*' || *ptr == '-' || *ptr == '+') && + *(ptr + 1) == ' ') { + for (int i = 0; i < indent_level; i++) + putchar(' '); + printf(FG_MAGENTA "• " RESET); + ptr += 2; + is_start_of_line = false; + continue; } else { - putchar(*ptr); - ptr++; + const char *temp_ptr = ptr; + while (isdigit((unsigned char)*temp_ptr)) + temp_ptr++; + if (temp_ptr > ptr && *temp_ptr == '.' && *(temp_ptr + 1) == ' ') { + for (int i = 0; i < indent_level; i++) + putchar(' '); + printf(FG_MAGENTA); + fwrite(ptr, 1, (temp_ptr - ptr) + 1, stdout); + printf(" " RESET); + ptr = temp_ptr + 2; + is_start_of_line = false; + continue; + } else { + block_processed = false; + ptr = line_start_ptr; + } + } + if (block_processed) { + while (*ptr && *ptr != '\n') + putchar(*ptr++); + printf(RESET "\n"); + if (*ptr == '\n') + ptr++; + is_start_of_line = true; + continue; } } + + // --- Inline Elements (order is important) --- + if (strncmp(ptr, "***", 3) == 0 || strncmp(ptr, "___", 3) == 0) { + const char *marker = strncmp(ptr, "***", 3) == 0 ? "***" : "___"; + printf(BOLD ITALIC); + ptr += 3; + const char *end = strstr(ptr, marker); + if (end) { + fwrite(ptr, 1, end - ptr, stdout); + ptr = end + 3; + } else { + fputs(ptr, stdout); + ptr += strlen(ptr); + } + printf(RESET); + continue; + } + if (strncmp(ptr, "**", 2) == 0 || strncmp(ptr, "__", 2) == 0) { + const char *marker = strncmp(ptr, "**", 2) == 0 ? "**" : "__"; + printf(BOLD); + ptr += 2; + const char *end = strstr(ptr, marker); + if (end) { + fwrite(ptr, 1, end - ptr, stdout); + ptr = end + 2; + } else { + fputs(ptr, stdout); + ptr += strlen(ptr); + } + printf(RESET); + continue; + } + if ((*ptr == '*' || *ptr == '_') && !isspace(*(ptr - 1)) && + !isspace(*(ptr + 1))) { + char marker = *ptr; + printf(ITALIC); + ptr++; + const char *start = ptr; + while (*ptr && *ptr != marker) + ptr++; + if (*ptr == marker) { + fwrite(start, 1, ptr - start, stdout); + ptr++; + } else { + putchar(marker); + ptr = start; + } + printf(RESET); + continue; + } + if (strncmp(ptr, "~~", 2) == 0) { + printf(STRIKETHROUGH); + ptr += 2; + const char *end = strstr(ptr, "~~"); + if (end) { + fwrite(ptr, 1, end - ptr, stdout); + ptr = end + 2; + } else { + fputs(ptr, stdout); + ptr += strlen(ptr); + } + printf(RESET); + continue; + } + if (strncmp(ptr, "==", 2) == 0) { + printf(BG_YELLOW_FG_BLACK); + ptr += 2; + const char *end = strstr(ptr, "=="); + if (end) { + fwrite(ptr, 1, end - ptr, stdout); + ptr = end + 2; + } else { + fputs(ptr, stdout); + ptr += strlen(ptr); + } + printf(RESET); + continue; + } + if (*ptr == '`' && *(ptr + 1) != '`') { + printf(FG_YELLOW); + ptr++; + const char *start = ptr; + while (*ptr && *ptr != '`') + ptr++; + fwrite(start, 1, ptr - start, stdout); + if (*ptr == '`') + ptr++; + printf(RESET); + continue; + } + if (*ptr == '[') { + const char *text_start = ptr + 1; + const char *text_end = strchr(text_start, ']'); + if (text_end && *(text_end + 1) == '(') { + const char *url_start = text_end + 2; + const char *url_end = strchr(url_start, ')'); + if (url_end) { + printf(FG_BLUE); + fwrite(text_start, 1, text_end - text_start, stdout); + printf(RESET " ("); + printf(ITALIC FG_CYAN); + fwrite(url_start, 1, url_end - url_start, stdout); + printf(RESET ")"); + ptr = url_end + 1; + continue; + } + } + } + + // --- Default Character --- + if (*ptr == '\n') { + is_start_of_line = true; + } else if (!isspace((unsigned char)*ptr)) { + is_start_of_line = false; + } + putchar(*ptr); + ptr++; } } diff --git a/messages.h b/messages.h old mode 100644 new mode 100755 diff --git a/openai.h b/openai.h old mode 100644 new mode 100755 diff --git a/plugin.h b/plugin.h old mode 100644 new mode 100755 diff --git a/r.desktop b/r.desktop old mode 100644 new mode 100755 diff --git a/r.h b/r.h index 321cd75..ef639d8 100644 --- a/r.h +++ b/r.h @@ -32,31 +32,30 @@ char *_model = NULL; #define DB_FILE "~/.r.db" #define PROMPT_TEMPERATURE 0.1 - -bool use_tools(){ - if(getenv("R_USE_TOOLS") != NULL){ - const char *value = getenv("R_USE_TOOLS"); - if (!strcmp(value, "true")) { - return true; - } - if (!strcmp(value, "false")) { - return false; - } - if (!strcmp(value, "1")) { - return true; - } - if (!strcmp(value, "0")) { - return false; - } +bool use_tools() { + if (getenv("R_USE_TOOLS") != NULL) { + const char *value = getenv("R_USE_TOOLS"); + if (!strcmp(value, "true")) { + return true; } - return true; + if (!strcmp(value, "false")) { + return false; + } + if (!strcmp(value, "1")) { + return true; + } + if (!strcmp(value, "0")) { + return false; + } + } + return true; } -char * get_env_system_message(){ - if (getenv("R_SYSTEM_MESSAGE") != NULL) { - return strdup(getenv("R_SYSTEM_MESSAGE")); - } - return NULL; +char *get_env_system_message() { + if (getenv("R_SYSTEM_MESSAGE") != NULL) { + return strdup(getenv("R_SYSTEM_MESSAGE")); + } + return NULL; } bool get_use_strict() { diff --git a/r.png b/r.png old mode 100644 new mode 100755 diff --git a/review.md b/review.md old mode 100644 new mode 100755 diff --git a/rpylib.c b/rpylib.c old mode 100644 new mode 100755 diff --git a/screenshot1.png b/screenshot1.png old mode 100644 new mode 100755 diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 diff --git a/tools.h b/tools.h index 366e8d2..452294b 100644 --- a/tools.h +++ b/tools.h @@ -56,7 +56,6 @@ struct json_object *tool_description_rag_chunk(); char *tool_function_rag_search(char *query, int top_k); char *tool_function_rag_chunk(char *file_path); - char *tool_function_python_execute(char *source_code); struct json_object *tools_descriptions() { @@ -66,7 +65,7 @@ struct json_object *tools_descriptions() { json_object_array_add(root, tool_description_directory_glob()); json_object_array_add(root, tool_description_read_file()); json_object_array_add(root, tool_description_write_file()); - //json_object_array_add(root, tool_description_directory_rglob()); + // json_object_array_add(root, tool_description_directory_rglob()); json_object_array_add(root, tool_description_linux_terminal_interactive()); json_object_array_add(root, tool_description_index_source_directory()); json_object_array_add(root, tool_description_chdir()); @@ -424,81 +423,88 @@ char *tool_function_linux_terminal_interactive(char *command) { // ---- PYTHON EXECUTE TOOL ---- char *tool_function_python_execute(char *source_code) { - char tmp_file[] = "/tmp/r_python_tool_XXXXXX.py"; - int fd = mkstemps(tmp_file, 3); // 3 for ".py" - if (fd == -1) { - return strdup("Failed to create temporary file for Python code."); - } - FILE *fp = fdopen(fd, "w"); - if (!fp) { - close(fd); - return strdup("Failed to open temporary file for writing."); - } - fwrite(source_code, 1, strlen(source_code), fp); - fclose(fp); + char tmp_file[] = "/tmp/r_python_tool_XXXXXX.py"; + int fd = mkstemps(tmp_file, 3); // 3 for ".py" + if (fd == -1) { + return strdup("Failed to create temporary file for Python code."); + } + FILE *fp = fdopen(fd, "w"); + if (!fp) { + close(fd); + return strdup("Failed to open temporary file for writing."); + } + fwrite(source_code, 1, strlen(source_code), fp); + fclose(fp); - char command[4096]; - snprintf(command, sizeof(command), "python3 '%s' 2>&1", tmp_file); + char command[4096]; + snprintf(command, sizeof(command), "python3 '%s' 2>&1", tmp_file); - FILE *proc = popen(command, "r"); - if (!proc) { - unlink(tmp_file); - return strdup("Failed to execute python3."); - } - char buffer[1024]; - size_t total = 0; - char *output = NULL; - while (fgets(buffer, sizeof(buffer), proc)) { - size_t len = strlen(buffer); - char *new_output = realloc(output, total + len + 1); - if (!new_output) { - free(output); - pclose(proc); - unlink(tmp_file); - return strdup("Memory allocation failed."); - } - output = new_output; - strcpy(output + total, buffer); - total += len; - } - if (output) - output[total] = 0; - else - output = strdup(""); - pclose(proc); + FILE *proc = popen(command, "r"); + if (!proc) { unlink(tmp_file); - return output; + return strdup("Failed to execute python3."); + } + char buffer[1024]; + size_t total = 0; + char *output = NULL; + while (fgets(buffer, sizeof(buffer), proc)) { + size_t len = strlen(buffer); + char *new_output = realloc(output, total + len + 1); + if (!new_output) { + free(output); + pclose(proc); + unlink(tmp_file); + return strdup("Memory allocation failed."); + } + output = new_output; + strcpy(output + total, buffer); + total += len; + } + if (output) + output[total] = 0; + else + output = strdup(""); + pclose(proc); + unlink(tmp_file); + return output; } struct json_object *tool_description_python_execute() { - struct json_object *root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); - struct json_object *function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("python_execute")); - json_object_object_add(function, "description", json_object_new_string("Executes Python source code using the python3 interpreter and returns stdout/stderr.")); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("python_execute")); + json_object_object_add( + function, "description", + json_object_new_string("Executes Python source code using the python3 " + "interpreter and returns stdout/stderr.")); - struct json_object *parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); - struct json_object *properties = json_object_new_object(); - struct json_object *source = json_object_new_object(); - json_object_object_add(source, "type", json_object_new_string("string")); - json_object_object_add(source, "description", json_object_new_string("Python source code to execute.")); - json_object_object_add(properties, "source", source); + struct json_object *properties = json_object_new_object(); + struct json_object *source = json_object_new_object(); + json_object_object_add(source, "type", json_object_new_string("string")); + json_object_object_add( + source, "description", + json_object_new_string("Python source code to execute.")); + json_object_object_add(properties, "source", source); - json_object_object_add(parameters, "properties", properties); + json_object_object_add(parameters, "properties", properties); - struct json_object *required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("source")); - json_object_object_add(parameters, "required", required); + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("source")); + json_object_object_add(parameters, "required", required); - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - json_object_object_add(function, "parameters", parameters); + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + json_object_object_add(function, "parameters", parameters); - json_object_object_add(root, "function", function); + json_object_object_add(root, "function", function); - return root; + return root; } // ---- END PYTHON EXECUTE TOOL ---- @@ -646,9 +652,10 @@ struct json_object *tool_description_linux_terminal_interactive() { struct json_object *properties = json_object_new_object(); struct json_object *path = json_object_new_object(); json_object_object_add(path, "type", json_object_new_string("string")); - json_object_object_add(path, "description", - json_object_new_string( - "Executable with parameters to execute interactively.")); + json_object_object_add( + path, "description", + json_object_new_string( + "Executable with parameters to execute interactively.")); json_object_object_add(properties, "command", path); json_object_object_add(parameters, "properties", properties); @@ -672,7 +679,7 @@ struct json_object *tool_description_linux_terminal_interactive() { } struct json_object *tool_description_directory_rglob() { - + struct json_object *root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); @@ -816,9 +823,9 @@ struct json_object *tool_description_write_file() { } char *tool_function_index_source_directory(char *path) { - char * result = index_directory(path); - if(!result) - return strdup("Failed to index directory!"); + char *result = index_directory(path); + if (!result) + return strdup("Failed to index directory!"); return result; } @@ -1207,33 +1214,32 @@ struct json_object *tool_description_linux_terminal() { } char *tool_function_mkdir(char *path) { - char temp[2048]; - char *p = NULL; - size_t len; + char temp[2048]; + char *p = NULL; + size_t len; - snprintf(temp, sizeof(temp), "%s", path); - len = strlen(temp); + snprintf(temp, sizeof(temp), "%s", path); + len = strlen(temp); - if (temp[len - 1] == '/') { - temp[len - 1] = '\0'; - } + if (temp[len - 1] == '/') { + temp[len - 1] = '\0'; + } - for (p = temp + 1; *p; p++) { - if (*p == '/') { - *p = '\0'; - if (mkdir(temp, 0777) != 0 && errno != EEXIST) { - return strdup("Failed to create directory!"); - } - *p = '/'; - } - } - if (mkdir(temp, 0777) != 0 && errno != EEXIST) { + for (p = temp + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkdir(temp, 0777) != 0 && errno != EEXIST) { return strdup("Failed to create directory!"); + } + *p = '/'; } - return strdup("Directory successfully created."); + } + if (mkdir(temp, 0777) != 0 && errno != EEXIST) { + return strdup("Failed to create directory!"); + } + return strdup("Directory successfully created."); } - struct json_object *tool_description_mkdir() { struct json_object *root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); @@ -1562,15 +1568,18 @@ struct json_object *tools_execute(struct json_object *tools_array) { } } else if (!strcmp(function_name, "python_execute")) { struct json_object *arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object *source_obj; - if (json_object_object_get_ex(arguments, "source", &source_obj)) { - char *source = (char *)json_object_get_string(source_obj); - char *result = tool_function_python_execute(source); - json_object_object_add(tool_result, "content", json_object_new_string(result)); - free(result); - } + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *source_obj; + if (json_object_object_get_ex(arguments, "source", &source_obj)) { + char *source = (char *)json_object_get_string(source_obj); + char *result = tool_function_python_execute(source); + json_object_object_add(tool_result, "content", + json_object_new_string(result)); + free(result); + } } } else { fprintf(stderr, "Unknown function: %s\n", function_name); diff --git a/url.h b/url.h old mode 100644 new mode 100755 diff --git a/utils.h b/utils.h old mode 100644 new mode 100755