Warning and error links for GCC based targets are now working with the code editor.

This commit is contained in:
Scott Duensing 2023-06-03 19:26:19 -05:00
parent 0d50e3bc83
commit 99010a03bd
4 changed files with 161 additions and 28 deletions

View file

@ -24,7 +24,11 @@
#define EDITOR_H #define EDITOR_H
#include "common.h"
void winEditorCreate(char *filename); void winEditorCreate(char *filename);
void winEditorGoto(char *filename, size_t line, size_t column);
#endif // EDITOR_H #endif // EDITOR_H

View file

@ -22,7 +22,6 @@
#include <ctype.h> #include <ctype.h>
#include "common.h"
#include "editor.h" #include "editor.h"
#include "utils.h" #include "utils.h"
#include "scintillaHeaders.h" #include "scintillaHeaders.h"
@ -42,6 +41,9 @@ typedef struct EditorDataS {
void *pLexer; void *pLexer;
int id; int id;
guint statusBarId; guint statusBarId;
size_t textLine;
size_t textColumn;
gboolean editorPainted;
} EditorDataT; } EditorDataT;
typedef struct LexerDataS { typedef struct LexerDataS {
@ -50,6 +52,8 @@ typedef struct LexerDataS {
} LexerDataT; } LexerDataT;
static EditorDataT **_editorWindows = NULL;
static LexerDataT _lexerInfo[] = { static LexerDataT _lexerInfo[] = {
{ "h", "cpp" }, { "h", "cpp" },
{ "c", "cpp" }, { "c", "cpp" },
@ -67,6 +71,7 @@ static void clearEditor(EditorDataT *self);
static int determineLexer(char *filename); 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 gboolean fileIsSupported(char *filename);
static EditorDataT *isAlreadyOpen(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);
@ -83,6 +88,7 @@ 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);
static gboolean winEditorGotoUpdate(gpointer userData);
static void writeEditorConfig(char *lexer, EditorDataT *self); static void writeEditorConfig(char *lexer, EditorDataT *self);
@ -157,6 +163,9 @@ EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotifi
} }
break; break;
case SCN_PAINTED:
self->editorPainted = TRUE;
break;
} }
} }
@ -174,6 +183,20 @@ static gboolean fileIsSupported(char *filename) {
} }
static EditorDataT *isAlreadyOpen(char *filename) {
int i;
for (i=0; i<arrlen(_editorWindows); i++) {
if (strcmp(_editorWindows[i]->windowData.filename, filename) == 0) {
// Focus the existing window.
gtk_window_present_with_time(GTK_WINDOW(_editorWindows[i]->windowData.window), GDK_CURRENT_TIME);
return _editorWindows[i];
}
}
return NULL;
}
static void loadEditor(EditorDataT *self) { static void loadEditor(EditorDataT *self) {
FILE *in = NULL; FILE *in = NULL;
char *line = NULL; char *line = NULL;
@ -364,6 +387,10 @@ EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData) {
if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) { if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) {
if (!fileIsSupported(self->windowData.filename)) return; if (!fileIsSupported(self->windowData.filename)) return;
if (isAlreadyOpen(self->windowData.filename) != NULL) {
DEL(self->windowData.filename);
return;
}
clearEditor(self); clearEditor(self);
setLexer(self, determineLexer(self->windowData.filename)); setLexer(self, determineLexer(self->windowData.filename));
loadEditor(self); loadEditor(self);
@ -421,6 +448,7 @@ EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData) {
(void)object; (void)object;
//***TODO*** If they save over an existing file that is open to edit they will have two editors open on the same filename.
if (utilFileSaveAs((WindowDataT *)userData, "*.*", "Code")) { if (utilFileSaveAs((WindowDataT *)userData, "*.*", "Code")) {
menuEditorFileSave(object, (EditorDataT *)userData); menuEditorFileSave(object, (EditorDataT *)userData);
} }
@ -488,8 +516,12 @@ void winEditorCreate(char *filename) {
NULL NULL
}; };
// Can we edit this?
if (filename && !fileIsSupported(filename)) return; if (filename && !fileIsSupported(filename)) return;
// Is there already an editor window open for this file?
if (isAlreadyOpen(filename) != NULL) return;
// Set up instance data. // Set up instance data.
self = NEW(EditorDataT); self = NEW(EditorDataT);
self->windowData.closeWindow = winEditorClose; self->windowData.closeWindow = winEditorClose;
@ -565,6 +597,9 @@ void winEditorCreate(char *filename) {
// Show window. // Show window.
gtk_widget_show_all(self->windowData.window); gtk_widget_show_all(self->windowData.window);
// Remember window.
arrput(_editorWindows, self);
if (filename != NULL) { if (filename != NULL) {
self->windowData.filename = strdup(filename); self->windowData.filename = strdup(filename);
loadEditor(self); loadEditor(self);
@ -574,16 +609,59 @@ void winEditorCreate(char *filename) {
static void winEditorDelete(gpointer userData) { static void winEditorDelete(gpointer userData) {
EditorDataT *self = (EditorDataT *)userData; EditorDataT *self = (EditorDataT *)userData;
int i;
// Scintilla keeps sending events after we delete things it expects to still exist. Prevent that. // Scintilla keeps sending events after we delete things it expects to still exist. Prevent that.
g_signal_handlers_disconnect_by_func(G_OBJECT(self->editor), G_CALLBACK(editorEditorNotify), self); g_signal_handlers_disconnect_by_func(G_OBJECT(self->editor), G_CALLBACK(editorEditorNotify), self);
// Remove from open results window list.
for (i=0; i<arrlen(_editorWindows); i++) {
if (_editorWindows[i] == self) {
arrdel(_editorWindows, i);
break;
}
}
utilWindowUnRegister(userData); utilWindowUnRegister(userData);
DEL(self); DEL(self);
} }
void winEditorGoto(char *filename, size_t line, size_t column) {
EditorDataT *self = NULL;
// Ensure the editor exists.
winEditorCreate(filename);
// Find it.
self = isAlreadyOpen(filename);
if (self != NULL) {
// Move caret after GTK has a bit to settle down.
self->textLine = line;
self->textColumn = column;
self->editorPainted = FALSE;
g_idle_add(winEditorGotoUpdate, self);
}
}
static gboolean winEditorGotoUpdate(gpointer userData) {
EditorDataT *self = (EditorDataT *)userData;
int position;
// Wait for Scintilla to be ready.
if (self->editorPainted == FALSE) return G_SOURCE_CONTINUE;
// Move caret.
SSM(SCI_GRABFOCUS, 0, 0);
position = SSM(SCI_POSITIONFROMLINE, (uptr_t)self->textLine, (sptr_t)0) + self->textColumn;
SSM(SCI_GOTOPOS, (uptr_t)position, (sptr_t)0);
return G_SOURCE_REMOVE;
}
static void writeEditorConfig(char *lexer, EditorDataT *self) { static void writeEditorConfig(char *lexer, EditorDataT *self) {
char *name = NULL; char *name = NULL;
char *tags = NULL; char *tags = NULL;

View file

@ -27,6 +27,7 @@
#include "common.h" #include "common.h"
#include "results.h" #include "results.h"
#include "utils.h" #include "utils.h"
#include "editor.h"
typedef struct ResultsDataS { typedef struct ResultsDataS {
@ -45,6 +46,7 @@ typedef struct ResultsDataS {
static ResultsDataT **_resultWindows = NULL; static ResultsDataT **_resultWindows = NULL;
EVENT void messageClicked(GtkButton *widget, gpointer userData);
EVENT void resultClicked(GtkButton *widget, gpointer userData); EVENT void resultClicked(GtkButton *widget, gpointer userData);
static void resultLoadRaw(gboolean release, int target, int arch, ResultsDataT *self); static void resultLoadRaw(gboolean release, int target, int arch, ResultsDataT *self);
static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *self); static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *self);
@ -53,6 +55,34 @@ EVENT gboolean winBuildResultsClose(GtkWidget *object, gpointer userData);
static void winBuildResultsDelete(gpointer userData); static void winBuildResultsDelete(gpointer userData);
EVENT void messageClicked(GtkButton *widget, gpointer userData) {
ResultsDataT *self = (ResultsDataT *)userData;
const char *name = gtk_widget_get_name(GTK_WIDGET(widget));
char *tok;
char *temp;
char *file;
size_t line;
size_t column;
gboolean isWarning;
// Extract info from button name.
tok = strdup(name);
temp = strtok(tok, ":");
isWarning = (temp[0] == 'w');
temp = strtok(NULL, ":");
file = utilCreateString("%s%s", self->project->windowData.path, temp);
temp = strtok(NULL, ":");
line = atol(temp);
temp = strtok(NULL, ":");
column = atol(temp);
winEditorGoto(file, line, column);
DEL(tok);
DEL(file);
}
EVENT void resultClicked(GtkButton *widget, gpointer userData) { EVENT void resultClicked(GtkButton *widget, gpointer userData) {
ResultsDataT *self = (ResultsDataT *)userData; ResultsDataT *self = (ResultsDataT *)userData;
const char *name = gtk_widget_get_name(GTK_WIDGET(widget)); const char *name = gtk_widget_get_name(GTK_WIDGET(widget));
@ -60,9 +90,9 @@ EVENT void resultClicked(GtkButton *widget, gpointer userData) {
int a; int a;
gboolean r; gboolean r;
// Highlight the button pressed button. // Highlight the pressed button.
gtk_button_set_relief(widget, GTK_RELIEF_NONE); gtk_button_set_relief(widget, GTK_RELIEF_NORMAL);
gtk_button_set_relief(GTK_BUTTON(self->pressedButton), GTK_RELIEF_NORMAL); gtk_button_set_relief(GTK_BUTTON(self->pressedButton), GTK_RELIEF_NONE);
self->pressedButton = GTK_WIDGET(widget); self->pressedButton = GTK_WIDGET(widget);
// Extract button info from widget name. // Extract button info from widget name.
@ -127,7 +157,11 @@ static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *sel
GtkWidget *button; GtkWidget *button;
int i; int i;
char *temp; char *temp;
char *tok;
char *text; char *text;
char *file;
size_t line;
size_t column;
gboolean isWarning; gboolean isWarning;
messages = release ? self->lstRelease : self->lstDebug; messages = release ? self->lstRelease : self->lstDebug;
@ -135,6 +169,9 @@ static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *sel
for (i=0; i<arrlen(lineArray); i++) { for (i=0; i<arrlen(lineArray); i++) {
text = NULL; text = NULL;
isWarning = FALSE; isWarning = FALSE;
file = NULL;
line = 0;
column = 0;
// ***TODO*** This is going to need to be a lot more complicated. // ***TODO*** This is going to need to be a lot more complicated.
// We need the line number and filename from multiple compilers. // We need the line number and filename from multiple compilers.
@ -145,6 +182,17 @@ static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *sel
if (strstr(lineArray[i], " error: ") != NULL) { if (strstr(lineArray[i], " error: ") != NULL) {
text = lineArray[i]; text = lineArray[i];
} }
if (text) {
tok = strdup(text);
temp = strtok(tok, ":");
file = strdup(temp);
temp = strtok(NULL, ":");
line = atol(temp) - 1;
temp = strtok(NULL, ":");
column = atol(temp) - 1;
DEL(tok);
}
// --- The above is basically GCC only. And lame.
if (text) { if (text) {
// New listbox row. // New listbox row.
@ -154,10 +202,11 @@ static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *sel
// Icon button. // Icon button.
button = gtk_button_new_from_icon_name(isWarning ? "dialog-warning" : "dialog-error", GTK_ICON_SIZE_BUTTON); button = gtk_button_new_from_icon_name(isWarning ? "dialog-warning" : "dialog-error", GTK_ICON_SIZE_BUTTON);
temp = utilCreateString("%c", isWarning ? 'w' : 'e'); // We store data about this button in its name. temp = utilCreateString("%c:%s:%lu:%lu", isWarning ? 'w' : 'e', file, line, column); // We store data about this button in its name.
gtk_widget_set_name(button, temp); gtk_widget_set_name(button, temp);
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
DEL(temp); DEL(temp);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(messageClicked), self);
// Message. // Message.
label = gtk_label_new(text); label = gtk_label_new(text);
@ -240,6 +289,7 @@ static void resultsUpdate(ResultsDataT *self) {
temp = utilCreateString("d%da%d", i, j); // We store data about this button in its name. temp = utilCreateString("d%da%d", i, j); // We store data about this button in its name.
gtk_widget_set_name(w, temp); gtk_widget_set_name(w, temp);
DEL(temp); DEL(temp);
gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
gtk_grid_attach(GTK_GRID(self->gridResults), w, 2, gridLine, 1, 1); gtk_grid_attach(GTK_GRID(self->gridResults), w, 2, gridLine, 1, 1);
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self);
@ -248,13 +298,14 @@ static void resultsUpdate(ResultsDataT *self) {
temp = utilCreateString("r%da%d", i, j); // We store data about this button in its name. temp = utilCreateString("r%da%d", i, j); // We store data about this button in its name.
gtk_widget_set_name(w, temp); gtk_widget_set_name(w, temp);
DEL(temp); DEL(temp);
gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
gtk_grid_attach(GTK_GRID(self->gridResults), w, 3, gridLine, 1, 1); gtk_grid_attach(GTK_GRID(self->gridResults), w, 3, gridLine, 1, 1);
g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self);
if (firstSystem < 0) { if (firstSystem < 0) {
firstSystem = i; firstSystem = i;
// Highlight the button pressed button. // Highlight the button pressed button.
gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE); gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
self->pressedButton = w; self->pressedButton = w;
} }