From b7ea1faa0311c839888676a7568fc3f7f1de28d2 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 8 Aug 2015 20:13:51 +1000 Subject: [PATCH 01/14] UI: add theme handling --- src/platform/sdl/settings.cpp | 7 ++- src/ui/textedit.cpp | 93 +++++++++++++++++++++++++---------- src/ui/textedit.h | 3 ++ 3 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/platform/sdl/settings.cpp b/src/platform/sdl/settings.cpp index 9336743b..7a80e379 100644 --- a/src/platform/sdl/settings.cpp +++ b/src/platform/sdl/settings.cpp @@ -17,6 +17,8 @@ #include "ui/utils.h" #include "common/smbas.h" +extern int g_themeId; + static const char *ENV_VARS[] = { "APPDATA", "HOME", "TMP", "TEMP", "TMPDIR" }; @@ -88,6 +90,7 @@ void restoreSettings(const char *configName, SDL_Rect &rect, int &fontScale) { fontScale = nextInteger(fp, DEFAULT_SCALE); opt_mute_audio = nextInteger(fp, 0); opt_ide = nextInteger(fp, 0); + g_themeId = nextInteger(fp, 0); fclose(fp); } else { rect.x = SDL_WINDOWPOS_UNDEFINED; @@ -97,6 +100,7 @@ void restoreSettings(const char *configName, SDL_Rect &rect, int &fontScale) { fontScale = DEFAULT_SCALE; opt_mute_audio = 0; opt_ide = IDE_NONE; + g_themeId = 0; } } @@ -109,7 +113,8 @@ void saveSettings(const char *configName, SDL_Window *window, int fontScale) { int x, y, w, h; SDL_GetWindowPosition(window, &x, &y); SDL_GetWindowSize(window, &w, &h); - fprintf(fp, "%d,%d,%d,%d,%d,%d,%d\n", x, y, w, h, fontScale, opt_mute_audio, opt_ide); + fprintf(fp, "%d,%d,%d,%d,%d,%d,%d,%d\n", x, y, w, h, + fontScale, opt_mute_audio, opt_ide, g_themeId); fclose(fp); } } diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index febb7034..e54c97a6 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -22,18 +22,34 @@ #define GROW_SIZE 128 #define LINE_BUFFER_SIZE 200 #define INDENT_LEVEL 2 -#define HELP_WIDTH 22 -#define THEME_FOREGROUND 0xa7aebc -#define THEME_BACKGROUND 0x272b33 -#define THEME_SELECTION_BACKGROUND 0x3d4350 -#define THEME_NUMBER_SELECTION_BACKGROUND 0x2b3039 -#define THEME_NUMBER_SELECTION 0xabb2c0 -#define THEME_NUMBER 0x484f5f -#define THEME_CURSOR 0xa7aebc -#define THEME_CURSOR_BACKGROUND 0x3875ed -#define THEME_MATCH_BACKGROUND 0x373b88 -#define THEME_ROW_CURSOR 0x2b313a -#define THEME_SYNTAX_COMMENTS 0x00bb00 +#define HELP_WIDTH 22 +#define NUM_THEMES 4 + +int g_themeId = 0; + +const int theme1[] = { + 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, +}; + +const int theme2[] = { + 0xa7aebc, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642 +}; + +const int theme3[] = { + 0xa7aebc, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x000d1a, +}; + +const int theme4[] = { + 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0x2e3436, 0x888a85, 0x000000, 0x4d483b, 0x000000, 0x2b313a, +}; + +const int* themes[] = { + theme1, theme2, theme3, theme4 +}; const char *helpText = "C-a select-all\n" @@ -56,6 +72,7 @@ const char *helpText = "A-c change case\n" "A-g goto line\n" "A-n trim line-endings\n" + "A-t select theme\n" "SHIFT- select\n" "TAB indent line\n" "F1,A-h keyword help\n" @@ -64,19 +81,8 @@ const char *helpText = // // EditTheme // -EditTheme::EditTheme() : - _color(THEME_FOREGROUND), - _background(THEME_BACKGROUND), - _selection_color(THEME_FOREGROUND), - _selection_background(THEME_SELECTION_BACKGROUND), - _number_color(THEME_NUMBER), - _number_selection_color(THEME_FOREGROUND), - _number_selection_background(THEME_NUMBER_SELECTION_BACKGROUND), - _cursor_color(THEME_CURSOR), - _cursor_background(THEME_CURSOR_BACKGROUND), - _match_background(THEME_MATCH_BACKGROUND), - _row_cursor(THEME_ROW_CURSOR), - _syntax_comments(THEME_SYNTAX_COMMENTS) { +EditTheme::EditTheme() { + selectTheme(themes[g_themeId]); } EditTheme::EditTheme(int fg, int bg) : @@ -91,6 +97,21 @@ EditTheme::EditTheme(int fg, int bg) : _syntax_comments(bg) { } +void EditTheme::selectTheme(const int theme[]) { + _color = theme[0]; + _selection_color = theme[1]; + _number_color = theme[2]; + _number_selection_color = theme[3]; + _cursor_color = theme[4]; + _syntax_comments = theme[5]; + _background = theme[6]; + _selection_background = theme[7]; + _number_selection_background = theme[8]; + _cursor_background = theme[9]; + _match_background = theme[10]; + _row_cursor = theme[11]; +} + // // EditBuffer // @@ -395,6 +416,9 @@ bool TextEditInput::edit(int key, int screenWidth, int charWidth) { case SB_KEY_ALT('n'): removeTrailingSpaces(); break; + case SB_KEY_ALT('t'): + cycleTheme(); + break; case SB_KEY_TAB: editTab(); break; @@ -636,6 +660,11 @@ void TextEditInput::changeCase() { free(selection); } +void TextEditInput::cycleTheme() { + g_themeId = (g_themeId + 1) % NUM_THEMES; + _theme->selectTheme(themes[g_themeId]); +} + void TextEditInput::drawLineNumber(int x, int y, int row, bool selected) { if (_marginWidth > 0) { if (selected) { @@ -1142,7 +1171,7 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { break; case kKeyword: _mode = kHelp; - completeWord(0); + completeLine(0); break; default: break; @@ -1156,6 +1185,18 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { return result; } +void TextEditHelpWidget::completeLine(int pos) { + int end = pos; + while (end < _buf._len && _buf._buffer[end] != '\n') { + end++; + } + char *text = _buf.textRange(pos, end); + if (text[0] != '\0' && text[0] != '[') { + _editor->completeWord(text); + } + free(text); +} + void TextEditHelpWidget::completeWord(int pos) { char *text = lineText(pos); if (text[0] != '\0' && text[0] != '[') { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 82cb0403..67095f85 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -27,6 +27,7 @@ struct TextEditInput; struct EditTheme { EditTheme(); EditTheme(int fg, int bg); + void selectTheme(const int theme[]); int _color; int _background; @@ -99,6 +100,7 @@ struct TextEditInput : public FormEditInput { protected: void changeCase(); + void cycleTheme(); void drawLineNumber(int x, int y, int row, bool selected); void editDeleteLine(); void editEnter(); @@ -167,6 +169,7 @@ struct TextEditHelpWidget : public TextEditInput { bool replaceDoneMode() const { return _mode == kReplaceDone; } private: + void completeLine(int pos); void completeWord(int pos); void createPackageIndex(); bool createKeywordHelp(const char *keyword); From 0a51c17eb4ae7743fbfc2fcda35da37a2b80614f Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 10 Aug 2015 22:41:58 +1000 Subject: [PATCH 02/14] UI: syntax highlighting for quoted text --- src/ui/textedit.cpp | 84 +++++++++++++++++++++++++++++++++++++-------- src/ui/textedit.h | 9 ++++- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index e54c97a6..cdce5cef 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -30,21 +30,25 @@ int g_themeId = 0; const int theme1[] = { 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, + 0x0000c0 }; const int theme2[] = { 0xa7aebc, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, - 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642 + 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642, + 0x0000c0 }; const int theme3[] = { 0xa7aebc, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x000d1a, + 0x0000c0 }; const int theme4[] = { 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x2e3436, 0x888a85, 0x000000, 0x4d483b, 0x000000, 0x2b313a, + 0x0000c0 }; const int* themes[] = { @@ -94,7 +98,8 @@ EditTheme::EditTheme(int fg, int bg) : _cursor_background(fg), _match_background(fg), _row_cursor(bg), - _syntax_comments(bg) { + _syntax_comments(bg), + _syntax_text(fg) { } void EditTheme::selectTheme(const int theme[]) { @@ -110,6 +115,7 @@ void EditTheme::selectTheme(const int theme[]) { _cursor_background = theme[9]; _match_background = theme[10]; _row_cursor = theme[11]; + _syntax_text = theme[12]; } // @@ -257,6 +263,7 @@ void TextEditInput::completeWord(const char *word) { } void TextEditInput::draw(int x, int y, int w, int h, int chw) { + SyntaxState syntax = kReset; StbTexteditRow r; int len = _buf._len; int i = 0; @@ -350,7 +357,12 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } else { drawLineNumber(x, y + baseY, row, false); if (numChars) { - drawText(x + _marginWidth, y + baseY, _buf._buffer + i, numChars); + if (_marginWidth > 0) { + drawText(x + _marginWidth, y + baseY, _buf._buffer + i, numChars, syntax); + } else { + maSetColor(_theme->_color); + maDrawText(x + _marginWidth, y + baseY, _buf._buffer + i, numChars); + } } } baseY += _charHeight; @@ -380,23 +392,67 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } -void TextEditInput::drawText(int x, int y, const char *str, int length) { - maSetColor(_theme->_color); - int i_next = 0; +void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { + int i = 0; + int offs = 0; - if (_marginWidth > 0) { - for (int i = 0; i < length; i++) { - if (str[i] == '\'' || strncasecmp(str + i, "rem ", 4) == 0) { - maDrawText(x, y, str + i_next, i - i_next); + while (offs < length) { + SyntaxState nextState = state; + int count = 0; + + // find the end of the current segment + while (i < length) { + if (state != kText && + (str[i] == '\'' || strncasecmp(str + i, "rem ", 4) == 0)) { + nextState = kComment; + break; + } else if (str[i] == '\"') { + nextState = (state == kText ? kReset : kText); + i++; + break; + } + i++; + count++; + } + + if (state == kText) { + count += 2; + } + + if (count > 0) { + // draw the current segment + switch (state) { + case kComment: maSetColor(_theme->_syntax_comments); - length -= i; - x += (i * _charWidth); - i_next = i; + break; + case kText: + maSetColor(_theme->_syntax_text); + break; + default: + maSetColor(_theme->_color); break; } + maDrawText(x, y, str + offs, count); + } + + state = nextState; + offs += count; + x += (count * _charWidth); + + if (state == kComment) { + // comments continue to the end of line + maSetColor(_theme->_syntax_comments); + maDrawText(x, y, str + offs, length - offs); + break; + } else if (count == 0) { + break; } } - maDrawText(x, y, str + i_next, length); + + char cend = str[length]; + if (cend == '\r' || cend == '\n') { + state = kReset; + } } bool TextEditInput::edit(int key, int screenWidth, int charWidth) { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 67095f85..063292e8 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -41,6 +41,7 @@ struct EditTheme { int _match_background; int _row_cursor; int _syntax_comments; + int _syntax_text; }; struct EditBuffer { @@ -68,7 +69,6 @@ struct TextEditInput : public FormEditInput { void completeWord(const char *word); void draw(int x, int y, int w, int h, int chw); - void drawText(int x, int y, const char *str, int length); bool edit(int key, int screenWidth, int charWidth); bool find(const char *word, bool next); int getCursorPos() const { return _state.cursor; } @@ -99,6 +99,13 @@ struct TextEditInput : public FormEditInput { bool replaceNext(const char *text); protected: + enum SyntaxState { + kReset = 0, + kComment, + kText, + }; + + void drawText(int x, int y, const char *str, int length, SyntaxState &state); void changeCase(); void cycleTheme(); void drawLineNumber(int x, int y, int row, bool selected); From 5f1ab9d680638f835275ce5d9dd099ba47fd9b0f Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 11 Aug 2015 22:24:05 +1000 Subject: [PATCH 03/14] UI: update syntax highlighting --- src/ui/textedit.cpp | 105 ++++++++++++++++++++++++++++---------------- src/ui/textedit.h | 4 ++ 2 files changed, 70 insertions(+), 39 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index cdce5cef..6913d497 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -30,25 +30,25 @@ int g_themeId = 0; const int theme1[] = { 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, - 0x0000c0 + 0x0083f8, 0x151c29 }; const int theme2[] = { 0xa7aebc, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642, - 0x0000c0 + 0x0083f8, 0xff8876 }; const int theme3[] = { 0xa7aebc, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, - 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x000d1a, - 0x0000c0 + 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x022444, + 0x0083f8, 0xff8876 }; const int theme4[] = { 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x2e3436, 0x888a85, 0x000000, 0x4d483b, 0x000000, 0x2b313a, - 0x0000c0 + 0x0083f8, 0xff8876 }; const int* themes[] = { @@ -99,7 +99,8 @@ EditTheme::EditTheme(int fg, int bg) : _match_background(fg), _row_cursor(bg), _syntax_comments(bg), - _syntax_text(fg) { + _syntax_text(fg), + _syntax_keywords(fg) { } void EditTheme::selectTheme(const int theme[]) { @@ -116,6 +117,7 @@ void EditTheme::selectTheme(const int theme[]) { _match_background = theme[10]; _row_cursor = theme[11]; _syntax_text = theme[12]; + _syntax_keywords = theme[13]; } // @@ -392,66 +394,74 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } +int TextEditInput::match(const char *str, const char *pattern , int len) { + int i, j; + for (i = 0, j = 0; i < len; i++, j += 2) { + if (str[i] != pattern[j] && str[i] != pattern[j + 1]) { + break; + } + } + if (str[i] != ' ') { + i = 0; + } + return i; +} + void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { int i = 0; int offs = 0; + SyntaxState nextState = state; - while (offs < length) { - SyntaxState nextState = state; + while (offs < length && i < length) { int count = 0; + int next = 0; + nextState = state; // find the end of the current segment while (i < length) { - if (state != kText && - (str[i] == '\'' || strncasecmp(str + i, "rem ", 4) == 0)) { + if (str[i] == '\'' || match(str + i, "RrEeMm", 3) == 3) { nextState = kComment; + next = length - offs; break; } else if (str[i] == '\"') { - nextState = (state == kText ? kReset : kText); - i++; + next++; + while (i + next < length && str[i + next] != '\"') { + next++; + } + if (str[i + next] == '\"') { + next++; + } + nextState = kText; break; } i++; count++; } - if (state == kText) { - count += 2; - } - + // draw the current segment if (count > 0) { - // draw the current segment - switch (state) { - case kComment: - maSetColor(_theme->_syntax_comments); - break; - case kText: - maSetColor(_theme->_syntax_text); - break; - default: - maSetColor(_theme->_color); - break; - } + setColor(state); maDrawText(x, y, str + offs, count); + offs += count; + x += (count * _charWidth); } - state = nextState; - offs += count; - x += (count * _charWidth); - - if (state == kComment) { - // comments continue to the end of line - maSetColor(_theme->_syntax_comments); - maDrawText(x, y, str + offs, length - offs); - break; - } else if (count == 0) { - break; + // draw the next segment + if (next > 0) { + setColor(nextState); + maDrawText(x, y, str + offs, next); + state = kReset; + offs += next; + x += (next * _charWidth); + i += next; } } char cend = str[length]; if (cend == '\r' || cend == '\n') { state = kReset; + } else { + state = nextState; } } @@ -1120,6 +1130,23 @@ void TextEditInput::removeTrailingSpaces() { setCursorRow(row - 1); } +void TextEditInput::setColor(SyntaxState &state) { + switch (state) { + case kComment: + maSetColor(_theme->_syntax_comments); + break; + case kText: + maSetColor(_theme->_syntax_text); + break; + case kKeyword: + maSetColor(_theme->_syntax_keywords); + break; + case kReset: + maSetColor(_theme->_color); + break; + } +} + void TextEditInput::updateScroll() { int pageRows = _height / _charHeight; if (_cursorRow + 1 < pageRows) { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 063292e8..bcf989c9 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -42,6 +42,7 @@ struct EditTheme { int _row_cursor; int _syntax_comments; int _syntax_text; + int _syntax_keywords; }; struct EditBuffer { @@ -103,6 +104,7 @@ struct TextEditInput : public FormEditInput { kReset = 0, kComment, kText, + kKeyword, }; void drawText(int x, int y, const char *str, int length, SyntaxState &state); @@ -122,8 +124,10 @@ struct TextEditInput : public FormEditInput { int lineEnd(int pos) { return linePos(pos, true); } int linePos(int pos, bool end, bool excludeBreak=true); int lineStart(int pos) { return linePos(pos, false); } + int match(const char *str, const char *pattern , int len); void pageNavigate(bool pageDown, bool shift); void removeTrailingSpaces(); + void setColor(SyntaxState &state); void updateScroll(); int wordStart(); From 0dfc7cd98ebbc209f4d0df310c8b17bdb0c372ec Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 11 Aug 2015 23:14:32 +1000 Subject: [PATCH 04/14] UI: update syntax highlighting --- src/ui/textedit.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 6913d497..4e4989fc 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -30,7 +30,7 @@ int g_themeId = 0; const int theme1[] = { 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, - 0x0083f8, 0x151c29 + 0x0083f8, 0xff8876 }; const int theme2[] = { @@ -420,8 +420,8 @@ void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxSt // find the end of the current segment while (i < length) { if (str[i] == '\'' || match(str + i, "RrEeMm", 3) == 3) { + next = length - i; nextState = kComment; - next = length - offs; break; } else if (str[i] == '\"') { next++; @@ -433,6 +433,10 @@ void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxSt } nextState = kText; break; + } else if (str[i] == '(' || str[i] == ')') { + next = 1; + nextState = kKeyword; + break; } i++; count++; From 57067e114b160e3f9a7aaaa69de46dd5b49c8ba7 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 12 Aug 2015 07:07:20 +1000 Subject: [PATCH 05/14] UI: update syntax highlighting --- documentation/build_kwp.cpp | 23 +++++++++++++++++++++++ src/ui/textedit.cpp | 33 ++++++++++++++++++++------------- src/ui/textedit.h | 2 +- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/documentation/build_kwp.cpp b/documentation/build_kwp.cpp index 3bf62d22..eaaa53e3 100644 --- a/documentation/build_kwp.cpp +++ b/documentation/build_kwp.cpp @@ -235,5 +235,28 @@ int main(int argc, char *argv[]) { } fprintf(stdout, "};\n"); fprintf(stdout, "const int keyword_help_len = %d;\n", helpItems.size()); + + int languageCount = 0; + fprintf(stdout, "\nstruct KEYWORD_SYNTAX {\n"); + fprintf(stdout, " const char *str;\n"); + fprintf(stdout, " const int len;\n"); + fprintf(stdout, "} keyword_syntax[] = {\n"); + List_each(HelpItem *, it, helpItems) { + HelpItem *item = (*it); + if (strcasecmp(item->package, "Language") == 0) { + languageCount++; + fputc('{', stdout); + fputc('\"', stdout); + int len = strlen(item->keyword); + for (int i = 0; i < len; i++) { + fputc(toupper(item->keyword[i]), stdout); + fputc(tolower(item->keyword[i]), stdout); + } + fprintf(stdout, "\",%d},\n", len); + } + } + fprintf(stdout, "};\n"); + fprintf(stdout, "const int keyword_syntax_len = %d;\n", languageCount); + return 0; } diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 4e4989fc..f1304be8 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -82,6 +82,16 @@ const char *helpText = "F1,A-h keyword help\n" "F9, C-r run\n"; +static inline bool match(const char *str, const char *pattern , int len) { + int i, j; + for (i = 0, j = 0; i < len; i++, j += 2) { + if (str[i] != pattern[j] && str[i] != pattern[j + 1]) { + break; + } + } + return i == len; +} + // // EditTheme // @@ -394,17 +404,15 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } -int TextEditInput::match(const char *str, const char *pattern , int len) { - int i, j; - for (i = 0, j = 0; i < len; i++, j += 2) { - if (str[i] != pattern[j] && str[i] != pattern[j + 1]) { - break; +bool TextEditInput::matchKeyword(const char *str, int &count) { + for (int i = 0; i < keyword_syntax_len; i++) { + if (match(str, keyword_syntax[i].str, keyword_syntax[i].len) && + (str[keyword_syntax[i].len] == ' ' || str[keyword_syntax[i].len] == '\n')) { + count = keyword_syntax[i].len; + return true; } } - if (str[i] != ' ') { - i = 0; - } - return i; + return false; } void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { @@ -419,12 +427,12 @@ void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxSt // find the end of the current segment while (i < length) { - if (str[i] == '\'' || match(str + i, "RrEeMm", 3) == 3) { + if (str[i] == '\'' || match(str + i, "RrEeMm ", 3)) { next = length - i; nextState = kComment; break; } else if (str[i] == '\"') { - next++; + next = 1; while (i + next < length && str[i + next] != '\"') { next++; } @@ -433,8 +441,7 @@ void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxSt } nextState = kText; break; - } else if (str[i] == '(' || str[i] == ')') { - next = 1; + } else if (state == kReset && matchKeyword(str + i, next)) { nextState = kKeyword; break; } diff --git a/src/ui/textedit.h b/src/ui/textedit.h index bcf989c9..08cb6370 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -124,7 +124,7 @@ struct TextEditInput : public FormEditInput { int lineEnd(int pos) { return linePos(pos, true); } int linePos(int pos, bool end, bool excludeBreak=true); int lineStart(int pos) { return linePos(pos, false); } - int match(const char *str, const char *pattern , int len); + bool matchKeyword(const char *str, int &count); void pageNavigate(bool pageDown, bool shift); void removeTrailingSpaces(); void setColor(SyntaxState &state); From 7f0a981b9b0d09a63d0d1dfcab2f19837ecd933c Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 12 Aug 2015 08:27:20 +1000 Subject: [PATCH 06/14] UI: update syntax highlighting --- src/ui/textedit.cpp | 20 ++++++++++++-------- src/ui/textedit.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index f1304be8..a452b675 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -404,15 +404,19 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } -bool TextEditInput::matchKeyword(const char *str, int &count) { - for (int i = 0; i < keyword_syntax_len; i++) { - if (match(str, keyword_syntax[i].str, keyword_syntax[i].len) && - (str[keyword_syntax[i].len] == ' ' || str[keyword_syntax[i].len] == '\n')) { - count = keyword_syntax[i].len; - return true; +bool TextEditInput::matchKeyword(const char *str, int offs, int &count) { + bool result = false; + if (offs == 0 || (str[offs - 1] == ' ' || str[offs - 1] == '\n')) { + for (int i = 0; i < keyword_syntax_len; i++) { + if (match(str + offs, keyword_syntax[i].str, keyword_syntax[i].len) && + (str[keyword_syntax[i].len] == ' ' || str[keyword_syntax[i].len] == '\n')) { + count = keyword_syntax[i].len; + result = true; + break; + } } } - return false; + return result; } void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { @@ -441,7 +445,7 @@ void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxSt } nextState = kText; break; - } else if (state == kReset && matchKeyword(str + i, next)) { + } else if (state == kReset && matchKeyword(str, i, next)) { nextState = kKeyword; break; } diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 08cb6370..6ec04a15 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -124,7 +124,7 @@ struct TextEditInput : public FormEditInput { int lineEnd(int pos) { return linePos(pos, true); } int linePos(int pos, bool end, bool excludeBreak=true); int lineStart(int pos) { return linePos(pos, false); } - bool matchKeyword(const char *str, int &count); + bool matchKeyword(const char *str, int offs, int &count); void pageNavigate(bool pageDown, bool shift); void removeTrailingSpaces(); void setColor(SyntaxState &state); From eb3d42fc66a9060a7b6b367084af41f7a65b836a Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 12 Aug 2015 19:31:25 +1000 Subject: [PATCH 07/14] UI: update syntax highlighting --- src/ui/textedit.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index a452b675..f4c98298 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -299,7 +299,8 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } if (row++ >= _scroll) { - if (_matchingBrace != -1 && _matchingBrace >= i && _matchingBrace < i + r.num_chars) { + if (_matchingBrace != -1 && _matchingBrace >= i && + _matchingBrace < i + r.num_chars) { cursorMatchX = x + ((_matchingBrace - i) * chw); cursorMatchY = y + baseY; } @@ -409,7 +410,8 @@ bool TextEditInput::matchKeyword(const char *str, int offs, int &count) { if (offs == 0 || (str[offs - 1] == ' ' || str[offs - 1] == '\n')) { for (int i = 0; i < keyword_syntax_len; i++) { if (match(str + offs, keyword_syntax[i].str, keyword_syntax[i].len) && - (str[keyword_syntax[i].len] == ' ' || str[keyword_syntax[i].len] == '\n')) { + (str[offs + keyword_syntax[i].len] == ' ' || + str[offs + keyword_syntax[i].len] == '\n')) { count = keyword_syntax[i].len; result = true; break; @@ -419,7 +421,8 @@ bool TextEditInput::matchKeyword(const char *str, int offs, int &count) { return result; } -void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { +void TextEditInput::drawText(int x, int y, const char *str, + int length, SyntaxState &state) { int i = 0; int offs = 0; SyntaxState nextState = state; @@ -435,7 +438,7 @@ void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxSt next = length - i; nextState = kComment; break; - } else if (str[i] == '\"') { + } else if (state == kReset && str[i] == '\"') { next = 1; while (i + next < length && str[i + next] != '\"') { next++; @@ -638,7 +641,8 @@ bool TextEditInput::updateUI(var_p_t form, var_p_t field) { } bool TextEditInput::selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw) { - stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, pt.y + scrollY + (_scroll * _charHeight)); + stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, + pt.y + scrollY + (_scroll * _charHeight)); redraw = true; return 1; } From 6c6084af3cbccabf77e7b101688fa98c48625ac7 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 13 Aug 2015 22:27:20 +1000 Subject: [PATCH 08/14] UI: use keyword hash for syntax highlighting --- documentation/build_kwp.cpp | 53 ++++++++++++++------ src/ui/textedit.cpp | 98 +++++++++++++++++++++++++------------ src/ui/textedit.h | 10 ++-- 3 files changed, 112 insertions(+), 49 deletions(-) diff --git a/documentation/build_kwp.cpp b/documentation/build_kwp.cpp index eaaa53e3..ec11abad 100644 --- a/documentation/build_kwp.cpp +++ b/documentation/build_kwp.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../src/ui/strlib.h" #define code_t int @@ -45,6 +46,7 @@ struct spopr_keyword_s { struct HelpItem { char package[20]; char keyword[20]; + char type[20]; char id[20]; char signature[128]; char help[1024]; @@ -177,6 +179,8 @@ bool readHelpReference(strlib::List *helpItems) { break; case 1: // type + strncpy(item->type, lineBuffer + start, fieldLen); + item->type[fieldLen] = '\0'; break; case 2: // keyword @@ -215,6 +219,16 @@ bool readHelpReference(strlib::List *helpItems) { return true; } +uint32_t getHash(const char *key) { + uint32_t hash, i; + for (hash = i = 0; key[i] != '\0'; i++) { + hash += tolower(key[i]); + hash += (hash << 3); + hash ^= (hash >> 1); + } + return hash; +} + int main(int argc, char *argv[]) { strlib::List helpItems; if (!readHelpReference(&helpItems)) { @@ -228,35 +242,44 @@ int main(int argc, char *argv[]) { fprintf(stdout, " const char *signature;\n"); fprintf(stdout, " const char *help;\n"); fprintf(stdout, "} keyword_help[] = {\n"); + + int max_keyword_len = 0; List_each(HelpItem *, it, helpItems) { HelpItem *item = (*it); fprintf(stdout, "{\"%s\",\"%s\",\"%s\",\"%s\"},\n", item->package, item->keyword, item->signature, item->help); + int len = strlen(item->keyword); + if (len > max_keyword_len) { + max_keyword_len = len; + } } fprintf(stdout, "};\n"); fprintf(stdout, "const int keyword_help_len = %d;\n", helpItems.size()); + fprintf(stdout, "const int keyword_max_len = %d;\n", max_keyword_len); - int languageCount = 0; - fprintf(stdout, "\nstruct KEYWORD_SYNTAX {\n"); - fprintf(stdout, " const char *str;\n"); - fprintf(stdout, " const int len;\n"); - fprintf(stdout, "} keyword_syntax[] = {\n"); + int count = 0; + fprintf(stdout, "const uint32_t keyword_hash_statement[] = {\n"); List_each(HelpItem *, it, helpItems) { HelpItem *item = (*it); if (strcasecmp(item->package, "Language") == 0) { - languageCount++; - fputc('{', stdout); - fputc('\"', stdout); - int len = strlen(item->keyword); - for (int i = 0; i < len; i++) { - fputc(toupper(item->keyword[i]), stdout); - fputc(tolower(item->keyword[i]), stdout); - } - fprintf(stdout, "\",%d},\n", len); + count++; + fprintf(stdout, " %u,\n", getHash(item->keyword)); + } + } + fprintf(stdout, "};\n"); + fprintf(stdout, "const int keyword_hash_statement_len = %d;\n", count); + + count = 0; + fprintf(stdout, "const uint32_t keyword_hash_command[] = {\n"); + List_each(HelpItem *, it, helpItems) { + HelpItem *item = (*it); + if (strcasecmp(item->package, "Language") != 0) { + count++; + fprintf(stdout, " %u,\n", getHash(item->keyword)); } } fprintf(stdout, "};\n"); - fprintf(stdout, "const int keyword_syntax_len = %d;\n", languageCount); + fprintf(stdout, "const int keyword_hash_command_len = %d;\n", count); return 0; } diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index f4c98298..c2f5adff 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -28,27 +28,27 @@ int g_themeId = 0; const int theme1[] = { - 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xffffff, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, - 0x0083f8, 0xff8876 + 0x0083f8, 0xff9d00, 0x31ccac }; const int theme2[] = { - 0xa7aebc, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xffffff, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642, - 0x0083f8, 0xff8876 + 0x0083f8, 0xff9d00, 0x31ccac }; const int theme3[] = { - 0xa7aebc, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xffffff, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x022444, - 0x0083f8, 0xff8876 + 0x0083f8, 0xff9d00, 0x31ccac }; const int theme4[] = { - 0xa7aebc, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xffffff, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x2e3436, 0x888a85, 0x000000, 0x4d483b, 0x000000, 0x2b313a, - 0x0083f8, 0xff8876 + 0x0083f8, 0xff9d00, 0x31ccac }; const int* themes[] = { @@ -110,7 +110,8 @@ EditTheme::EditTheme(int fg, int bg) : _row_cursor(bg), _syntax_comments(bg), _syntax_text(fg), - _syntax_keywords(fg) { + _syntax_command(fg), + _syntax_statement(fg) { } void EditTheme::selectTheme(const int theme[]) { @@ -127,7 +128,8 @@ void EditTheme::selectTheme(const int theme[]) { _match_background = theme[10]; _row_cursor = theme[11]; _syntax_text = theme[12]; - _syntax_keywords = theme[13]; + _syntax_command = theme[13]; + _syntax_statement = theme[14]; } // @@ -405,22 +407,6 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } -bool TextEditInput::matchKeyword(const char *str, int offs, int &count) { - bool result = false; - if (offs == 0 || (str[offs - 1] == ' ' || str[offs - 1] == '\n')) { - for (int i = 0; i < keyword_syntax_len; i++) { - if (match(str + offs, keyword_syntax[i].str, keyword_syntax[i].len) && - (str[offs + keyword_syntax[i].len] == ' ' || - str[offs + keyword_syntax[i].len] == '\n')) { - count = keyword_syntax[i].len; - result = true; - break; - } - } - } - return result; -} - void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { int i = 0; @@ -448,9 +434,23 @@ void TextEditInput::drawText(int x, int y, const char *str, } nextState = kText; break; - } else if (state == kReset && matchKeyword(str, i, next)) { - nextState = kKeyword; - break; + } else if (state == kReset) { + int size = 0; + uint32_t hash = getHash(str, i, size); + if (hash > 0) { + if (matchCommand(hash)) { + nextState = kCommand; + next = size; + break; + } else if (matchStatement(hash)) { + nextState = kStatement; + next = size; + break; + } else { + i += size - 1; + count += size - 1; + } + } } i++; count++; @@ -947,6 +947,19 @@ int TextEditInput::getCursorRow() const { return row + 1; } +uint32_t TextEditInput::getHash(const char *str, int offs, int &count) { + uint32_t result = 0; + if ((offs == 0 || str[offs - 1] == ' ' || str[offs - 1] == '\n') + && str[offs] != ' ' && str[offs] != '\n' && str[offs] != '\0') { + for (count = 0; count < keyword_max_len && isalpha(str[offs + count]); count++) { + result += tolower(str[offs + count]); + result += (result << 3); + result ^= (result >> 1); + } + } + return result; +} + int TextEditInput::getIndent(char *spaces, int len, int pos) { // count the indent level and find the start of text char *buf = lineText(pos); @@ -1114,6 +1127,26 @@ int TextEditInput::linePos(int pos, bool end, bool excludeBreak) { return start; } +bool TextEditInput::matchCommand(uint32_t hash) { + bool result = false; + for (int i = 0; i < keyword_hash_command_len && !result; i++) { + if (keyword_hash_command[i] == hash) { + result = true; + } + } + return result; +} + +bool TextEditInput::matchStatement(uint32_t hash) { + bool result = false; + for (int i = 0; i < keyword_hash_statement_len && !result; i++) { + if (keyword_hash_statement[i] == hash) { + result = true; + } + } + return result; +} + void TextEditInput::pageNavigate(bool pageDown, bool shift) { int pageRows = (_height / _charHeight) + 1; int nextRow = _cursorRow + (pageDown ? pageRows : -pageRows); @@ -1157,8 +1190,11 @@ void TextEditInput::setColor(SyntaxState &state) { case kText: maSetColor(_theme->_syntax_text); break; - case kKeyword: - maSetColor(_theme->_syntax_keywords); + case kCommand: + maSetColor(_theme->_syntax_command); + break; + case kStatement: + maSetColor(_theme->_syntax_statement); break; case kReset: maSetColor(_theme->_color); diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 6ec04a15..c5458882 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -42,7 +42,8 @@ struct EditTheme { int _row_cursor; int _syntax_comments; int _syntax_text; - int _syntax_keywords; + int _syntax_command; + int _syntax_statement; }; struct EditBuffer { @@ -104,7 +105,8 @@ struct TextEditInput : public FormEditInput { kReset = 0, kComment, kText, - kKeyword, + kCommand, + kStatement, }; void drawText(int x, int y, const char *str, int length, SyntaxState &state); @@ -116,6 +118,7 @@ struct TextEditInput : public FormEditInput { void editTab(); void findMatchingBrace(); int getCursorRow() const; + uint32_t getHash(const char *str, int offs, int &count); int getIndent(char *spaces, int len, int pos); int getLineChars(StbTexteditRow *row, int pos); char *getSelection(int *start, int *end); @@ -124,7 +127,8 @@ struct TextEditInput : public FormEditInput { int lineEnd(int pos) { return linePos(pos, true); } int linePos(int pos, bool end, bool excludeBreak=true); int lineStart(int pos) { return linePos(pos, false); } - bool matchKeyword(const char *str, int offs, int &count); + bool matchCommand(uint32_t hash); + bool matchStatement(uint32_t hash); void pageNavigate(bool pageDown, bool shift); void removeTrailingSpaces(); void setColor(SyntaxState &state); From 144d9d6319bc49e2460af96ebff0f041aa3ca5cb Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 14 Aug 2015 17:57:49 +1000 Subject: [PATCH 09/14] UI: fix line no for wrapped lines --- src/ui/textedit.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index c2f5adff..a15d34a1 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -300,7 +300,13 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { break; } - if (row++ >= _scroll) { + if (i == 0 || + _buf._buffer[i - 1] == '\r' || + _buf._buffer[i - 1] == '\n') { + row++; + } + + if (row >= _scroll) { if (_matchingBrace != -1 && _matchingBrace >= i && _matchingBrace < i + r.num_chars) { cursorMatchX = x + ((_matchingBrace - i) * chw); @@ -568,6 +574,8 @@ void TextEditInput::gotoLine(const char *buffer) { } void TextEditInput::reload(const char *text) { + _scroll = 0; + _cursorRow = 0; _buf.clear(); _buf.insertChars(0, text, strlen(text)); stb_textedit_initialize_state(&_state, false); @@ -672,20 +680,23 @@ void TextEditInput::paste(const char *text) { void TextEditInput::layout(StbTexteditRow *row, int start) const { int i = start; int len = _buf._len; + int x1 = 0; int x2 = _width - _charWidth - _marginWidth; - row->x1 = 0; - row->num_chars = 0; + int numChars = 0; // advance to newline or rectangle edge while (i < len && (int)row->x1 < x2 && _buf._buffer[i] != '\r' && _buf._buffer[i] != '\n') { - row->x1 += _charWidth; - row->num_chars++; + x1 += _charWidth; + numChars++; i++; } + row->num_chars = numChars; + row->x1 = x1; + if (_buf._buffer[i] == '\r') { // advance over DOS newline row->num_chars++; From a5c49a54a67eb9eb6e6e3f697994899f28a21160 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 14 Aug 2015 21:18:33 +1000 Subject: [PATCH 10/14] UI: fix android build --- documentation/build_kwp.cpp | 4 ++-- src/ui/textedit.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/build_kwp.cpp b/documentation/build_kwp.cpp index ec11abad..e921e3a5 100644 --- a/documentation/build_kwp.cpp +++ b/documentation/build_kwp.cpp @@ -263,7 +263,7 @@ int main(int argc, char *argv[]) { HelpItem *item = (*it); if (strcasecmp(item->package, "Language") == 0) { count++; - fprintf(stdout, " %u,\n", getHash(item->keyword)); + fprintf(stdout, " %uu,\n", getHash(item->keyword)); } } fprintf(stdout, "};\n"); @@ -275,7 +275,7 @@ int main(int argc, char *argv[]) { HelpItem *item = (*it); if (strcasecmp(item->package, "Language") != 0) { count++; - fprintf(stdout, " %u,\n", getHash(item->keyword)); + fprintf(stdout, " %uu,\n", getHash(item->keyword)); } } fprintf(stdout, "};\n"); diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index a15d34a1..5621fcdb 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -686,7 +686,7 @@ void TextEditInput::layout(StbTexteditRow *row, int start) const { // advance to newline or rectangle edge while (i < len - && (int)row->x1 < x2 + && x1 < x2 && _buf._buffer[i] != '\r' && _buf._buffer[i] != '\n') { x1 += _charWidth; From 1d2e2ea99dd715ae51441cf76d05993cfbddf0cf Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 15 Aug 2015 08:22:22 +1000 Subject: [PATCH 11/14] UI: fix underscore input --- src/platform/sdl/keymap.h | 2 +- src/ui/textedit.cpp | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/platform/sdl/keymap.h b/src/platform/sdl/keymap.h index 3118bae3..a354176c 100644 --- a/src/platform/sdl/keymap.h +++ b/src/platform/sdl/keymap.h @@ -63,7 +63,7 @@ const int shiftmap[][2] = { {'8', '*'}, {'9', '('}, {'0', ')'}, - {'-', '-'}, + {'-', '_'}, {'=', '+'}, {'[', '{'}, {']', '}'}, diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 5621fcdb..a27a6437 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -82,7 +82,7 @@ const char *helpText = "F1,A-h keyword help\n" "F9, C-r run\n"; -static inline bool match(const char *str, const char *pattern , int len) { +inline bool match(const char *str, const char *pattern , int len) { int i, j; for (i = 0, j = 0; i < len; i++, j += 2) { if (str[i] != pattern[j] && str[i] != pattern[j + 1]) { @@ -92,6 +92,10 @@ static inline bool match(const char *str, const char *pattern , int len) { return i == len; } +inline bool is_comment(const char *str, int offs) { + return str[offs] == '\'' || str[offs] == '#' || match(str + offs, "RrEeMm ", 3); +} + // // EditTheme // @@ -426,7 +430,7 @@ void TextEditInput::drawText(int x, int y, const char *str, // find the end of the current segment while (i < length) { - if (str[i] == '\'' || match(str + i, "RrEeMm ", 3)) { + if (is_comment(str, i)) { next = length - i; nextState = kComment; break; @@ -962,7 +966,11 @@ uint32_t TextEditInput::getHash(const char *str, int offs, int &count) { uint32_t result = 0; if ((offs == 0 || str[offs - 1] == ' ' || str[offs - 1] == '\n') && str[offs] != ' ' && str[offs] != '\n' && str[offs] != '\0') { - for (count = 0; count < keyword_max_len && isalpha(str[offs + count]); count++) { + for (count = 0; count < keyword_max_len; count++) { + char ch = str[offs + count]; + if (!isalpha(ch) && ch != '_') { + break; + } result += tolower(str[offs + count]); result += (result << 3); result ^= (result >> 1); @@ -998,7 +1006,7 @@ int TextEditInput::getIndent(char *spaces, int len, int pos) { int j = i + 4; while (buf[j] != 0 && buf[j] != '\n') { // line also 'ends' at start of comments - if (strncasecmp(buf + j, "rem", 3) == 0 || buf[j] == '\'') { + if (is_comment(buf, j)) { break; } j++; From 4f52c96c0103d38f17d1204796a1cb2ead1ffda8 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 15 Aug 2015 14:50:33 +1000 Subject: [PATCH 12/14] UI: add highlighting for digits --- src/ui/textedit.cpp | 43 +++++++++++++++++++++++++++++++------------ src/ui/textedit.h | 2 ++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index a27a6437..c7a03c2c 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -28,27 +28,27 @@ int g_themeId = 0; const int theme1[] = { - 0xffffff, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xc8cedb, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, - 0x0083f8, 0xff9d00, 0x31ccac + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd }; const int theme2[] = { - 0xffffff, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xc8cedb, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642, - 0x0083f8, 0xff9d00, 0x31ccac + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd }; const int theme3[] = { - 0xffffff, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xc8cedb, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x022444, - 0x0083f8, 0xff9d00, 0x31ccac + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd }; const int theme4[] = { - 0xffffff, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, + 0xc8cedb, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x2e3436, 0x888a85, 0x000000, 0x4d483b, 0x000000, 0x2b313a, - 0x0083f8, 0xff9d00, 0x31ccac + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd }; const int* themes[] = { @@ -115,7 +115,8 @@ EditTheme::EditTheme(int fg, int bg) : _syntax_comments(bg), _syntax_text(fg), _syntax_command(fg), - _syntax_statement(fg) { + _syntax_statement(fg), + _syntax_digit(fg) { } void EditTheme::selectTheme(const int theme[]) { @@ -134,6 +135,7 @@ void EditTheme::selectTheme(const int theme[]) { _syntax_text = theme[12]; _syntax_command = theme[13]; _syntax_statement = theme[14]; + _syntax_digit = theme[15]; } // @@ -434,7 +436,9 @@ void TextEditInput::drawText(int x, int y, const char *str, next = length - i; nextState = kComment; break; - } else if (state == kReset && str[i] == '\"') { + } else if (state != kReset) { + break; + } else if (str[i] == '\"') { next = 1; while (i + next < length && str[i + next] != '\"') { next++; @@ -444,7 +448,18 @@ void TextEditInput::drawText(int x, int y, const char *str, } nextState = kText; break; - } else if (state == kReset) { + } else if (isdigit(str[i]) && (i == 0 || !isalpha(str[i - 1]))) { + next = 1; + while (i + next < length && isdigit(str[i + next])) { + next++; + } + if (i > 0 && str[i - 1] == '.') { + count--; + next++; + } + nextState = kDigit; + break; + } else { int size = 0; uint32_t hash = getHash(str, i, size); if (hash > 0) { @@ -1190,6 +1205,7 @@ void TextEditInput::pageNavigate(bool pageDown, bool shift) { } else { _state.select_start = _state.select_end; } + _state.cursor = i; _cursorRow = row; updateScroll(); @@ -1215,6 +1231,9 @@ void TextEditInput::setColor(SyntaxState &state) { case kStatement: maSetColor(_theme->_syntax_statement); break; + case kDigit: + maSetColor(_theme->_syntax_digit); + break; case kReset: maSetColor(_theme->_color); break; @@ -1225,7 +1244,7 @@ void TextEditInput::updateScroll() { int pageRows = _height / _charHeight; if (_cursorRow + 1 < pageRows) { _scroll = 0; - } else if (_cursorRow > _scroll + pageRows || _cursorRow <= _scroll) { + } else if (_cursorRow >= _scroll + pageRows || _cursorRow <= _scroll) { // cursor outside current view _scroll = _cursorRow - (pageRows / 2); } diff --git a/src/ui/textedit.h b/src/ui/textedit.h index c5458882..66d09b49 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -44,6 +44,7 @@ struct EditTheme { int _syntax_text; int _syntax_command; int _syntax_statement; + int _syntax_digit; }; struct EditBuffer { @@ -107,6 +108,7 @@ struct TextEditInput : public FormEditInput { kText, kCommand, kStatement, + kDigit, }; void drawText(int x, int y, const char *str, int length, SyntaxState &state); From 37419e6dadb3e9902f2ae571d76427c8c99b391b Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 15 Aug 2015 18:06:15 +1000 Subject: [PATCH 13/14] UI: fix text editor display issues --- src/ui/textedit.cpp | 39 +++++++++++++++++---------------------- src/ui/textedit.h | 1 - 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index c7a03c2c..8fcd52ee 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -93,7 +93,8 @@ inline bool match(const char *str, const char *pattern , int len) { } inline bool is_comment(const char *str, int offs) { - return str[offs] == '\'' || str[offs] == '#' || match(str + offs, "RrEeMm ", 3); + return (str[offs] == '\'' || (str[offs] == '#' && !isdigit(str[offs + 1])) + || match(str + offs, "RrEeMm ", 3)); } // @@ -205,12 +206,6 @@ char *EditBuffer::textRange(int start, int end) { return result; } -void EditBuffer::replaceChars(const char *replace, int start, int end) { - for (int i = start, j = 0; i < end && i < _len && replace[j] != '\0'; i++, j++) { - _buffer[i] = replace[j]; - } -} - void EditBuffer::removeTrailingSpaces(STB_TexteditState *state) { int lineEnd = _len - 1; int lastChar = lineEnd; @@ -293,6 +288,7 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { int cursorMatchX = x; int cursorMatchY = y; int row = 0; + int line = 0; int selectStart = MIN(_state.select_start, _state.select_end); int selectEnd = MAX(_state.select_start, _state.select_end); @@ -309,10 +305,10 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { if (i == 0 || _buf._buffer[i - 1] == '\r' || _buf._buffer[i - 1] == '\n') { - row++; + line++; } - if (row >= _scroll) { + if (row++ >= _scroll) { if (_matchingBrace != -1 && _matchingBrace >= i && _matchingBrace < i + r.num_chars) { cursorMatchX = x + ((_matchingBrace - i) * chw); @@ -380,9 +376,9 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { maSetColor(_theme->_selection_background); maFillRect(x + _marginWidth, y + baseY, _charWidth / 2, _charHeight); } - drawLineNumber(x, y + baseY, row, true); + drawLineNumber(x, y + baseY, line, true); } else { - drawLineNumber(x, y + baseY, row, false); + drawLineNumber(x, y + baseY, line, false); if (numChars) { if (_marginWidth > 0) { drawText(x + _marginWidth, y + baseY, _buf._buffer + i, numChars, syntax); @@ -397,7 +393,7 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { i += r.num_chars; } - drawLineNumber(x, y + baseY, row + 1, false); + drawLineNumber(x, y + baseY, line + 1, false); // draw cursor maSetColor(_theme->_cursor_background); @@ -432,13 +428,11 @@ void TextEditInput::drawText(int x, int y, const char *str, // find the end of the current segment while (i < length) { - if (is_comment(str, i)) { + if (state == kComment || is_comment(str, i)) { next = length - i; nextState = kComment; break; - } else if (state != kReset) { - break; - } else if (str[i] == '\"') { + } else if (state == kText || str[i] == '\"') { next = 1; while (i + next < length && str[i + next] != '\"') { next++; @@ -448,7 +442,8 @@ void TextEditInput::drawText(int x, int y, const char *str, } nextState = kText; break; - } else if (isdigit(str[i]) && (i == 0 || !isalpha(str[i - 1]))) { + } else if (state == kReset && isdigit(str[i]) && + (i == 0 || !isalpha(str[i - 1]))) { next = 1; while (i + next < length && isdigit(str[i + next])) { next++; @@ -459,7 +454,7 @@ void TextEditInput::drawText(int x, int y, const char *str, } nextState = kDigit; break; - } else { + } else if (state == kReset) { int size = 0; uint32_t hash = getHash(str, i, size); if (hash > 0) { @@ -471,7 +466,7 @@ void TextEditInput::drawText(int x, int y, const char *str, nextState = kStatement; next = size; break; - } else { + } else if (size > 0) { i += size - 1; count += size - 1; } @@ -768,9 +763,9 @@ void TextEditInput::changeCase() { } } if (selection[0]) { - _buf.replaceChars(selection, start, end); _state.select_start = start; _state.select_end = end; + stb_textedit_paste(&_buf, &_state, selection, strlen(selection)); } free(selection); } @@ -979,8 +974,8 @@ int TextEditInput::getCursorRow() const { uint32_t TextEditInput::getHash(const char *str, int offs, int &count) { uint32_t result = 0; - if ((offs == 0 || str[offs - 1] == ' ' || str[offs - 1] == '\n') - && str[offs] != ' ' && str[offs] != '\n' && str[offs] != '\0') { + if ((offs == 0 || IS_WHITE(str[offs - 1])) + && !IS_WHITE(str[offs]) && str[offs] != '\0') { for (count = 0; count < keyword_max_len; count++) { char ch = str[offs + count]; if (!isalpha(ch) && ch != '_') { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 66d09b49..15a6700e 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -62,7 +62,6 @@ struct EditBuffer { int deleteChars(int pos, int num); int insertChars(int pos, const char *text, int num); void removeTrailingSpaces(STB_TexteditState *state); - void replaceChars(const char *replace, int start, int end); char *textRange(int start, int end); }; From bf0fa010a0dfa2bd0b4fc48dc0e6e5d8bcff9fe3 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 16 Aug 2015 10:45:29 +1000 Subject: [PATCH 14/14] UI: update help message --- src/ui/system.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui/system.cpp b/src/ui/system.cpp index b04fc0b5..719a8d41 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -95,14 +95,15 @@ void System::editSource(strlib::String &loadPath) { fileName = loadPath; } + const char *help = " Ctrl+h (C-h)=Help"; strlib::String dirtyFile; dirtyFile.append(" * "); dirtyFile.append(fileName); - dirtyFile.append(" C-h=Help"); + dirtyFile.append(help); strlib::String cleanFile; cleanFile.append(" - "); cleanFile.append(fileName); - cleanFile.append(" C-h=Help"); + cleanFile.append(help); int w = _output->getWidth(); int h = _output->getHeight();