Editor now handles multiple lexers based on file extension.
This commit is contained in:
parent
f775bcb13c
commit
767e09969c
5 changed files with 125 additions and 15 deletions
|
@ -101,7 +101,8 @@ add_definitions(
|
||||||
)
|
)
|
||||||
|
|
||||||
if(DEBUG_MODE)
|
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()
|
else()
|
||||||
add_definitions(-O2)
|
add_definitions(-O2)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -54,6 +54,7 @@ GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name);
|
||||||
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock);
|
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock);
|
||||||
WindowDataT *utilGetWindowData(GtkWidget *window);
|
WindowDataT *utilGetWindowData(GtkWidget *window);
|
||||||
gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData);
|
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);
|
gboolean utilMkDirP(const char *dir, const mode_t mode);
|
||||||
char *utilObfuscateASCII(char *clearText);
|
char *utilObfuscateASCII(char *clearText);
|
||||||
gboolean utilQuestionDialog(GtkWidget *parent, char *title, char *question);
|
gboolean utilQuestionDialog(GtkWidget *parent, char *title, char *question);
|
||||||
|
|
102
src/editor.c
102
src/editor.c
|
@ -20,6 +20,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "editor.h"
|
#include "editor.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -42,12 +44,29 @@ typedef struct EditorDataS {
|
||||||
guint statusBarId;
|
guint statusBarId;
|
||||||
} EditorDataT;
|
} 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 int _nextEditorId = 0;
|
||||||
|
|
||||||
|
|
||||||
static void clearEditor(EditorDataT *self);
|
static void clearEditor(EditorDataT *self);
|
||||||
|
static int determineLexer(char *filename);
|
||||||
EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData);
|
EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData);
|
||||||
|
static gboolean fileIsSupported(char *filename);
|
||||||
static void loadEditor(EditorDataT *self);
|
static void loadEditor(EditorDataT *self);
|
||||||
static void loadEditorConfig(char *lexer, EditorDataT *self);
|
static void loadEditorConfig(char *lexer, EditorDataT *self);
|
||||||
EVENT void menuEditorEditCopy(GtkWidget *object, gpointer userData);
|
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 menuEditorFileSave(GtkWidget *object, gpointer userData);
|
||||||
EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData);
|
EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData);
|
||||||
EVENT void menuEditorHelpEditor(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);
|
static void status(EditorDataT *self, char *message);
|
||||||
EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData);
|
EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData);
|
||||||
static void winEditorDelete(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) {
|
EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData) {
|
||||||
EditorDataT *self = (EditorDataT *)userData;
|
EditorDataT *self = (EditorDataT *)userData;
|
||||||
int lineNumber = (int)SSM(SCI_LINEFROMPOSITION, (uptr_t)notifyData->position, (sptr_t)0);
|
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) {
|
static void loadEditor(EditorDataT *self) {
|
||||||
FILE *in = NULL;
|
FILE *in = NULL;
|
||||||
char *line = 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?")) {
|
if (!utilQuestionDialog(self->windowData.window, "New", "You have unsaved changes. Start new?")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
status(self, "New image.");
|
status(self, "New document.");
|
||||||
}
|
}
|
||||||
|
|
||||||
clearEditor(self);
|
clearEditor(self);
|
||||||
|
@ -280,6 +349,9 @@ EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData) {
|
||||||
// Clear any filename.
|
// Clear any filename.
|
||||||
DEL(self->windowData.filename);
|
DEL(self->windowData.filename);
|
||||||
|
|
||||||
|
// Clear lexer.
|
||||||
|
setLexer(self, -1);
|
||||||
|
|
||||||
// Mark clean.
|
// Mark clean.
|
||||||
utilSetDirty((WindowDataT *)self, FALSE);
|
utilSetDirty((WindowDataT *)self, FALSE);
|
||||||
}
|
}
|
||||||
|
@ -291,7 +363,9 @@ EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData) {
|
||||||
(void)object;
|
(void)object;
|
||||||
|
|
||||||
if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) {
|
if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) {
|
||||||
|
if (!fileIsSupported(self->windowData.filename)) return;
|
||||||
clearEditor(self);
|
clearEditor(self);
|
||||||
|
setLexer(self, determineLexer(self->windowData.filename));
|
||||||
loadEditor(self);
|
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);
|
message(MSG_SEVERE, "Unknown error attempting to save %s!", self->windowData.filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Did the lexer change?
|
||||||
|
setLexer(self, determineLexer(self->windowData.filename));
|
||||||
|
|
||||||
// Release code.
|
// Release code.
|
||||||
DEL(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) {
|
static void status(EditorDataT *self, char *message) {
|
||||||
gtk_statusbar_remove_all(GTK_STATUSBAR(self->statusBar), self->statusBarId);
|
gtk_statusbar_remove_all(GTK_STATUSBAR(self->statusBar), self->statusBarId);
|
||||||
gtk_statusbar_push(GTK_STATUSBAR(self->statusBar), self->statusBarId, message);
|
gtk_statusbar_push(GTK_STATUSBAR(self->statusBar), self->statusBarId, message);
|
||||||
|
@ -397,7 +488,7 @@ void winEditorCreate(char *filename) {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
//***TODO*** Be sure this is something we can edit as text.
|
if (filename && !fileIsSupported(filename)) return;
|
||||||
|
|
||||||
// Set up instance data.
|
// Set up instance data.
|
||||||
self = NEW(EditorDataT);
|
self = NEW(EditorDataT);
|
||||||
|
@ -466,12 +557,7 @@ void winEditorCreate(char *filename) {
|
||||||
SSM(SCI_MARKERDEFINE, MARKER_ERROR_HIGHLIGHT, SC_MARK_BACKGROUND); // Error
|
SSM(SCI_MARKERDEFINE, MARKER_ERROR_HIGHLIGHT, SC_MARK_BACKGROUND); // Error
|
||||||
SSM(SCI_MARKERSETBACK, MARKER_ERROR_HIGHLIGHT, 127 | (0 << 8) | (0 << 16)); // RGB
|
SSM(SCI_MARKERSETBACK, MARKER_ERROR_HIGHLIGHT, 127 | (0 << 8) | (0 << 16)); // RGB
|
||||||
|
|
||||||
// Add lexer for language support.
|
setLexer(self, determineLexer(filename));
|
||||||
self->pLexer = CreateLexer("cpp");
|
|
||||||
SSM(SCI_SETILEXER, 0, (sptr_t)self->pLexer);
|
|
||||||
|
|
||||||
writeEditorConfig("cpp", self);
|
|
||||||
loadEditorConfig("cpp", self);
|
|
||||||
|
|
||||||
// Connect editor to our code.
|
// Connect editor to our code.
|
||||||
g_signal_connect(G_OBJECT(self->editor), "sci-notify", G_CALLBACK(editorEditorNotify), self);
|
g_signal_connect(G_OBJECT(self->editor), "sci-notify", G_CALLBACK(editorEditorNotify), self);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "cwalk.h"
|
||||||
|
|
||||||
|
|
||||||
char *__resourcePath = NULL;
|
char *__resourcePath = NULL;
|
||||||
|
@ -38,6 +39,12 @@ int main(int argc, char **argv) {
|
||||||
unlink("memwatch.log");
|
unlink("memwatch.log");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
cwk_path_set_style(CWK_STYLE_WINDOWS);
|
||||||
|
#else
|
||||||
|
cwk_path_set_style(CWK_STYLE_UNIX);
|
||||||
|
#endif
|
||||||
|
|
||||||
gtk_init(&argc, &argv);
|
gtk_init(&argc, &argv);
|
||||||
|
|
||||||
// Make sure we have a config & resources folder.
|
// Make sure we have a config & resources folder.
|
||||||
|
|
27
src/utils.c
27
src/utils.c
|
@ -310,7 +310,7 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha
|
||||||
GtkFileFilter *filter;
|
GtkFileFilter *filter;
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
char *files = utilCreateString("%s Files", what);
|
char *files = utilCreateString("%s Files", what);
|
||||||
int x;
|
size_t x;
|
||||||
|
|
||||||
dialog = gtk_file_chooser_dialog_new("Save As",
|
dialog = gtk_file_chooser_dialog_new("Save As",
|
||||||
GTK_WINDOW(self->window),
|
GTK_WINDOW(self->window),
|
||||||
|
@ -321,7 +321,7 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha
|
||||||
|
|
||||||
if (*filename != NULL) {
|
if (*filename != NULL) {
|
||||||
memcpy(__utilFilenameBuffer, *filename, strlen(*filename) + 1);
|
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;
|
if (x > 0) __utilFilenameBuffer[x] = 0;
|
||||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),__utilFilenameBuffer);
|
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) {
|
gboolean utilMkDirP(const char *dir, const mode_t mode) {
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
@ -584,15 +599,15 @@ void utilSetDirty(WindowDataT *self, gboolean dirty) {
|
||||||
|
|
||||||
|
|
||||||
void utilUpdatePath(WindowDataT *self) {
|
void utilUpdatePath(WindowDataT *self) {
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
|
DEL(self->path);
|
||||||
|
|
||||||
if (self->filename) {
|
if (self->filename) {
|
||||||
// Derive the path from the filename.
|
// Derive the path from the filename.
|
||||||
self->path = strdup(self->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;
|
if (i > 0) self->path[i] = 0;
|
||||||
} else {
|
|
||||||
DEL(self->path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue