From 2882b15d45bd44d9ff1111e224d5013019cf81a8 Mon Sep 17 00:00:00 2001 From: klein panic Date: Sun, 29 Sep 2024 02:35:15 -0400 Subject: [PATCH] initial commit --- readme.md | 1 + source/codews | Bin 0 -> 38752 bytes source/main.c | 783 ++++++++++++++++++++++++++++++ source/main.c.bak | 755 ++++++++++++++++++++++++++++ source/main.c.bak2 | 757 +++++++++++++++++++++++++++++ source/main.c.bak3 | 1161 ++++++++++++++++++++++++++++++++++++++++++++ source/main.o | Bin 0 -> 30784 bytes source/makefile | 28 ++ source/tags | 59 +++ 9 files changed, 3544 insertions(+) create mode 100644 readme.md create mode 100755 source/codews create mode 100644 source/main.c create mode 100644 source/main.c.bak create mode 100644 source/main.c.bak2 create mode 100644 source/main.c.bak3 create mode 100644 source/main.o create mode 100644 source/makefile create mode 100644 source/tags diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..560d92e --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +# This is a readme file diff --git a/source/codews b/source/codews new file mode 100755 index 0000000000000000000000000000000000000000..5ac8d9aaa3ba8e2ee28680ed0b588e3c133366f9 GIT binary patch literal 38752 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 literal 0 HcmV?d00001 diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..669ea28 --- /dev/null +++ b/source/main.c @@ -0,0 +1,783 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FILE_PATH_COLUMN 0 + +static GtkListStore *store; +static GtkWidget *tree_view, *window; +static VteTerminal *terminal; +static int inotify_fd; +static char *base_dir; +static char *current_dir; + +// Function declarations +static void show_new_directory_dialog(); +static void create_new_directory(const char *dir_name); +static void show_deletion_dialog(); +static void delete_selected_item(); +// static int get_directory_depth(const char *dir); // Unused function +static gboolean recursive_delete(const char *path); +static void make_file_executable(const char *path); +static void make_file_not_executable(const char *path); +static const char *get_language_from_path(const char *path); +static void compile_and_run(const char *path, const char *language); +static gboolean show_confirmation_dialog(const char *message); +static void create_new_file(const char *file_name); +static void show_new_file_dialog(); +static void display_directory(const char *dir); +static void open_file_with_appropriate_application(const char *filepath); +static gboolean on_key_press(GtkWidget *widget __attribute__((unused)), GdkEventKey *event, gpointer userdata __attribute__((unused))); +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata __attribute__((unused))); +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col __attribute__((unused)), gpointer userdata __attribute__((unused))); +static GtkWidget* create_tree_view(); +static void on_window_destroy(GtkWidget *widget __attribute__((unused)), gpointer data __attribute__((unused))); +static char *strip_html_markup(const char *input); +void run_executable(GtkMenuItem *menu_item __attribute__((unused)), gpointer user_data); +void make_file_executable_menu(GtkMenuItem *menu_item __attribute__((unused)), gpointer user_data); +void make_file_not_executable_menu(GtkMenuItem *menu_item __attribute__((unused)), gpointer user_data); + +// static void handle_file_open_error(const char *filepath); // Unused function + +static gboolean has_extension(const char *filename, const char *extension) { + const char *dot = strrchr(filename, '.'); + return dot && !g_strcmp0(dot + 1, extension); +} + +static gboolean show_confirmation_dialog(const char *message) { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, + "%s", message); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return (response == GTK_RESPONSE_OK); +} + +/* +static void handle_file_open_error(const char *filepath) { + gchar *msg = g_strdup_printf("\nFailed to open '%s'\n", filepath); + vte_terminal_feed_child(VTE_TERMINAL(terminal), msg, -1); + g_free(msg); +} +*/ + +static void open_file_with_appropriate_application(const char *filepath) { + struct stat path_stat; + if (stat(filepath, &path_stat) != 0 || S_ISDIR(path_stat.st_mode)) { + g_print("Attempted to open a directory or invalid path: %s\n", filepath); + return; + } + + gchar *command = NULL; + + if (has_extension(filepath, "jpg") || has_extension(filepath, "png")) { + command = g_strdup_printf("feh \"%s\"", filepath); + } else if (has_extension(filepath, "pdf")) { + command = g_strdup_printf("zathura \"%s\"", filepath); + } else { + command = g_strdup_printf("nvim \"%s\"", filepath); + } + + gchar *argv[] = {"/bin/sh", "-c", command, NULL}; + + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, + NULL, + -1, + NULL, NULL, + NULL); + + g_free(command); +} + +static void display_directory(const char *dir) { + DIR *d; + struct dirent *entry; + GtkTreeIter iter; + struct stat statbuf; + gboolean readme_found = FALSE; + char *readme_path = NULL; + + if ((d = opendir(dir)) == NULL) { + fprintf(stderr, "Failed to open directory: %s\n", strerror(errno)); + return; + } + + gtk_list_store_clear(store); + + while ((entry = readdir(d)) != NULL) { + char *full_path = g_strdup_printf("%s/%s", dir, entry->d_name); + if (stat(full_path, &statbuf) == -1) { + g_free(full_path); + continue; + } + + gchar *display_name; + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, "codeWS") != 0) { + if (S_ISDIR(statbuf.st_mode)) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else if (statbuf.st_mode & S_IXUSR) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else { + display_name = g_strdup(entry->d_name); + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, display_name, 1, entry->d_name, -1); + g_free(display_name); + + if (g_ascii_strcasecmp(entry->d_name, "readme.md") == 0) { + readme_found = TRUE; + readme_path = g_strdup_printf("%s/%s", dir, entry->d_name); + } + } + g_free(full_path); + } + closedir(d); + + if (readme_found && readme_path) { + open_file_with_appropriate_application(readme_path); + g_free(readme_path); + } +} + +static void navigate_up_directory() { + if (strcmp(current_dir, base_dir) == 0) { + return; + } + + char *last_slash = strrchr(current_dir, '/'); + if (last_slash != NULL) { + *last_slash = '\0'; + if (strcmp(current_dir, base_dir) >= 0) { + display_directory(current_dir); + } else { + strcpy(current_dir, base_dir); + display_directory(current_dir); + } + } +} + +static char *strip_html_markup(const char *input) { + if (input == NULL) return NULL; + + GError *error = NULL; + GRegex *regex = g_regex_new("<[^>]*>", 0, 0, &error); + if (error != NULL) { + g_print("Regex error: %s\n", error->message); + g_error_free(error); + return NULL; + } + + gchar *stripped = g_regex_replace_literal(regex, input, -1, 0, "", 0, NULL); + g_regex_unref(regex); + + return stripped; +} + +gboolean is_executable(const char *path) { + struct stat st; + if (stat(path, &st) == 0) { + return st.st_mode & S_IXUSR; + } + return FALSE; +} + +static gboolean on_key_press(GtkWidget *widget __attribute__((unused)), GdkEventKey *event, gpointer userdata __attribute__((unused))) { + if (event->keyval == GDK_KEY_BackSpace && !vte_terminal_get_has_selection(VTE_TERMINAL(terminal))) { + navigate_up_directory(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_n) { + show_new_directory_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_d) { + show_deletion_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_r) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + const char *language = get_language_from_path(path); + char *clean_path = strip_html_markup(path); + + if (clean_path) { + g_print("Cleaned path: %s\n", clean_path); // Debug print + compile_and_run(clean_path, language); + g_free(clean_path); + } else { + g_print("Failed to clean path: %s\n", path); // Debug print + } + + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_e) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + make_file_executable(path); + display_directory(current_dir); + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_f) { + show_new_file_dialog(); + return TRUE; + } + return FALSE; +} + +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata __attribute__((unused))) { + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + GtkTreePath *path; + GtkTreeView *tree_view = GTK_TREE_VIEW(widget); + + if (gtk_tree_view_get_path_at_pos(tree_view, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL)) { + GtkTreeModel *model = gtk_tree_view_get_model(tree_view); + GtkTreeIter iter; + if (gtk_tree_model_get_iter(model, &iter, path)) { + gchar *file_name; + gtk_tree_model_get(model, &iter, 1, &file_name, -1); + + // Construct the full path + gchar *file_path = g_strdup_printf("%s/%s", current_dir, file_name); + + struct stat path_stat; + if (stat(file_path, &path_stat) == 0 && !S_ISDIR(path_stat.st_mode)) { // Check if not a directory + GtkWidget *menu = gtk_menu_new(); + + // Create and add "Make File Executable" item + GtkWidget *make_exec_item = gtk_menu_item_new_with_label("Make File Executable"); + g_signal_connect(make_exec_item, "activate", G_CALLBACK(make_file_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_exec_item); + + // Create and add "Make File Not Executable" item + GtkWidget *make_not_exec_item = gtk_menu_item_new_with_label("Make File Not Executable"); + g_signal_connect(make_not_exec_item, "activate", G_CALLBACK(make_file_not_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_not_exec_item); + + // Create and add "Run" item if the file is executable + if (is_executable(file_path)) { + GtkWidget *run_item = gtk_menu_item_new_with_label("Run"); + g_signal_connect(run_item, "activate", G_CALLBACK(run_executable), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), run_item); + } + + gtk_widget_show_all(menu); + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); + } else { + g_print("Right-clicked on a directory or invalid path: %s\n", file_path); + } + + g_free(file_path); + g_free(file_name); + } + gtk_tree_path_free(path); + } + return TRUE; + } + return FALSE; +} + +void run_executable(GtkMenuItem *menu_item __attribute__((unused)), gpointer user_data) { + const char *file_path = (const char *)user_data; + gchar *clean_path = g_strdup(file_path); // Duplicate the file path + gchar *command = g_strdup_printf("clear && '%s'", clean_path); // Use single quotes to handle spaces in paths + gchar *argv[] = {"bash", "-c", command, NULL}; + + g_print("Running executable: %s\n", clean_path); // Debug print + g_print("Command: %s\n", command); // Print the command for debugging + + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + current_dir, // Set the working directory + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); + g_free(clean_path); + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_executable_menu(GtkMenuItem *menu_item __attribute__((unused)), gpointer user_data) { + const char *file_path = (const char *)user_data; + make_file_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_not_executable_menu(GtkMenuItem *menu_item __attribute__((unused)), gpointer user_data) { + const char *file_path = (const char *)user_data; + make_file_not_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col __attribute__((unused)), gpointer userdata __attribute__((unused))) { + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_model_get_iter(model, &iter, path)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + + char *new_path = g_strdup_printf("%s/%s", current_dir, actual_name); + struct stat path_stat; + if (stat(new_path, &path_stat) == 0) { + if (S_ISDIR(path_stat.st_mode)) { + g_free(current_dir); + current_dir = new_path; + display_directory(current_dir); + } else { + open_file_with_appropriate_application(new_path); + g_free(new_path); + } + } else { + g_printerr("Failed to access %s: %s\n", new_path, strerror(errno)); + g_free(new_path); + } + g_free(actual_name); + } +} + +static GtkWidget* create_tree_view() { + tree_view = gtk_tree_view_new(); + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("Entries", renderer, "markup", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + g_signal_connect(tree_view, "row-activated", G_CALLBACK(on_row_activated), NULL); + g_signal_connect(tree_view, "key-press-event", G_CALLBACK(on_key_press), NULL); + g_signal_connect(tree_view, "button-press-event", G_CALLBACK(on_button_press), NULL); + + return tree_view; +} + +static void on_window_destroy(GtkWidget *widget __attribute__((unused)), gpointer data __attribute__((unused))) { + close(inotify_fd); + g_free(base_dir); + g_free(current_dir); + gtk_main_quit(); +} + +/* +static int get_directory_depth(const char *dir) { + const char *base = base_dir; + const char *tmp = dir; + + while (*base != '\0' && *tmp == *base) { + base++; + tmp++; + } + + int depth = 0; + while (*tmp != '\0') { + if (*tmp == '/') { + depth++; + } + tmp++; + } + + return depth; +} +*/ + +static char *extract_first_directory(const char *path) { + if (!path) return NULL; + path += strlen(base_dir); + if (*path == '/') path++; + + const char *end = strchr(path, '/'); + if (!end) end = path + strlen(path); + + size_t len = end - path; + char *dir = malloc(len + 1); + if (dir) { + strncpy(dir, path, len); + dir[len] = '\0'; + } + return dir; +} + +static const char *get_language_from_path(const char *path) { + if (!path) { + printf("Error: Path is NULL\n"); + return NULL; + } + + char *language_dir = extract_first_directory(path); + if (!language_dir) { + printf("No language directory found or error in path processing.\n"); + return NULL; + } + + const char *language = NULL; + if (strcmp(language_dir, "C") == 0) { + language = "C"; + } else if (strcmp(language_dir, "Python3") == 0) { + language = "Python3"; + } else if (strcmp(language_dir, "Asm") == 0) { + language = "Assembly"; + } + + if (language) { + printf("Detected language: %s\n", language); + } else { + printf("No recognized language found in the directory name.\n"); + } + + free(language_dir); + return language; +} + +static void compile_and_run(const char *path, const char *language) { + if (path == NULL) { + g_print("Error: Path is NULL\n"); + return; + } + + char *clean_path = strip_html_markup(path); + if (clean_path == NULL) { + g_print("Failed to clean path from HTML markup.\n"); + return; + } + + gchar *compile_cmd = NULL; + gchar *cmd = g_strdup_printf("Are you sure you want to compile and run this %s program?", language); + if (show_confirmation_dialog(cmd)) { + gchar *dir_path = g_path_get_dirname(clean_path); + if (dir_path == NULL) { + g_print("Error: Unable to determine directory from path: %s\n", clean_path); + g_free(cmd); + g_free(clean_path); + return; + } + + if (strcasecmp(language, "C") == 0) { + compile_cmd = g_strdup_printf("clear && cd '%s' && make clean && make", dir_path); + } else if (strcasecmp(language, "Python3") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && python3 %s\n", dir_path, clean_path); + } else if (strcasecmp(language, "Assembly") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && nasm -f elf64 %s -o %s.o && ld %s.o -o %s && ./%s\n", dir_path, clean_path, clean_path, clean_path, clean_path, clean_path); + } + + g_free(dir_path); + + if (compile_cmd) { + g_print("Compile command: %s\n", compile_cmd); + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + (char *[]){ "bash", "-c", compile_cmd, NULL }, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + g_free(compile_cmd); + } else { + g_print("Unsupported language: %s\n", language); + } + } + g_free(cmd); + g_free(clean_path); +} + +static void make_file_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod +x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void make_file_not_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod -x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void create_new_file(const char *file_name) { + if (file_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, file_name); + FILE *file = fopen(full_path, "w"); + if (file) { + fclose(file); + } else { + g_print("Error creating file: %s\n", strerror(errno)); + } + g_free(full_path); +} + +static void show_new_file_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New File", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *file_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_file(file_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void show_new_directory_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New Directory", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *dir_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_directory(dir_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void create_new_directory(const char *dir_name) { + if (dir_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, dir_name); + if (mkdir(full_path, 0755) == -1) { + g_print("Error creating directory: %s\n", strerror(errno)); + } else { + display_directory(current_dir); + } + g_free(full_path); +} + +/* +static int get_directory_depth(const char *dir) { + const char *base = base_dir; + const char *tmp = dir; + + while (*base != '\0' && *tmp == *base) { + base++; + tmp++; + } + + int depth = 0; + while (*tmp != '\0') { + if (*tmp == '/') { + depth++; + } + tmp++; + } + + return depth; +} +*/ + +static gboolean recursive_delete(const char *path) { + DIR *d = opendir(path); + if (d == NULL) { + g_printerr("Failed to open directory for deletion: %s\n", strerror(errno)); + return FALSE; + } + + struct dirent *entry; + gboolean result = TRUE; + + while ((entry = readdir(d)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, "codeWS") == 0) { + continue; + } + + char *full_path = g_strdup_printf("%s/%s", path, entry->d_name); + if (entry->d_type == DT_DIR) { + if (!recursive_delete(full_path)) { + result = FALSE; + g_free(full_path); + break; + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + result = FALSE; + g_free(full_path); + break; + } + } + g_free(full_path); + } + + closedir(d); + + if (result) { + if (rmdir(path) != 0) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + result = FALSE; + } + } + + return result; +} + +static void show_deletion_dialog() { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, + "Are you sure you want to delete the selected item?"); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (response == GTK_RESPONSE_OK) { + delete_selected_item(); + } +} + +static void delete_selected_item() { + GtkTreeModel *model; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + char *full_path = g_strdup_printf("%s/%s", current_dir, actual_name); + + if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) { + if (!recursive_delete(full_path)) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + } + } + + g_free(full_path); + g_free(actual_name); + display_directory(current_dir); + } +} + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + fprintf(stderr, "Environment variable HOME is not set.\n"); + return EXIT_FAILURE; + } + + base_dir = g_strdup_printf("%s/codeWS", home_dir); + current_dir = strdup(base_dir); + + inotify_fd = inotify_init(); + if (inotify_fd < 0) { + perror("inotify_init"); + return EXIT_FAILURE; + } + + inotify_add_watch(inotify_fd, current_dir, IN_CREATE | IN_DELETE | IN_MODIFY); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL); + gtk_window_set_title(GTK_WINDOW(window), "Code Workshop"); + gtk_window_set_default_size(GTK_WINDOW(window), 1200, 600); + + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_container_add(GTK_CONTAINER(window), hbox); + + GtkWidget *view = create_tree_view(); + gtk_box_pack_start(GTK_BOX(hbox), view, FALSE, FALSE, 5); + + terminal = VTE_TERMINAL(vte_terminal_new()); + gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(terminal), TRUE, TRUE, 5); + + display_directory(current_dir); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} diff --git a/source/main.c.bak b/source/main.c.bak new file mode 100644 index 0000000..7fd3100 --- /dev/null +++ b/source/main.c.bak @@ -0,0 +1,755 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FILE_PATH_COLUMN 0 + +static GtkListStore *store; +static GtkWidget *tree_view, *window; +static VteTerminal *terminal; +static int inotify_fd; +static char *base_dir; +static char *current_dir; + +// Function declarations +static void show_new_directory_dialog(); +static void create_new_directory(const char *dir_name); +static void show_deletion_dialog(); +static void delete_selected_item(); +static int get_directory_depth(const char *dir); +static gboolean recursive_delete(const char *path); +static void make_file_executable(const char *path); +static void make_file_not_executable(const char *path); +static const char *get_language_from_path(const char *path); +static void compile_and_run(const char *path, const char *language); +static gboolean show_confirmation_dialog(const char *message); +static void create_new_file(const char *file_name); +static void show_new_file_dialog(); +static void display_directory(const char *dir); +static void open_file_with_appropriate_application(const char *filepath); +static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata); +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata); +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata); +static GtkWidget* create_tree_view(); +static void on_window_destroy(GtkWidget *widget, gpointer data); +static char *strip_html_markup(const char *input); +void run_executable(GtkMenuItem *menu_item, gpointer user_data); +void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data); +void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data); + +static gboolean has_extension(const char *filename, const char *extension) { + const char *dot = strrchr(filename, '.'); + return dot && !g_strcmp0(dot + 1, extension); +} + +static gboolean show_confirmation_dialog(const char *message) { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, + "%s", message); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return (response == GTK_RESPONSE_OK); +} + +static void handle_file_open_error(const char *filepath) { + gchar *msg = g_strdup_printf("\nFailed to open '%s'\n", filepath); + vte_terminal_feed_child(VTE_TERMINAL(terminal), msg, -1); + g_free(msg); +} + +static void open_file_with_appropriate_application(const char *filepath) { + struct stat path_stat; + if (stat(filepath, &path_stat) != 0 || S_ISDIR(path_stat.st_mode)) { + g_print("Attempted to open a directory or invalid path: %s\n", filepath); + return; + } + + const char *const_argv[3] = {NULL, filepath, NULL}; + char *argv[3]; + + if (has_extension(filepath, "jpg") || has_extension(filepath, "png")) { + const_argv[0] = "feh"; + } else if (has_extension(filepath, "pdf")) { + const_argv[0] = "zathura"; + } else { + const_argv[0] = "nvim"; + } + + for (int i = 0; i < 3; i++) { + argv[i] = (char *)const_argv[i]; + } + + vte_terminal_spawn_async(VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, + NULL, + -1, + NULL, NULL, + NULL); +} + +static void display_directory(const char *dir) { + DIR *d; + struct dirent *entry; + GtkTreeIter iter; + struct stat statbuf; + gboolean readme_found = FALSE; + char *readme_path = NULL; + + if ((d = opendir(dir)) == NULL) { + fprintf(stderr, "Failed to open directory: %s\n", strerror(errno)); + return; + } + + gtk_list_store_clear(store); + + while ((entry = readdir(d)) != NULL) { + char *full_path = g_strdup_printf("%s/%s", dir, entry->d_name); + if (stat(full_path, &statbuf) == -1) { + g_free(full_path); + continue; + } + + gchar *display_name; + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, "codeWS") != 0) { + if (S_ISDIR(statbuf.st_mode)) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else if (statbuf.st_mode & S_IXUSR) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else { + display_name = g_strdup(entry->d_name); + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, display_name, 1, entry->d_name, -1); + g_free(display_name); + + if (g_ascii_strcasecmp(entry->d_name, "readme.md") == 0) { + readme_found = TRUE; + readme_path = g_strdup_printf("%s/%s", dir, entry->d_name); + } + } + g_free(full_path); + } + closedir(d); + + if (readme_found && readme_path) { + open_file_with_appropriate_application(readme_path); + g_free(readme_path); + } +} + +static void navigate_up_directory() { + if (strcmp(current_dir, base_dir) == 0) { + return; + } + + char *last_slash = strrchr(current_dir, '/'); + if (last_slash != NULL) { + *last_slash = '\0'; + if (strcmp(current_dir, base_dir) >= 0) { + display_directory(current_dir); + } else { + strcpy(current_dir, base_dir); + display_directory(current_dir); + } + } +} + +static char *strip_html_markup(const char *input) { + if (input == NULL) return NULL; + + GError *error = NULL; + GRegex *regex = g_regex_new("<[^>]*>", 0, 0, &error); + if (error != NULL) { + g_print("Regex error: %s\n", error->message); + g_error_free(error); + return NULL; + } + + gchar *stripped = g_regex_replace_literal(regex, input, -1, 0, "", 0, NULL); + g_regex_unref(regex); + + return stripped; +} + +gboolean is_executable(const char *path) { + struct stat st; + if (stat(path, &st) == 0) { + return st.st_mode & S_IXUSR; + } + return FALSE; +} + +static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata) { + if (event->keyval == GDK_KEY_BackSpace && !vte_terminal_get_has_selection(VTE_TERMINAL(terminal))) { + navigate_up_directory(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_n) { + show_new_directory_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_d) { + show_deletion_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_r) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + const char *language = get_language_from_path(path); + char *clean_path = strip_html_markup(path); + + if (clean_path) { + g_print("Cleaned path: %s\n", clean_path); // Debug print + compile_and_run(clean_path, language); + g_free(clean_path); + } else { + g_print("Failed to clean path: %s\n", path); // Debug print + } + + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_e) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + make_file_executable(path); + display_directory(current_dir); + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_f) { + show_new_file_dialog(); + return TRUE; + } + return FALSE; +} + +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata) { + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + GtkTreePath *path; + GtkTreeView *tree_view = GTK_TREE_VIEW(widget); + + if (gtk_tree_view_get_path_at_pos(tree_view, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL)) { + GtkTreeModel *model = gtk_tree_view_get_model(tree_view); + GtkTreeIter iter; + if (gtk_tree_model_get_iter(model, &iter, path)) { + gchar *file_name; + gtk_tree_model_get(model, &iter, 1, &file_name, -1); + + // Construct the full path + gchar *file_path = g_strdup_printf("%s/%s", current_dir, file_name); + + struct stat path_stat; + if (stat(file_path, &path_stat) == 0 && !S_ISDIR(path_stat.st_mode)) { // Check if not a directory + GtkWidget *menu = gtk_menu_new(); + + // Create and add "Make File Executable" item + GtkWidget *make_exec_item = gtk_menu_item_new_with_label("Make File Executable"); + g_signal_connect(make_exec_item, "activate", G_CALLBACK(make_file_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_exec_item); + + // Create and add "Make File Not Executable" item + GtkWidget *make_not_exec_item = gtk_menu_item_new_with_label("Make File Not Executable"); + g_signal_connect(make_not_exec_item, "activate", G_CALLBACK(make_file_not_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_not_exec_item); + + // Create and add "Run" item if the file is executable + if (is_executable(file_path)) { + GtkWidget *run_item = gtk_menu_item_new_with_label("Run"); + g_signal_connect(run_item, "activate", G_CALLBACK(run_executable), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), run_item); + } + + gtk_widget_show_all(menu); + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); + } else { + g_print("Right-clicked on a directory or invalid path: %s\n", file_path); + } + + g_free(file_path); + g_free(file_name); + } + gtk_tree_path_free(path); + } + return TRUE; + } + return FALSE; +} + +void run_executable(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + gchar *clean_path = g_strdup(file_path); // Duplicate the file path + gchar *command = g_strdup_printf("clear && '%s'", clean_path); // Use single quotes to handle spaces in paths + gchar *argv[] = {"bash", "-c", command, NULL}; + + g_print("Running executable: %s\n", clean_path); // Debug print + g_print("Command: %s\n", command); // Print the command for debugging + + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + current_dir, // Set the working directory + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); + g_free(clean_path); + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + make_file_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + make_file_not_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_model_get_iter(model, &iter, path)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + + char *new_path = g_strdup_printf("%s/%s", current_dir, actual_name); + struct stat path_stat; + if (stat(new_path, &path_stat) == 0) { + if (S_ISDIR(path_stat.st_mode)) { + g_free(current_dir); + current_dir = new_path; + display_directory(current_dir); + } else { + open_file_with_appropriate_application(new_path); + g_free(new_path); + } + } else { + g_printerr("Failed to access %s: %s\n", new_path, strerror(errno)); + g_free(new_path); + } + g_free(actual_name); + } +} + +static GtkWidget* create_tree_view() { + tree_view = gtk_tree_view_new(); + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("Entries", renderer, "markup", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + g_signal_connect(tree_view, "row-activated", G_CALLBACK(on_row_activated), NULL); + g_signal_connect(tree_view, "key-press-event", G_CALLBACK(on_key_press), NULL); + g_signal_connect(tree_view, "button-press-event", G_CALLBACK(on_button_press), NULL); + + return tree_view; +} + +static void on_window_destroy(GtkWidget *widget, gpointer data) { + close(inotify_fd); + g_free(base_dir); + g_free(current_dir); + gtk_main_quit(); +} + +static char *extract_first_directory(const char *path) { + if (!path) return NULL; + path += strlen(base_dir); + if (*path == '/') path++; + + const char *end = strchr(path, '/'); + if (!end) end = path + strlen(path); + + size_t len = end - path; + char *dir = malloc(len + 1); + if (dir) { + strncpy(dir, path, len); + dir[len] = '\0'; + } + return dir; +} + +static const char *get_language_from_path(const char *path) { + if (!path) { + printf("Error: Path is NULL\n"); + return NULL; + } + + char *language_dir = extract_first_directory(path); + if (!language_dir) { + printf("No language directory found or error in path processing.\n"); + return NULL; + } + + const char *language = NULL; + if (strcmp(language_dir, "C") == 0) { + language = "C"; + } else if (strcmp(language_dir, "Python3") == 0) { + language = "Python3"; + } else if (strcmp(language_dir, "Asm") == 0) { + language = "Assembly"; + } + + if (language) { + printf("Detected language: %s\n", language); + } else { + printf("No recognized language found in the directory name.\n"); + } + + free(language_dir); + return language; +} + +static void compile_and_run(const char *path, const char *language) { + if (path == NULL) { + g_print("Error: Path is NULL\n"); + return; + } + + char *clean_path = strip_html_markup(path); + if (clean_path == NULL) { + g_print("Failed to clean path from HTML markup.\n"); + return; + } + + gchar *compile_cmd = NULL; + gchar *cmd = g_strdup_printf("Are you sure you want to compile and run this %s program?", language); + if (show_confirmation_dialog(cmd)) { + gchar *dir_path = g_path_get_dirname(clean_path); + if (dir_path == NULL) { + g_print("Error: Unable to determine directory from path: %s\n", clean_path); + g_free(cmd); + g_free(clean_path); + return; + } + + if (strcasecmp(language, "C") == 0) { + compile_cmd = g_strdup_printf("clear && cd '%s' && make clean && make", dir_path); + } else if (strcasecmp(language, "Python3") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && python3 %s\n", dir_path, clean_path); + } else if (strcasecmp(language, "Assembly") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && nasm -f elf64 %s -o %s.o && ld %s.o -o %s && ./%s\n", dir_path, clean_path, clean_path, clean_path, clean_path, clean_path); + } + + g_free(dir_path); + + if (compile_cmd) { + g_print("Compile command: %s\n", compile_cmd); + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + (char *[]){ "bash", "-c", compile_cmd, NULL }, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + g_free(compile_cmd); + } else { + g_print("Unsupported language: %s\n", language); + } + } + g_free(cmd); + g_free(clean_path); +} + +static void make_file_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod +x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void make_file_not_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod -x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void create_new_file(const char *file_name) { + if (file_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, file_name); + FILE *file = fopen(full_path, "w"); + if (file) { + fclose(file); + } else { + g_print("Error creating file: %s\n", strerror(errno)); + } + g_free(full_path); +} + +static void show_new_file_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New File", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *file_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_file(file_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void show_new_directory_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New Directory", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *dir_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_directory(dir_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void create_new_directory(const char *dir_name) { + if (dir_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, dir_name); + if (mkdir(full_path, 0755) == -1) { + g_print("Error creating directory: %s\n", strerror(errno)); + } else { + display_directory(current_dir); + } + g_free(full_path); +} + +static int get_directory_depth(const char *dir) { + const char *base = base_dir; + const char *tmp = dir; + + while (*base != '\0' && *tmp == *base) { + base++; + tmp++; + } + + int depth = 0; + while (*tmp != '\0') { + if (*tmp == '/') { + depth++; + } + tmp++; + } + + return depth; +} + +static gboolean recursive_delete(const char *path) { + DIR *d = opendir(path); + if (d == NULL) { + g_printerr("Failed to open directory for deletion: %s\n", strerror(errno)); + return FALSE; + } + + struct dirent *entry; + gboolean result = TRUE; + + while ((entry = readdir(d)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, "codeWS") == 0) { + continue; + } + + char *full_path = g_strdup_printf("%s/%s", path, entry->d_name); + if (entry->d_type == DT_DIR) { + if (!recursive_delete(full_path)) { + result = FALSE; + g_free(full_path); + break; + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + result = FALSE; + g_free(full_path); + break; + } + } + g_free(full_path); + } + + closedir(d); + + if (result) { + if (rmdir(path) != 0) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + result = FALSE; + } + } + + return result; +} + +static void show_deletion_dialog() { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, + "Are you sure you want to delete the selected item?"); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (response == GTK_RESPONSE_OK) { + delete_selected_item(); + } +} + +static void delete_selected_item() { + GtkTreeModel *model; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + char *full_path = g_strdup_printf("%s/%s", current_dir, actual_name); + + if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) { + if (!recursive_delete(full_path)) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + } + } + + g_free(full_path); + g_free(actual_name); + display_directory(current_dir); + } +} + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + fprintf(stderr, "Environment variable HOME is not set.\n"); + return EXIT_FAILURE; + } + + base_dir = g_strdup_printf("%s/codeWS", home_dir); + current_dir = strdup(base_dir); + + inotify_fd = inotify_init(); + if (inotify_fd < 0) { + perror("inotify_init"); + return EXIT_FAILURE; + } + + inotify_add_watch(inotify_fd, current_dir, IN_CREATE | IN_DELETE | IN_MODIFY); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL); + gtk_window_set_title(GTK_WINDOW(window), "Code Workshop"); + gtk_window_set_default_size(GTK_WINDOW(window), 1200, 600); + + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_container_add(GTK_CONTAINER(window), hbox); + + GtkWidget *view = create_tree_view(); + gtk_box_pack_start(GTK_BOX(hbox), view, FALSE, FALSE, 5); + + terminal = VTE_TERMINAL(vte_terminal_new()); + gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(terminal), TRUE, TRUE, 5); + + display_directory(current_dir); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} diff --git a/source/main.c.bak2 b/source/main.c.bak2 new file mode 100644 index 0000000..5fd730b --- /dev/null +++ b/source/main.c.bak2 @@ -0,0 +1,757 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FILE_PATH_COLUMN 0 + +static GtkListStore *store; +static GtkWidget *tree_view, *window; +static VteTerminal *terminal; +static int inotify_fd; +static char *base_dir; +static char *current_dir; + +// Function declarations +static void show_new_directory_dialog(); +static void create_new_directory(const char *dir_name); +static void show_deletion_dialog(); +static void delete_selected_item(); +static int get_directory_depth(const char *dir); +static gboolean recursive_delete(const char *path); +static void make_file_executable(const char *path); +static void make_file_not_executable(const char *path); +static const char *get_language_from_path(const char *path); +static void compile_and_run(const char *path, const char *language); +static gboolean show_confirmation_dialog(const char *message); +static void create_new_file(const char *file_name); +static void show_new_file_dialog(); +static void display_directory(const char *dir); +static void open_file_with_appropriate_application(const char *filepath); +static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata); +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata); +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata); +static GtkWidget* create_tree_view(); +static void on_window_destroy(GtkWidget *widget, gpointer data); +static char *strip_html_markup(const char *input); +void run_executable(GtkMenuItem *menu_item, gpointer user_data); +void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data); +void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data); + +static gboolean has_extension(const char *filename, const char *extension) { + const char *dot = strrchr(filename, '.'); + return dot && !g_strcmp0(dot + 1, extension); +} + +static gboolean show_confirmation_dialog(const char *message) { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, + "%s", message); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return (response == GTK_RESPONSE_OK); +} + +static void handle_file_open_error(const char *filepath) { + gchar *msg = g_strdup_printf("\nFailed to open '%s'\n", filepath); + vte_terminal_feed_child(VTE_TERMINAL(terminal), msg, -1); + g_free(msg); +} + +static void open_file_with_appropriate_application(const char *filepath) { + struct stat path_stat; + if (stat(filepath, &path_stat) != 0 || S_ISDIR(path_stat.st_mode)) { + g_print("Attempted to open a directory or invalid path: %s\n", filepath); + return; + } + + const char *const_argv[3] = {NULL, filepath, NULL}; + char *argv[3]; + + if (has_extension(filepath, "jpg") || has_extension(filepath, "png")) { + const_argv[0] = "feh"; + } else if (has_extension(filepath, "pdf")) { + const_argv[0] = "zathura"; + } else { + const_argv[0] = "nvim"; + } + + for (int i = 0; i < 3; i++) { + argv[i] = (char *)const_argv[i]; + } + + vte_terminal_spawn_async(VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, + NULL, + -1, + NULL, NULL, + NULL); +} + +static void display_directory(const char *dir) { + DIR *d; + struct dirent *entry; + GtkTreeIter iter; + struct stat statbuf; + gboolean readme_found = FALSE; + char *readme_path = NULL; + + if ((d = opendir(dir)) == NULL) { + fprintf(stderr, "Failed to open directory: %s\n", strerror(errno)); + return; + } + + gtk_list_store_clear(store); + + while ((entry = readdir(d)) != NULL) { + char *full_path = g_strdup_printf("%s/%s", dir, entry->d_name); + if (stat(full_path, &statbuf) == -1) { + g_free(full_path); + continue; + } + + gchar *display_name; + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, "codeWS") != 0) { + if (S_ISDIR(statbuf.st_mode)) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else if (statbuf.st_mode & S_IXUSR) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else { + display_name = g_strdup(entry->d_name); + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, display_name, 1, entry->d_name, -1); + g_free(display_name); + + if (g_ascii_strcasecmp(entry->d_name, "readme.md") == 0) { + readme_found = TRUE; + readme_path = g_strdup_printf("%s/%s", dir, entry->d_name); + } + } + g_free(full_path); + } + closedir(d); + + if (readme_found && readme_path) { + open_file_with_appropriate_application(readme_path); + g_free(readme_path); + } +} + +static void navigate_up_directory() { + if (strcmp(current_dir, base_dir) == 0) { + return; + } + + char *last_slash = strrchr(current_dir, '/'); + if (last_slash != NULL) { + *last_slash = '\0'; + if (strcmp(current_dir, base_dir) >= 0) { + display_directory(current_dir); + } else { + strcpy(current_dir, base_dir); + display_directory(current_dir); + } + } +} + +static char *strip_html_markup(const char *input) { + if (input == NULL) return NULL; + + GError *error = NULL; + GRegex *regex = g_regex_new("<[^>]*>", 0, 0, &error); + if (error != NULL) { + g_print("Regex error: %s\n", error->message); + g_error_free(error); + return NULL; + } + + gchar *stripped = g_regex_replace_literal(regex, input, -1, 0, "", 0, NULL); + g_regex_unref(regex); + + return stripped; +} + +gboolean is_executable(const char *path) { + struct stat st; + if (stat(path, &st) == 0) { + return st.st_mode & S_IXUSR; + } + return FALSE; +} + +static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata) { + if (event->keyval == GDK_KEY_BackSpace && !vte_terminal_get_has_selection(VTE_TERMINAL(terminal))) { + navigate_up_directory(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_n) { + show_new_directory_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_d) { + show_deletion_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_r) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + const char *language = get_language_from_path(path); + char *clean_path = strip_html_markup(path); + + if (clean_path) { + g_print("Cleaned path: %s\n", clean_path); // Debug print + compile_and_run(clean_path, language); + g_free(clean_path); + } else { + g_print("Failed to clean path: %s\n", path); // Debug print + } + + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_e) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + make_file_executable(path); + display_directory(current_dir); + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_f) { + show_new_file_dialog(); + return TRUE; + } + return FALSE; +} + +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata) { + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + GtkTreePath *path; + GtkTreeView *tree_view = GTK_TREE_VIEW(widget); + + if (gtk_tree_view_get_path_at_pos(tree_view, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL)) { + GtkTreeModel *model = gtk_tree_view_get_model(tree_view); + GtkTreeIter iter; + if (gtk_tree_model_get_iter(model, &iter, path)) { + gchar *file_name; + gtk_tree_model_get(model, &iter, 1, &file_name, -1); + + // Construct the full path + gchar *file_path = g_strdup_printf("%s/%s", current_dir, file_name); + + struct stat path_stat; + if (stat(file_path, &path_stat) == 0 && !S_ISDIR(path_stat.st_mode)) { // Check if not a directory + GtkWidget *menu = gtk_menu_new(); + + // Create and add "Make File Executable" item + GtkWidget *make_exec_item = gtk_menu_item_new_with_label("Make File Executable"); + g_signal_connect(make_exec_item, "activate", G_CALLBACK(make_file_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_exec_item); + + // Create and add "Make File Not Executable" item + GtkWidget *make_not_exec_item = gtk_menu_item_new_with_label("Make File Not Executable"); + g_signal_connect(make_not_exec_item, "activate", G_CALLBACK(make_file_not_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_not_exec_item); + + // Create and add "Run" item if the file is executable + if (is_executable(file_path)) { + GtkWidget *run_item = gtk_menu_item_new_with_label("Run"); + g_signal_connect(run_item, "activate", G_CALLBACK(run_executable), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), run_item); + } + + gtk_widget_show_all(menu); + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); + } else { + g_print("Right-clicked on a directory or invalid path: %s\n", file_path); + } + + g_free(file_path); + g_free(file_name); + } + gtk_tree_path_free(path); + } + return TRUE; + } + return FALSE; +} + +void run_executable(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + gchar *clean_path = g_strdup(file_path); // Duplicate the file path + gchar *command = g_strdup_printf("clear && '%s'", clean_path); // Use single quotes to handle spaces in paths + gchar *argv[] = {"bash", "-c", command, NULL}; + + g_print("Running executable: %s\n", clean_path); // Debug print + g_print("Command: %s\n", command); // Print the command for debugging + + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + current_dir, // Set the working directory + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); + g_free(clean_path); + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + g_print("Making file executable: %s\n", file_path); + make_file_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + g_print("Making file not executable: %s\n", file_path); + make_file_not_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_model_get_iter(model, &iter, path)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + + char *new_path = g_strdup_printf("%s/%s", current_dir, actual_name); + struct stat path_stat; + if (stat(new_path, &path_stat) == 0) { + if (S_ISDIR(path_stat.st_mode)) { + g_free(current_dir); + current_dir = new_path; + display_directory(current_dir); + } else { + open_file_with_appropriate_application(new_path); + g_free(new_path); + } + } else { + g_printerr("Failed to access %s: %s\n", new_path, strerror(errno)); + g_free(new_path); + } + g_free(actual_name); + } +} + +static GtkWidget* create_tree_view() { + tree_view = gtk_tree_view_new(); + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("Entries", renderer, "markup", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + g_signal_connect(tree_view, "row-activated", G_CALLBACK(on_row_activated), NULL); + g_signal_connect(tree_view, "key-press-event", G_CALLBACK(on_key_press), NULL); + g_signal_connect(tree_view, "button-press-event", G_CALLBACK(on_button_press), NULL); + + return tree_view; +} + +static void on_window_destroy(GtkWidget *widget, gpointer data) { + close(inotify_fd); + g_free(base_dir); + g_free(current_dir); + gtk_main_quit(); +} + +static char *extract_first_directory(const char *path) { + if (!path) return NULL; + path += strlen(base_dir); + if (*path == '/') path++; + + const char *end = strchr(path, '/'); + if (!end) end = path + strlen(path); + + size_t len = end - path; + char *dir = malloc(len + 1); + if (dir) { + strncpy(dir, path, len); + dir[len] = '\0'; + } + return dir; +} + +static const char *get_language_from_path(const char *path) { + if (!path) { + printf("Error: Path is NULL\n"); + return NULL; + } + + char *language_dir = extract_first_directory(path); + if (!language_dir) { + printf("No language directory found or error in path processing.\n"); + return NULL; + } + + const char *language = NULL; + if (strcmp(language_dir, "C") == 0) { + language = "C"; + } else if (strcmp(language_dir, "Python3") == 0) { + language = "Python3"; + } else if (strcmp(language_dir, "Asm") == 0) { + language = "Assembly"; + } + + if (language) { + printf("Detected language: %s\n", language); + } else { + printf("No recognized language found in the directory name.\n"); + } + + free(language_dir); + return language; +} + +static void compile_and_run(const char *path, const char *language) { + if (path == NULL) { + g_print("Error: Path is NULL\n"); + return; + } + + char *clean_path = strip_html_markup(path); + if (clean_path == NULL) { + g_print("Failed to clean path from HTML markup.\n"); + return; + } + + gchar *compile_cmd = NULL; + gchar *cmd = g_strdup_printf("Are you sure you want to compile and run this %s program?", language); + if (show_confirmation_dialog(cmd)) { + gchar *dir_path = g_path_get_dirname(clean_path); + if (dir_path == NULL) { + g_print("Error: Unable to determine directory from path: %s\n", clean_path); + g_free(cmd); + g_free(clean_path); + return; + } + + if (strcasecmp(language, "C") == 0) { + compile_cmd = g_strdup_printf("clear && cd '%s' && make clean && make", dir_path); + } else if (strcasecmp(language, "Python3") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && python3 %s\n", dir_path, clean_path); + } else if (strcasecmp(language, "Assembly") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && nasm -f elf64 %s -o %s.o && ld %s.o -o %s && ./%s\n", dir_path, clean_path, clean_path, clean_path, clean_path, clean_path); + } + + g_free(dir_path); + + if (compile_cmd) { + g_print("Compile command: %s\n", compile_cmd); + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + (char *[]){ "bash", "-c", compile_cmd, NULL }, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + g_free(compile_cmd); + } else { + g_print("Unsupported language: %s\n", language); + } + } + g_free(cmd); + g_free(clean_path); +} + +static void make_file_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod +x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void make_file_not_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod -x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void create_new_file(const char *file_name) { + if (file_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, file_name); + FILE *file = fopen(full_path, "w"); + if (file) { + fclose(file); + } else { + g_print("Error creating file: %s\n", strerror(errno)); + } + g_free(full_path); +} + +static void show_new_file_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New File", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *file_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_file(file_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void show_new_directory_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New Directory", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *dir_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_directory(dir_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void create_new_directory(const char *dir_name) { + if (dir_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, dir_name); + if (mkdir(full_path, 0755) == -1) { + g_print("Error creating directory: %s\n", strerror(errno)); + } else { + display_directory(current_dir); + } + g_free(full_path); +} + +static int get_directory_depth(const char *dir) { + const char *base = base_dir; + const char *tmp = dir; + + while (*base != '\0' && *tmp == *base) { + base++; + tmp++; + } + + int depth = 0; + while (*tmp != '\0') { + if (*tmp == '/') { + depth++; + } + tmp++; + } + + return depth; +} + +static gboolean recursive_delete(const char *path) { + DIR *d = opendir(path); + if (d == NULL) { + g_printerr("Failed to open directory for deletion: %s\n", strerror(errno)); + return FALSE; + } + + struct dirent *entry; + gboolean result = TRUE; + + while ((entry = readdir(d)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, "codeWS") == 0) { + continue; + } + + char *full_path = g_strdup_printf("%s/%s", path, entry->d_name); + if (entry->d_type == DT_DIR) { + if (!recursive_delete(full_path)) { + result = FALSE; + g_free(full_path); + break; + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + result = FALSE; + g_free(full_path); + break; + } + } + g_free(full_path); + } + + closedir(d); + + if (result) { + if (rmdir(path) != 0) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + result = FALSE; + } + } + + return result; +} + +static void show_deletion_dialog() { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, + "Are you sure you want to delete the selected item?"); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (response == GTK_RESPONSE_OK) { + delete_selected_item(); + } +} + +static void delete_selected_item() { + GtkTreeModel *model; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + char *full_path = g_strdup_printf("%s/%s", current_dir, actual_name); + + if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) { + if (!recursive_delete(full_path)) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + } + } + + g_free(full_path); + g_free(actual_name); + display_directory(current_dir); + } +} + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + fprintf(stderr, "Environment variable HOME is not set.\n"); + return EXIT_FAILURE; + } + + base_dir = g_strdup_printf("%s/codeWS", home_dir); + current_dir = strdup(base_dir); + + inotify_fd = inotify_init(); + if (inotify_fd < 0) { + perror("inotify_init"); + return EXIT_FAILURE; + } + + inotify_add_watch(inotify_fd, current_dir, IN_CREATE | IN_DELETE | IN_MODIFY); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL); + gtk_window_set_title(GTK_WINDOW(window), "Code Workshop"); + gtk_window_set_default_size(GTK_WINDOW(window), 1200, 600); + + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_container_add(GTK_CONTAINER(window), hbox); + + GtkWidget *view = create_tree_view(); + gtk_box_pack_start(GTK_BOX(hbox), view, FALSE, FALSE, 5); + + terminal = VTE_TERMINAL(vte_terminal_new()); + gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(terminal), TRUE, TRUE, 5); + + display_directory(current_dir); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} diff --git a/source/main.c.bak3 b/source/main.c.bak3 new file mode 100644 index 0000000..9b1cbe8 --- /dev/null +++ b/source/main.c.bak3 @@ -0,0 +1,1161 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FILE_PATH_COLUMN 0 + +static GtkListStore *store; +static GtkWidget *tree_view, *window; +static VteTerminal *terminal; +static int inotify_fd; +static char *base_dir; +static char *current_dir; + +// Function declarations +static void show_new_directory_dialog(); +static void create_new_directory(const char *dir_name); +static void show_deletion_dialog(); +static void delete_selected_item(); +static int get_directory_depth(const char *dir); +static gboolean recursive_delete(const char *path); +static void make_file_executable(const char *path); +static void make_file_not_executable(const char *path); +static const char *get_language_from_path(const char *path); +static void compile_and_run(const char *path, const char *language); +static gboolean show_confirmation_dialog(const char *message); +static void create_new_file(const char *file_name); +static void show_new_file_dialog(); +static void display_directory(const char *dir); +static void open_file_with_appropriate_application(const char *filepath); +static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata); +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata); +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata); +static GtkWidget* create_tree_view(); +static void on_window_destroy(GtkWidget *widget, gpointer data); +static char *strip_html_markup(const char *input); +void run_executable(GtkMenuItem *menu_item, gpointer user_data); +void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data); +void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data); + +static gboolean has_extension(const char *filename, const char *extension) { + const char *dot = strrchr(filename, '.'); + return dot && !g_strcmp0(dot + 1, extension); +} + +static gboolean show_confirmation_dialog(const char *message) { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, + "%s", message); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return (response == GTK_RESPONSE_OK); +} + +static void handle_file_open_error(const char *filepath) { + gchar *msg = g_strdup_printf("\nFailed to open '%s'\n", filepath); + vte_terminal_feed_child(VTE_TERMINAL(terminal), msg, -1); + g_free(msg); +} + +static void open_file_with_appropriate_application(const char *filepath) { + struct stat path_stat; + if (stat(filepath, &path_stat) != 0 || S_ISDIR(path_stat.st_mode)) { + g_print("Attempted to open a directory or invalid path: %s\n", filepath); + return; + } + + const char *const_argv[3] = {NULL, filepath, NULL}; + char *argv[3]; + + if (has_extension(filepath, "jpg") || has_extension(filepath, "png")) { + const_argv[0] = "feh"; + } else if (has_extension(filepath, "pdf")) { + const_argv[0] = "zathura"; + } else { + const_argv[0] = "nvim"; + } + + for (int i = 0; i < 3; i++) { + argv[i] = (char *)const_argv[i]; + } + + vte_terminal_spawn_async(VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, + NULL, + -1, + NULL, NULL, + NULL); +} + +static void display_directory(const char *dir) { + DIR *d; + struct dirent *entry; + GtkTreeIter iter; + struct stat statbuf; + gboolean readme_found = FALSE; + char *readme_path = NULL; + + if ((d = opendir(dir)) == NULL) { + fprintf(stderr, "Failed to open directory: %s\n", strerror(errno)); + return; + } + + gtk_list_store_clear(store); + + while ((entry = readdir(d)) != NULL) { + char *full_path = g_strdup_printf("%s/%s", dir, entry->d_name); + if (stat(full_path, &statbuf) == -1) { + g_free(full_path); + continue; + } + + gchar *display_name; + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, "codeWS") != 0) { + if (S_ISDIR(statbuf.st_mode)) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else if (statbuf.st_mode & S_IXUSR) { + display_name = g_markup_printf_escaped("%s", entry->d_name); + } else { + display_name = g_strdup(entry->d_name); + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, display_name, 1, entry->d_name, -1); + g_free(display_name); + + if (g_ascii_strcasecmp(entry->d_name, "readme.md") == 0) { + readme_found = TRUE; + readme_path = g_strdup_printf("%s/%s", dir, entry->d_name); + } + } + g_free(full_path); + } + closedir(d); + + if (readme_found && readme_path) { + open_file_with_appropriate_application(readme_path); + g_free(readme_path); + } +} + +static void navigate_up_directory() { + if (strcmp(current_dir, base_dir) == 0) { + return; + } + + char *last_slash = strrchr(current_dir, '/'); + if (last_slash != NULL) { + *last_slash = '\0'; + if (strcmp(current_dir, base_dir) >= 0) { + display_directory(current_dir); + } else { + strcpy(current_dir, base_dir); + display_directory(current_dir); + } + } +} + +static char *strip_html_markup(const char *input) { + if (input == NULL) return NULL; + + GError *error = NULL; + GRegex *regex = g_regex_new("<[^>]*>", 0, 0, &error); + if (error != NULL) { + g_print("Regex error: %s\n", error->message); + g_error_free(error); + return NULL; + } + + gchar *stripped = g_regex_replace_literal(regex, input, -1, 0, "", 0, NULL); + g_regex_unref(regex); + + return stripped; +} + +gboolean is_executable(const char *path) { + struct stat st; + if (stat(path, &st) == 0) { + return st.st_mode & S_IXUSR; + } + return FALSE; +} + +static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata) { + if (event->keyval == GDK_KEY_BackSpace && !vte_terminal_get_has_selection(VTE_TERMINAL(terminal))) { + navigate_up_directory(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_n) { + show_new_directory_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_d) { + show_deletion_dialog(); + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_r) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + const char *language = get_language_from_path(path); + char *clean_path = strip_html_markup(path); + + if (clean_path) { + g_print("Cleaned path: %s\n", clean_path); // Debug print + compile_and_run(clean_path, language); + g_free(clean_path); + } else { + g_print("Failed to clean path: %s\n", path); // Debug print + } + + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_e) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 0, &filename, -1); + char *clean_filename = strip_html_markup(filename); + char *path = g_strdup_printf("%s/%s", current_dir, clean_filename); + make_file_executable(path); + display_directory(current_dir); + g_free(clean_filename); + g_free(filename); + g_free(path); + } + return TRUE; + } + if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_f) { + show_new_file_dialog(); + return TRUE; + } + return FALSE; +} + +static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata) { + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + GtkTreePath *path; + GtkTreeView *tree_view = GTK_TREE_VIEW(widget); + + if (gtk_tree_view_get_path_at_pos(tree_view, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL)) { + GtkTreeModel *model = gtk_tree_view_get_model(tree_view); + GtkTreeIter iter; + if (gtk_tree_model_get_iter(model, &iter, path)) { + gchar *file_name; + gtk_tree_model_get(model, &iter, 1, &file_name, -1); + + // Construct the full path + gchar *file_path = g_strdup_printf("%s/%s", current_dir, file_name); + + struct stat path_stat; + if (stat(file_path, &path_stat) == 0 && !S_ISDIR(path_stat.st_mode)) { // Check if not a directory + GtkWidget *menu = gtk_menu_new(); + + // Create and add "Make File Executable" item + GtkWidget *make_exec_item = gtk_menu_item_new_with_label("Make File Executable"); + g_signal_connect(make_exec_item, "activate", G_CALLBACK(make_file_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_exec_item); + + // Create and add "Make File Not Executable" item + GtkWidget *make_not_exec_item = gtk_menu_item_new_with_label("Make File Not Executable"); + g_signal_connect(make_not_exec_item, "activate", G_CALLBACK(make_file_not_executable_menu), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), make_not_exec_item); + + // Create and add "Run" item if the file is executable + if (is_executable(file_path)) { + GtkWidget *run_item = gtk_menu_item_new_with_label("Run"); + g_signal_connect(run_item, "activate", G_CALLBACK(run_executable), g_strdup(file_path)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), run_item); + } + + gtk_widget_show_all(menu); + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); + } else { + g_print("Right-clicked on a directory or invalid path: %s\n", file_path); + } + + g_free(file_path); + g_free(file_name); + } + gtk_tree_path_free(path); + } + return TRUE; + } + return FALSE; +} + +void run_executable(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + gchar *clean_path = g_strdup(file_path); // Duplicate the file path + gchar *command = g_strdup_printf("clear && '%s'", clean_path); // Use single quotes to handle spaces in paths + gchar *argv[] = {"bash", "-c", command, NULL}; + + g_print("Running executable: %s\n", clean_path); // Debug print + g_print("Command: %s\n", command); // Print the command for debugging + + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + current_dir, // Set the working directory + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); + g_free(clean_path); + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + make_file_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data) { + const char *file_path = (const char *)user_data; + make_file_not_executable(file_path); + display_directory(current_dir); // Update the directory view immediately + g_free((char *)file_path); // Free the strdup-ed file path +} + +static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_model_get_iter(model, &iter, path)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + + char *new_path = g_strdup_printf("%s/%s", current_dir, actual_name); + struct stat path_stat; + if (stat(new_path, &path_stat) == 0) { + if (S_ISDIR(path_stat.st_mode)) { + g_free(current_dir); + current_dir = new_path; + display_directory(current_dir); + } else { + open_file_with_appropriate_application(new_path); + g_free(new_path); + } + } else { + g_printerr("Failed to access %s: %s\n", new_path, strerror(errno)); + g_free(new_path); + } + g_free(actual_name); + } +} + +static GtkWidget* create_tree_view() { + tree_view = gtk_tree_view_new(); + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("Entries", renderer, "markup", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + g_signal_connect(tree_view, "row-activated", G_CALLBACK(on_row_activated), NULL); + g_signal_connect(tree_view, "key-press-event", G_CALLBACK(on_key_press), NULL); + g_signal_connect(tree_view, "button-press-event", G_CALLBACK(on_button_press), NULL); + + return tree_view; +} + +static void on_window_destroy(GtkWidget *widget, gpointer data) { + close(inotify_fd); + g_free(base_dir); + g_free(current_dir); + gtk_main_quit(); +} + +static char *extract_first_directory(const char *path) { + if (!path) return NULL; + path += strlen(base_dir); + if (*path == '/') path++; + + const char *end = strchr(path, '/'); + if (!end) end = path + strlen(path); + + size_t len = end - path; + char *dir = malloc(len + 1); + if (dir) { + strncpy(dir, path, len); + dir[len] = '\0'; + } + return dir; +} + +static const char *get_language_from_path(const char *path) { + if (!path) { + printf("Error: Path is NULL\n"); + return NULL; + } + + char *language_dir = extract_first_directory(path); + if (!language_dir) { + printf("No language directory found or error in path processing.\n"); + return NULL; + } + + const char *language = NULL; + if (strcmp(language_dir, "C") == 0) { + language = "C"; + } else if (strcmp(language_dir, "Python3") == 0) { + language = "Python3"; + } else if (strcmp(language_dir, "Asm") == 0) { + language = "Assembly"; + } + + if (language) { + printf("Detected language: %s\n", language); + } else { + printf("No recognized language found in the directory name.\n"); + } + + free(language_dir); + return language; +} + +static void compile_and_run(const char *path, const char *language) { + if (path == NULL) { + g_print("Error: Path is NULL\n"); + return; + } + + char *clean_path = strip_html_markup(path); + if (clean_path == NULL) { + g_print("Failed to clean path from HTML markup.\n"); + return; + } + + gchar *compile_cmd = NULL; + gchar *cmd = g_strdup_printf("Are you sure you want to compile and run this %s program?", language); + if (show_confirmation_dialog(cmd)) { + gchar *dir_path = g_path_get_dirname(clean_path); + if (dir_path == NULL) { + g_print("Error: Unable to determine directory from path: %s\n", clean_path); + g_free(cmd); + g_free(clean_path); + return; + } + + if (strcasecmp(language, "C") == 0) { + compile_cmd = g_strdup_printf("clear && cd '%s' && make clean && make", dir_path); + } else if (strcasecmp(language, "Python3") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && python3 %s\n", dir_path, clean_path); + } else if (strcasecmp(language, "Assembly") == 0) { + compile_cmd = g_strdup_printf("clear && cd %s && nasm -f elf64 %s -o %s.o && ld %s.o -o %s && ./%s\n", dir_path, clean_path, clean_path, clean_path, clean_path, clean_path); + } + + g_free(dir_path); + + if (compile_cmd) { + g_print("Compile command: %s\n", compile_cmd); + vte_terminal_spawn_async( + VTE_TERMINAL(terminal), + VTE_PTY_DEFAULT, + NULL, + (char *[]){ "bash", "-c", compile_cmd, NULL }, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + g_free(compile_cmd); + } else { + g_print("Unsupported language: %s\n", language); + } + } + g_free(cmd); + g_free(clean_path); +} + +static void make_file_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod +x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void make_file_not_executable(const char *path) { + if (path == NULL) return; + gchar *command = g_strdup_printf("chmod -x \"%s\"", path); + gchar *argv[] = {"bash", "-c", command, NULL}; + VteTerminal *vte_terminal = VTE_TERMINAL(terminal); + + vte_terminal_spawn_async( + vte_terminal, + VTE_PTY_DEFAULT, + current_dir, + argv, + NULL#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_COMMAND_LENGTH 256 +#define SSH_LIST_FILE_PATH "/home/klein/codeWS/C/ssh_gui/ssh_list.txt" +#define PRIVATE_KEY_PATH "/home/klein/.ssh/id_rsa" + +// Function to get local IP address +void get_local_ip(char *ip_buffer) { + struct ifaddrs *ifaddr, *ifa; + int family, s; + char host[NI_MAXHOST]; + + if (getifaddrs(&ifaddr) == -1) { + perror("getifaddrs"); + exit(EXIT_FAILURE); + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + family = ifa->ifa_addr->sa_family; + + if (family == AF_INET) { + s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (s != 0) { + printf("getnameinfo() failed: %s\n", gai_strerror(s)); + exit(EXIT_FAILURE); + } + + if (strcmp(ifa->ifa_name, "lo") != 0) { + strncpy(ip_buffer, host, NI_MAXHOST); + break; + } + } + } + + freeifaddrs(ifaddr); +} + +// Function to get public IP address +void get_public_ip(char *ip_buffer) { + FILE *fp; + char path[1035]; + + fp = popen("curl -s ifconfig.me", "r"); + if (fp == NULL) { + printf("Failed to run command\n"); + exit(1); + } + + if (fgets(path, sizeof(path) - 1, fp) != NULL) { + strncpy(ip_buffer, path, 1035); + } + + pclose(fp); +} + +// Function to get SSID using nmcli +void get_ssid(char *ssid_buffer) { + FILE *fp; + char path[1035]; + + fp = popen("nmcli -t -f active,ssid dev wifi | egrep '^yes' | cut -d: -f2", "r"); + if (fp == NULL) { + printf("Failed to run command\n"); + exit(1); + } + + if (fgets(path, sizeof(path) - 1, fp) != NULL) { + strncpy(ssid_buffer, path, 1035); + } + + pclose(fp); +} + +// Function to get SSH service status +void get_ssh_service_status(char *ssh_service_status) { + FILE *fp; + char path[1035]; + + fp = popen("systemctl is-active ssh", "r"); + if (fp == NULL) { + printf("Failed to run command\n"); + exit(1); + } + + if (fgets(path, sizeof(path) - 1, fp) != NULL) { + strncpy(ssh_service_status, path, 1035); + } + + pclose(fp); +} + +// Function to check if port 22 is open and display relevant SSH information +void get_port_22_status(char *port_22_status) { + FILE *fp; + char path[1035]; + + fp = popen("ss -tunlp | grep ':22 '", "r"); + if (fp == NULL) { + printf("Failed to run command\n"); + exit(1); + } + + // Clear the buffer before appending + port_22_status[0] = '\0'; + + while (fgets(path, sizeof(path) - 1, fp) != NULL) { + // Append the relevant lines to the status buffer + strcat(port_22_status, path); + } + + pclose(fp); +} + +// Function to get active connections using ss +void get_active_connections(char *conn_buffer) { + FILE *fp; + char path[1035]; + + fp = popen("ss -tunap", "r"); + if (fp == NULL) { + printf("Failed to run command\n"); + exit(1); + } + + while (fgets(path, sizeof(path) - 1, fp) != NULL) { + strcat(conn_buffer, path); + } + + pclose(fp); +} + +// Function to execute SSH command +void execute_ssh(GtkWidget *widget, gpointer data) { + const char *command = (const char *)data; + + char full_command[MAX_COMMAND_LENGTH]; + snprintf(full_command, sizeof(full_command), "ssh -i %s %s", PRIVATE_KEY_PATH, command); + + printf("Executing command: %s\n", full_command); // Debugging output + + pid_t pid = fork(); + if (pid == 0) { + // Child process + printf("Attempting to execute alacritty with command: %s\n", full_command); + execlp("alacritty", "alacritty", "-e", "bash", "-c", full_command, NULL); + printf("alacritty failed, attempting to execute st with command: %s\n", full_command); + execlp("st", "st", "-e", "bash", "-c", full_command, NULL); + perror("execlp"); + exit(EXIT_FAILURE); + } else if (pid < 0) { + perror("fork"); + } else { + // Parent process + gtk_main_quit(); // Close the GTK main loop + } +} + +// Function to create buttons for each SSH command +void create_buttons(GtkWidget *box) { + FILE *file = fopen(SSH_LIST_FILE_PATH, "r"); + if (!file) { + perror("Error opening file"); + printf("Path attempted: %s\n", SSH_LIST_FILE_PATH); // Debugging output + return; + } + + char line[MAX_COMMAND_LENGTH]; + GtkWidget *prev_button = NULL; + + while (fgets(line, sizeof(line), file)) { + // Remove newline character from the line + line[strcspn(line, "\n")] = 0; + + // Find the first space to locate the start of the SSH command + char *command = strchr(line, ' '); + if (command && strlen(command) > 1) { + command++; // Skip the space to get the actual command + GtkWidget *button = gtk_button_new_with_label(command); + gtk_widget_set_name(button, "ssh-button"); // Set name for CSS + gtk_widget_set_can_focus(button, TRUE); + g_signal_connect(button, "clicked", G_CALLBACK(execute_ssh), g_strdup(command)); + gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0); + } + } + + fclose(file); +} + +// Function to open SSH instructions in Neovim +void open_ssh_instructions(GtkWidget *widget, gpointer data) { + const char *file_path = (const char *)data; + + pid_t pid = fork(); + if (pid == 0) { + // Child process + execlp("alacritty", "alacritty", "-e", "nvim", file_path, NULL); + perror("execlp"); + exit(EXIT_FAILURE); + } else if (pid < 0) { + perror("fork"); + } else { + // Parent process + gtk_main_quit(); // Close the GTK main loop + } +} + +// Key press event handler for buttons +gboolean on_button_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { + GtkWidget *parent = gtk_widget_get_parent(widget); + GList *children = gtk_container_get_children(GTK_CONTAINER(parent)); + GList *current = g_list_find(children, widget); + + switch (event->keyval) { + case GDK_KEY_Up: + case GDK_KEY_Left: + if (current->prev) { + gtk_widget_grab_focus(GTK_WIDGET(current->prev->data)); + } + break; + case GDK_KEY_Down: + case GDK_KEY_Right: + if (current->next) { + gtk_widget_grab_focus(GTK_WIDGET(current->next->data)); + } + break; + default: + return FALSE; + } + return TRUE; +} + +// Key press event handler for window +gboolean on_window_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { + if (event->keyval == GDK_KEY_q || event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_Delete) { + gtk_main_quit(); + return TRUE; + } + return FALSE; +} + +void apply_css(GtkWidget *widget, GtkStyleProvider *provider) { + gtk_style_context_add_provider(gtk_widget_get_style_context(widget), provider, GTK_STYLE_PROVIDER_PRIORITY_USER); + if (GTK_IS_CONTAINER(widget)) { + gtk_container_forall(GTK_CONTAINER(widget), (GtkCallback)apply_css, provider); + } +} + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + // Get system info + char local_ip[NI_MAXHOST] = {0}; + char public_ip[1035] = {0}; + char ssid[1035] = {0}; + char username[256] = {0}; + char ssh_service_status[1035] = {0}; + char port_22_status[2048] = {0}; + char active_connections[2048] = {0}; + char info[512]; // Declare the info variable + + get_local_ip(local_ip); + get_public_ip(public_ip); + get_ssid(ssid); + getlogin_r(username, sizeof(username)); + get_ssh_service_status(ssh_service_status); + get_port_22_status(port_22_status); + get_active_connections(active_connections); + + // Create CSS provider and load CSS + GtkCssProvider *cssProvider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(cssProvider, + "* { font-family: 'Arial'; }\n" + "#app-title { font-size: 24px; font-weight: bold; color: #00FF00; }\n" + "#info-label { font-size: 14px; color: #FFFFFF; }\n" + "#ssh-button { font-size: 14px; background-color: #1E1E1E; color: #000000; border-radius: 4px; padding: 5px 10px; }\n" + "#ssh-button:hover { background-color: #333333; }\n" + "window { background-color: #2E2E2E; }\n", + -1, NULL); + + // Create GTK window + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "SSH Commands"); + gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect(window, "key-press-event", G_CALLBACK(on_window_key_press), NULL); + + // Create a horizontal box to organize sections + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_container_add(GTK_CONTAINER(window), hbox); + + // Create left box for SSH and firewall info + GtkWidget *left_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start(GTK_BOX(hbox), left_box, FALSE, FALSE, 10); + + // Add SSH service status to left box + GtkWidget *label = gtk_label_new("SSH Service Status:"); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(left_box), label, FALSE, FALSE, 5); + + char ssh_status_markup[512]; + if (strncmp(ssh_service_status, "active", 6) == 0) { + snprintf(ssh_status_markup, sizeof(ssh_status_markup), "Active ✓"); + } else { + snprintf(ssh_status_markup, sizeof(ssh_status_markup), "Inactive ✗"); + } + + GtkWidget *ssh_service_label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(ssh_service_label), ssh_status_markup); + gtk_widget_set_name(ssh_service_label, "info-label"); + gtk_box_pack_start(GTK_BOX(left_box), ssh_service_label, FALSE, FALSE, 5); + + label = gtk_label_new("Port 22 Status:"); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(left_box), label, FALSE, FALSE, 5); + + GtkWidget *port_22_text_view = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(port_22_text_view), FALSE); + gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(port_22_text_view), FALSE); + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(port_22_text_view)); + gtk_text_buffer_set_text(buffer, port_22_status, -1); + gtk_box_pack_start(GTK_BOX(left_box), port_22_text_view, TRUE, TRUE, 5); + + // Create center box for user info and buttons + GtkWidget *center_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start(GTK_BOX(hbox), center_box, TRUE, TRUE, 10); + + // Add application title to center box + label = gtk_label_new("SSH Command Center"); + gtk_widget_set_name(label, "app-title"); + gtk_box_pack_start(GTK_BOX(center_box), label, FALSE, FALSE, 10); + + // Add system info labels to center box + snprintf(info, sizeof(info), "Username: %s", username); + label = gtk_label_new(info); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(center_box), label, FALSE, FALSE, 5); + + snprintf(info, sizeof(info), "Local IP: %s", local_ip); + label = gtk_label_new(info); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(center_box), label, FALSE, FALSE, 5); + + snprintf(info, sizeof(info), "Public IP: %s", public_ip); + label = gtk_label_new(info); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(center_box), label, FALSE, FALSE, 5); + + snprintf(info, sizeof(info), "SSID: %s", ssid); + label = gtk_label_new(info); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(center_box), label, FALSE, FALSE, 5); + + // Create buttons for SSH commands + GtkWidget *button_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + create_buttons(button_box); + gtk_box_pack_start(GTK_BOX(center_box), button_box, FALSE, FALSE, 5); + + // Add button to open SSH instructions in Neovim + GtkWidget *edit_button = gtk_button_new_with_label("Edit SSH Instructions"); + gtk_widget_set_name(edit_button, "ssh-button"); + gtk_widget_set_can_focus(edit_button, TRUE); + g_signal_connect(edit_button, "clicked", G_CALLBACK(open_ssh_instructions), (gpointer)SSH_LIST_FILE_PATH); + gtk_box_pack_start(GTK_BOX(center_box), edit_button, FALSE, FALSE, 5); + + // Create right box for active connections + GtkWidget *right_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start(GTK_BOX(hbox), right_box, TRUE, TRUE, 10); + + // Add active connections to right box + label = gtk_label_new("Active Connections:"); + gtk_widget_set_name(label, "info-label"); + gtk_box_pack_start(GTK_BOX(right_box), label, FALSE, FALSE, 5); + + GtkWidget *conn_text_view = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(conn_text_view), FALSE); + gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(conn_text_view), FALSE); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(conn_text_view)); + gtk_text_buffer_set_text(buffer, active_connections, -1); + gtk_box_pack_start(GTK_BOX(right_box), conn_text_view, TRUE, TRUE, 5); + + // Apply CSS to all widgets + apply_css(window, GTK_STYLE_PROVIDER(cssProvider)); + + // Set up key press event handlers for buttons + GList *buttons = gtk_container_get_children(GTK_CONTAINER(button_box)); + for (GList *iter = buttons; iter != NULL; iter = iter->next) { + g_signal_connect(iter->data, "key-press-event", G_CALLBACK(on_button_key_press), NULL); + } + g_signal_connect(edit_button, "key-press-event", G_CALLBACK(on_button_key_press), NULL); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +}, + G_SPAWN_DEFAULT, + NULL, NULL, NULL, -1, + NULL, NULL, NULL); + + g_free(command); +} + +static void create_new_file(const char *file_name) { + if (file_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, file_name); + FILE *file = fopen(full_path, "w"); + if (file) { + fclose(file); + } else { + g_print("Error creating file: %s\n", strerror(errno)); + } + g_free(full_path); +} + +static void show_new_file_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New File", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *file_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_file(file_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void show_new_directory_dialog() { + GtkWidget *dialog, *content_area, *entry; + dialog = gtk_dialog_new_with_buttons("New Directory", GTK_WINDOW(window), + GTK_DIALOG_MODAL, + "_OK", GTK_RESPONSE_OK, + "_Cancel", GTK_RESPONSE_CANCEL, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(content_area), entry); + gtk_widget_show_all(dialog); + + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) { + const char *dir_name = gtk_entry_get_text(GTK_ENTRY(entry)); + create_new_directory(dir_name); + display_directory(current_dir); + } + gtk_widget_destroy(dialog); +} + +static void create_new_directory(const char *dir_name) { + if (dir_name == NULL) return; + + gchar *full_path = g_strdup_printf("%s/%s", current_dir, dir_name); + if (mkdir(full_path, 0755) == -1) { + g_print("Error creating directory: %s\n", strerror(errno)); + } else { + display_directory(current_dir); + } + g_free(full_path); +} + +static int get_directory_depth(const char *dir) { + const char *base = base_dir; + const char *tmp = dir; + + while (*base != '\0' && *tmp == *base) { + base++; + tmp++; + } + + int depth = 0; + while (*tmp != '\0') { + if (*tmp == '/') { + depth++; + } + tmp++; + } + + return depth; +} + +static gboolean recursive_delete(const char *path) { + DIR *d = opendir(path); + if (d == NULL) { + g_printerr("Failed to open directory for deletion: %s\n", strerror(errno)); + return FALSE; + } + + struct dirent *entry; + gboolean result = TRUE; + + while ((entry = readdir(d)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, "codeWS") == 0) { + continue; + } + + char *full_path = g_strdup_printf("%s/%s", path, entry->d_name); + if (entry->d_type == DT_DIR) { + if (!recursive_delete(full_path)) { + result = FALSE; + g_free(full_path); + break; + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + result = FALSE; + g_free(full_path); + break; + } + } + g_free(full_path); + } + + closedir(d); + + if (result) { + if (rmdir(path) != 0) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + result = FALSE; + } + } + + return result; +} + +static void show_deletion_dialog() { + GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, + "Are you sure you want to delete the selected item?"); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (response == GTK_RESPONSE_OK) { + delete_selected_item(); + } +} + +static void delete_selected_item() { + GtkTreeModel *model; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); + GtkTreeIter iter; + gchar *actual_name; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, 1, &actual_name, -1); + char *full_path = g_strdup_printf("%s/%s", current_dir, actual_name); + + if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) { + if (!recursive_delete(full_path)) { + g_printerr("Failed to delete directory: %s\n", strerror(errno)); + } + } else { + if (remove(full_path) != 0) { + g_printerr("Failed to delete file: %s\n", strerror(errno)); + } + } + + g_free(full_path); + g_free(actual_name); + display_directory(current_dir); + } +} + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + fprintf(stderr, "Environment variable HOME is not set.\n"); + return EXIT_FAILURE; + } + + base_dir = g_strdup_printf("%s/codeWS", home_dir); + current_dir = strdup(base_dir); + + inotify_fd = inotify_init(); + if (inotify_fd < 0) { + perror("inotify_init"); + return EXIT_FAILURE; + } + + inotify_add_watch(inotify_fd, current_dir, IN_CREATE | IN_DELETE | IN_MODIFY); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL); + gtk_window_set_title(GTK_WINDOW(window), "Code Workshop"); + gtk_window_set_default_size(GTK_WINDOW(window), 1200, 600); + + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_container_add(GTK_CONTAINER(window), hbox); + + GtkWidget *view = create_tree_view(); + gtk_box_pack_start(GTK_BOX(hbox), view, FALSE, FALSE, 5); + + terminal = VTE_TERMINAL(vte_terminal_new()); + gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(terminal), TRUE, TRUE, 5); + + display_directory(current_dir); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} diff --git a/source/main.o b/source/main.o new file mode 100644 index 0000000000000000000000000000000000000000..9f23693ba16c15cc22fce72376093e59dc21ee1c GIT binary patch literal 30784 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 literal 0 HcmV?d00001 diff --git a/source/makefile b/source/makefile new file mode 100644 index 0000000..e99650d --- /dev/null +++ b/source/makefile @@ -0,0 +1,28 @@ +CC = gcc +CFLAGS = $(shell pkg-config --cflags gtk+-3.0 vte-2.91 glib-2.0) -Wall -Wextra -Werror +LDFLAGS = $(shell pkg-config --libs gtk+-3.0 vte-2.91 glib-2.0) + +TARGET = codews +SRCS = main.c +OBJS = $(SRCS:.c=.o) +INSTALL_DIR = /usr/local/bin + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $(TARGET) $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) + +install: $(TARGET) + sudo cp $(TARGET) $(INSTALL_DIR)/$(TARGET) + sudo chmod +x $(INSTALL_DIR)/$(TARGET) + +uninstall: + sudo rm -f $(INSTALL_DIR)/$(TARGET) + +.PHONY: all clean install uninstall diff --git a/source/tags b/source/tags new file mode 100644 index 0000000..33808e9 --- /dev/null +++ b/source/tags @@ -0,0 +1,59 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ +!_TAG_OUTPUT_FILESEP slash /slash or backslash/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/ +!_TAG_PROC_CWD /home/klein/codeWS/C/corews/test3/ // +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 5.9.0 // +$(TARGET) makefile /^$(TARGET): $(OBJS)$/;" t +%.o makefile /^%.o: %.c$/;" t +CC makefile /^CC = gcc$/;" m +CFLAGS makefile /^CFLAGS = $(shell pkg-config --cflags gtk+-3.0 vte-2.91 glib-2.0)$/;" m +FILE_PATH_COLUMN main.c /^#define FILE_PATH_COLUMN /;" d file: +LDFLAGS makefile /^LDFLAGS = $(shell pkg-config --libs gtk+-3.0 vte-2.91 glib-2.0)$/;" m +OBJS makefile /^OBJS = $(SRCS:.c=.o)$/;" m +SRCS makefile /^SRCS = main.c$/;" m +TARGET makefile /^TARGET = app$/;" m +all makefile /^all: $(TARGET)$/;" t +base_dir main.c /^static char *base_dir;$/;" v typeref:typename:char * file: +clean makefile /^clean:$/;" t +compile_and_run main.c /^static void compile_and_run(const char *path, const char *language) {$/;" f typeref:typename:void file: +create_new_directory main.c /^static void create_new_directory(const char *dir_name) {$/;" f typeref:typename:void file: +create_new_file main.c /^static void create_new_file(const char *file_name) {$/;" f typeref:typename:void file: +create_tree_view main.c /^static GtkWidget* create_tree_view() {$/;" f typeref:typename:GtkWidget * file: +current_dir main.c /^static char *current_dir;$/;" v typeref:typename:char * file: +delete_selected_item main.c /^static void delete_selected_item() {$/;" f typeref:typename:void file: +display_directory main.c /^static void display_directory(const char *dir) {$/;" f typeref:typename:void file: +extract_first_directory main.c /^static char *extract_first_directory(const char *path) {$/;" f typeref:typename:char * file: +get_directory_depth main.c /^static int get_directory_depth(const char *dir) {$/;" f typeref:typename:int file: +get_language_from_path main.c /^static const char *get_language_from_path(const char *path) {$/;" f typeref:typename:const char * file: +handle_file_open_error main.c /^static void handle_file_open_error(const char *filepath) {$/;" f typeref:typename:void file: +has_extension main.c /^static gboolean has_extension(const char *filename, const char *extension) {$/;" f typeref:typename:gboolean file: +inotify_fd main.c /^static int inotify_fd;$/;" v typeref:typename:int file: +is_executable main.c /^gboolean is_executable(const char *path) {$/;" f typeref:typename:gboolean +main main.c /^int main(int argc, char *argv[]) {$/;" f typeref:typename:int +make_file_executable main.c /^static void make_file_executable(const char *path) {$/;" f typeref:typename:void file: +make_file_executable_menu main.c /^void make_file_executable_menu(GtkMenuItem *menu_item, gpointer user_data) {$/;" f typeref:typename:void +make_file_not_executable main.c /^static void make_file_not_executable(const char *path) {$/;" f typeref:typename:void file: +make_file_not_executable_menu main.c /^void make_file_not_executable_menu(GtkMenuItem *menu_item, gpointer user_data) {$/;" f typeref:typename:void +navigate_up_directory main.c /^static void navigate_up_directory() {$/;" f typeref:typename:void file: +on_button_press main.c /^static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer userdata) {$/;" f typeref:typename:gboolean file: +on_key_press main.c /^static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer userdata) {$/;" f typeref:typename:gboolean file: +on_row_activated main.c /^static void on_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, g/;" f typeref:typename:void file: +on_window_destroy main.c /^static void on_window_destroy(GtkWidget *widget, gpointer data) {$/;" f typeref:typename:void file: +open_file_with_appropriate_application main.c /^static void open_file_with_appropriate_application(const char *filepath) {$/;" f typeref:typename:void file: +recursive_delete main.c /^static gboolean recursive_delete(const char *path) {$/;" f typeref:typename:gboolean file: +run_executable main.c /^void run_executable(GtkMenuItem *menu_item, gpointer user_data) {$/;" f typeref:typename:void +show_confirmation_dialog main.c /^static gboolean show_confirmation_dialog(const char *message) {$/;" f typeref:typename:gboolean file: +show_deletion_dialog main.c /^static void show_deletion_dialog() {$/;" f typeref:typename:void file: +show_new_directory_dialog main.c /^static void show_new_directory_dialog() {$/;" f typeref:typename:void file: +show_new_file_dialog main.c /^static void show_new_file_dialog() {$/;" f typeref:typename:void file: +store main.c /^static GtkListStore *store;$/;" v typeref:typename:GtkListStore * file: +strip_html_markup main.c /^static char *strip_html_markup(const char *input) {$/;" f typeref:typename:char * file: +terminal main.c /^static VteTerminal *terminal;$/;" v typeref:typename:VteTerminal * file: +tree_view main.c /^static GtkWidget *tree_view, *window;$/;" v typeref:typename:GtkWidget * file: +window main.c /^static GtkWidget *tree_view, *window;$/;" v typeref:typename:GtkWidget * file: