From 767e09969c7bdc0d011303f8e85f695c7c472046 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Thu, 27 Apr 2023 19:01:32 -0500 Subject: [PATCH] Editor now handles multiple lexers based on file extension. --- CMakeLists.txt | 3 +- include/utils.h | 1 + src/editor.c | 102 ++++++++++++++++++++++++++++++++++++++++++++---- src/main.c | 7 ++++ src/utils.c | 27 ++++++++++--- 5 files changed, 125 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bda7ed3..669a5ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,8 @@ add_definitions( ) if(DEBUG_MODE) - add_definitions(-O0) + add_definitions(-O0) # -fno-stack-protector -g -fsanitize=address) + # target_link_options(${CMAKE_PROJECT_NAME} PRIVATE -g -fsanitize=address) else() add_definitions(-O2) endif() diff --git a/include/utils.h b/include/utils.h index b2f84e8..d10e257 100644 --- a/include/utils.h +++ b/include/utils.h @@ -54,6 +54,7 @@ GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name); char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock); WindowDataT *utilGetWindowData(GtkWidget *window); gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData); +void utilMessageDialog(GtkWidget *parent, char *title, char *message); gboolean utilMkDirP(const char *dir, const mode_t mode); char *utilObfuscateASCII(char *clearText); gboolean utilQuestionDialog(GtkWidget *parent, char *title, char *question); diff --git a/src/editor.c b/src/editor.c index 01550cd..1762a2e 100644 --- a/src/editor.c +++ b/src/editor.c @@ -20,6 +20,8 @@ */ +#include + #include "common.h" #include "editor.h" #include "utils.h" @@ -42,12 +44,29 @@ typedef struct EditorDataS { guint statusBarId; } EditorDataT; +typedef struct LexerDataS { + char *extension; + char *lexerName; +} LexerDataT; + + +static LexerDataT _lexerInfo[] = { + { "h", "cpp" }, + { "c", "cpp" }, + { "asm", "txt" }, //***TODO*** Need a custom lexer for these - and a way to tell different platforms apart. + { "txt", "txt" }, + { "log", "txt" }, + { "vic", "txt" }, //***TODO*** Need a custom lexer for this. + { NULL, NULL } +}; static int _nextEditorId = 0; static void clearEditor(EditorDataT *self); +static int determineLexer(char *filename); EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData); +static gboolean fileIsSupported(char *filename); static void loadEditor(EditorDataT *self); static void loadEditorConfig(char *lexer, EditorDataT *self); EVENT void menuEditorEditCopy(GtkWidget *object, gpointer userData); @@ -60,6 +79,7 @@ EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData); EVENT void menuEditorFileSave(GtkWidget *object, gpointer userData); EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData); EVENT void menuEditorHelpEditor(GtkWidget *object, gpointer userData); +static void setLexer(EditorDataT *self, int lexer); static void status(EditorDataT *self, char *message); EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData); static void winEditorDelete(gpointer userData); @@ -78,6 +98,42 @@ static void clearEditor(EditorDataT *self) { } +static int determineLexer(char *filename) { + char *extension; + int x = 0; + int lexer = -1; + + // Be sure this is something we can edit. + + // Is there a file to load? + if (filename) { + // Find extension. + x = strlen(filename); + while (x >= 0) { + x--; + if (filename[x] == '.') break; + } + extension = strdup(&filename[x + 1]); + // Make it lower case. + for (x=0; xposition, (sptr_t)0); @@ -105,6 +161,19 @@ EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotifi } +static gboolean fileIsSupported(char *filename) { + int lexer = determineLexer(filename); + + // Can we edit this? + if (lexer < 0) { + utilMessageDialog(NULL, "Unknown File Type", "JoeyDev doesn't know how to edit this type of file.\n\nSorry."); + return FALSE; + } + + return TRUE; +} + + static void loadEditor(EditorDataT *self) { FILE *in = NULL; char *line = NULL; @@ -272,7 +341,7 @@ EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData) { if (!utilQuestionDialog(self->windowData.window, "New", "You have unsaved changes. Start new?")) { return; } - status(self, "New image."); + status(self, "New document."); } clearEditor(self); @@ -280,6 +349,9 @@ EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData) { // Clear any filename. DEL(self->windowData.filename); + // Clear lexer. + setLexer(self, -1); + // Mark clean. utilSetDirty((WindowDataT *)self, FALSE); } @@ -291,7 +363,9 @@ EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData) { (void)object; if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) { + if (!fileIsSupported(self->windowData.filename)) return; clearEditor(self); + setLexer(self, determineLexer(self->windowData.filename)); loadEditor(self); } } @@ -334,6 +408,9 @@ EVENT void menuEditorFileSave(GtkWidget *object, gpointer userData) { message(MSG_SEVERE, "Unknown error attempting to save %s!", self->windowData.filename); } + // Did the lexer change? + setLexer(self, determineLexer(self->windowData.filename)); + // Release code. DEL(code); } @@ -358,6 +435,20 @@ EVENT void menuEditorHelpEditor(GtkWidget *object, gpointer userData) { } +static void setLexer(EditorDataT *self, int lexer) { + + if (lexer < 0) { + DEL(self->pLexer); + } else { + self->pLexer = CreateLexer(_lexerInfo[lexer].lexerName); + writeEditorConfig(_lexerInfo[lexer].lexerName, self); // Create default config if a custom one doesn't exist. + loadEditorConfig(_lexerInfo[lexer].lexerName, self); // Load custom config. + } + + SSM(SCI_SETILEXER, 0, (sptr_t)self->pLexer); +} + + static void status(EditorDataT *self, char *message) { gtk_statusbar_remove_all(GTK_STATUSBAR(self->statusBar), self->statusBarId); gtk_statusbar_push(GTK_STATUSBAR(self->statusBar), self->statusBarId, message); @@ -397,7 +488,7 @@ void winEditorCreate(char *filename) { NULL }; - //***TODO*** Be sure this is something we can edit as text. + if (filename && !fileIsSupported(filename)) return; // Set up instance data. self = NEW(EditorDataT); @@ -466,12 +557,7 @@ void winEditorCreate(char *filename) { SSM(SCI_MARKERDEFINE, MARKER_ERROR_HIGHLIGHT, SC_MARK_BACKGROUND); // Error SSM(SCI_MARKERSETBACK, MARKER_ERROR_HIGHLIGHT, 127 | (0 << 8) | (0 << 16)); // RGB - // Add lexer for language support. - self->pLexer = CreateLexer("cpp"); - SSM(SCI_SETILEXER, 0, (sptr_t)self->pLexer); - - writeEditorConfig("cpp", self); - loadEditorConfig("cpp", self); + setLexer(self, determineLexer(filename)); // Connect editor to our code. g_signal_connect(G_OBJECT(self->editor), "sci-notify", G_CALLBACK(editorEditorNotify), self); diff --git a/src/main.c b/src/main.c index 916bab4..3179e07 100644 --- a/src/main.c +++ b/src/main.c @@ -27,6 +27,7 @@ #include "http.h" #include "ssh.h" #include "utils.h" +#include "cwalk.h" char *__resourcePath = NULL; @@ -38,6 +39,12 @@ int main(int argc, char **argv) { unlink("memwatch.log"); #endif +#ifdef _WIN32 + cwk_path_set_style(CWK_STYLE_WINDOWS); +#else + cwk_path_set_style(CWK_STYLE_UNIX); +#endif + gtk_init(&argc, &argv); // Make sure we have a config & resources folder. diff --git a/src/utils.c b/src/utils.c index 24c72d9..0d2b1fb 100644 --- a/src/utils.c +++ b/src/utils.c @@ -310,7 +310,7 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha GtkFileFilter *filter; gboolean result = FALSE; char *files = utilCreateString("%s Files", what); - int x; + size_t x; dialog = gtk_file_chooser_dialog_new("Save As", GTK_WINDOW(self->window), @@ -321,7 +321,7 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha if (*filename != NULL) { memcpy(__utilFilenameBuffer, *filename, strlen(*filename) + 1); - cwk_path_get_dirname(__utilFilenameBuffer, (size_t *)&x); + cwk_path_get_dirname(__utilFilenameBuffer, &x); if (x > 0) __utilFilenameBuffer[x] = 0; gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),__utilFilenameBuffer); } @@ -454,6 +454,21 @@ gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widg } +void utilMessageDialog(GtkWidget *parent, char *title, char *message) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new( + GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", message); + gtk_window_set_title(GTK_WINDOW(dialog), title); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + + gboolean utilMkDirP(const char *dir, const mode_t mode) { char *p = NULL; struct stat sb; @@ -584,15 +599,15 @@ void utilSetDirty(WindowDataT *self, gboolean dirty) { void utilUpdatePath(WindowDataT *self) { - int i; + size_t i; + + DEL(self->path); if (self->filename) { // Derive the path from the filename. self->path = strdup(self->filename); - cwk_path_get_dirname(self->path, (size_t *)&i); + cwk_path_get_dirname(self->path, &i); if (i > 0) self->path[i] = 0; - } else { - DEL(self->path); } }