Warning and error links for GCC based targets are now working with the code editor.
This commit is contained in:
parent
0d50e3bc83
commit
99010a03bd
4 changed files with 161 additions and 28 deletions
|
@ -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
|
||||||
|
|
80
src/editor.c
80
src/editor.c
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue