mirror of https://gitlab.com/nakst/essence
475 lines
17 KiB
C++
475 lines
17 KiB
C++
// This file is part of the Essence operating system.
|
|
// It is released under the terms of the MIT license -- see LICENSE.md.
|
|
// Written by: nakst.
|
|
|
|
#define ES_INSTANCE_TYPE Instance
|
|
#include <essence.h>
|
|
|
|
#include <shared/strings.cpp>
|
|
|
|
// TODO Document save/load model, then merge into API.
|
|
// TODO Replace toolbar, then merge into API.
|
|
// TODO Merge Format menu into API.
|
|
// TODO Word wrap (textbox feature).
|
|
|
|
// TODO Possible extension features:
|
|
// - Block selection
|
|
// - Folding
|
|
// - Tab settings and auto-indent
|
|
// - Macros
|
|
// - Status bar
|
|
// - Goto line
|
|
// - Find in files
|
|
// - Convert case
|
|
// - Sort lines
|
|
// - Trim trailing space
|
|
// - Indent/comment/join/split shortcuts
|
|
|
|
#define SETTINGS_FILE "|Settings:/Default.ini"
|
|
|
|
const EsInstanceClassEditorSettings editorSettings = {
|
|
INTERFACE_STRING(TextEditorNewFileName),
|
|
INTERFACE_STRING(TextEditorNewDocument),
|
|
ES_ICON_TEXT,
|
|
};
|
|
|
|
const EsStyle styleFormatPopupColumn = {
|
|
.metrics = {
|
|
.mask = ES_THEME_METRICS_GAP_MAJOR,
|
|
.gapMajor = 5,
|
|
},
|
|
};
|
|
|
|
struct Instance : EsInstance {
|
|
EsTextbox *textboxDocument,
|
|
*textboxSearch;
|
|
|
|
EsElement *toolbarMain, *toolbarSearch;
|
|
|
|
EsTextDisplay *displaySearch;
|
|
|
|
EsButton *buttonFormat;
|
|
|
|
EsCommand commandFindNext,
|
|
commandFindPrevious,
|
|
commandFind,
|
|
commandFormat,
|
|
commandZoomIn,
|
|
commandZoomOut;
|
|
|
|
uint32_t syntaxHighlightingLanguage;
|
|
int32_t textSize;
|
|
int32_t scrollCumulative;
|
|
};
|
|
|
|
const int presetTextSizes[] = {
|
|
8, 9, 10, 11, 12, 13,
|
|
14, 16,
|
|
18, 24, 30,
|
|
36, 48, 60,
|
|
72, 96, 120, 144,
|
|
};
|
|
|
|
int32_t globalTextSize = 10;
|
|
|
|
void Find(Instance *instance, bool backwards) {
|
|
EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_SLIDE_UP);
|
|
|
|
size_t needleBytes;
|
|
char *needle = EsTextboxGetContents(instance->textboxSearch, &needleBytes);
|
|
|
|
int32_t line0, byte0, line1, byte1;
|
|
EsTextboxGetSelection(instance->textboxDocument, &line0, &byte0, &line1, &byte1);
|
|
|
|
if (backwards) {
|
|
if (line1 < line0) {
|
|
line0 = line1;
|
|
byte0 = byte1;
|
|
} else if (line1 == line0 && byte1 < byte0) {
|
|
byte0 = byte1;
|
|
}
|
|
} else {
|
|
if (line1 > line0) {
|
|
line0 = line1;
|
|
byte0 = byte1;
|
|
} else if (line1 == line0 && byte1 > byte0) {
|
|
byte0 = byte1;
|
|
}
|
|
}
|
|
|
|
bool found = EsTextboxFind(instance->textboxDocument, needle, needleBytes, &line0, &byte0, backwards ? ES_TEXTBOX_FIND_BACKWARDS : ES_FLAGS_DEFAULT);
|
|
|
|
if (found) {
|
|
EsTextDisplaySetContents(instance->displaySearch, "");
|
|
EsTextboxSetSelection(instance->textboxDocument, line0, byte0, line0, byte0 + needleBytes);
|
|
EsTextboxEnsureCaretVisible(instance->textboxDocument, true);
|
|
EsElementFocus(instance->textboxDocument);
|
|
} else if (!needleBytes) {
|
|
EsTextDisplaySetContents(instance->displaySearch, INTERFACE_STRING(CommonSearchPrompt2));
|
|
EsElementFocus(instance->textboxSearch);
|
|
} else {
|
|
EsTextDisplaySetContents(instance->displaySearch, INTERFACE_STRING(CommonSearchNoMatches));
|
|
EsElementFocus(instance->textboxSearch);
|
|
}
|
|
|
|
EsHeapFree(needle);
|
|
}
|
|
|
|
void SetLanguage(Instance *instance, uint32_t newLanguage) {
|
|
EsFont font = {};
|
|
font.family = newLanguage ? ES_FONT_MONOSPACED : ES_FONT_SANS;
|
|
font.weight = ES_FONT_REGULAR;
|
|
EsTextboxSetFont(instance->textboxDocument, font);
|
|
|
|
instance->syntaxHighlightingLanguage = newLanguage;
|
|
EsTextboxSetupSyntaxHighlighting(instance->textboxDocument, newLanguage);
|
|
EsTextboxEnableSmartReplacement(instance->textboxDocument, !newLanguage);
|
|
}
|
|
|
|
void FormatPopupCreate(Instance *instance) {
|
|
EsMenu *menu = EsMenuCreate(instance->buttonFormat, ES_FLAGS_DEFAULT);
|
|
EsPanel *panel = EsPanelCreate(menu, ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_POPUP);
|
|
|
|
{
|
|
EsPanel *column = EsPanelCreate(panel, ES_FLAGS_DEFAULT, EsStyleIntern(&styleFormatPopupColumn));
|
|
EsTextDisplayCreate(column, ES_CELL_H_EXPAND, ES_STYLE_TEXT_LABEL, INTERFACE_STRING(CommonFormatSize));
|
|
EsListView *list = EsListViewCreate(column, ES_LIST_VIEW_CHOICE_SELECT | ES_LIST_VIEW_FIXED_ITEMS, ES_STYLE_LIST_CHOICE_BORDERED);
|
|
|
|
size_t presetSizeCount = sizeof(presetTextSizes) / sizeof(presetTextSizes[0]);
|
|
int currentSize = instance->textSize;
|
|
char buffer[64];
|
|
|
|
if (currentSize < presetTextSizes[0]) {
|
|
// The current size is not in the list; add it.
|
|
EsListViewFixedItemSetString(list, EsListViewFixedItemInsert(list, currentSize), 0, buffer,
|
|
EsStringFormat(buffer, sizeof(buffer), "%d pt", currentSize));
|
|
}
|
|
|
|
for (uintptr_t i = 0; i < presetSizeCount; i++) {
|
|
EsListViewFixedItemSetString(list, EsListViewFixedItemInsert(list, presetTextSizes[i]), 0, buffer,
|
|
EsStringFormat(buffer, sizeof(buffer), "%d pt", presetTextSizes[i]));
|
|
|
|
if (currentSize > presetTextSizes[i] && (i == presetSizeCount - 1 || (i != presetSizeCount - 1 && currentSize < presetTextSizes[i + 1]))) {
|
|
// The current size is not in the list; add it.
|
|
EsListViewFixedItemSetString(list, EsListViewFixedItemInsert(list, currentSize), 0, buffer,
|
|
EsStringFormat(buffer, sizeof(buffer), "%d pt", currentSize));
|
|
}
|
|
}
|
|
|
|
EsListViewFixedItemSelect(list, currentSize);
|
|
|
|
list->messageUser = [] (EsElement *element, EsMessage *message) {
|
|
if (message->type == ES_MSG_LIST_VIEW_SELECT) {
|
|
Instance *instance = element->instance;
|
|
EsGeneric newSize;
|
|
|
|
if (EsListViewFixedItemGetSelected(((EsListView *) element), &newSize)) {
|
|
globalTextSize = instance->textSize = newSize.u;
|
|
EsTextboxSetTextSize(instance->textboxDocument, instance->textSize);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
}
|
|
|
|
{
|
|
EsPanel *column = EsPanelCreate(panel, ES_FLAGS_DEFAULT, EsStyleIntern(&styleFormatPopupColumn));
|
|
EsTextDisplayCreate(column, ES_CELL_H_EXPAND, ES_STYLE_TEXT_LABEL, INTERFACE_STRING(CommonFormatLanguage));
|
|
EsListView *list = EsListViewCreate(column, ES_LIST_VIEW_CHOICE_SELECT | ES_LIST_VIEW_FIXED_ITEMS, ES_STYLE_LIST_CHOICE_BORDERED);
|
|
EsListViewFixedItemSetString(list, EsListViewFixedItemInsert(list, 0), 0, INTERFACE_STRING(CommonFormatPlainText));
|
|
EsListViewFixedItemSetString(list, EsListViewFixedItemInsert(list, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C), 0, "C/C++", -1);
|
|
EsListViewFixedItemSetString(list, EsListViewFixedItemInsert(list, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI), 0, "Ini", -1);
|
|
EsListViewFixedItemSelect(list, instance->syntaxHighlightingLanguage);
|
|
|
|
list->messageUser = [] (EsElement *element, EsMessage *message) {
|
|
if (message->type == ES_MSG_LIST_VIEW_SELECT) {
|
|
Instance *instance = element->instance;
|
|
EsGeneric newLanguage;
|
|
|
|
if (EsListViewFixedItemGetSelected(((EsListView *) element), &newLanguage)) {
|
|
SetLanguage(instance, newLanguage.u);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
}
|
|
|
|
EsMenuShow(menu);
|
|
}
|
|
|
|
void CommandZoom(Instance *instance, EsElement *, EsCommand *command) {
|
|
int32_t delta = instance->scrollCumulative > 0
|
|
? instance->scrollCumulative / ES_SCROLL_WHEEL_NOTCH
|
|
: -(-instance->scrollCumulative / ES_SCROLL_WHEEL_NOTCH);
|
|
instance->scrollCumulative -= delta * ES_SCROLL_WHEEL_NOTCH;
|
|
|
|
if (command) delta += command->data.i;
|
|
|
|
intptr_t presetSizeCount = sizeof(presetTextSizes) / sizeof(presetTextSizes[0]);
|
|
int32_t newIndex = delta;
|
|
|
|
for (intptr_t i = 0; i <= presetSizeCount; i++) {
|
|
if (i == presetSizeCount || presetTextSizes[i] > instance->textSize) {
|
|
newIndex = i - 1 + delta;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (newIndex < 0) newIndex = 0;
|
|
if (newIndex > presetSizeCount - 1) newIndex = presetSizeCount - 1;
|
|
|
|
if (instance->textSize != presetTextSizes[newIndex]) {
|
|
globalTextSize = instance->textSize = presetTextSizes[newIndex];
|
|
EsTextboxSetTextSize(instance->textboxDocument, instance->textSize);
|
|
}
|
|
}
|
|
|
|
int TextboxDocumentMessage(EsElement *element, EsMessage *message) {
|
|
if (message->type == ES_MSG_SCROLL_WHEEL && EsKeyboardIsCtrlHeld()) {
|
|
// TODO Maybe detecting the input needed to do this (Ctrl+Scroll) should be dealt with in the API,
|
|
// so that the user could potentially customize it.
|
|
Instance *instance = element->instance;
|
|
instance->scrollCumulative += message->scrollWheel.dy;
|
|
CommandZoom(instance, element, nullptr);
|
|
return ES_HANDLED;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool StringEndsWith(const char *string, size_t stringBytes, const char *prefix, size_t prefixBytes, bool caseInsensitive) {
|
|
string += stringBytes - 1;
|
|
prefix += prefixBytes - 1;
|
|
|
|
while (true) {
|
|
if (!prefixBytes) return true;
|
|
if (!stringBytes) return false;
|
|
|
|
char c1 = *string;
|
|
char c2 = *prefix;
|
|
|
|
if (caseInsensitive) {
|
|
if (c1 >= 'a' && c1 <= 'z') c1 = c1 - 'a' + 'A';
|
|
if (c2 >= 'a' && c2 <= 'z') c2 = c2 - 'a' + 'A';
|
|
}
|
|
|
|
if (c1 != c2) return false;
|
|
|
|
stringBytes--;
|
|
prefixBytes--;
|
|
string--;
|
|
prefix--;
|
|
}
|
|
}
|
|
|
|
int InstanceCallback(Instance *instance, EsMessage *message) {
|
|
if (message->type == ES_MSG_INSTANCE_SAVE) {
|
|
size_t byteCount;
|
|
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
|
|
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
|
|
|
bool fileNameContainsExtension = false;
|
|
|
|
for (uintptr_t i = 0; i < (uintptr_t) message->instanceSave.nameOrPathBytes && i < 5; i++) {
|
|
if (message->instanceSave.nameOrPath[message->instanceSave.nameOrPathBytes - i - 1] == '.') {
|
|
fileNameContainsExtension = true;
|
|
}
|
|
}
|
|
|
|
if (fileNameContainsExtension) {
|
|
// Don't set a content type, it should be matched from the file extension.
|
|
} else {
|
|
EsUniqueIdentifier plainText = (EsUniqueIdentifier)
|
|
{{ 0x25, 0x65, 0x4C, 0x89, 0xE7, 0x29, 0xEA, 0x9E, 0xB5, 0xBE, 0xB5, 0xCA, 0xA7, 0x60, 0xBD, 0x3D }};
|
|
EsFileStoreSetContentType(message->instanceSave.file, plainText);
|
|
}
|
|
|
|
EsHeapFree(contents);
|
|
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
|
|
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
|
size_t fileSize;
|
|
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
|
|
|
if (!file) {
|
|
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
|
} else if (!EsUTF8IsValid(file, fileSize)) {
|
|
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
|
} else {
|
|
EsTextboxSelectAll(instance->textboxDocument);
|
|
EsTextboxInsert(instance->textboxDocument, file, fileSize);
|
|
EsTextboxSetSelection(instance->textboxDocument, 0, 0, 0, 0);
|
|
EsElementRelayout(instance->textboxDocument);
|
|
|
|
if (StringEndsWith(message->instanceOpen.nameOrPath, message->instanceOpen.nameOrPathBytes, EsLiteral(".c"), true)
|
|
|| StringEndsWith(message->instanceOpen.nameOrPath, message->instanceOpen.nameOrPathBytes, EsLiteral(".cpp"), true)
|
|
|| StringEndsWith(message->instanceOpen.nameOrPath, message->instanceOpen.nameOrPathBytes, EsLiteral(".h"), true)) {
|
|
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C);
|
|
} else if (StringEndsWith(message->instanceOpen.nameOrPath, message->instanceOpen.nameOrPathBytes, EsLiteral(".ini"), true)) {
|
|
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI);
|
|
} else {
|
|
SetLanguage(instance, 0);
|
|
}
|
|
|
|
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
|
|
}
|
|
|
|
EsHeapFree(file);
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
return ES_HANDLED;
|
|
}
|
|
|
|
void ProcessApplicationMessage(EsMessage *message) {
|
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
|
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(TextEditorTitle));
|
|
instance->callback = InstanceCallback;
|
|
EsInstanceSetClassEditor(instance, &editorSettings);
|
|
|
|
EsWindow *window = instance->window;
|
|
EsWindowSetIcon(window, ES_ICON_ACCESSORIES_TEXT_EDITOR);
|
|
EsButton *button;
|
|
|
|
// Commands:
|
|
|
|
uint32_t stableID = 1;
|
|
|
|
EsCommandRegister(&instance->commandFindNext, instance, INTERFACE_STRING(CommonSearchNext), [] (Instance *instance, EsElement *, EsCommand *) {
|
|
Find(instance, false);
|
|
}, stableID++, "F3", true);
|
|
|
|
EsCommandRegister(&instance->commandFindPrevious, instance, INTERFACE_STRING(CommonSearchPrevious), [] (Instance *instance, EsElement *, EsCommand *) {
|
|
Find(instance, true);
|
|
}, stableID++, "Shift+F3", true);
|
|
|
|
EsCommandRegister(&instance->commandFind, instance, INTERFACE_STRING(CommonSearchOpen), [] (Instance *instance, EsElement *, EsCommand *) {
|
|
EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_ZOOM_OUT);
|
|
EsElementFocus(instance->textboxSearch);
|
|
}, stableID++, "Ctrl+F", true);
|
|
|
|
EsCommandRegister(&instance->commandFormat, instance, INTERFACE_STRING(CommonFormatPopup), [] (Instance *instance, EsElement *, EsCommand *) {
|
|
FormatPopupCreate(instance);
|
|
}, stableID++, "Ctrl+Alt+T", true);
|
|
|
|
EsCommandRegister(&instance->commandZoomIn, instance, INTERFACE_STRING(CommonZoomIn), CommandZoom, stableID++, "Ctrl+=", true)->data.i = 1;
|
|
EsCommandRegister(&instance->commandZoomOut, instance, INTERFACE_STRING(CommonZoomOut), CommandZoom, stableID++, "Ctrl+-", true)->data.i = -1;
|
|
|
|
// Content:
|
|
|
|
EsPanel *panel = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
|
uint64_t documentFlags = ES_CELL_FILL | ES_TEXTBOX_MULTILINE | ES_TEXTBOX_ALLOW_TABS | ES_TEXTBOX_MARGIN;
|
|
instance->textboxDocument = EsTextboxCreate(panel, documentFlags, ES_STYLE_TEXTBOX_NO_BORDER);
|
|
instance->textboxDocument->cName = "document";
|
|
instance->textboxDocument->messageUser = TextboxDocumentMessage;
|
|
instance->textSize = globalTextSize;
|
|
EsTextboxSetTextSize(instance->textboxDocument, globalTextSize);
|
|
EsTextboxSetUndoManager(instance->textboxDocument, instance->undoManager);
|
|
EsElementFocus(instance->textboxDocument);
|
|
|
|
// Main toolbar:
|
|
|
|
EsElement *toolbarMain = instance->toolbarMain = EsWindowGetToolbar(window, true);
|
|
|
|
EsFileMenuAddToToolbar(toolbarMain);
|
|
|
|
button = EsButtonCreate(toolbarMain, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchOpen));
|
|
button->accessKey = 'S';
|
|
EsButtonSetIcon(button, ES_ICON_EDIT_FIND_SYMBOLIC);
|
|
|
|
EsButtonOnCommand(button, [] (Instance *instance, EsElement *, EsCommand *) {
|
|
EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_SLIDE_UP);
|
|
EsElementFocus(instance->textboxSearch);
|
|
});
|
|
|
|
EsSpacerCreate(toolbarMain, ES_CELL_H_FILL);
|
|
|
|
button = EsButtonCreate(toolbarMain, ES_BUTTON_DROPDOWN, {}, INTERFACE_STRING(CommonFormatPopup));
|
|
button->accessKey = 'M';
|
|
EsButtonSetIcon(button, ES_ICON_FORMAT_TEXT_LARGER_SYMBOLIC);
|
|
EsCommandAddButton(&instance->commandFormat, button);
|
|
instance->buttonFormat = button;
|
|
|
|
EsWindowSwitchToolbar(window, toolbarMain, ES_TRANSITION_NONE);
|
|
|
|
// Search toolbar:
|
|
|
|
EsElement *toolbarSearch = instance->toolbarSearch = EsWindowGetToolbar(window, true);
|
|
|
|
button = EsButtonCreate(toolbarSearch, ES_FLAGS_DEFAULT, 0);
|
|
button->cName = "go back", button->accessKey = 'X';
|
|
EsButtonSetIcon(button, ES_ICON_GO_FIRST_SYMBOLIC);
|
|
|
|
EsButtonOnCommand(button, [] (Instance *instance, EsElement *, EsCommand *) {
|
|
EsWindowSwitchToolbar(instance->window, instance->toolbarMain, ES_TRANSITION_SLIDE_DOWN);
|
|
});
|
|
|
|
EsSpacerCreate(toolbarSearch, ES_FLAGS_DEFAULT, 0, 14, 0);
|
|
|
|
EsTextDisplayCreate(toolbarSearch, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(CommonSearchPrompt));
|
|
instance->textboxSearch = EsTextboxCreate(toolbarSearch, ES_FLAGS_DEFAULT, {});
|
|
instance->textboxSearch->cName = "search textbox";
|
|
instance->textboxSearch->accessKey = 'S';
|
|
|
|
instance->textboxSearch->messageUser = [] (EsElement *element, EsMessage *message) {
|
|
Instance *instance = element->instance;
|
|
|
|
if (message->type == ES_MSG_KEY_DOWN && message->keyboard.scancode == ES_SCANCODE_ENTER) {
|
|
EsCommand *command = (message->keyboard.modifiers & ES_MODIFIER_SHIFT) ? &instance->commandFindPrevious : &instance->commandFindNext;
|
|
command->callback(instance, element, command);
|
|
return ES_HANDLED;
|
|
} else if (message->type == ES_MSG_KEY_DOWN && message->keyboard.scancode == ES_SCANCODE_ESCAPE) {
|
|
EsWindowSwitchToolbar(instance->window, instance->toolbarMain, ES_TRANSITION_SLIDE_DOWN);
|
|
EsElementFocus(instance->textboxDocument);
|
|
return ES_HANDLED;
|
|
} else if (message->type == ES_MSG_FOCUSED_START) {
|
|
EsTextboxSelectAll(instance->textboxSearch);
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
EsSpacerCreate(toolbarSearch, ES_FLAGS_DEFAULT, 0, 7, 0);
|
|
instance->displaySearch = EsTextDisplayCreate(toolbarSearch, ES_CELL_H_FILL, {}, "");
|
|
|
|
EsPanel *buttonGroup = EsPanelCreate(toolbarSearch, ES_PANEL_HORIZONTAL | ES_ELEMENT_AUTO_GROUP);
|
|
button = EsButtonCreate(buttonGroup, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchNext));
|
|
button->accessKey = 'N';
|
|
EsCommandAddButton(&instance->commandFindNext, button);
|
|
EsSpacerCreate(buttonGroup, ES_CELL_V_FILL, ES_STYLE_TOOLBAR_BUTTON_GROUP_SEPARATOR);
|
|
button = EsButtonCreate(buttonGroup, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchPrevious));
|
|
button->accessKey = 'P';
|
|
EsCommandAddButton(&instance->commandFindPrevious, button);
|
|
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
|
|
EsBuffer buffer = {};
|
|
buffer.canGrow = true;
|
|
EsBufferFormat(&buffer, "[general]\ntext_size=%d\n", globalTextSize);
|
|
EsFileWriteAll(EsLiteral(SETTINGS_FILE), buffer.out, buffer.position);
|
|
EsHeapFree(buffer.out);
|
|
}
|
|
}
|
|
|
|
void _start() {
|
|
_init();
|
|
|
|
size_t settingsFileBytes = 0;
|
|
char *settingsFile = (char *) EsFileReadAll(EsLiteral(SETTINGS_FILE), &settingsFileBytes);
|
|
EsINIState state = { .buffer = settingsFile, .bytes = settingsFileBytes };
|
|
|
|
while (EsINIParse(&state)) {
|
|
if (0 == EsStringCompareRaw(state.section, state.sectionBytes, EsLiteral("general"))) {
|
|
if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("text_size"))) {
|
|
globalTextSize = EsIntegerParse(state.value, state.valueBytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
EsHeapFree(settingsFile);
|
|
|
|
while (true) {
|
|
ProcessApplicationMessage(EsMessageReceive());
|
|
}
|
|
}
|