Editor now handles multiple lexers based on file extension.

This commit is contained in:
Scott Duensing 2023-04-27 19:01:32 -05:00
parent f775bcb13c
commit 767e09969c
5 changed files with 125 additions and 15 deletions

View file

@ -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()

View file

@ -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);

View file

@ -20,6 +20,8 @@
*/
#include <ctype.h>
#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; x<strlen(extension); x++) {
extension[x] = (char)tolower(extension[x]);
}
// Do we know how to cope with this?
x = 0;
while (_lexerInfo[x].extension != NULL) {
if (strcmp(extension, _lexerInfo[x].extension) == 0) {
lexer = x;
break;
}
x++;
}
DEL(extension);
}
return lexer;
}
EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData) {
EditorDataT *self = (EditorDataT *)userData;
int lineNumber = (int)SSM(SCI_LINEFROMPOSITION, (uptr_t)notifyData->position, (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);

View file

@ -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.

View file

@ -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);
}
}