601 lines
17 KiB
C
601 lines
17 KiB
C
/*
|
|
* JoeyDev
|
|
* Copyright (C) 2018-2023 Scott Duensing <scott@kangaroopunch.com>
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
|
|
#include "common.h"
|
|
#include "editor.h"
|
|
#include "utils.h"
|
|
#include "scintillaHeaders.h"
|
|
|
|
|
|
#define MARKER_ERROR_ARROW 0
|
|
#define MARKER_ERROR_HIGHLIGHT 1
|
|
|
|
|
|
typedef struct EditorDataS {
|
|
WindowDataT windowData;
|
|
GtkWidget *boxForEditor;
|
|
GtkWidget *statusBar;
|
|
GtkWidget *editor;
|
|
ScintillaObject *sci;
|
|
void *pLexer;
|
|
int id;
|
|
int statusBarId;
|
|
} EditorDataT;
|
|
|
|
|
|
static int _nextEditorId = 0;
|
|
|
|
|
|
static void clearEditor(EditorDataT *self);
|
|
EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData);
|
|
static void loadEditor(EditorDataT *self);
|
|
static void loadEditorConfig(char *lexer, EditorDataT *self);
|
|
EVENT void menuEditorEditCopy(GtkWidget *object, gpointer userData);
|
|
EVENT void menuEditorEditCut(GtkWidget *object, gpointer userData);
|
|
EVENT void menuEditorEditDelete(GtkWidget *object, gpointer userData);
|
|
EVENT void menuEditorEditPaste(GtkWidget *object, gpointer userData);
|
|
EVENT void menuEditorFileClose(GtkWidget *object, gpointer userData);
|
|
EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData);
|
|
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 status(EditorDataT *self, char *message);
|
|
EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData);
|
|
static void winEditorDelete(gpointer userData);
|
|
static void writeEditorConfig(char *lexer, EditorDataT *self);
|
|
|
|
|
|
static void clearEditor(EditorDataT *self) {
|
|
(void)self;
|
|
|
|
// Clear editor.
|
|
SSM(SCI_CLEARALL, 0, 0);
|
|
|
|
// Clear error markers.
|
|
SSM(SCI_MARKERDELETEALL, MARKER_ERROR_ARROW, 0);
|
|
SSM(SCI_MARKERDELETEALL, MARKER_ERROR_HIGHLIGHT, 0);
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
(void)sciWidget;
|
|
(void)ctrlID;
|
|
|
|
switch (notifyData->nmhdr.code) {
|
|
case SCN_MODIFIED:
|
|
if (notifyData->modificationType & SC_MOD_INSERTTEXT || notifyData->modificationType & SC_MOD_DELETETEXT) {
|
|
// Mark text dirty. SCN_SAVEPOINTLEFT isn't being reliable.
|
|
utilSetDirty((WindowDataT *)self, TRUE);
|
|
}
|
|
break;
|
|
|
|
case SCN_MARGINCLICK:
|
|
switch (notifyData->margin) {
|
|
case MARGIN_SCRIPT_FOLD_INDEX:
|
|
SSM(SCI_TOGGLEFOLD, lineNumber, (sptr_t)0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void loadEditor(EditorDataT *self) {
|
|
FILE *in = NULL;
|
|
char *line = NULL;
|
|
size_t len = 0;
|
|
|
|
in = fopen(self->windowData.filename, "rt");
|
|
if (in != NULL) {
|
|
utilEnsureBufferSize((unsigned char **)&line, (int *)&len, 1024); // Not technically needed, but fixes a pointer warning from memmaker.
|
|
while (getline(&line, &len, in) != -1) {
|
|
SSM(SCI_ADDTEXT, strlen(line), (sptr_t)line);
|
|
}
|
|
fclose(in);
|
|
DEL(line);
|
|
}
|
|
|
|
// Do again - loading text marks us dirty.
|
|
utilSetDirty((WindowDataT *)self, FALSE);
|
|
}
|
|
|
|
|
|
static void loadEditorConfig(char *lexer, EditorDataT *self) {
|
|
char *config = NULL;
|
|
FILE *in = NULL;
|
|
char *line = NULL;
|
|
size_t len = 0;
|
|
char *c = NULL;
|
|
char *type = NULL;
|
|
char *name = NULL;
|
|
unsigned int number;
|
|
unsigned int integer;
|
|
|
|
config = utilCreateString("%s%cjoeydev%ceditor-%s.conf", g_get_user_config_dir(), UTIL_PATH_CHAR, UTIL_PATH_CHAR, lexer);
|
|
if (!utilFileExists(config)) {
|
|
// Nothing to load.
|
|
DEL(config);
|
|
return;
|
|
}
|
|
|
|
in = fopen(config, "rt");
|
|
DEL(config);
|
|
|
|
if (in) {
|
|
// Load config.
|
|
utilEnsureBufferSize((unsigned char **)&line, (int *)&len, 4096); // Not technically needed, but fixes a pointer warning from memmaker.
|
|
while (getline(&line, &len, in) != -1) {
|
|
if (strlen(line) > 0) line[strlen(line) - 1] = 0;
|
|
c = utilGetToken(line, " ", "\"", "\"");
|
|
utilDequote(c);
|
|
|
|
// Is this a 'style' line?
|
|
if (strcasecmp(c, "style") == 0) {
|
|
// style number "tags" "description" ... (style keywords)
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
number = strtol(c, NULL, 10);
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
do {
|
|
if (strcmp(c, "fore") == 0) {
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
integer = strtol(c, NULL, 16);
|
|
SSM(SCI_STYLESETFORE, number, integer);
|
|
}
|
|
if (strcmp(c, "back") == 0) {
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
integer = strtol(c, NULL, 16);
|
|
SSM(SCI_STYLESETBACK, number, integer);
|
|
}
|
|
if (strcmp(c, "bold") == 0) {
|
|
SSM(SCI_STYLESETBOLD, number, 1);
|
|
}
|
|
if (strcmp(c, "italic") == 0) {
|
|
SSM(SCI_STYLESETITALIC, number, 1);
|
|
}
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
} while (c != NULL);
|
|
continue;
|
|
}
|
|
|
|
// Is this a 'property' line?
|
|
if (strcasecmp(c, "property") == 0) {
|
|
// property type name "description" value
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
type = strdup(c);
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
name = strdup(c);
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
utilDequote(c);
|
|
SSM(SCI_SETPROPERTY, (sptr_t)name, (sptr_t)c);
|
|
DEL(name);
|
|
DEL(type);
|
|
continue;
|
|
}
|
|
|
|
// Is this a 'keywords' line?
|
|
if (strcasecmp(c, "keywords") == 0) {
|
|
// keywords number "description" wordlist
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
number = strtol(c, NULL, 10);
|
|
c = utilGetToken(NULL, " ", "\"", "\"");
|
|
c = utilGetToken(NULL, "\n", "\"", "\"");
|
|
if (c && strlen(c) > 0) SSM(SCI_SETKEYWORDS, number, (sptr_t)c);
|
|
continue;
|
|
}
|
|
}
|
|
DEL(line);
|
|
fclose(in);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
EVENT void menuEditorEditCopy(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
SSM(SCI_COPY, 0, 0);
|
|
}
|
|
|
|
|
|
EVENT void menuEditorEditCut(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
SSM(SCI_CUT, 0, 0);
|
|
}
|
|
|
|
|
|
EVENT void menuEditorEditDelete(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
SSM(SCI_CLEAR, 0, 0);
|
|
}
|
|
|
|
|
|
EVENT void menuEditorEditPaste(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
SSM(SCI_PASTE, 0, 0);
|
|
}
|
|
|
|
|
|
EVENT void menuEditorFileClose(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
gtk_window_close(GTK_WINDOW(self->windowData.window));
|
|
}
|
|
|
|
|
|
EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
if (self->windowData.isDirty == TRUE) {
|
|
if (!utilQuestionDialog(self->windowData.window, "New", "You have unsaved changes. Start new?")) {
|
|
return;
|
|
}
|
|
status(self, "New image.");
|
|
}
|
|
|
|
clearEditor(self);
|
|
|
|
// Clear any filename.
|
|
DEL(self->windowData.filename);
|
|
|
|
// Mark clean.
|
|
utilSetDirty((WindowDataT *)self, FALSE);
|
|
}
|
|
|
|
|
|
EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
(void)object;
|
|
|
|
if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) {
|
|
clearEditor(self);
|
|
loadEditor(self);
|
|
}
|
|
}
|
|
|
|
|
|
EVENT void menuEditorFileSave(GtkWidget *object, gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
int length = SSM(SCI_GETLENGTH, 0, 0);
|
|
FILE *out = NULL;
|
|
char *code = NULL;
|
|
|
|
// Do we need to save?
|
|
if (self->windowData.isDirty == TRUE) {
|
|
|
|
// Do we have a filename? If not, kick 'em to SaveAs.
|
|
if (self->windowData.filename == NULL) {
|
|
menuEditorFileSaveAs(object, userData);
|
|
return;
|
|
}
|
|
|
|
// Allocate space to fetch code from editor.
|
|
code = (char *)malloc(length + 1);
|
|
if (!code) {
|
|
//***TODO*** Something bad happened.
|
|
return;
|
|
}
|
|
|
|
// Fetch code.
|
|
SSM(SCI_GETTEXT, length, (sptr_t)code);
|
|
|
|
out = fopen(self->windowData.filename, "wt");
|
|
if (out != NULL) {
|
|
// Save!
|
|
fprintf(out, "%s\n", code);
|
|
fclose(out);
|
|
status(self, "Saved.");
|
|
// We're clean now.
|
|
utilSetDirty((WindowDataT *)self, FALSE);
|
|
} else {
|
|
//***TODO*** Something bad happened.
|
|
}
|
|
|
|
// Release code.
|
|
DEL(code);
|
|
}
|
|
}
|
|
|
|
|
|
EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData) {
|
|
|
|
(void)object;
|
|
|
|
if (utilFileSaveAs((WindowDataT *)userData, "*.*", "Code")) {
|
|
menuEditorFileSave(object, (EditorDataT *)userData);
|
|
}
|
|
}
|
|
|
|
|
|
EVENT void menuEditorHelpEditor(GtkWidget *object, gpointer userData) {
|
|
(void)object;
|
|
(void)userData;
|
|
|
|
gtk_show_uri_on_window(NULL, "https://skunkworks.kangaroopunch.com/skunkworks/joeydev/-/wikis/Code-Editor", GDK_CURRENT_TIME, NULL);
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData) {
|
|
// userData is not reliable due to menuVectorFileClose and util indirectly calling us.
|
|
EditorDataT *self = (EditorDataT *)utilGetWindowData(object);
|
|
|
|
(void)userData;
|
|
|
|
if (self->windowData.isDirty == TRUE) {
|
|
if (utilQuestionDialog(self->windowData.window, "Exit", "You have unsaved changes. Exit?")) {
|
|
winEditorDelete(self);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
winEditorDelete(self);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void winEditorCreate(char *filename) {
|
|
EditorDataT *self;
|
|
char *widgetNames[] = {
|
|
"winEditor",
|
|
"boxEditorForEditor",
|
|
"statusEditor",
|
|
NULL
|
|
};
|
|
GtkWidget **widgets[] = {
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
// Set up instance data.
|
|
self = NEW(EditorDataT);
|
|
self->windowData.closeWindow = winEditorClose;
|
|
|
|
// Load widgets from XML.
|
|
widgets[0] = &self->windowData.window;
|
|
widgets[1] = &self->boxForEditor;
|
|
widgets[2] = &self->statusBar;
|
|
utilGetWidgetsFromMemory("/com/kangaroopunch/joeydev/Editor.glade", widgetNames, widgets, self);
|
|
|
|
// Register window.
|
|
utilWindowRegister(self);
|
|
|
|
// Get status bar context ID.
|
|
self->statusBarId = gtk_statusbar_get_context_id(GTK_STATUSBAR(self->statusBar), "JoeyDev");
|
|
|
|
// Create Scintilla editor.
|
|
self->editor = scintilla_new();
|
|
self->sci = SCINTILLA(self->editor);
|
|
self->id = _nextEditorId++;
|
|
scintilla_set_id(self->sci, self->id);
|
|
gtk_widget_set_halign(self->editor, GTK_ALIGN_FILL);
|
|
gtk_widget_set_valign(self->editor, GTK_ALIGN_FILL);
|
|
gtk_widget_set_hexpand(self->editor, TRUE);
|
|
gtk_widget_set_vexpand(self->editor, TRUE);
|
|
gtk_box_set_child_packing(GTK_BOX(self->boxForEditor), self->editor, TRUE, TRUE, 0, GTK_PACK_START);
|
|
gtk_container_add(GTK_CONTAINER(self->boxForEditor), self->editor);
|
|
|
|
// Configure editor.
|
|
SSM(SCI_SETCODEPAGE, SC_CP_UTF8, 0);
|
|
SSM(SCI_SETIMEINTERACTION, SC_IME_WINDOWED, 0);
|
|
SSM(SCI_STYLESETCHARACTERSET, STYLE_DEFAULT, SC_CHARSET_DEFAULT);
|
|
SSM(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Monospace");
|
|
SSM(SCI_STYLESETSIZEFRACTIONAL, STYLE_DEFAULT, 11 * SC_FONT_SIZE_MULTIPLIER);
|
|
SSM(SCI_STYLESETFORE, STYLE_DEFAULT, 0xFFFFFF);
|
|
SSM(SCI_STYLESETBACK, STYLE_DEFAULT, 0);
|
|
SSM(SCI_STYLECLEARALL, 0, 0);
|
|
SSM(SCI_SETTABWIDTH, 3, 0);
|
|
//SSM(SCI_SETEOLMODE, SC_EOL_CR, 0);
|
|
SSM(SCI_SETMARGINWIDTHN, 0, (int)SSM(SCI_TEXTWIDTH, STYLE_LINENUMBER, (sptr_t)"_99999"));
|
|
SSM(SCI_SETMARGINWIDTHN, 1, 16);
|
|
SSM(SCI_SETWRAPMODE, SC_WRAP_NONE, 0);
|
|
SSM(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK | CARETSTYLE_OVERSTRIKE_BLOCK, 0);
|
|
SSM(SCI_SETCARETFORE, 0x00ffff, 0);
|
|
SSM(SCI_STYLESETBACK, STYLE_LINENUMBER, 0x222222);
|
|
|
|
SSM(SCI_SETFOLDMARGINCOLOUR, 1, 0x222222);
|
|
SSM(SCI_SETFOLDMARGINHICOLOUR, 1, 0x222222);
|
|
SSM(SCI_SETMARGINTYPEN, MARGIN_SCRIPT_FOLD_INDEX, SC_MARGIN_SYMBOL);
|
|
SSM(SCI_SETMARGINMASKN, MARGIN_SCRIPT_FOLD_INDEX, SC_MASK_FOLDERS);
|
|
SSM(SCI_SETMARGINWIDTHN, MARGIN_SCRIPT_FOLD_INDEX, 20);
|
|
SSM(SCI_SETMARGINSENSITIVEN, MARGIN_SCRIPT_FOLD_INDEX, 1);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
|
|
SSM(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
|
|
SSM(SCI_SETFOLDFLAGS, SC_FOLDFLAG_LINEAFTER_CONTRACTED , 0);
|
|
|
|
// Margin markers.
|
|
SSM(SCI_MARKERDEFINE, MARKER_ERROR_ARROW, SC_MARK_SHORTARROW); // Error
|
|
SSM(SCI_MARKERSETBACK, MARKER_ERROR_ARROW, 255 | (0 << 8) | (0 << 16)); // RGB
|
|
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);
|
|
|
|
// Connect editor to our code.
|
|
g_signal_connect(G_OBJECT(self->editor), "sci-notify", G_CALLBACK(editorEditorNotify), self);
|
|
|
|
// Show window.
|
|
gtk_widget_show_all(self->windowData.window);
|
|
|
|
if (filename != NULL) {
|
|
self->windowData.filename = strdup(filename);
|
|
loadEditor(self);
|
|
}
|
|
}
|
|
|
|
|
|
static void winEditorDelete(gpointer userData) {
|
|
EditorDataT *self = (EditorDataT *)userData;
|
|
|
|
// 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);
|
|
|
|
utilWindowUnRegister(userData);
|
|
|
|
DEL(self);
|
|
}
|
|
|
|
|
|
static void writeEditorConfig(char *lexer, EditorDataT *self) {
|
|
char *name = NULL;
|
|
char *tags = NULL;
|
|
char *description = NULL;
|
|
char *config = NULL;
|
|
FILE *out = NULL;
|
|
int result = -1;
|
|
int size = -1;
|
|
int x;
|
|
|
|
config = utilCreateString("%s%cjoeydev%ceditor-%s.conf", g_get_user_config_dir(), UTIL_PATH_CHAR, UTIL_PATH_CHAR, lexer);
|
|
if (utilFileExists(config)) {
|
|
// Don't clobber existing files.
|
|
DEL(config);
|
|
return;
|
|
}
|
|
|
|
out = fopen(config, "wt");
|
|
DEL(config);
|
|
|
|
if (out) {
|
|
// Header
|
|
fprintf(out, "%s\n", LEXER_VERSION);
|
|
fprintf(out, "------------------------------------------------------------------------------\n");
|
|
|
|
// Styles
|
|
result = SSM(SCI_GETNAMEDSTYLES, 0, 0);
|
|
if (result > 0) {
|
|
for (x = 0; x < result; x++) {
|
|
size = SSM(SCI_NAMEOFSTYLE, x, 0);
|
|
name = (char *)malloc(size + 1);
|
|
SSM(SCI_NAMEOFSTYLE, x, (sptr_t)name);
|
|
size = SSM(SCI_TAGSOFSTYLE, x, 0);
|
|
tags = (char *)malloc(size + 1);
|
|
SSM(SCI_TAGSOFSTYLE, x, (sptr_t)tags);
|
|
size = SSM(SCI_DESCRIPTIONOFSTYLE, x, 0);
|
|
description = (char *)malloc(size + 1);
|
|
SSM(SCI_DESCRIPTIONOFSTYLE, x, (sptr_t)description);
|
|
if (strlen(tags) > 0) {
|
|
fprintf(out, "style %d \"%s\" \"%s\" fore 0xffffff\n", x, tags, description);
|
|
}
|
|
DEL(description);
|
|
DEL(tags);
|
|
DEL(name);
|
|
}
|
|
}
|
|
fprintf(out, "\n");
|
|
|
|
// Properties
|
|
size = SSM(SCI_PROPERTYNAMES, 0, 0);
|
|
name = (char *)malloc(size + 1);
|
|
SSM(SCI_PROPERTYNAMES, 0, (sptr_t)name);
|
|
tags = strtok(name, "\n");
|
|
do {
|
|
size = SSM(SCI_DESCRIBEPROPERTY, (sptr_t)tags, 0);
|
|
description = (char *)malloc(size + 1);
|
|
SSM(SCI_DESCRIBEPROPERTY, (sptr_t)tags, (sptr_t)description);
|
|
result = SSM(SCI_PROPERTYTYPE, (sptr_t)tags, 0);
|
|
fprintf(out, "property ");
|
|
switch (result) {
|
|
case SC_TYPE_BOOLEAN:
|
|
fprintf(out, "boolean");
|
|
size = SSM(SCI_GETPROPERTYINT, (sptr_t)tags, 0);
|
|
config = utilCreateString("%d", size);
|
|
break;
|
|
|
|
case SC_TYPE_STRING:
|
|
fprintf(out, "string");
|
|
//***TODO*** This doesn't appear to be working.
|
|
size = SSM(SCI_GETPROPERTY, (sptr_t)tags, 0);
|
|
config = (char *)malloc(size + 1);
|
|
SSM(SCI_GETPROPERTY, (sptr_t)tags, (sptr_t)config);
|
|
break;
|
|
|
|
case SC_TYPE_INTEGER:
|
|
fprintf(out, "integer");
|
|
size = SSM(SCI_GETPROPERTYINT, (sptr_t)tags, 0);
|
|
config = utilCreateString("%d", size);
|
|
break;
|
|
}
|
|
fprintf(out, " %s \"%s\" %s\n", tags, description, config);
|
|
DEL(config);
|
|
DEL(description);
|
|
tags = strtok(NULL, "\n");
|
|
} while (tags != NULL);
|
|
DEL(name);
|
|
fprintf(out, "\n");
|
|
|
|
// Keyword Sets
|
|
size = SSM(SCI_DESCRIBEKEYWORDSETS, 0, 0);
|
|
name = (char *)malloc(size + 1);
|
|
SSM(SCI_DESCRIBEKEYWORDSETS, 0, (sptr_t)name);
|
|
tags = strtok(name, "\n");
|
|
size = 0;
|
|
do {
|
|
fprintf(out, "keywords %d \"%s\"\n", size, tags);
|
|
size++;
|
|
tags = strtok(NULL, "\n");
|
|
} while (tags != NULL);
|
|
DEL(name);
|
|
|
|
fclose(out);
|
|
}
|
|
}
|