From af0ad3091f378e3773c6d5d737b0469528264fc7 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Mon, 6 Apr 2026 19:31:39 -0500 Subject: [PATCH] Debug Layout option added. --- apps/dvxbasic/ide/ideMain.c | 123 +++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 2 deletions(-) diff --git a/apps/dvxbasic/ide/ideMain.c b/apps/dvxbasic/ide/ideMain.c index 93e6851..b6fba7a 100644 --- a/apps/dvxbasic/ide/ideMain.c +++ b/apps/dvxbasic/ide/ideMain.c @@ -109,6 +109,7 @@ #define CMD_WIN_CALLSTACK 153 #define CMD_WIN_WATCH 154 #define CMD_WIN_BREAKPOINTS 155 +#define CMD_DEBUG_LAYOUT 156 #define IDE_MAX_IMM 1024 #define IDE_DESIGN_W 400 #define IDE_DESIGN_H 300 @@ -281,8 +282,9 @@ static int32_t sOutputLen = 0; // swaps directly between buffers with no splicing needed. static char *sGeneralBuf = NULL; // (General) section: module-level code static char **sProcBufs = NULL; // stb_ds array: one buffer per procedure -static int32_t sCurProcIdx = -2; // which buffer is in the editor (-1=General, -2=none) -static int32_t sEditorFileIdx = -1; // which project file owns sProcBufs (-1=none) +static int32_t sCurProcIdx = -2; // which buffer is in the editor (-1=General, -2=none) +static int32_t sEditorFileIdx = -1; // which project file owns sProcBufs (-1=none) +static int32_t sEditorLineCount = 0; // line count for breakpoint adjustment on edit // Find/Replace state static char sFindText[256] = ""; @@ -730,6 +732,8 @@ static void buildWindow(void) { MenuT *toolsMenu = wmAddMenu(menuBar, "&Tools"); wmAddMenuItem(toolsMenu, "&Preferences...", CMD_PREFERENCES); + wmAddMenuSeparator(toolsMenu); + wmAddMenuCheckItem(toolsMenu, "Debug &Layout", CMD_DEBUG_LAYOUT, false); MenuT *helpMenu = wmAddMenu(menuBar, "&Help"); wmAddMenuItem(helpMenu, "&About DVX BASIC...", CMD_HELP_ABOUT); @@ -1135,6 +1139,54 @@ static void toggleBreakpointLine(int32_t editorLine) { } } + // Validate that this line is breakable (not blank, comment, or SUB/FUNCTION decl/end) + if (sEditor) { + const char *text = wgtGetText(sEditor); + + if (text) { + // Find the start of editorLine (1-based) + const char *p = text; + int32_t ln = 1; + + while (*p && ln < editorLine) { + if (*p == '\n') { + ln++; + } + + p++; + } + + // Skip leading whitespace + while (*p == ' ' || *p == '\t') { + p++; + } + + // Blank line + if (*p == '\0' || *p == '\n' || *p == '\r') { + return; + } + + // Comment (single quote or REM) + if (*p == '\'') { + return; + } + + if (strncasecmp(p, "REM ", 4) == 0 || strncasecmp(p, "REM\n", 4) == 0 || + strncasecmp(p, "REM\r", 4) == 0 || strcasecmp(p, "REM") == 0) { + return; + } + + // SUB/FUNCTION declaration or END SUB/FUNCTION + if (strncasecmp(p, "SUB ", 4) == 0 || strncasecmp(p, "FUNCTION ", 9) == 0) { + return; + } + + if (strncasecmp(p, "END SUB", 7) == 0 || strncasecmp(p, "END FUNCTION", 12) == 0) { + return; + } + } + } + // Add new breakpoint IdeBreakpointT bp; memset(&bp, 0, sizeof(bp)); @@ -4225,6 +4277,10 @@ static void onMenu(WindowT *win, int32_t menuId) { showPreferencesDialog(); } + if (menuId == CMD_DEBUG_LAYOUT && sWin && sWin->menuBar) { + wgtSetDebugLayout(sAc, wmMenuItemIsChecked(sWin->menuBar, CMD_DEBUG_LAYOUT)); + } + if (menuId == CMD_HELP_ABOUT) { dvxMessageBox(sAc, "About DVX BASIC", "DVX BASIC 1.0\n" @@ -7070,9 +7126,71 @@ static void updateWatchWindow(void) { // setStatus // ============================================================ +static int32_t countLines(const char *text) { + if (!text || !text[0]) { + return 1; + } + + int32_t n = 1; + + for (const char *p = text; *p; p++) { + if (*p == '\n') { + n++; + } + } + + return n; +} + + static void onEditorChange(WidgetT *w) { (void)w; + // Adjust breakpoints when lines are added or removed + if (sEditor && sBreakpointCount > 0) { + const char *text = wgtGetText(sEditor); + int32_t newLineCount = countLines(text); + int32_t delta = newLineCount - sEditorLineCount; + + if (delta != 0) { + int32_t fileIdx = sProject.activeFileIdx; + int32_t cursorLine = wgtTextAreaGetCursorLine(sEditor); + + // Convert editor cursor line to file code line + int32_t editCodeLine = cursorLine; + + if (sCurProcIdx >= 0 && sCurProcIdx < (int32_t)arrlen(sProcTable)) { + editCodeLine = sProcTable[sCurProcIdx].lineNum + cursorLine - 1; + } + + bool changed = false; + + for (int32_t i = sBreakpointCount - 1; i >= 0; i--) { + if (sBreakpoints[i].fileIdx != fileIdx) { + continue; + } + + if (sBreakpoints[i].codeLine >= editCodeLine) { + sBreakpoints[i].codeLine += delta; + + // Remove if shifted to invalid line + if (sBreakpoints[i].codeLine < 1) { + arrdel(sBreakpoints, i); + sBreakpointCount = (int32_t)arrlen(sBreakpoints); + } + + changed = true; + } + } + + if (changed) { + updateBreakpointWindow(); + } + + sEditorLineCount = newLineCount; + } + } + // Mark the active file as modified if (sProject.activeFileIdx >= 0 && sProject.activeFileIdx < sProject.fileCount) { sProject.files[sProject.activeFileIdx].modified = true; @@ -7841,6 +7959,7 @@ static void showProc(int32_t procIdx) { sCurProcIdx = procIdx; } + sEditorLineCount = countLines(wgtGetText(sEditor)); sEditor->onChange = savedOnChange; }