From cff64bbb1b48c4222abc6dfcf634a2fdc42fd8fc Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 25 Aug 2015 06:42:26 +1000 Subject: [PATCH 01/15] UI: fix num highlight, add edit cursor --- configure.ac | 2 +- ide/android/assets/main.bas | 2 +- src/platform/android/jni/runtime.h | 2 +- src/platform/sdl/runtime.cpp | 20 +++++++++++++++++--- src/platform/sdl/runtime.h | 3 ++- src/ui/ansiwidget.h | 3 ++- src/ui/system.cpp | 10 ++++++---- src/ui/system.h | 6 +++++- src/ui/textedit.cpp | 19 +++++++++++++------ 9 files changed, 48 insertions(+), 19 deletions(-) diff --git a/configure.ac b/configure.ac index a8ebb284..c5309fcb 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ dnl This program is distributed under the terms of the GPL v2.0 dnl Download the GNU Public License (GPL) from www.gnu.org dnl -AC_INIT([smallbasic], [0.11.19]) +AC_INIT([smallbasic], [0.11.20]) AC_CONFIG_SRCDIR([configure.ac]) AC_CANONICAL_TARGET diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index 5a480c9e..c9608c08 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -56,7 +56,7 @@ sub do_about() print "(_ ._ _ _.|||_) /\ (_ |/ " print "__)| | |(_||||_)/--\__)|\_" print - print "Version 0.11.19" + print "Version 0.11.20" print print "Copyright (c) 2002-2015 Chris Warren-Smith" print "Copyright (c) 1999-2006 Nic Christopoulos" + chr(10) diff --git a/src/platform/android/jni/runtime.h b/src/platform/android/jni/runtime.h index 950db4f4..951f6360 100644 --- a/src/platform/android/jni/runtime.h +++ b/src/platform/android/jni/runtime.h @@ -44,7 +44,7 @@ struct Runtime : public System { char *loadResource(const char *fileName); void optionsBox(StringList *items); void setWindowTitle(const char *title) {} - void showCursor(bool hand) {} + void showCursor(CursorType cursorType) {} void showKeypad(bool show); void onResize(int w, int h); void loadConfig(); diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index b840da89..42c7b18c 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -61,7 +61,8 @@ Runtime::Runtime(SDL_Window *window) : _eventQueue(NULL), _window(window), _cursorHand(NULL), - _cursorArrow(NULL) { + _cursorArrow(NULL), + _cursorIBeam(NULL) { runtime = this; } @@ -77,8 +78,10 @@ Runtime::~Runtime() { SDL_FreeCursor(_cursorHand); SDL_FreeCursor(_cursorArrow); + SDL_FreeCursor(_cursorIBeam); _cursorHand = NULL; _cursorArrow = NULL; + _cursorIBeam = NULL; } void Runtime::alert(const char *title, const char *message) { @@ -120,6 +123,7 @@ void Runtime::construct(const char *font, const char *boldFont) { _cursorHand = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); _cursorArrow = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + _cursorIBeam = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); if (_graphics && _graphics->construct(font, boldFont)) { int w, h; @@ -461,8 +465,18 @@ void Runtime::setWindowTitle(const char *title) { } } -void Runtime::showCursor(bool hand) { - SDL_SetCursor(hand ? _cursorHand : _cursorArrow); +void Runtime::showCursor(CursorType cursorType) { + switch (cursorType) { + case kHand: + SDL_SetCursor(_cursorHand); + break; + case kArrow: + SDL_SetCursor(_cursorArrow); + break; + case kIBeam: + SDL_SetCursor(_cursorIBeam); + break; + } } void Runtime::onResize(int width, int height) { diff --git a/src/platform/sdl/runtime.h b/src/platform/sdl/runtime.h index f0e4c245..a9cc9921 100644 --- a/src/platform/sdl/runtime.h +++ b/src/platform/sdl/runtime.h @@ -34,7 +34,7 @@ struct Runtime : public System { void processEvent(MAEvent &event); void pushEvent(MAEvent *event); void setWindowTitle(const char *title); - void showCursor(bool hand); + void showCursor(CursorType cursorType); int runShell(const char *startupBas, int fontScale); char *loadResource(const char *fileName); void optionsBox(StringList *items); @@ -49,6 +49,7 @@ struct Runtime : public System { SDL_Window *_window; SDL_Cursor *_cursorHand; SDL_Cursor *_cursorArrow; + SDL_Cursor *_cursorIBeam; }; #endif diff --git a/src/ui/ansiwidget.h b/src/ui/ansiwidget.h index c0839161..1ee564e3 100755 --- a/src/ui/ansiwidget.h +++ b/src/ui/ansiwidget.h @@ -58,7 +58,8 @@ struct AnsiWidget { int getWidth() { return _width; } int getX() { return _back->_curX; } int getY() { return _back->_curY; } - bool hasHover() { return _hoverInput != NULL; } + bool hasHover() const { return _hoverInput != NULL; } + bool hasMenu() const { return _back == _screens[MENU_SCREEN]; } int insetMenuScreen(int x, int y, int w, int h); int insetTextScreen(int x, int y, int w, int h); bool pointerTouchEvent(MAEvent &event); diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 719a8d41..5049b4d5 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -136,6 +136,7 @@ void System::editSource(strlib::String &loadPath) { _state = kEditState; maShowVirtualKeyboard(); + showCursor(kIBeam); while (_state == kEditState) { MAEvent event = getNextEvent(); @@ -540,9 +541,7 @@ void System::handleEvent(MAEvent &event) { _touchY = _touchCurY = event.point.y; dev_pushkey(SB_KEY_MK_PUSH); _buttonPressed = _output->pointerTouchEvent(event); - if (_buttonPressed) { - showCursor(true); - } + showCursor(get_focus_edit() != NULL ? kIBeam : kHand); break; case EVENT_TYPE_POINTER_DRAGGED: _touchCurX = event.point.x; @@ -550,13 +549,16 @@ void System::handleEvent(MAEvent &event) { hasHover = _output->hasHover(); _output->pointerMoveEvent(event); if (hasHover != _output->hasHover()) { - showCursor(!hasHover); + showCursor(hasHover ? kArrow : kHand); + } else if (_output->hasMenu()) { + showCursor(kArrow); } break; case EVENT_TYPE_POINTER_RELEASED: _buttonPressed = false; _touchX = _touchY = _touchCurX = _touchCurY = -1; _output->pointerReleaseEvent(event); + showCursor(get_focus_edit() != NULL ? kIBeam : kArrow); break; default: // no event diff --git a/src/ui/system.h b/src/ui/system.h index f568267b..3359ee35 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -42,13 +42,17 @@ struct System { void systemPrint(const char *msg, ...); AnsiWidget *getOutput() { return _output; } + enum CursorType { + kHand, kArrow, kIBeam + }; + virtual void alert(const char *title, const char *message) = 0; virtual int ask(const char *title, const char *prompt, bool cancel=true) = 0; virtual MAEvent processEvents(int waitFlag) = 0; virtual char *loadResource(const char *fileName); virtual void optionsBox(StringList *items) = 0; virtual void setWindowTitle(const char *title) = 0; - virtual void showCursor(bool hand) = 0; + virtual void showCursor(CursorType cursorType) = 0; virtual void setClipboardText(const char *text) = 0; virtual char *getClipboardText() = 0; diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 8fcd52ee..aece8b03 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -443,17 +443,24 @@ void TextEditInput::drawText(int x, int y, const char *str, nextState = kText; break; } else if (state == kReset && isdigit(str[i]) && - (i == 0 || !isalpha(str[i - 1]))) { + (i == 0 || !isalnum(str[i - 1]))) { next = 1; while (i + next < length && isdigit(str[i + next])) { next++; } - if (i > 0 && str[i - 1] == '.') { - count--; - next++; + if (!isalnum(str[i + next])) { + if (i > 0 && str[i - 1] == '.') { + i--; + count--; + next++; + } + nextState = kDigit; + break; + } else { + i += next; + count += next; + next = 0; } - nextState = kDigit; - break; } else if (state == kReset) { int size = 0; uint32_t hash = getHash(str, i, size); From 67c6ea5127f9c7ba2721873494af8ee848a7a529 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 27 Aug 2015 06:58:35 +1000 Subject: [PATCH 02/15] UI: minor editor fixes --- ChangeLog | 5 +++++ src/lib/stb_textedit.h | 4 +++- src/ui/system.cpp | 1 + src/ui/textedit.cpp | 18 +++++++++++++++--- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index dc8ef4a4..a2e97189 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-08-26 + Fix editor highlighting for numbers and keywords + Fix F1 editor key for keywords surrounded by punctuation + Fix page scrolling with up/down arrow keys + 2015-08-02 Fix display output before DELAY Fix LET command problem found in 32bit linux diff --git a/src/lib/stb_textedit.h b/src/lib/stb_textedit.h index f46160eb..eed1be3f 100644 --- a/src/lib/stb_textedit.h +++ b/src/lib/stb_textedit.h @@ -604,7 +604,9 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat #ifdef STB_TEXTEDIT_IS_SPACE static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx ) { - return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1; + return _idx > 0 ? ((STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(_str,_idx-1)) || + STB_TEXTEDIT_IS_PUNCT(STB_TEXTEDIT_GETCHAR(_str,_idx-1))) && + !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(_str, _idx))) : 1; } static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 5049b4d5..87f0edb9 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -318,6 +318,7 @@ bool System::execute(const char *bas) { _state = kRunState; setWindowTitle(bas); + showCursor(kArrow); int result = ::sbasic_main(bas); if (isRunning()) { diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index aece8b03..b3dd0eec 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -16,6 +16,7 @@ #include "ui/kwp.h" #define STB_TEXTEDIT_IS_SPACE(ch) IS_WHITE(ch) +#define STB_TEXTEDIT_IS_PUNCT(ch) ispunct(ch) #define STB_TEXTEDIT_IMPLEMENTATION #include "lib/stb_textedit.h" @@ -559,7 +560,18 @@ bool TextEditInput::edit(int key, int screenWidth, int charWidth) { } _cursorRow = getCursorRow(); - updateScroll(); + if (key == STB_TEXTEDIT_K_UP) { + if (_cursorRow == _scroll) { + updateScroll(); + } + } else if (key == STB_TEXTEDIT_K_DOWN) { + int pageRows = _height / _charHeight; + if (_cursorRow - _scroll > pageRows) { + updateScroll(); + } + } else { + updateScroll(); + } findMatchingBrace(); return true; } @@ -981,7 +993,7 @@ int TextEditInput::getCursorRow() const { uint32_t TextEditInput::getHash(const char *str, int offs, int &count) { uint32_t result = 0; - if ((offs == 0 || IS_WHITE(str[offs - 1])) + if ((offs == 0 || IS_WHITE(str[offs - 1]) || ispunct(str[offs - 1])) && !IS_WHITE(str[offs]) && str[offs] != '\0') { for (count = 0; count < keyword_max_len; count++) { char ch = str[offs + count]; @@ -1069,7 +1081,7 @@ char *TextEditInput::getSelection(int *start, int *end) { } else { *start = wordStart(); int i = _state.cursor; - while (!IS_WHITE(_buf._buffer[i]) && i < _buf._len) { + while (!IS_WHITE(_buf._buffer[i]) && !ispunct(_buf._buffer[i]) && i < _buf._len) { i++; } *end = i; From cfd4c751a000ee49883154079871af990e1dc0a7 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 27 Aug 2015 22:20:42 +1000 Subject: [PATCH 03/15] UI: fix tab handling --- ChangeLog | 9 ++++++--- src/platform/sdl/runtime.cpp | 15 ++++++++++----- src/ui/system.cpp | 1 + src/ui/textedit.cpp | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index a2e97189..222d1c6f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,10 @@ 2015-08-26 - Fix editor highlighting for numbers and keywords - Fix F1 editor key for keywords surrounded by punctuation - Fix page scrolling with up/down arrow keys + Editor fixes: + - now displays an i-beam/edit cursor + - highlighting for numbers and keywords + - F1 key for keywords surrounded by punctuation + - page scrolling with up/down arrow keys + - pressing tab at the bottom no longer jumps to the top 2015-08-02 Fix display output before DELAY diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 42c7b18c..3d299973 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -554,12 +554,17 @@ void Runtime::optionsBox(StringList *items) { _output->selectScreen(screenId); _menuX = 2; _menuY = 2; - if (selectedIndex != -1) { - MAEvent *maEvent = new MAEvent(); - maEvent->type = EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED; - maEvent->optionsBoxButtonIndex = selectedIndex; - pushEvent(maEvent); + if (_systemMenu == NULL && isRunning() && + !form_ui::optionSelected(selectedIndex)) { + dev_clrkb(); + dev_pushkey(selectedIndex); + } else { + MAEvent *maEvent = new MAEvent(); + maEvent->type = EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED; + maEvent->optionsBoxButtonIndex = selectedIndex; + pushEvent(maEvent); + } } else { delete [] _systemMenu; _systemMenu = NULL; diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 87f0edb9..899d6b69 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -530,6 +530,7 @@ void System::handleEvent(MAEvent &event) { handleMenu(event.optionsBoxButtonIndex); } else if (isRunning()) { if (!form_ui::optionSelected(event.optionsBoxButtonIndex)) { + dev_clrkb(); dev_pushkey(event.optionsBoxButtonIndex); } } diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index b3dd0eec..8b686483 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -903,7 +903,7 @@ void TextEditInput::editTab() { // remove excess spaces stb_textedit_delete(&_buf, &_state, start, curIndent - indent); _state.cursor = start + indent; - } else { + } else if (start + indent > 0) { // already have ideal indent - soft-tab to indent _state.cursor = start + indent; } From ba536cc07bef298f81624fc38b8da71ad05d5310 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 30 Aug 2015 17:57:30 +1000 Subject: [PATCH 04/15] SDL: added basic debugger backend --- samples/distro-examples/games/sokoban.levels | 3 +- src/common/brun.c | 13 +-- src/common/device.c | 6 + src/common/device.h | 7 ++ src/common/inet.h | 8 ++ src/common/pproc.h | 1 + src/common/proc.c | 4 + src/common/smbas.h | 3 +- src/platform/sdl/main.cpp | 23 +++- src/platform/sdl/runtime.cpp | 116 ++++++++++++++++++- src/platform/sdl/runtime.h | 2 +- 11 files changed, 169 insertions(+), 17 deletions(-) diff --git a/samples/distro-examples/games/sokoban.levels b/samples/distro-examples/games/sokoban.levels index 1cece6a4..9cc5c770 100644 --- a/samples/distro-examples/games/sokoban.levels +++ b/samples/distro-examples/games/sokoban.levels @@ -1,4 +1,3 @@ -; $Id$ ; Original sokoban levels ; @@ -466,7 +465,7 @@ ; 30 - ########### + ########### # # # ##### # $ $ # # ##### $## # ## diff --git a/src/common/brun.c b/src/common/brun.c index 4de8185d..5f73822b 100755 --- a/src/common/brun.c +++ b/src/common/brun.c @@ -746,7 +746,6 @@ void bc_loop(int isf) { bcip_t next_ip; int i; int proc_level = 0; - byte trace_flag = 0; byte code = 0; // setup event checker time = 50ms @@ -815,8 +814,8 @@ void bc_loop(int isf) { continue; case kwTYPE_LINE: prog_line = code_getaddr(); - if (trace_flag) { - dev_printf("<%d>", prog_line); + if (opt_trace_on) { + dev_trace_line(prog_line); } continue; case kwLET: @@ -1031,10 +1030,10 @@ void bc_loop(int isf) { cmd_fseek(); break; case kwTRON: - trace_flag = 1; + opt_trace_on = 1; continue; case kwTROFF: - trace_flag = 0; + opt_trace_on = 0; continue; case kwSTOP: case kwEND: @@ -1088,8 +1087,8 @@ void bc_loop(int isf) { prog_ip++; if (code == kwTYPE_LINE) { prog_line = code_getaddr(); - if (trace_flag) { - dev_printf("<%d>", prog_line); + if (opt_trace_on) { + dev_trace_line(prog_line); } } } diff --git a/src/common/device.c b/src/common/device.c index 0eb82d17..caf7f84e 100644 --- a/src/common/device.c +++ b/src/common/device.c @@ -426,3 +426,9 @@ void v_create_form(var_p_t var) {} void v_create_window(var_p_t var) {} void dev_show_page() {} #endif + +#if !defined(_SDL) +void dev_trace_line(int lineNo) { + dev_printf("<%d>", lineNo); +} +#endif diff --git a/src/common/device.h b/src/common/device.h index 7d75a11e..94816a4c 100644 --- a/src/common/device.h +++ b/src/common/device.h @@ -1036,6 +1036,13 @@ void dev_destroy_file_list(char_p_t *list, int count); */ dword dev_get_millisecond_count(); +/** + * @ingroup dev_f + * + * Trace or debug at the given line number + */ +void dev_trace_line(int lineNo); + #if defined(__cplusplus) } #endif diff --git a/src/common/inet.h b/src/common/inet.h index 8eb102e1..47bbb477 100644 --- a/src/common/inet.h +++ b/src/common/inet.h @@ -18,6 +18,10 @@ #include #include +#if defined(__cplusplus) +extern "C" { +#endif + typedef int socket_t; /** @@ -127,4 +131,8 @@ void net_disconnect(socket_t s); */ int net_peek(socket_t s); +#if defined(__cplusplus) +} +#endif + #endif diff --git a/src/common/pproc.h b/src/common/pproc.h index 68ababb0..d89f6264 100644 --- a/src/common/pproc.h +++ b/src/common/pproc.h @@ -31,6 +31,7 @@ #define PV_FILE 1 #define PV_LOG 2 #define PV_STRING 3 +#define PV_NET 4 #if defined(__cplusplus) extern "C" { diff --git a/src/common/proc.c b/src/common/proc.c index fab9c56e..68092225 100644 --- a/src/common/proc.c +++ b/src/common/proc.c @@ -10,6 +10,7 @@ #include "common/sys.h" #include "common/pproc.h" #include "common/messages.h" +#include "common/inet.h" #include /* @@ -254,6 +255,9 @@ void pv_write(char *str, int method, int handle) { } strcat((char *) vp->v.p.ptr, str); break; + case PV_NET: + net_print((socket_t) handle, (const char *)str); + break; default: dev_print(str); } diff --git a/src/common/smbas.h b/src/common/smbas.h index f8c6aa7e..aaf92cec 100644 --- a/src/common/smbas.h +++ b/src/common/smbas.h @@ -126,7 +126,8 @@ EXTERN byte opt_usepcre; /**< OPTION PREDEF PCRE */ EXTERN byte opt_file_permitted; /**< file system permission */ EXTERN byte opt_show_page; /**< SHOWPAGE graphics flush mode */ EXTERN byte opt_mute_audio; /**< whether to mute sounds */ -EXTERN byte opt_antialias; /**< OPTION ANTIALIAS OFF */ +EXTERN byte opt_antialias; /**< OPTION ANTIALIAS OFF */ +EXTERN byte opt_trace_on; /**< initial value for the TRON command */ #define IDE_NONE 0 #define IDE_INTERNAL 1 diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index db15ffc1..07151a47 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -47,6 +47,7 @@ static struct option OPTIONS[] = { {"run", optional_argument, NULL, 'r'}, {"module", optional_argument, NULL, 'm'}, {"edit", optional_argument, NULL, 'e'}, + {"debug", optional_argument, NULL, 'd'}, {0, 0, 0, 0} }; @@ -232,6 +233,7 @@ int main(int argc, char* argv[]) { char *fontFamily = NULL; char *runFile = NULL; + int debugPort = 0; int fontScale; SDL_Rect rect; @@ -239,7 +241,7 @@ int main(int argc, char* argv[]) { while (1) { int option_index = 0; - int c = getopt_long(argc, argv, "hvkc:f:r:m:e:", OPTIONS, &option_index); + int c = getopt_long(argc, argv, "hvkc:f:r:m:e:d:", OPTIONS, &option_index); if (c == -1) { // no more options if (!option_index) { @@ -257,9 +259,17 @@ int main(int argc, char* argv[]) { } break; } - if (OPTIONS[option_index].has_arg && !optarg) { - showHelp(); - exit(1); + + int i = 0; + while (OPTIONS[i].name != NULL) { + if (OPTIONS[i].has_arg && OPTIONS[i].val == c && + (!optarg || strcmp(OPTIONS[i].name + 1, optarg) == 0)) { + // no arg or passed single '-' for long form arg + showHelp(); + exit(1); + break; + } + i++; } switch (c) { case 'v': @@ -284,6 +294,9 @@ int main(int argc, char* argv[]) { opt_loadmod = 1; strcpy(opt_modlist, optarg); break; + case 'd': + debugPort = atoi(optarg); + break; case 'h': showHelp(); exit(1); @@ -311,7 +324,7 @@ int main(int argc, char* argv[]) { loadIcon(window); Runtime *runtime = new Runtime(window); runtime->construct(font.c_str(), fontBold.c_str()); - fontScale = runtime->runShell(runFile, fontScale); + fontScale = runtime->runShell(runFile, fontScale, debugPort); delete runtime; } else { fprintf(stderr, "Failed to locate display font\n"); diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 3d299973..9a8c65fa 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -14,6 +14,8 @@ #include "common/device.h" #include "common/fs_socket_client.h" #include "common/keymap.h" +#include "common/inet.h" +#include "common/pproc.h" #include "lib/maapi.h" #include "ui/utils.h" #include "platform/sdl/runtime.h" @@ -27,6 +29,7 @@ #include #define WAIT_INTERVAL 5 +#define COND_WAIT_TIME 250 #define MAIN_BAS "__main_bas__" #define AMPLITUDE 22000 #define FREQUENCY 44100 @@ -35,6 +38,11 @@ #define OPTIONS_BOX_FG 0x3e3f3e Runtime *runtime; +SDL_mutex *g_lock = NULL; +SDL_cond *g_cond = NULL; +SDL_bool g_condFlag = SDL_FALSE; +SDL_bool g_debug = SDL_FALSE; +strlib::List g_breakPoints; struct SoundObject { double v; @@ -44,6 +52,7 @@ struct SoundObject { std::queue sounds; void audio_callback(void *beeper, Uint8 *stream8, int length); +int debugThread(void *data); MAEvent *getMotionEvent(int type, SDL_Event *event) { MAEvent *result = new MAEvent(); @@ -150,7 +159,7 @@ MAEvent *Runtime::popEvent() { return _eventQueue->pop(); } -int Runtime::runShell(const char *startupBas, int fontScale) { +int Runtime::runShell(const char *startupBas, int fontScale, int debugPort) { logEntered(); os_graphics = 1; @@ -182,6 +191,15 @@ int Runtime::runShell(const char *startupBas, int fontScale) { SDL_AudioSpec obtainedSpec; SDL_OpenAudio(&desiredSpec, &obtainedSpec); + if (debugPort > 0) { + g_lock = SDL_CreateMutex(); + g_cond = SDL_CreateCond(); + opt_trace_on = 1; + SDL_Thread *thread = + SDL_CreateThread(debugThread, "DBg", (void *)(intptr_t)debugPort); + SDL_DetachThread(thread); + } + if (startupBas != NULL) { String bas = startupBas; if (opt_ide == IDE_INTERNAL) { @@ -200,6 +218,11 @@ int Runtime::runShell(const char *startupBas, int fontScale) { runMain(MAIN_BAS); } + if (debugPort > 0) { + SDL_DestroyCond(g_cond); + SDL_DestroyMutex(g_lock); + } + SDL_CloseAudio(); _state = kDoneState; logLeaving(); @@ -677,6 +700,12 @@ int osd_devinit(void) { setsysvar_str(SYSVAR_OSNAME, "SDL"); runtime->setRunning(true); osd_clear_sound_queue(); + + SDL_LockMutex(g_lock); + g_condFlag = SDL_FALSE; + g_debug = SDL_FALSE; + SDL_UnlockMutex(g_lock); + return 1; } @@ -703,3 +732,88 @@ void osd_sound(int frq, int ms, int vol, int bgplay) { void osd_clear_sound_queue() { flush_queue(); } + +// +// debugging +// +void signalTrace(SDL_bool debug) { + SDL_LockMutex(g_lock); + g_condFlag = SDL_TRUE; + g_debug = debug; + SDL_CondSignal(g_cond); + SDL_UnlockMutex(g_lock); +} + +int debugThread(void *data) { + int port = ((intptr_t) data); + socket_t socket = net_listen(port); + char buf[OS_PATHNAME_SIZE + 1]; + net_print(socket, "SmallBASIC debugger\n"); + + while (socket != -1) { + int size = net_input(socket, buf, sizeof(buf), "\r\n"); + if (size > 0) { + char cmd = buf[0]; + switch (cmd) { + case 'n': + // step over next line + signalTrace(SDL_TRUE); + net_printf(socket, "%d\n", prog_line); + for (unsigned i = 0; i < prog_varcount; i++) { + pv_writevar(tvar[i], PV_NET, socket); + net_print(socket, "\n"); + } + break; + case 'c': + // continue + signalTrace(SDL_FALSE); + break; + case 'b': + // set breakpoint + SDL_LockMutex(g_lock); + g_breakPoints.add(new int(atoi(buf + 2))); + SDL_UnlockMutex(g_lock); + break; + case 'q': + // quit + signalTrace(SDL_FALSE); + g_breakPoints.removeAll(); + net_print(socket, "Bye\n"); + net_disconnect(socket); + socket = -1; + break; + default: + // unknown command + net_printf(socket, "Unknown command '%s'\n", buf); + break; + }; + } else fprintf(stderr, "."); + } + return 0; +} + +extern "C" void dev_trace_line(int lineNo) { + SDL_LockMutex(g_lock); + if (!g_debug) { + List_each(int *, it, g_breakPoints) { + int breakPoint = *(*it); + if (breakPoint == lineNo) { + runtime->systemPrint("Break point hit at line: %d", lineNo); + g_debug = SDL_TRUE; + break; + } + } + } + if (g_debug) { + g_condFlag = SDL_FALSE; + while (!g_condFlag) { + SDL_CondWaitTimeout(g_cond, g_lock, COND_WAIT_TIME); + runtime->processEvents(0); + if (!runtime->isRunning()) { + break; + } + } + } + SDL_UnlockMutex(g_lock); +} + diff --git a/src/platform/sdl/runtime.h b/src/platform/sdl/runtime.h index a9cc9921..bc279f5d 100644 --- a/src/platform/sdl/runtime.h +++ b/src/platform/sdl/runtime.h @@ -35,7 +35,7 @@ struct Runtime : public System { void pushEvent(MAEvent *event); void setWindowTitle(const char *title); void showCursor(CursorType cursorType); - int runShell(const char *startupBas, int fontScale); + int runShell(const char *startupBas, int fontScale, int debugPort); char *loadResource(const char *fileName); void optionsBox(StringList *items); void onResize(int w, int h); From c4ed932441e6d41abb14486184bfe7da567634f6 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 1 Sep 2015 22:11:29 +1000 Subject: [PATCH 05/15] SDL: launch debug window --- src/platform/android/jni/Android.mk | 1 + src/platform/android/jni/runtime.cpp | 2 + src/platform/sdl/Makefile.am | 1 + src/platform/sdl/main.cpp | 41 +++-- src/platform/sdl/runtime.cpp | 69 ++++---- src/platform/sdl/settings.cpp | 20 ++- src/platform/sdl/settings.h | 6 +- src/platform/sdl/syswm.cpp | 27 +++ src/platform/sdl/syswm.h | 1 + src/ui/editor.cpp | 247 +++++++++++++++++++++++++++ src/ui/system.cpp | 224 +----------------------- src/ui/textedit.cpp | 4 + 12 files changed, 363 insertions(+), 280 deletions(-) create mode 100644 src/ui/editor.cpp diff --git a/src/platform/android/jni/Android.mk b/src/platform/android/jni/Android.mk index c13752b1..1d087953 100644 --- a/src/platform/android/jni/Android.mk +++ b/src/platform/android/jni/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES := main.cpp \ ../../../ui/textedit.cpp \ ../../../ui/strlib.cpp \ ../../../ui/graphics.cpp \ + ../../../ui/editor.cpp \ ../../../ui/system.cpp LOCAL_LDLIBS := -llog -landroid -ljnigraphics LOCAL_STATIC_LIBRARIES := sb_common freetype android_native_app_glue diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 7a0b28c3..f00d7bd0 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -33,6 +33,8 @@ Runtime *runtime; +void launchDebug(const char *file) {} + MAEvent *getMotionEvent(int type, AInputEvent *event) { MAEvent *result = new MAEvent(); result->type = type; diff --git a/src/platform/sdl/Makefile.am b/src/platform/sdl/Makefile.am index d72e0acc..cfa57b7b 100644 --- a/src/platform/sdl/Makefile.am +++ b/src/platform/sdl/Makefile.am @@ -20,6 +20,7 @@ sbasicg_SOURCES = \ ../../ui/window.cpp \ ../../ui/screen.cpp \ ../../ui/system.cpp \ + ../../ui/editor.cpp \ ../../ui/form.cpp \ ../../ui/inputs.cpp \ ../../ui/textedit.cpp \ diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 07151a47..1e609422 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -39,19 +39,21 @@ const char* FONTS[] = { }; static struct option OPTIONS[] = { - {"help", no_argument, NULL, 'h'}, - {"verbose", no_argument, NULL, 'v'}, - {"keywords", no_argument, NULL, 'k'}, - {"command", optional_argument, NULL, 'c'}, - {"font", optional_argument, NULL, 'f'}, - {"run", optional_argument, NULL, 'r'}, - {"module", optional_argument, NULL, 'm'}, - {"edit", optional_argument, NULL, 'e'}, - {"debug", optional_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"verbose", no_argument, NULL, 'v'}, + {"keywords", no_argument, NULL, 'k'}, + {"command", optional_argument, NULL, 'c'}, + {"font", optional_argument, NULL, 'f'}, + {"run", optional_argument, NULL, 'r'}, + {"module", optional_argument, NULL, 'm'}, + {"edit", optional_argument, NULL, 'e'}, + {"debug", optional_argument, NULL, 'd'}, + {"debugPort", optional_argument, NULL, 'p'}, {0, 0, 0, 0} }; -const char *CONFIG_NAME = "SmallBASIC"; +const char *g_appPath; +int g_debugPort = 4000; void appLog(const char *format, ...) { char buf[4096], *p = buf; @@ -230,18 +232,17 @@ int main(int argc, char* argv[]) { opt_command[0] = '\0'; opt_verbose = false; opt_quiet = true; + g_appPath = argv[0]; char *fontFamily = NULL; char *runFile = NULL; - int debugPort = 0; + bool debug = false; int fontScale; SDL_Rect rect; - restoreSettings(CONFIG_NAME, rect, fontScale); - while (1) { int option_index = 0; - int c = getopt_long(argc, argv, "hvkc:f:r:m:e:d:", OPTIONS, &option_index); + int c = getopt_long(argc, argv, "hvkc:f:r:m:e:d:p:", OPTIONS, &option_index); if (c == -1) { // no more options if (!option_index) { @@ -295,7 +296,12 @@ int main(int argc, char* argv[]) { strcpy(opt_modlist, optarg); break; case 'd': - debugPort = atoi(optarg); + runFile = strdup(optarg); + opt_ide = IDE_EXTERNAL; + debug = true; + break; + case 'p': + g_debugPort = atoi(optarg); break; case 'h': showHelp(); @@ -311,6 +317,7 @@ int main(int argc, char* argv[]) { } } + restoreSettings(rect, fontScale, debug); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_Window *window = SDL_CreateWindow("SmallBASIC", rect.x, rect.y, rect.w, rect.h, @@ -324,12 +331,12 @@ int main(int argc, char* argv[]) { loadIcon(window); Runtime *runtime = new Runtime(window); runtime->construct(font.c_str(), fontBold.c_str()); - fontScale = runtime->runShell(runFile, fontScale, debugPort); + fontScale = runtime->runShell(runFile, fontScale, debug ? g_debugPort : 0); delete runtime; } else { fprintf(stderr, "Failed to locate display font\n"); } - saveSettings(CONFIG_NAME, window, fontScale); + saveSettings(window, fontScale, debug); SDL_DestroyWindow(window); } else { fprintf(stderr, "Could not create window: %s\n", SDL_GetError()); diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 9a8c65fa..af2b0ca6 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -40,8 +40,9 @@ Runtime *runtime; SDL_mutex *g_lock = NULL; SDL_cond *g_cond = NULL; -SDL_bool g_condFlag = SDL_FALSE; -SDL_bool g_debug = SDL_FALSE; +SDL_bool g_debugPause = SDL_FALSE; +SDL_bool g_debugBreak = SDL_FALSE; +SDL_bool g_debugError = SDL_FALSE; strlib::List g_breakPoints; struct SoundObject { @@ -192,9 +193,11 @@ int Runtime::runShell(const char *startupBas, int fontScale, int debugPort) { SDL_OpenAudio(&desiredSpec, &obtainedSpec); if (debugPort > 0) { + appLog("Debug active on port %d\n", debugPort); g_lock = SDL_CreateMutex(); g_cond = SDL_CreateCond(); opt_trace_on = 1; + g_debugBreak = SDL_TRUE; SDL_Thread *thread = SDL_CreateThread(debugThread, "DBg", (void *)(intptr_t)debugPort); SDL_DetachThread(thread); @@ -700,12 +703,6 @@ int osd_devinit(void) { setsysvar_str(SYSVAR_OSNAME, "SDL"); runtime->setRunning(true); osd_clear_sound_queue(); - - SDL_LockMutex(g_lock); - g_condFlag = SDL_FALSE; - g_debug = SDL_FALSE; - SDL_UnlockMutex(g_lock); - return 1; } @@ -736,10 +733,11 @@ void osd_clear_sound_queue() { // // debugging // -void signalTrace(SDL_bool debug) { +void signalTrace(SDL_bool debugBreak, SDL_bool debugError = SDL_FALSE) { SDL_LockMutex(g_lock); - g_condFlag = SDL_TRUE; - g_debug = debug; + g_debugPause = SDL_FALSE; + g_debugBreak = debugBreak; + g_debugError = debugError; SDL_CondSignal(g_cond); SDL_UnlockMutex(g_lock); } @@ -748,8 +746,13 @@ int debugThread(void *data) { int port = ((intptr_t) data); socket_t socket = net_listen(port); char buf[OS_PATHNAME_SIZE + 1]; - net_print(socket, "SmallBASIC debugger\n"); + if (socket == -1) { + signalTrace(SDL_FALSE, SDL_TRUE); + return -1; + } + + net_print(socket, "SmallBASIC debugger\n"); while (socket != -1) { int size = net_input(socket, buf, sizeof(buf), "\r\n"); if (size > 0) { @@ -758,6 +761,9 @@ int debugThread(void *data) { case 'n': // step over next line signalTrace(SDL_TRUE); + break; + case 's': + // status net_printf(socket, "%d\n", prog_line); for (unsigned i = 0; i < prog_varcount; i++) { pv_writevar(tvar[i], PV_NET, socket); @@ -776,7 +782,7 @@ int debugThread(void *data) { break; case 'q': // quit - signalTrace(SDL_FALSE); + signalTrace(SDL_FALSE, SDL_TRUE); g_breakPoints.removeAll(); net_print(socket, "Bye\n"); net_disconnect(socket); @@ -787,32 +793,37 @@ int debugThread(void *data) { net_printf(socket, "Unknown command '%s'\n", buf); break; }; - } else fprintf(stderr, "."); + } } return 0; } extern "C" void dev_trace_line(int lineNo) { SDL_LockMutex(g_lock); - if (!g_debug) { - List_each(int *, it, g_breakPoints) { - int breakPoint = *(*it); - if (breakPoint == lineNo) { - runtime->systemPrint("Break point hit at line: %d", lineNo); - g_debug = SDL_TRUE; - break; + + if (!g_debugError) { + if (!g_debugBreak) { + List_each(int *, it, g_breakPoints) { + int breakPoint = *(*it); + if (breakPoint == lineNo) { + runtime->systemPrint("Break point hit at line: %d", lineNo); + g_debugBreak = SDL_TRUE; + break; + } } } - } - if (g_debug) { - g_condFlag = SDL_FALSE; - while (!g_condFlag) { - SDL_CondWaitTimeout(g_cond, g_lock, COND_WAIT_TIME); - runtime->processEvents(0); - if (!runtime->isRunning()) { - break; + if (g_debugBreak) { + g_debugPause = SDL_TRUE; + while (g_debugPause) { + SDL_CondWaitTimeout(g_cond, g_lock, COND_WAIT_TIME); + runtime->processEvents(0); + if (!runtime->isRunning()) { + break; + } } } + } else { + runtime->setExit(true); } SDL_UnlockMutex(g_lock); } diff --git a/src/platform/sdl/settings.cpp b/src/platform/sdl/settings.cpp index 7a80e379..642a44dd 100644 --- a/src/platform/sdl/settings.cpp +++ b/src/platform/sdl/settings.cpp @@ -37,7 +37,7 @@ static const char *ENV_VARS[] = { #define makedir(f) mkdir(f, 0700) #endif -FILE *openConfig(const char *configName, const char *flags) { +FILE *openConfig(const char *flags, bool debug) { FILE *result = NULL; char path[PATH_MAX]; int vars_len = sizeof(ENV_VARS) / sizeof(ENV_VARS[0]); @@ -52,11 +52,13 @@ FILE *openConfig(const char *configName, const char *flags) { strcat(path, "/.config"); makedir(path); } - strcat(path, "/"); - strcat(path, configName); + strcat(path, "/SmallBASIC"); makedir(path); - - strcat(path, "/settings.txt"); + if (debug) { + strcat(path, "/settings_debug.txt"); + } else { + strcat(path, "/settings.txt"); + } result = fopen(path, flags); } } @@ -80,8 +82,8 @@ int nextInteger(FILE *fp, int def) { // // restore window position // -void restoreSettings(const char *configName, SDL_Rect &rect, int &fontScale) { - FILE *fp = openConfig(configName, "r"); +void restoreSettings(SDL_Rect &rect, int &fontScale, bool debug) { + FILE *fp = openConfig("r", debug); if (fp) { rect.x = nextInteger(fp, SDL_WINDOWPOS_UNDEFINED); rect.y = nextInteger(fp, SDL_WINDOWPOS_UNDEFINED); @@ -107,8 +109,8 @@ void restoreSettings(const char *configName, SDL_Rect &rect, int &fontScale) { // // save the window position // -void saveSettings(const char *configName, SDL_Window *window, int fontScale) { - FILE *fp = openConfig(configName, "w"); +void saveSettings(SDL_Window *window, int fontScale, bool debug) { + FILE *fp = openConfig("w", debug); if (fp) { int x, y, w, h; SDL_GetWindowPosition(window, &x, &y); diff --git a/src/platform/sdl/settings.h b/src/platform/sdl/settings.h index 8dc1d1d2..1b601edb 100644 --- a/src/platform/sdl/settings.h +++ b/src/platform/sdl/settings.h @@ -1,6 +1,6 @@ // This file is part of SmallBASIC // -// Copyright(C) 2001-2014 Chris Warren-Smith. +// Copyright(C) 2001-2015 Chris Warren-Smith. // // This program is distributed under the terms of the GPL v2.0 or later // Download the GNU Public License (GPL) from www.gnu.org @@ -11,8 +11,8 @@ #include -void restoreSettings(const char *configName, SDL_Rect &rect, int &fontScale); -void saveSettings(const char *configName, SDL_Window *window, int fontScale); +void restoreSettings(SDL_Rect &rect, int &fontScale, bool debug); +void saveSettings(SDL_Window *window, int fontScale, bool debug); #endif diff --git a/src/platform/sdl/syswm.cpp b/src/platform/sdl/syswm.cpp index 74ec994e..16d39bf8 100644 --- a/src/platform/sdl/syswm.cpp +++ b/src/platform/sdl/syswm.cpp @@ -12,6 +12,9 @@ #define DEFAULT_FONT_SIZE 12 #define DEFAULT_FONT_SIZE_PTS 11 +extern const char *g_appPath; +extern int g_debugPort; + #if defined(_Win32) #include @@ -41,7 +44,12 @@ int getStartupFontSize(SDL_Window *window) { return result; } +void launchDebug(const char *file) { + // TODO +} + #else +#include void loadIcon(SDL_Window *window) { } @@ -50,4 +58,23 @@ int getStartupFontSize(SDL_Window *window) { return DEFAULT_FONT_SIZE; } +void launchDebug(const char *file) { + pid_t pid = fork(); + char port[20]; + + switch (pid) { + case -1: + // failed + break; + case 0: + // child process + sprintf(port, "-p %d", g_debugPort); + execl(g_appPath, g_appPath, port, "-d", file, (char *)0); + break; + default: + // parent process - continue + break; + } +} + #endif diff --git a/src/platform/sdl/syswm.h b/src/platform/sdl/syswm.h index 2381e996..09fbee6a 100644 --- a/src/platform/sdl/syswm.h +++ b/src/platform/sdl/syswm.h @@ -13,5 +13,6 @@ void loadIcon(SDL_Window *window); int getStartupFontSize(SDL_Window *window); +void launchDebug(const char *file); #endif diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp new file mode 100644 index 00000000..7f1dbe65 --- /dev/null +++ b/src/ui/editor.cpp @@ -0,0 +1,247 @@ +// This file is part of SmallBASIC +// +// Copyright(C) 2001-2015 Chris Warren-Smith. +// +// This program is distributed under the terms of the GPL v2.0 or later +// Download the GNU Public License (GPL) from www.gnu.org +// + +#include "config.h" + +#include "common/sbapp.h" +#include "ui/system.h" +#include "ui/textedit.h" + +void launchDebug(const char *file); + +void debugStepNext(TextEditInput *editWidget) { +} + +void debugContinue(TextEditInput *editWidget) { +} + +void System::editSource(strlib::String &loadPath) { + logEntered(); + + strlib::String fileName; + int i = loadPath.lastIndexOf('/', 0); + if (i != -1) { + fileName = loadPath.substring(i + 1); + } else { + fileName = loadPath; + } + + const char *help = " Ctrl+h (C-h)=Help"; + strlib::String dirtyFile; + dirtyFile.append(" * "); + dirtyFile.append(fileName); + dirtyFile.append(help); + strlib::String cleanFile; + cleanFile.append(" - "); + cleanFile.append(fileName); + cleanFile.append(help); + + int w = _output->getWidth(); + int h = _output->getHeight(); + int charWidth = _output->getCharWidth(); + int charHeight = _output->getCharHeight(); + int prevScreenId = _output->selectScreen(SOURCE_SCREEN); + TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); + TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight); + TextEditInput *widget = editWidget; + _modifiedTime = getModifiedTime(); + + editWidget->updateUI(NULL, NULL); + editWidget->setLineNumbers(); + editWidget->setFocus(); + if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { + editWidget->setCursorRow(gsb_last_line - 1); + } + if (gsb_last_error && !isBack()) { + editWidget->setCursorRow(gsb_last_line - 1); + helpWidget->setText(gsb_last_errmsg); + widget = helpWidget; + helpWidget->show(); + } + _srcRendered = false; + _output->clearScreen(); + _output->addInput(editWidget); + _output->addInput(helpWidget); + _output->setStatus(cleanFile); + _output->redraw(); + _state = kEditState; + + maShowVirtualKeyboard(); + showCursor(kIBeam); + + while (_state == kEditState) { + MAEvent event = getNextEvent(); + if (event.type == EVENT_TYPE_KEY_PRESSED && _userScreenId == -1) { + dev_clrkb(); + int sw = _output->getScreenWidth(); + bool redraw = true; + bool dirty = editWidget->isDirty(); + char *text; + + if (_modifiedTime != 0 && _modifiedTime != getModifiedTime()) { + const char *msg = "Do you want to reload the file?"; + if (ask("File has changed on disk", msg, false) == 0) { + loadSource(loadPath.c_str()); + editWidget->reload(_programSrc); + dirty = !editWidget->isDirty(); + } + _modifiedTime = getModifiedTime(); + event.key = 0; + } + + switch (event.key) { + case SB_KEY_F(2): + case SB_KEY_F(3): + case SB_KEY_F(4): + case SB_KEY_F(8): + case SB_KEY_F(10): + case SB_KEY_F(11): + case SB_KEY_F(12): + redraw = false; + break; + case SB_KEY_ESCAPE: + widget = editWidget; + helpWidget->hide(); + dirty = !editWidget->isDirty(); + break; + case SB_KEY_F(9): + case SB_KEY_CTRL('r'): + _state = kRunState; + if (!editWidget->isDirty()) { + break; + } + // otherwise fallthrough + case SB_KEY_CTRL('s'): + if (!editWidget->save(loadPath)) { + alert("", "Failed to save file"); + } + _modifiedTime = getModifiedTime(); + break; + case SB_KEY_CTRL('c'): + case SB_KEY_CTRL('x'): + text = widget->copy(event.key == (int)SB_KEY_CTRL('x')); + if (text) { + setClipboardText(text); + free(text); + } + break; + case SB_KEY_F(1): + case SB_KEY_ALT('h'): + _output->setStatus("Keyword Help. Esc=Close"); + widget = helpWidget; + helpWidget->createKeywordIndex(); + helpWidget->show(); + break; + case SB_KEY_F(5): + launchDebug(loadPath.c_str()); + break; + case SB_KEY_F(6): + debugStepNext(editWidget); + break; + case SB_KEY_F(7): + debugContinue(editWidget); + break; + case SB_KEY_CTRL('h'): + _output->setStatus("Keystroke help. Esc=Close"); + widget = helpWidget; + helpWidget->createHelp(); + helpWidget->show(); + break; + case SB_KEY_CTRL('l'): + _output->setStatus("Outline. Esc=Close"); + widget = helpWidget; + helpWidget->createOutline(); + helpWidget->show(); + break; + case SB_KEY_CTRL('f'): + _output->setStatus("Find in buffer. Esc=Close"); + widget = helpWidget; + helpWidget->createSearch(false); + helpWidget->show(); + break; + case SB_KEY_CTRL('n'): + _output->setStatus("Replace string. Esc=Close"); + widget = helpWidget; + helpWidget->createSearch(true); + helpWidget->show(); + break; + case SB_KEY_ALT('g'): + _output->setStatus("Goto line. Esc=Close"); + widget = helpWidget; + helpWidget->createGotoLine(); + helpWidget->show(); + break; + case SB_KEY_CTRL(' '): + _output->setStatus("Auto-complete. Esc=Close"); + widget = helpWidget; + helpWidget->createCompletionHelp(); + helpWidget->show(); + break; + case SB_KEY_CTRL('v'): + text = getClipboardText(); + widget->paste(text); + free(text); + break; + case SB_KEY_CTRL('o'): + _output->selectScreen(USER_SCREEN1); + showCompletion(true); + _output->redraw(); + waitForBack(); + _output->selectScreen(SOURCE_SCREEN); + _state = kEditState; + break; + default: + redraw = widget->edit(event.key, sw, charWidth); + break; + } + if (event.key == SB_KEY_ENTER) { + if (helpWidget->replaceMode()) { + _output->setStatus("Replace string with. Esc=Close"); + dirty = editWidget->isDirty(); + } else if (helpWidget->closeOnEnter() && helpWidget->isVisible()) { + if (helpWidget->replaceDoneMode()) { + _output->setStatus(dirtyFile); + } + widget = editWidget; + helpWidget->hide(); + redraw = true; + dirty = !editWidget->isDirty(); + } + } + if (editWidget->isDirty() && !dirty) { + _output->setStatus(dirtyFile); + } else if (!editWidget->isDirty() && dirty) { + _output->setStatus(cleanFile); + } + if (redraw) { + _output->redraw(); + } + } + + if ((isBack() || isClosing()) && editWidget->isDirty()) { + const char *message = "The current file has not been saved.\n" + "Would you like to save it now?"; + int choice = ask("Save changes?", message, isBack()); + if (choice == 0) { + if (!editWidget->save(loadPath)) { + alert("", "Failed to save file"); + } + } else if (choice == 2) { + // cancel + _state = kEditState; + } + } + } + + _output->removeInputs(); + if (!isClosing()) { + _output->selectScreen(prevScreenId); + } + logLeaving(); +} + diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 899d6b69..c34ecb99 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -6,20 +6,19 @@ // Download the GNU Public License (GPL) from www.gnu.org // +#include "config.h" + #include #include #include #include "common/sbapp.h" -#include "common/sys.h" -#include "common/smbas.h" #include "common/osd.h" #include "common/device.h" #include "common/fs_socket_client.h" #include "common/keymap.h" #include "ui/system.h" #include "ui/inputs.h" -#include "ui/textedit.h" #define MENU_CONSOLE 0 #define MENU_SOURCE 1 @@ -84,225 +83,6 @@ void System::checkModifiedTime() { } } -void System::editSource(strlib::String &loadPath) { - logEntered(); - - strlib::String fileName; - int i = loadPath.lastIndexOf('/', 0); - if (i != -1) { - fileName = loadPath.substring(i + 1); - } else { - fileName = loadPath; - } - - const char *help = " Ctrl+h (C-h)=Help"; - strlib::String dirtyFile; - dirtyFile.append(" * "); - dirtyFile.append(fileName); - dirtyFile.append(help); - strlib::String cleanFile; - cleanFile.append(" - "); - cleanFile.append(fileName); - cleanFile.append(help); - - int w = _output->getWidth(); - int h = _output->getHeight(); - int charWidth = _output->getCharWidth(); - int charHeight = _output->getCharHeight(); - int prevScreenId = _output->selectScreen(SOURCE_SCREEN); - TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); - TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight); - TextEditInput *widget = editWidget; - _modifiedTime = getModifiedTime(); - - editWidget->updateUI(NULL, NULL); - editWidget->setLineNumbers(); - editWidget->setFocus(); - if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { - editWidget->setCursorRow(gsb_last_line - 1); - } - if (gsb_last_error && !isBack()) { - editWidget->setCursorRow(gsb_last_line - 1); - helpWidget->setText(gsb_last_errmsg); - widget = helpWidget; - helpWidget->show(); - } - _srcRendered = false; - _output->clearScreen(); - _output->addInput(editWidget); - _output->addInput(helpWidget); - _output->setStatus(cleanFile); - _output->redraw(); - _state = kEditState; - - maShowVirtualKeyboard(); - showCursor(kIBeam); - - while (_state == kEditState) { - MAEvent event = getNextEvent(); - if (event.type == EVENT_TYPE_KEY_PRESSED && _userScreenId == -1) { - dev_clrkb(); - int sw = _output->getScreenWidth(); - bool redraw = true; - bool dirty = editWidget->isDirty(); - char *text; - - if (_modifiedTime != 0 && _modifiedTime != getModifiedTime()) { - const char *msg = "Do you want to reload the file?"; - if (ask("File has changed on disk", msg, false) == 0) { - loadSource(loadPath.c_str()); - editWidget->reload(_programSrc); - dirty = !editWidget->isDirty(); - } - _modifiedTime = getModifiedTime(); - event.key = 0; - } - - switch (event.key) { - case SB_KEY_F(2): - case SB_KEY_F(3): - case SB_KEY_F(4): - case SB_KEY_F(5): - case SB_KEY_F(6): - case SB_KEY_F(7): - case SB_KEY_F(8): - case SB_KEY_F(10): - case SB_KEY_F(11): - case SB_KEY_F(12): - redraw = false; - break; - case SB_KEY_ESCAPE: - widget = editWidget; - helpWidget->hide(); - dirty = !editWidget->isDirty(); - break; - case SB_KEY_F(9): - case SB_KEY_CTRL('r'): - _state = kRunState; - if (!editWidget->isDirty()) { - break; - } - // otherwise fallthrough - case SB_KEY_CTRL('s'): - if (!editWidget->save(loadPath)) { - alert("", "Failed to save file"); - } - _modifiedTime = getModifiedTime(); - break; - case SB_KEY_CTRL('c'): - case SB_KEY_CTRL('x'): - text = widget->copy(event.key == (int)SB_KEY_CTRL('x')); - if (text) { - setClipboardText(text); - free(text); - } - break; - case SB_KEY_F(1): - case SB_KEY_ALT('h'): - _output->setStatus("Keyword Help. Esc=Close"); - widget = helpWidget; - helpWidget->createKeywordIndex(); - helpWidget->show(); - break; - case SB_KEY_CTRL('h'): - _output->setStatus("Keystroke help. Esc=Close"); - widget = helpWidget; - helpWidget->createHelp(); - helpWidget->show(); - break; - case SB_KEY_CTRL('l'): - _output->setStatus("Outline. Esc=Close"); - widget = helpWidget; - helpWidget->createOutline(); - helpWidget->show(); - break; - case SB_KEY_CTRL('f'): - _output->setStatus("Find in buffer. Esc=Close"); - widget = helpWidget; - helpWidget->createSearch(false); - helpWidget->show(); - break; - case SB_KEY_CTRL('n'): - _output->setStatus("Replace string. Esc=Close"); - widget = helpWidget; - helpWidget->createSearch(true); - helpWidget->show(); - break; - case SB_KEY_ALT('g'): - _output->setStatus("Goto line. Esc=Close"); - widget = helpWidget; - helpWidget->createGotoLine(); - helpWidget->show(); - break; - case SB_KEY_CTRL(' '): - _output->setStatus("Auto-complete. Esc=Close"); - widget = helpWidget; - helpWidget->createCompletionHelp(); - helpWidget->show(); - break; - case SB_KEY_CTRL('v'): - text = getClipboardText(); - widget->paste(text); - free(text); - break; - case SB_KEY_CTRL('o'): - _output->selectScreen(USER_SCREEN1); - showCompletion(true); - _output->redraw(); - waitForBack(); - _output->selectScreen(SOURCE_SCREEN); - _state = kEditState; - break; - default: - redraw = widget->edit(event.key, sw, charWidth); - break; - } - if (event.key == SB_KEY_ENTER) { - if (helpWidget->replaceMode()) { - _output->setStatus("Replace string with. Esc=Close"); - dirty = editWidget->isDirty(); - } else if (helpWidget->closeOnEnter() && helpWidget->isVisible()) { - if (helpWidget->replaceDoneMode()) { - _output->setStatus(dirtyFile); - } - widget = editWidget; - helpWidget->hide(); - redraw = true; - dirty = !editWidget->isDirty(); - } - } - if (editWidget->isDirty() && !dirty) { - _output->setStatus(dirtyFile); - } else if (!editWidget->isDirty() && dirty) { - _output->setStatus(cleanFile); - } - if (redraw) { - _output->redraw(); - } - } - - if ((isBack() || isClosing()) && editWidget->isDirty()) { - const char *message = "The current file has not been saved.\n" - "Would you like to save it now?"; - int choice = ask("Save changes?", message, isBack()); - if (choice == 0) { - if (!editWidget->save(loadPath)) { - alert("", "Failed to save file"); - } - } else if (choice == 2) { - // cancel - _state = kEditState; - } - } - } - - _output->removeInputs(); - if (!isClosing()) { - _output->selectScreen(prevScreenId); - } - logLeaving(); -} - bool System::execute(const char *bas) { _output->reset(); diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 8b686483..ce4939ee 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -81,6 +81,9 @@ const char *helpText = "SHIFT- select\n" "TAB indent line\n" "F1,A-h keyword help\n" + "F5 debug\n" + "F6 debug step\n" + "F7 debug continue\n" "F9, C-r run\n"; inline bool match(const char *str, const char *pattern , int len) { @@ -1325,6 +1328,7 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { if (key == SB_KEY_ENTER) { _editor->gotoLine(_buf._buffer); } + break; default: switch (key) { case STB_TEXTEDIT_K_LEFT: From c3d76b01d7b9d58bf0edf147b546a22fd6dd579f Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 2 Sep 2015 11:38:26 +1000 Subject: [PATCH 06/15] SDL: debug stepthru --- src/platform/android/jni/runtime.h | 3 + src/platform/sdl/runtime.cpp | 97 ++++++++++++++++++++++++++---- src/platform/sdl/runtime.h | 3 + src/platform/unix/inet.c | 7 +++ src/ui/editor.cpp | 34 +++++------ src/ui/system.h | 4 ++ src/ui/textedit.cpp | 2 - src/ui/textedit.h | 4 +- 8 files changed, 123 insertions(+), 31 deletions(-) diff --git a/src/platform/android/jni/runtime.h b/src/platform/android/jni/runtime.h index 951f6360..61be38b2 100644 --- a/src/platform/android/jni/runtime.h +++ b/src/platform/android/jni/runtime.h @@ -25,6 +25,9 @@ struct Runtime : public System { int ask(const char *title, const char *prompt, bool cancel); void clearSoundQueue(); void construct(); + void debugStart(TextEditInput *edit, const char *file) {} + void debugStep(TextEditInput *edit, TextEditHelpWidget *help, bool cont) {} + void debugStop() {} bool getUntrusted(); String getString(const char *methodName); int getInteger(const char *methodName); diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index af2b0ca6..dbcf8339 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -12,7 +12,6 @@ #include "common/smbas.h" #include "common/osd.h" #include "common/device.h" -#include "common/fs_socket_client.h" #include "common/keymap.h" #include "common/inet.h" #include "common/pproc.h" @@ -30,6 +29,7 @@ #define WAIT_INTERVAL 5 #define COND_WAIT_TIME 250 +#define PAUSE_DEBUG_LAUNCH 250 #define MAIN_BAS "__main_bas__" #define AMPLITUDE 22000 #define FREQUENCY 44100 @@ -43,7 +43,10 @@ SDL_cond *g_cond = NULL; SDL_bool g_debugPause = SDL_FALSE; SDL_bool g_debugBreak = SDL_FALSE; SDL_bool g_debugError = SDL_FALSE; +int g_debugLine = 0; strlib::List g_breakPoints; +socket_t g_debugee = -1; +extern int g_debugPort; struct SoundObject { double v; @@ -152,6 +155,66 @@ void Runtime::construct(const char *font, const char *boldFont) { } } +void Runtime::debugStart(TextEditInput *editWidget, const char *file) { + char buf[OS_PATHNAME_SIZE + 1]; + bool open; + int size; + + if (g_debugee != -1) { + net_print(g_debugee, "l\n"); + open = net_input(g_debugee, buf, sizeof(buf), "\r\n") > 0; + } else { + open = false; + } + + if (!open) { + launchDebug(file); + pause(PAUSE_DEBUG_LAUNCH); + SDL_RaiseWindow(_window); + + g_debugee = net_connect("localhost", g_debugPort); + if (g_debugee != -1) { + net_print(g_debugee, "l\n"); + size = net_input(g_debugee, buf, sizeof(buf), "\r\n"); + if (size > 0) { + editWidget->gotoLine(buf); + appLog("Debug session ready"); + } + } else { + appLog("Failed to attach to debug window"); + } + } else { + debugStop(); + } +} + +void Runtime::debugStep(TextEditInput *edit, TextEditHelpWidget *help, bool cont) { + if (g_debugee != -1) { + char buf[OS_PATHNAME_SIZE + 1]; + int size; + net_print(g_debugee, cont ? "c\n" : "n\n"); + net_print(g_debugee, "l\n"); + size = net_input(g_debugee, buf, sizeof(buf), "\r\n"); + if (size > 0) { + edit->gotoLine(buf); + net_print(g_debugee, "v\n"); + size = net_input(g_debugee, buf, sizeof(buf), "\1"); + if (size > 0) { + help->reload(buf); + } + } + } +} + +void Runtime::debugStop() { + if (g_debugee != -1) { + net_print(g_debugee, "q\n"); + net_disconnect(g_debugee); + g_debugee = -1; + appLog("Closed debug session"); + } +} + void Runtime::pushEvent(MAEvent *event) { _eventQueue->push(event); } @@ -191,6 +254,7 @@ int Runtime::runShell(const char *startupBas, int fontScale, int debugPort) { SDL_AudioSpec obtainedSpec; SDL_OpenAudio(&desiredSpec, &obtainedSpec); + net_init(); if (debugPort > 0) { appLog("Debug active on port %d\n", debugPort); @@ -226,6 +290,8 @@ int Runtime::runShell(const char *startupBas, int fontScale, int debugPort) { SDL_DestroyMutex(g_lock); } + debugStop(); + net_close(); SDL_CloseAudio(); _state = kDoneState; logLeaving(); @@ -752,7 +818,6 @@ int debugThread(void *data) { return -1; } - net_print(socket, "SmallBASIC debugger\n"); while (socket != -1) { int size = net_input(socket, buf, sizeof(buf), "\r\n"); if (size > 0) { @@ -762,18 +827,24 @@ int debugThread(void *data) { // step over next line signalTrace(SDL_TRUE); break; - case 's': - // status - net_printf(socket, "%d\n", prog_line); - for (unsigned i = 0; i < prog_varcount; i++) { - pv_writevar(tvar[i], PV_NET, socket); - net_print(socket, "\n"); - } - break; case 'c': // continue signalTrace(SDL_FALSE); break; + case 'l': + // current line number + SDL_LockMutex(g_lock); + net_printf(socket, "%d\n", g_debugLine); + SDL_UnlockMutex(g_lock); + break; + case 'v': + // variables + for (unsigned i = SYSVAR_COUNT; i < prog_varcount; i++) { + pv_writevar(tvar[i], PV_NET, socket); + net_print(socket, "\n"); + } + net_print(socket, "\1"); + break; case 'b': // set breakpoint SDL_LockMutex(g_lock); @@ -788,6 +859,9 @@ int debugThread(void *data) { net_disconnect(socket); socket = -1; break; + case 'h': + net_print(socket, "SmallBASIC debugger\n"); + break; default: // unknown command net_printf(socket, "Unknown command '%s'\n", buf); @@ -799,7 +873,9 @@ int debugThread(void *data) { } extern "C" void dev_trace_line(int lineNo) { + runtime->getOutput()->redraw(); SDL_LockMutex(g_lock); + g_debugLine = lineNo; if (!g_debugError) { if (!g_debugBreak) { @@ -827,4 +903,3 @@ extern "C" void dev_trace_line(int lineNo) { } SDL_UnlockMutex(g_lock); } - diff --git a/src/platform/sdl/runtime.h b/src/platform/sdl/runtime.h index bc279f5d..cce255d3 100644 --- a/src/platform/sdl/runtime.h +++ b/src/platform/sdl/runtime.h @@ -24,6 +24,9 @@ struct Runtime : public System { void alert(const char *title, const char *message); int ask(const char *title, const char *prompt, bool cancel); void construct(const char *font, const char *boldFont); + void debugStart(TextEditInput *edit, const char *file); + void debugStep(TextEditInput *edit, TextEditHelpWidget *help, bool cont); + void debugStop(); void redraw() { _graphics->redraw(); } void handleKeyEvent(MAEvent &event); bool hasEvent() { return _eventQueue && _eventQueue->size() > 0; } diff --git a/src/platform/unix/inet.c b/src/platform/unix/inet.c index 7ce1b5e7..840ef1d3 100644 --- a/src/platform/unix/inet.c +++ b/src/platform/unix/inet.c @@ -22,6 +22,7 @@ static int inetlib_init = 0; #include #include #include +#include #endif #if !defined(socklen_t) @@ -44,6 +45,12 @@ int net_init() { } return 1; } +#else + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGPIPE, &sa, 0); #endif return 1; } diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp index 7f1dbe65..1433aed9 100644 --- a/src/ui/editor.cpp +++ b/src/ui/editor.cpp @@ -12,13 +12,10 @@ #include "ui/system.h" #include "ui/textedit.h" -void launchDebug(const char *file); - -void debugStepNext(TextEditInput *editWidget) { -} - -void debugContinue(TextEditInput *editWidget) { -} +#define SAVE_FILE() \ + if (!editWidget->save(loadPath)) \ + alert("", "Failed to save file"); \ + else _modifiedTime = getModifiedTime(); void System::editSource(strlib::String &loadPath) { logEntered(); @@ -108,19 +105,17 @@ void System::editSource(strlib::String &loadPath) { widget = editWidget; helpWidget->hide(); dirty = !editWidget->isDirty(); + debugStop(); break; case SB_KEY_F(9): case SB_KEY_CTRL('r'): _state = kRunState; - if (!editWidget->isDirty()) { - break; + if (editWidget->isDirty()) { + SAVE_FILE(); } - // otherwise fallthrough + break; case SB_KEY_CTRL('s'): - if (!editWidget->save(loadPath)) { - alert("", "Failed to save file"); - } - _modifiedTime = getModifiedTime(); + SAVE_FILE(); break; case SB_KEY_CTRL('c'): case SB_KEY_CTRL('x'): @@ -138,13 +133,18 @@ void System::editSource(strlib::String &loadPath) { helpWidget->show(); break; case SB_KEY_F(5): - launchDebug(loadPath.c_str()); + SAVE_FILE(); + _output->setStatus("Debug. F6=Step, F7=Continue, Esc=Close"); + widget = helpWidget; + helpWidget->createMessage(); + helpWidget->show(); + debugStart(editWidget, loadPath.c_str()); break; case SB_KEY_F(6): - debugStepNext(editWidget); + debugStep(editWidget, helpWidget, false); break; case SB_KEY_F(7): - debugContinue(editWidget); + debugStep(editWidget, helpWidget, true); break; case SB_KEY_CTRL('h'): _output->setStatus("Keystroke help. Esc=Close"); diff --git a/src/ui/system.h b/src/ui/system.h index 3359ee35..b3536ab2 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -12,6 +12,7 @@ #include "config.h" #include "ui/strlib.h" #include "ui/ansiwidget.h" +#include "ui/textedit.h" #if defined(_FLTK) #include "platform/fltk/system.h" @@ -48,6 +49,9 @@ struct System { virtual void alert(const char *title, const char *message) = 0; virtual int ask(const char *title, const char *prompt, bool cancel=true) = 0; + virtual void debugStart(TextEditInput *edit, const char *file) = 0; + virtual void debugStep(TextEditInput *edit, TextEditHelpWidget *help, bool cont) = 0; + virtual void debugStop() = 0; virtual MAEvent processEvents(int waitFlag) = 0; virtual char *loadResource(const char *fileName); virtual void optionsBox(StringList *items) = 0; diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index ce4939ee..d241056e 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -82,8 +82,6 @@ const char *helpText = "TAB indent line\n" "F1,A-h keyword help\n" "F5 debug\n" - "F6 debug step\n" - "F7 debug continue\n" "F9, C-r run\n"; inline bool match(const char *str, const char *pattern , int len) { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 15a6700e..7f36b964 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -165,13 +165,15 @@ struct TextEditHelpWidget : public TextEditInput { kSearchReplace, kReplace, kReplaceDone, - kGotoLine + kGotoLine, + kMessage }; void createCompletionHelp(); void createGotoLine(); void createHelp(); void createKeywordIndex(); + void createMessage() { reset(kMessage); } void createOutline(); void createSearch(bool replace); bool edit(int key, int screenWidth, int charWidth); From c3064c016a5d0aacd70f7adeb7a5444c70931104 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 2 Sep 2015 16:58:45 +1000 Subject: [PATCH 07/15] SDL: add editing context items --- src/platform/sdl/runtime.cpp | 5 ++-- src/platform/sdl/syswm.cpp | 6 ++++- src/ui/system.cpp | 46 +++++++++++++++++++++++++++++++++--- src/ui/system.h | 2 +- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index dbcf8339..f17cfe4c 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -605,7 +605,7 @@ void Runtime::optionsBox(StringList *items) { width += (charWidth * OPTIONS_BOX_WIDTH_EXTRA); int charHeight = _output->getCharHeight(); - int textHeight = charHeight + (charHeight / 2); + int textHeight = charHeight + (charHeight / 3); int height = textHeight * items->size(); if (_menuX + width >= _output->getWidth()) { _menuX = _output->getWidth() - width; @@ -855,7 +855,6 @@ int debugThread(void *data) { // quit signalTrace(SDL_FALSE, SDL_TRUE); g_breakPoints.removeAll(); - net_print(socket, "Bye\n"); net_disconnect(socket); socket = -1; break; @@ -873,7 +872,6 @@ int debugThread(void *data) { } extern "C" void dev_trace_line(int lineNo) { - runtime->getOutput()->redraw(); SDL_LockMutex(g_lock); g_debugLine = lineNo; @@ -889,6 +887,7 @@ extern "C" void dev_trace_line(int lineNo) { } } if (g_debugBreak) { + runtime->getOutput()->redraw(); g_debugPause = SDL_TRUE; while (g_debugPause) { SDL_CondWaitTimeout(g_cond, g_lock, COND_WAIT_TIME); diff --git a/src/platform/sdl/syswm.cpp b/src/platform/sdl/syswm.cpp index 16d39bf8..c71d6c73 100644 --- a/src/platform/sdl/syswm.cpp +++ b/src/platform/sdl/syswm.cpp @@ -45,7 +45,11 @@ int getStartupFontSize(SDL_Window *window) { } void launchDebug(const char *file) { - // TODO + STARTUPINFO info={sizeof(info)}; + PROCESS_INFORMATION processInfo; + char cmd[1024]; + sprintf(cmd, "-p %d -d %s", g_debugPort, file); + CreateProcess(g_appPath, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo); } #else diff --git a/src/ui/system.cpp b/src/ui/system.cpp index c34ecb99..1ae388d3 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -35,7 +35,12 @@ #define MENU_AUDIO 12 #define MENU_SCREENSHOT 13 #define MENU_SCRATCHPAD 14 -#define MENU_SIZE 15 +#define MENU_UNDO 15 +#define MENU_REDO 16 +#define MENU_SAVE 17 +#define MENU_RUN 18 +#define MENU_DEBUG 19 +#define MENU_SIZE 20 #define FONT_SCALE_INTERVAL 10 #define FONT_MIN 20 @@ -216,7 +221,8 @@ uint32_t System::getModifiedTime() { return result; } -void System::handleMenu(int menuId) { +void System::handleMenu(MAEvent &event) { + int menuId = event.optionsBoxButtonIndex; int fontSize = _output->getFontSize(); int menuItem = _systemMenu[menuId]; delete [] _systemMenu; @@ -288,6 +294,26 @@ void System::handleMenu(int menuId) { case MENU_SCRATCHPAD: scratchPad(); break; + case MENU_UNDO: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_CTRL('z'); + break; + case MENU_REDO: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_CTRL('y'); + break; + case MENU_SAVE: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_CTRL('s'); + break; + case MENU_RUN: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_F(9); + break; + case MENU_DEBUG: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_F(5); + break; } if (fontSize != _output->getFontSize()) { @@ -307,7 +333,7 @@ void System::handleEvent(MAEvent &event) { switch (event.type) { case EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED: if (_systemMenu != NULL) { - handleMenu(event.optionsBoxButtonIndex); + handleMenu(event); } else if (isRunning()) { if (!form_ui::optionSelected(event.optionsBoxButtonIndex)) { dev_clrkb(); @@ -687,6 +713,20 @@ void System::showMenu() { _systemMenu[index++] = MENU_CUT; _systemMenu[index++] = MENU_COPY; _systemMenu[index++] = MENU_PASTE; + + if (isEditing()) { + items->add(new String("Undo")); + items->add(new String("Redo")); + items->add(new String("Save")); + items->add(new String("Run")); + items->add(new String("Debug")); + _systemMenu[index++] = MENU_UNDO; + _systemMenu[index++] = MENU_REDO; + _systemMenu[index++] = MENU_SAVE; + _systemMenu[index++] = MENU_RUN; + _systemMenu[index++] = MENU_DEBUG; + } + #if defined(_SDL) items->add(new String("Back")); _systemMenu[index++] = MENU_BACK; diff --git a/src/ui/system.h b/src/ui/system.h index b3536ab2..9bb383ee 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -67,7 +67,7 @@ struct System { MAEvent getNextEvent() { return processEvents(1); } uint32_t getModifiedTime(); void handleEvent(MAEvent &event); - void handleMenu(int menuId); + void handleMenu(MAEvent &event); bool loadSource(const char *fileName); void resize(); void runEdit(const char *startupBas); From 771267c067a9e1eb7cff6a8e3fee9f81c3dbb08e Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 3 Sep 2015 20:01:46 +1000 Subject: [PATCH 08/15] SDL: update context menu --- ChangeLog | 2 ++ src/common/inet.h | 4 ++-- src/platform/sdl/runtime.cpp | 23 +++++++++++++++-------- src/ui/inputs.cpp | 11 ++++++++++- src/ui/system.cpp | 9 ++++++++- src/ui/textedit.cpp | 4 +++- src/ui/textedit.h | 1 + 7 files changed, 41 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 222d1c6f..9bdd3597 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ - F1 key for keywords surrounded by punctuation - page scrolling with up/down arrow keys - pressing tab at the bottom no longer jumps to the top + - display additional editor context menu items + Added a basic debugger 2015-08-02 Fix display output before DELAY diff --git a/src/common/inet.h b/src/common/inet.h index 47bbb477..2e0e34ff 100644 --- a/src/common/inet.h +++ b/src/common/inet.h @@ -124,10 +124,10 @@ void net_disconnect(socket_t s); /** * @ingroup net * - * returns true if something is waitting in input-buffer + * returns true if something is waiting in input-buffer * * @param s the socket - * @return non-zero if something is waitting in input-buffer; otherwise returns 0 + * @return non-zero if something is waiting in input-buffer; otherwise returns 0 */ int net_peek(socket_t s); diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index f17cfe4c..51763155 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -162,7 +162,7 @@ void Runtime::debugStart(TextEditInput *editWidget, const char *file) { if (g_debugee != -1) { net_print(g_debugee, "l\n"); - open = net_input(g_debugee, buf, sizeof(buf), "\r\n") > 0; + open = net_input(g_debugee, buf, sizeof(buf), "\n") > 0; } else { open = false; } @@ -175,7 +175,7 @@ void Runtime::debugStart(TextEditInput *editWidget, const char *file) { g_debugee = net_connect("localhost", g_debugPort); if (g_debugee != -1) { net_print(g_debugee, "l\n"); - size = net_input(g_debugee, buf, sizeof(buf), "\r\n"); + size = net_input(g_debugee, buf, sizeof(buf), "\n"); if (size > 0) { editWidget->gotoLine(buf); appLog("Debug session ready"); @@ -194,14 +194,21 @@ void Runtime::debugStep(TextEditInput *edit, TextEditHelpWidget *help, bool cont int size; net_print(g_debugee, cont ? "c\n" : "n\n"); net_print(g_debugee, "l\n"); - size = net_input(g_debugee, buf, sizeof(buf), "\r\n"); + size = net_input(g_debugee, buf, sizeof(buf), "\n"); if (size > 0) { edit->gotoLine(buf); net_print(g_debugee, "v\n"); - size = net_input(g_debugee, buf, sizeof(buf), "\1"); - if (size > 0) { - help->reload(buf); - } + help->reload(NULL); + do { + size = net_input(g_debugee, buf, sizeof(buf), "\1\n"); + if (buf[0] == '\1') { + break; + } + if (size > 0) { + help->append(buf, size); + help->append("\n", 1); + } + } while (size > 0); } } } @@ -630,7 +637,7 @@ void Runtime::optionsBox(StringList *items) { } _output->redraw(); - while (selectedIndex == -1) { + while (selectedIndex == -1 && !isClosing()) { MAEvent ev = processEvents(true); if (ev.type == EVENT_TYPE_KEY_PRESSED && ev.key == 27) { diff --git a/src/ui/inputs.cpp b/src/ui/inputs.cpp index 90330b3a..b6a1b97a 100644 --- a/src/ui/inputs.cpp +++ b/src/ui/inputs.cpp @@ -1079,7 +1079,16 @@ void MenuButton::draw(int x, int y, int w, int h, int chw) { if (len * chw >= _width) { len = _width / chw; } + int charHeight = g_system->getOutput()->getCharHeight(); + int textY = y + (_height - charHeight) / 2; + maSetColor(_pressed ? _fg : _bg); - maDrawText(x + 4, y + 4, _label.c_str(), len); + maDrawText(x + 4, textY, _label.c_str(), len); + if (!_pressed && _index > 0 && _index % 2 == 0) { + maSetColor(0x3b3a36); + maLine(x + 2, y, x + _width - 2, y); + maSetColor(0x46453f); + maLine(x + 2, y - 1, x + _width - 2, y - 1); + } } } diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 1ae388d3..8ddc3458 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -40,7 +40,8 @@ #define MENU_SAVE 17 #define MENU_RUN 18 #define MENU_DEBUG 19 -#define MENU_SIZE 20 +#define MENU_OUTPUT 20 +#define MENU_SIZE 21 #define FONT_SCALE_INTERVAL 10 #define FONT_MIN 20 @@ -314,6 +315,10 @@ void System::handleMenu(MAEvent &event) { event.type = EVENT_TYPE_KEY_PRESSED; event.key = SB_KEY_F(5); break; + case MENU_OUTPUT: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_CTRL('o'); + break; } if (fontSize != _output->getFontSize()) { @@ -720,11 +725,13 @@ void System::showMenu() { items->add(new String("Save")); items->add(new String("Run")); items->add(new String("Debug")); + items->add(new String("Output")); _systemMenu[index++] = MENU_UNDO; _systemMenu[index++] = MENU_REDO; _systemMenu[index++] = MENU_SAVE; _systemMenu[index++] = MENU_RUN; _systemMenu[index++] = MENU_DEBUG; + _systemMenu[index++] = MENU_OUTPUT; } #if defined(_SDL) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index d241056e..de679fb9 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -611,7 +611,9 @@ void TextEditInput::reload(const char *text) { _scroll = 0; _cursorRow = 0; _buf.clear(); - _buf.insertChars(0, text, strlen(text)); + if (text != NULL) { + _buf.insertChars(0, text, strlen(text)); + } stb_textedit_initialize_state(&_state, false); } diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 7f36b964..0e576ef9 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -69,6 +69,7 @@ struct TextEditInput : public FormEditInput { TextEditInput(const char *text, int chW, int chH, int x, int y, int w, int h); virtual ~TextEditInput(); + void append(const char *text, int len) { _buf.append(text, len); } void completeWord(const char *word); void draw(int x, int y, int w, int h, int chw); bool edit(int key, int screenWidth, int charWidth); From f2fc4c46d3e28f836e57c62222a4992be5a63718 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 4 Sep 2015 06:29:31 +1000 Subject: [PATCH 09/15] UI: update menus --- src/ui/editor.cpp | 1 + src/ui/system.cpp | 37 ++++++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp index 1433aed9..a8325b2a 100644 --- a/src/ui/editor.cpp +++ b/src/ui/editor.cpp @@ -191,6 +191,7 @@ void System::editSource(strlib::String &loadPath) { _output->selectScreen(USER_SCREEN1); showCompletion(true); _output->redraw(); + _state = kActiveState; waitForBack(); _output->selectScreen(SOURCE_SCREEN); _state = kEditState; diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 8ddc3458..8cb00b58 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -712,28 +712,33 @@ void System::showMenu() { _systemMenu = new int[MENU_SIZE]; int index = 0; if (get_focus_edit() != NULL) { - items->add(new String("Cut")); - items->add(new String("Copy")); - items->add(new String("Paste")); - _systemMenu[index++] = MENU_CUT; - _systemMenu[index++] = MENU_COPY; - _systemMenu[index++] = MENU_PASTE; - if (isEditing()) { items->add(new String("Undo")); items->add(new String("Redo")); + items->add(new String("Cut")); + items->add(new String("Copy")); + items->add(new String("Paste")); items->add(new String("Save")); items->add(new String("Run")); items->add(new String("Debug")); - items->add(new String("Output")); + items->add(new String("Show output")); _systemMenu[index++] = MENU_UNDO; _systemMenu[index++] = MENU_REDO; + _systemMenu[index++] = MENU_CUT; + _systemMenu[index++] = MENU_COPY; + _systemMenu[index++] = MENU_PASTE; _systemMenu[index++] = MENU_SAVE; _systemMenu[index++] = MENU_RUN; _systemMenu[index++] = MENU_DEBUG; _systemMenu[index++] = MENU_OUTPUT; + } else { + items->add(new String("Cut")); + items->add(new String("Copy")); + items->add(new String("Paste")); + _systemMenu[index++] = MENU_CUT; + _systemMenu[index++] = MENU_COPY; + _systemMenu[index++] = MENU_PASTE; } - #if defined(_SDL) items->add(new String("Back")); _systemMenu[index++] = MENU_BACK; @@ -752,12 +757,10 @@ void System::showMenu() { _systemMenu[index++] = MENU_CONSOLE; _systemMenu[index++] = MENU_SOURCE; } -#if defined(_SDL) - items->add(new String("Back")); - _systemMenu[index++] = MENU_BACK; -#endif - items->add(new String("Restart")); - _systemMenu[index++] = MENU_RESTART; + if (!isEditing()) { + items->add(new String("Restart")); + _systemMenu[index++] = MENU_RESTART; + } #if !defined(_SDL) items->add(new String("Show keypad")); _systemMenu[index++] = MENU_KEYPAD; @@ -785,6 +788,10 @@ void System::showMenu() { items->add(new String("Screenshot")); _systemMenu[index++] = MENU_SCREENSHOT; +#if defined(_SDL) + items->add(new String("Back")); + _systemMenu[index++] = MENU_BACK; +#endif } optionsBox(items); delete items; From 2ff3bc4f63e3b68cc0d3ea0f2dc1c1d6498b49c0 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 4 Sep 2015 18:31:24 +1000 Subject: [PATCH 10/15] UI: fix debuggee launch --- src/platform/sdl/main.cpp | 20 ++++++++++++++++++-- src/platform/sdl/syswm.cpp | 8 ++++++-- src/ui/system.cpp | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 1e609422..0a809fe1 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -52,7 +52,7 @@ static struct option OPTIONS[] = { {0, 0, 0, 0} }; -const char *g_appPath; +char g_appPath[OS_PATHNAME_SIZE + 1]; int g_debugPort = 4000; void appLog(const char *format, ...) { @@ -209,6 +209,22 @@ void printKeywords() { } } +void setupAppPath(const char *path) { + g_appPath[0] = '\0'; + if (path[0] == '/' || (path[1] == ':' && path[2] == '/')) { + // full path or C:/ + strcpy(g_appPath, path); + } else { + // relative path + char cwd[OS_PATHNAME_SIZE + 1]; + cwd[0] = '\0'; + getcwd(cwd, sizeof(cwd) - 1); + strcat(g_appPath, cwd); + strcat(g_appPath, "/"); + strcat(g_appPath, path); + } +} + void showHelp() { fprintf(stdout, "SmallBASIC version %s - kw:%d, pc:%d, fc:%d, ae:%d I=%d N=%d\n\n", @@ -229,10 +245,10 @@ void showHelp() { int main(int argc, char* argv[]) { logEntered(); + setupAppPath(argv[0]); opt_command[0] = '\0'; opt_verbose = false; opt_quiet = true; - g_appPath = argv[0]; char *fontFamily = NULL; char *runFile = NULL; diff --git a/src/platform/sdl/syswm.cpp b/src/platform/sdl/syswm.cpp index c71d6c73..2e360762 100644 --- a/src/platform/sdl/syswm.cpp +++ b/src/platform/sdl/syswm.cpp @@ -12,7 +12,7 @@ #define DEFAULT_FONT_SIZE 12 #define DEFAULT_FONT_SIZE_PTS 11 -extern const char *g_appPath; +extern char g_appPath[]; extern int g_debugPort; #if defined(_Win32) @@ -54,6 +54,7 @@ void launchDebug(const char *file) { #else #include +#include void loadIcon(SDL_Window *window) { } @@ -73,7 +74,10 @@ void launchDebug(const char *file) { case 0: // child process sprintf(port, "-p %d", g_debugPort); - execl(g_appPath, g_appPath, port, "-d", file, (char *)0); + if (execl(g_appPath, g_appPath, port, "-d", file, (char *)0) == -1) { + fprintf(stderr, "exec failed %s\n", strerror(errno)); + exit(1); + } break; default: // parent process - continue diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 8cb00b58..af4e6149 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -731,7 +731,7 @@ void System::showMenu() { _systemMenu[index++] = MENU_RUN; _systemMenu[index++] = MENU_DEBUG; _systemMenu[index++] = MENU_OUTPUT; - } else { + } else if (isRunning()) { items->add(new String("Cut")); items->add(new String("Copy")); items->add(new String("Paste")); From ddc4029db676ed46d681b71578e16b2f65c589f1 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 5 Sep 2015 09:53:33 +1000 Subject: [PATCH 11/15] UI: display markers --- src/platform/sdl/main.cpp | 2 +- src/platform/sdl/runtime.cpp | 6 +++++ src/ui/editor.cpp | 1 - src/ui/textedit.cpp | 50 +++++++++++++++++++++++++++++++----- src/ui/textedit.h | 5 ++++ 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 0a809fe1..22cf7e1a 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -219,7 +219,7 @@ void setupAppPath(const char *path) { char cwd[OS_PATHNAME_SIZE + 1]; cwd[0] = '\0'; getcwd(cwd, sizeof(cwd) - 1); - strcat(g_appPath, cwd); + strcpy(g_appPath, cwd); strcat(g_appPath, "/"); strcat(g_appPath, path); } diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 51763155..5ac4aff2 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -177,6 +177,12 @@ void Runtime::debugStart(TextEditInput *editWidget, const char *file) { net_print(g_debugee, "l\n"); size = net_input(g_debugee, buf, sizeof(buf), "\n"); if (size > 0) { + int *marker = editWidget->getMarkers(); + for (int i = 0; i < MAX_MARKERS; i++) { + if (marker[i] != -1) { + net_printf(g_debugee, "b %d\n", marker[i]); + } + } editWidget->gotoLine(buf); appLog("Debug session ready"); } diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp index a8325b2a..ff4f2040 100644 --- a/src/ui/editor.cpp +++ b/src/ui/editor.cpp @@ -94,7 +94,6 @@ void System::editSource(strlib::String &loadPath) { switch (event.key) { case SB_KEY_F(2): case SB_KEY_F(3): - case SB_KEY_F(4): case SB_KEY_F(8): case SB_KEY_F(10): case SB_KEY_F(11): diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index de679fb9..fa769eba 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -31,25 +31,25 @@ int g_themeId = 0; const int theme1[] = { 0xc8cedb, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x272b33, 0x3d4350, 0x2b3039, 0x3875ed, 0x373b88, 0x2b313a, - 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd, 0x0083f8 }; const int theme2[] = { 0xc8cedb, 0x002b36, 0x3d4350, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x002b36, 0x657b83, 0x073642, 0x9f7d18, 0x2b313a, 0x073642, - 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd, 0x0083f8 }; const int theme3[] = { 0xc8cedb, 0xd7decc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x001b33, 0x0088ff, 0x000d1a, 0x0051b1, 0x373b88, 0x022444, - 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd, 0x0083f8 }; const int theme4[] = { 0xc8cedb, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, 0x2e3436, 0x888a85, 0x000000, 0x4d483b, 0x000000, 0x2b313a, - 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd + 0x0083f8, 0xff9d00, 0x31ccac, 0xc679dd, 0x0083f8 }; const int* themes[] = { @@ -81,6 +81,7 @@ const char *helpText = "SHIFT- select\n" "TAB indent line\n" "F1,A-h keyword help\n" + "F4 toggle marker\n" "F5 debug\n" "F9, C-r run\n"; @@ -119,7 +120,8 @@ EditTheme::EditTheme(int fg, int bg) : _syntax_text(fg), _syntax_command(fg), _syntax_statement(fg), - _syntax_digit(fg) { + _syntax_digit(fg), + _row_marker(fg) { } void EditTheme::selectTheme(const int theme[]) { @@ -139,6 +141,7 @@ void EditTheme::selectTheme(const int theme[]) { _syntax_command = theme[13]; _syntax_statement = theme[14]; _syntax_digit = theme[15]; + _row_marker = theme[16]; } // @@ -255,6 +258,7 @@ TextEditInput::TextEditInput(const char *text, int chW, int chH, _matchingBrace(-1), _dirty(false) { stb_textedit_initialize_state(&_state, false); + memset(_lineMarker, -1, sizeof(_lineMarker)); } TextEditInput::~TextEditInput() { @@ -535,6 +539,9 @@ bool TextEditInput::edit(int key, int screenWidth, int charWidth) { case SB_KEY_TAB: editTab(); break; + case SB_KEY_F(4): + toggleMarker(); + break; case SB_KEY_SHIFT(SB_KEY_PGUP): case SB_KEY_PGUP: pageNavigate(false, key == (int)SB_KEY_SHIFT(SB_KEY_PGUP)); @@ -799,7 +806,15 @@ void TextEditInput::cycleTheme() { void TextEditInput::drawLineNumber(int x, int y, int row, bool selected) { if (_marginWidth > 0) { - if (selected) { + bool markerRow = false; + for (int i = 0; i < MAX_MARKERS && !markerRow; i++) { + if (row == _lineMarker[i]) { + markerRow = true; + } + } + if (markerRow) { + maSetColor(_theme->_row_marker); + } else if (selected) { maSetColor(_theme->_number_selection_background); maFillRect(x, y, _marginWidth, _charHeight); maSetColor(_theme->_number_selection_color); @@ -1257,6 +1272,29 @@ void TextEditInput::setColor(SyntaxState &state) { } } +void TextEditInput::toggleMarker() { + _cursorRow = getCursorRow(); + bool found = false; + for (int i = 0; i < MAX_MARKERS && !found; i++) { + if (_cursorRow == _lineMarker[i]) { + _lineMarker[i] = -1; + found = true; + } + } + if (!found) { + for (int i = 0; i < MAX_MARKERS && !found; i++) { + if (_lineMarker[i] == -1) { + _lineMarker[i] = _cursorRow; + found = true; + break; + } + } + } + if (!found) { + _lineMarker[0] = _cursorRow; + } +} + void TextEditInput::updateScroll() { int pageRows = _height / _charHeight; if (_cursorRow + 1 < pageRows) { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 0e576ef9..9e62da23 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -12,6 +12,7 @@ #define STB_TEXTEDIT_CHARTYPE char #define STB_TEXTEDIT_UNDOCHARCOUNT 2000 #define MARGIN_CHARS 4 +#define MAX_MARKERS 10 #include #include @@ -45,6 +46,7 @@ struct EditTheme { int _syntax_command; int _syntax_statement; int _syntax_digit; + int _row_marker; }; struct EditBuffer { @@ -77,6 +79,7 @@ struct TextEditInput : public FormEditInput { int getCursorPos() const { return _state.cursor; } const char *getText() const { return _buf._buffer; } int getTextLength() const { return _buf._len; } + int *getMarkers() { return _lineMarker; } void gotoLine(const char *buffer); void reload(const char *text); bool save(const char *filePath); @@ -134,6 +137,7 @@ struct TextEditInput : public FormEditInput { void pageNavigate(bool pageDown, bool shift); void removeTrailingSpaces(); void setColor(SyntaxState &state); + void toggleMarker(); void updateScroll(); int wordStart(); @@ -147,6 +151,7 @@ struct TextEditInput : public FormEditInput { int _cursorRow; int _indentLevel; int _matchingBrace; + int _lineMarker[MAX_MARKERS]; bool _dirty; }; From da2429485c0db0bb3329f9c450785d5ef9ba3d3c Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 5 Sep 2015 14:04:59 +1000 Subject: [PATCH 12/15] UI: debug print stack --- src/platform/sdl/runtime.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 5ac4aff2..7d1afdd1 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -821,6 +821,20 @@ void signalTrace(SDL_bool debugBreak, SDL_bool debugError = SDL_FALSE) { SDL_UnlockMutex(g_lock); } +void dumpStack(socket_t socket) { + for (int i = prog_stack_count - 1; i > -1; i--) { + stknode_t node = prog_stack[i]; + switch (node.type) { + case kwFUNC: + net_print(socket, "FUNC\n"); + break; + case kwPROC: + net_print(socket, "SUB\n"); + break; + } + } +} + int debugThread(void *data) { int port = ((intptr_t) data); socket_t socket = net_listen(port); @@ -852,10 +866,15 @@ int debugThread(void *data) { break; case 'v': // variables + net_print(socket, "Variables:\n"); for (unsigned i = SYSVAR_COUNT; i < prog_varcount; i++) { - pv_writevar(tvar[i], PV_NET, socket); - net_print(socket, "\n"); + if (!v_isempty(tvar[i])) { + pv_writevar(tvar[i], PV_NET, socket); + net_print(socket, "\n"); + } } + net_print(socket, "Stack:\n"); + dumpStack(socket); net_print(socket, "\1"); break; case 'b': From ec6471ed79e6bc200c5fd2d979bc88c6882d631c Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 6 Sep 2015 10:38:47 +1000 Subject: [PATCH 13/15] UI: use edit marker for bookmarks --- src/ui/textedit.cpp | 49 +++++++++++++++++++++++++++++++++++++++------ src/ui/textedit.h | 2 ++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index fa769eba..3d5a6651 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -69,6 +69,8 @@ const char *helpText = "C-y redo\n" "C-f find, find-next\n" "C-n find, replace\n" + "C-t toggle marker\n" + "C-g goto marker\n" "C-l outline\n" "C-o show output\n" "C-SPC auto-complete\n" @@ -81,7 +83,6 @@ const char *helpText = "SHIFT- select\n" "TAB indent line\n" "F1,A-h keyword help\n" - "F4 toggle marker\n" "F5 debug\n" "F9, C-r run\n"; @@ -100,6 +101,12 @@ inline bool is_comment(const char *str, int offs) { || match(str + offs, "RrEeMm ", 3)); } +int compareIntegers(const void *p1, const void *p2) { + int i1 = *((int *)p1); + int i2 = *((int *)p2); + return i1 < i2 ? -1 : i1 == i2 ? 0 : 1; +} + // // EditTheme // @@ -254,6 +261,7 @@ TextEditInput::TextEditInput(const char *text, int chW, int chH, _marginWidth(0), _scroll(0), _cursorRow(0), + _cursorLine(0), _indentLevel(INDENT_LEVEL), _matchingBrace(-1), _dirty(false) { @@ -333,6 +341,8 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { cursorX = x + ((_state.cursor - i) * chw); cursorY = y + baseY; } + // the logical line, will be < _cursorRow when there are wrapped lines + _cursorLine = line; if (_marginWidth > 0 && selectStart == selectEnd) { maSetColor(_theme->_row_cursor); @@ -539,9 +549,12 @@ bool TextEditInput::edit(int key, int screenWidth, int charWidth) { case SB_KEY_TAB: editTab(); break; - case SB_KEY_F(4): + case SB_KEY_CTRL('t'): toggleMarker(); break; + case SB_KEY_CTRL('g'): + gotoNextMarker(); + break; case SB_KEY_SHIFT(SB_KEY_PGUP): case SB_KEY_PGUP: pageNavigate(false, key == (int)SB_KEY_SHIFT(SB_KEY_PGUP)); @@ -1132,6 +1145,30 @@ bool TextEditInput::replaceNext(const char *buffer) { return changed; } +void TextEditInput::gotoNextMarker() { + int next = 0; + int first = -1; + for (int i = 0; i < MAX_MARKERS; i++) { + if (_lineMarker[i] != -1) { + if (first == -1) { + first = i; + } + if (_lineMarker[i] == _cursorLine) { + next = i + 1 == MAX_MARKERS ? first : i + 1; + break; + } + } + } + if (first != -1) { + if (_lineMarker[next] == -1) { + next = first; + } + if (_lineMarker[next] != -1) { + setCursorRow(_lineMarker[next] - 1); + } + } +} + void TextEditInput::lineNavigate(bool lineDown) { if (lineDown) { for (int i = _state.cursor; i < _buf._len; i++) { @@ -1273,10 +1310,9 @@ void TextEditInput::setColor(SyntaxState &state) { } void TextEditInput::toggleMarker() { - _cursorRow = getCursorRow(); bool found = false; for (int i = 0; i < MAX_MARKERS && !found; i++) { - if (_cursorRow == _lineMarker[i]) { + if (_cursorLine == _lineMarker[i]) { _lineMarker[i] = -1; found = true; } @@ -1284,15 +1320,16 @@ void TextEditInput::toggleMarker() { if (!found) { for (int i = 0; i < MAX_MARKERS && !found; i++) { if (_lineMarker[i] == -1) { - _lineMarker[i] = _cursorRow; + _lineMarker[i] = _cursorLine; found = true; break; } } } if (!found) { - _lineMarker[0] = _cursorRow; + _lineMarker[0] = _cursorLine; } + qsort(_lineMarker, MAX_MARKERS, sizeof(int), compareIntegers); } void TextEditInput::updateScroll() { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 9e62da23..adf39983 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -127,6 +127,7 @@ struct TextEditInput : public FormEditInput { int getIndent(char *spaces, int len, int pos); int getLineChars(StbTexteditRow *row, int pos); char *getSelection(int *start, int *end); + void gotoNextMarker(); void lineNavigate(bool lineDown); char *lineText(int pos); int lineEnd(int pos) { return linePos(pos, true); } @@ -149,6 +150,7 @@ struct TextEditInput : public FormEditInput { int _marginWidth; int _scroll; int _cursorRow; + int _cursorLine; int _indentLevel; int _matchingBrace; int _lineMarker[MAX_MARKERS]; From a89fa736111fd48d0b7da6df179b66c364eacb7c Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 6 Sep 2015 10:58:45 +1000 Subject: [PATCH 14/15] SDL: add debug step pause --- src/platform/sdl/runtime.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 7d1afdd1..630b9631 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -30,6 +30,7 @@ #define WAIT_INTERVAL 5 #define COND_WAIT_TIME 250 #define PAUSE_DEBUG_LAUNCH 250 +#define PAUSE_DEBUG_STEP 50 #define MAIN_BAS "__main_bas__" #define AMPLITUDE 22000 #define FREQUENCY 44100 @@ -199,6 +200,7 @@ void Runtime::debugStep(TextEditInput *edit, TextEditHelpWidget *help, bool cont char buf[OS_PATHNAME_SIZE + 1]; int size; net_print(g_debugee, cont ? "c\n" : "n\n"); + pause(PAUSE_DEBUG_STEP); net_print(g_debugee, "l\n"); size = net_input(g_debugee, buf, sizeof(buf), "\n"); if (size > 0) { From 4e8770b1cae075b5394b3cd7c641668db61ab984 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 8 Sep 2015 07:23:06 +1000 Subject: [PATCH 15/15] SDL: fix path setup --- src/platform/sdl/main.cpp | 2 +- src/platform/sdl/syswm.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 22cf7e1a..d488c439 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -211,7 +211,7 @@ void printKeywords() { void setupAppPath(const char *path) { g_appPath[0] = '\0'; - if (path[0] == '/' || (path[1] == ':' && path[2] == '/')) { + if (path[0] == '/' || (path[1] == ':' && path[2] == '\\')) { // full path or C:/ strcpy(g_appPath, path); } else { diff --git a/src/platform/sdl/syswm.cpp b/src/platform/sdl/syswm.cpp index 2e360762..0173ff97 100644 --- a/src/platform/sdl/syswm.cpp +++ b/src/platform/sdl/syswm.cpp @@ -15,6 +15,8 @@ extern char g_appPath[]; extern int g_debugPort; +void appLog(const char *format, ...); + #if defined(_Win32) #include @@ -49,7 +51,9 @@ void launchDebug(const char *file) { PROCESS_INFORMATION processInfo; char cmd[1024]; sprintf(cmd, "-p %d -d %s", g_debugPort, file); - CreateProcess(g_appPath, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo); + if (!CreateProcess(g_appPath, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo)) { + appLog("failed to start %d %s %s\n", GetLastError(), g_appPath, cmd); + } } #else