ide; debugger; valgrind integration. gdb dialog command history. old valgrind launche...
authorRejean Loyer <rejean.loyer@gmail.com>
Fri, 5 Apr 2013 01:21:35 +0000 (21:21 -0400)
committerJerome St-Louis <jerome@ecere.com>
Fri, 9 Aug 2013 07:45:52 +0000 (03:45 -0400)
ide/src/debugger/Debugger.ec
ide/src/debugger/GDBDialog.ec
ide/src/designer/CodeEditor.ec
ide/src/dialogs/CompilersDetectionDialog.ec
ide/src/ide.ec
ide/src/project/Project.ec
ide/src/project/ProjectView.ec
ide/src/project/Workspace.ec

index 13ad732..da0ce93 100644 (file)
@@ -319,6 +319,9 @@ enum DebuggerEvaluationError { none, symbolNotFound, memoryCantBeRead, unknown }
 
 FileDialog debuggerFileDialog { type = selectDir };
 
+static DualPipe vgTargetHandle;
+static File vgLogFile;
+static char vgLogPath[MAX_LOCATION];
 static DualPipe gdbHandle;
 static DebugEvaluationData eval { };
 
@@ -341,6 +344,7 @@ class Debugger
    bool userBreakOnInternBreak;
    bool signalOn;
    //bool watchesInit;
+   bool usingValgrind;
 
    int ideProcessId;
    int gdbProcessId;
@@ -376,6 +380,8 @@ class Debugger
 
    CodeEditor codeEditor;
 
+   ValgrindLogThread vgLogThread { debugger = this };
+   ValgrindTargetThread vgTargetThread { debugger = this };
    GdbThread gdbThread { debugger = this };
    Timer gdbTimer
    {
@@ -405,7 +411,7 @@ class Debugger
          {
             case restart:
                breakType = none;
-               Restart(currentCompiler, prjConfig, bitDepth);
+               Restart(currentCompiler, prjConfig, bitDepth, usingValgrind);
                break;
             case stop:
                breakType = none;
@@ -671,7 +677,7 @@ class Debugger
       }
    }
 
-   void Restart(CompilerConfig compiler, ProjectConfig config, int bitDepth)
+   void Restart(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool useValgrind)
    {
       switch(state)
       {
@@ -686,7 +692,7 @@ class Debugger
             GdbAbortExec();
          case none:
          case terminated:
-            if(!GdbInit(compiler, config, bitDepth))
+            if(!GdbInit(compiler, config, bitDepth, useValgrind))
                break;
          case loaded:
             GdbExecRun();
@@ -833,15 +839,18 @@ class Debugger
       }
 
 #if defined(__unix__)
-      progThread.terminate = true;
-      if(fifoFile)
+      if(!usingValgrind)
       {
-         fifoFile.CloseInput();
-         app.Unlock();
-         progThread.Wait();
-         app.Lock();
-         delete fifoFile;
-      }         
+         progThread.terminate = true;
+         if(fifoFile)
+         {
+            fifoFile.CloseInput();
+            app.Unlock();
+            progThread.Wait();
+            app.Lock();
+            delete fifoFile;
+         }
+      }
 #endif
 
       {
@@ -861,14 +870,14 @@ class Debugger
       ide.Update(null);
    }
       
-   void Start(CompilerConfig compiler, ProjectConfig config, int bitDepth)
+   void Start(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool useValgrind)
    {
       ide.outputView.debugBox.Clear();
       switch(state)
       {
          case none:
          case terminated:
-            if(!GdbInit(compiler, config, bitDepth))
+            if(!GdbInit(compiler, config, bitDepth, useValgrind))
                break;
          case loaded:
             GdbExecRun();
@@ -876,13 +885,13 @@ class Debugger
       }
    }
 
-   void StepInto(CompilerConfig compiler, ProjectConfig config, int bitDepth)
+   void StepInto(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool useValgrind)
    {
       switch(state)
       {
          case none:
          case terminated:
-            if(!GdbInit(compiler, config, bitDepth)) 
+            if(!GdbInit(compiler, config, bitDepth, useValgrind))
                break;
          case loaded:
             ide.outputView.ShowClearSelectTab(debug);
@@ -896,13 +905,13 @@ class Debugger
       }
    }
 
-   void StepOver(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool ignoreBkpts)
+   void StepOver(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool useValgrind, bool ignoreBkpts)
    {
       switch(state)
       {
          case none:
          case terminated:
-            if(!GdbInit(compiler, config, bitDepth)) 
+            if(!GdbInit(compiler, config, bitDepth, useValgrind))
                break;
          case loaded:
             ide.outputView.ShowClearSelectTab(debug);
@@ -931,7 +940,7 @@ class Debugger
       }
    }
 
-   void RunToCursor(CompilerConfig compiler, ProjectConfig config, int bitDepth, char * absoluteFilePath, int lineNumber, bool ignoreBkpts, bool atSameLevel)
+   void RunToCursor(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool useValgrind, char * absoluteFilePath, int lineNumber, bool ignoreBkpts, bool atSameLevel)
    {
       char relativeFilePath[MAX_LOCATION];
       DebuggerState oldState = state;
@@ -942,7 +951,7 @@ class Debugger
       {
          case none:
          case terminated:
-            Start(compiler, config, bitDepth);
+            Start(compiler, config, bitDepth, useValgrind);
          case stopped:
          case loaded:
             if(symbols)
@@ -1727,17 +1736,25 @@ class Debugger
          if(!symbols)
             return true;
 
+         if(usingValgrind)
+         {
+            const char *vgdbCommand = "/usr/bin/vgdb"; // TODO: vgdb command config option
+            //GdbCommand(false, "-target-select remote | %s --pid=%d", "vgdb", targetProcessId);
+            printf("target remote | %s --pid=%d\n", vgdbCommand, targetProcessId);
+            GdbCommand(false, "target remote | %s --pid=%d", vgdbCommand, targetProcessId); // TODO: vgdb command config option
+         }
+
          for(prj : ide.workspace.projects)
          {
             if(prj == ide.workspace.projects.firstIterator.data)
                continue;
             GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
          }
-
          for(dir : ide.workspace.sourceDirs)
          {
             GdbCommand(false, "-environment-directory \"%s\"", dir);
          }
+
          GdbInsertInternalBreakpoints();
          targeted = true;
       }
@@ -1782,7 +1799,10 @@ class Debugger
       GdbTargetSet();
       GdbExecCommon();
       ShowDebuggerViews();
-      GdbCommand(true, "-exec-run");
+      if(usingValgrind)
+         GdbCommand(true, "-exec-continue");
+      else
+         GdbCommand(true, "-exec-run");
    }
 
    void GdbExecContinue(bool focus)
@@ -1863,12 +1883,13 @@ class Debugger
       return true;
    }
 
-   bool GdbInit(CompilerConfig compiler, ProjectConfig config, int bitDepth)
+   bool GdbInit(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool useValgrind)
    {
       bool result = true;
       char oldDirectory[MAX_LOCATION];
       char tempPath[MAX_LOCATION];
-      char command[MAX_LOCATION];
+      char command[MAX_F_STRING*4];
+      bool vgFullLeakCheck = ide.workspace.vgFullLeakCheck;
       Project project = ide.project;
       DirExpression targetDirExp = project.GetTargetDir(compiler, config, bitDepth);
       PathBackup pathBackup { };
@@ -1881,6 +1902,7 @@ class Debugger
       }
       prjConfig = config;
       this.bitDepth = bitDepth;
+      usingValgrind = useValgrind;
 
       ChangeState(loaded);
       sentKill = false;
@@ -1931,17 +1953,67 @@ class Debugger
          SetEnvironment(e.name, e.string);
       }
 
-      strcpy(command,
-         (compiler.targetPlatform == win32 && bitDepth == 64) ? "x86_64-w64-mingw32-gdb" :
-         (compiler.targetPlatform == win32 && bitDepth == 32) ? "i686-w64-mingw32-gdb" :
-         "gdb");
-      strcat(command, " -n -silent --interpreter=mi2"); //-async //\"%s\"
-      gdbTimer.Start();
-      gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
-      if(!gdbHandle)
+      if(usingValgrind)
       {
-         ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
-         result = false;
+         char * clArgs = ide.workspace.commandLineArgs;
+         const char *valgrindCommand = "valgrind"; // TODO: valgrind command config option //TODO: valgrind options
+         vgLogFile = CreateTemporaryFile(vgLogPath, "ecereidevglog");
+         if(vgLogFile)
+         {
+            incref vgLogFile;
+            vgLogThread.Create();
+         }
+         else
+         {
+            ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't open temporary log file for Valgrind output\n");
+            result = false;
+         }
+         if(result)
+         {
+            sprintf(command, "%s --vgdb=yes --vgdb-error=0 --log-file=%s%s %s%s%s",
+                  valgrindCommand, vgLogPath, vgFullLeakCheck ? " --leak-check=full" : "", targetFile, clArgs ? " " : "", clArgs ? clArgs : "");
+            vgTargetHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
+            if(!vgTargetHandle)
+            {
+               ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start Valgrind\n");
+               result = false;
+            }
+         }
+         if(result)
+         {
+            incref vgTargetHandle;
+            vgTargetThread.Create();
+
+            targetProcessId = vgTargetHandle.GetProcessID();
+            waitingForPID = false;
+            if(!targetProcessId)
+            {
+               ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get Valgrind process ID\n");
+               result = false;
+            }
+         }
+         if(result)
+         {
+            app.Unlock();
+            serialSemaphore.Wait();
+            app.Lock();
+         }
+      }
+
+      if(result)
+      {
+         strcpy(command,
+            (compiler.targetPlatform == win32 && bitDepth == 64) ? "x86_64-w64-mingw32-gdb" :
+            (compiler.targetPlatform == win32 && bitDepth == 32) ? "i686-w64-mingw32-gdb" :
+            "gdb");
+         strcat(command, " -n -silent --interpreter=mi2"); //-async //\"%s\"
+         gdbTimer.Start();
+         gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
+         if(!gdbHandle)
+         {
+            ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
+            result = false;
+         }
       }
       if(result)
       {
@@ -1954,66 +2026,70 @@ class Debugger
             ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get GDB process ID\n");
             result = false;
          }
-         if(result)
-         {
-            app.Unlock();
-            serialSemaphore.Wait();
-            app.Lock();
+      }
+      if(result)
+      {
+         app.Unlock();
+         serialSemaphore.Wait();
+         app.Lock();
 
-            if(!GdbTargetSet())
+         if(!GdbTargetSet())
+         {
+            //ChangeState(terminated);
+            result = false;
+         }
+      }
+      if(result)
+      {
+#if defined(__unix__)
+         {
+            CreateTemporaryDir(progFifoDir, "ecereide");
+            strcpy(progFifoPath, progFifoDir);
+            PathCat(progFifoPath, "ideprogfifo");
+            if(!mkfifo(progFifoPath, 0600))
             {
-               //ChangeState(terminated);
-               result = false;
+               //fileCreated = true;
             }
-
-            if(result)
+            else
             {
-#if defined(__unix__)
-               {
-                  CreateTemporaryDir(progFifoDir, "ecereide");
-                  strcpy(progFifoPath, progFifoDir);
-                  PathCat(progFifoPath, "ideprogfifo");
-                  if(!mkfifo(progFifoPath, 0600))
-                  {
-                     //fileCreated = true;
-                  }
-                  else
-                  {
-                     //app.Lock();
-                     ide.outputView.debugBox.Logf(createFIFOMsg, progFifoPath);
-                     //app.Unlock();
-                  }
-               }
+               //app.Lock();
+               ide.outputView.debugBox.Logf(createFIFOMsg, progFifoPath);
+               //app.Unlock();
+            }
+         }
 
-               progThread.terminate = false;
-               progThread.Create();
+         if(!usingValgrind)
+         {
+            progThread.terminate = false;
+            progThread.Create();
+         }
 #endif
-      
+
 #if defined(__WIN32__)
-               GdbCommand(false, "-gdb-set new-console on");
+         GdbCommand(false, "-gdb-set new-console on");
 #endif
-         
-               GdbCommand(false, "-gdb-set verbose off");
-               //GdbCommand(false, "-gdb-set exec-done-display on");
-               GdbCommand(false, "-gdb-set step-mode off");
-               GdbCommand(false, "-gdb-set unwindonsignal on");
-               //GdbCommand(false, "-gdb-set shell on");
-               GdbCommand(false, "set print elements 992");
-               GdbCommand(false, "-gdb-set backtrace limit 100000");
+
+         GdbCommand(false, "-gdb-set verbose off");
+         //GdbCommand(false, "-gdb-set exec-done-display on");
+         GdbCommand(false, "-gdb-set step-mode off");
+         GdbCommand(false, "-gdb-set unwindonsignal on");
+         //GdbCommand(false, "-gdb-set shell on");
+         GdbCommand(false, "set print elements 992");
+         GdbCommand(false, "-gdb-set backtrace limit 100000");
 
 #if defined(__unix__)
-               GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
+         if(!usingValgrind)
+            GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
 #endif
 
-               GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
-               /*
-               for(e : ide.workspace.environmentVars)
-               {
-                  GdbCommand(false, "set environment %s=%s", e.name, e.string);
-               }
-               */
-            }
+         if(!usingValgrind)
+            GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
+         /*
+         for(e : ide.workspace.environmentVars)
+         {
+            GdbCommand(false, "set environment %s=%s", e.name, e.string);
          }
+         */
       }
 
       ChangeWorkingDir(oldDirectory);
@@ -2061,7 +2137,7 @@ class Debugger
       ide.Update(null);
 
 #if defined(__unix__)
-      if(FileExists(progFifoPath)) //fileCreated)
+      if(!usingValgrind && FileExists(progFifoPath)) //fileCreated)
       {
          progThread.terminate = true;
          if(fifoFile)
@@ -2749,6 +2825,17 @@ class Debugger
       }
    }
 
+   void ValgrindTargetThreadExit()
+   {
+      ide.outputView.debugBox.Logf($"ValgrindTargetThreadExit\n");
+      if(vgTargetHandle)
+      {
+         vgTargetHandle.Wait();
+         delete vgTargetHandle;
+      }
+      HandleExit(null, null);
+   }
+
    void GdbThreadExit()
    {
       if(state != terminated)
@@ -2757,6 +2844,8 @@ class Debugger
          targetProcessId = 0;
          ClearBreakDisplay();
 
+         if(vgLogFile)
+            delete vgLogFile;
          if(gdbHandle)
          {
             serialSemaphore.Release();
@@ -3392,6 +3481,10 @@ class Debugger
                            else
                               DebuggerProtocolUnknown("Unknown reason", reason);
                         }
+                        else
+                        {
+                           PrintLn(output);
+                        }
                      }
                   }
                   app.SignalEvent();
@@ -3410,7 +3503,7 @@ class Debugger
                   int oldProcessID = targetProcessId;
                   GetLastDirectory(targetFile, exeFile);
 
-                  while(true)
+                  while(!targetProcessId/*true*/)
                   {
                      targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
                      if(targetProcessId || gdbHandle.Peek()) break;
@@ -3442,7 +3535,7 @@ class Debugger
                      ClearBreakDisplay();
 
                #if defined(__unix__)
-                     if(FileExists(progFifoPath)) //fileCreated)
+                     if(!usingValgrind && FileExists(progFifoPath)) //fileCreated)
                      {
                         progThread.terminate = true;
                         if(fifoFile)
@@ -3648,6 +3741,149 @@ class Debugger
    }
 }
 
+class ValgrindLogThread : Thread
+{
+   Debugger debugger;
+
+   unsigned int Main()
+   {
+      static char output[4096];
+      Array<char> dynamicBuffer { minAllocSize = 4096 };
+      File oldValgrindHandle = vgLogFile;
+      incref oldValgrindHandle;
+
+      app.Lock();
+      while(debugger.state != terminated && vgLogFile)
+      {
+         int result;
+         app.Unlock();
+         result = vgLogFile.Read(output, 1, sizeof(output));
+         app.Lock();
+         if(debugger.state == terminated || !vgLogFile/* || vgLogFile.Eof()*/)
+            break;
+         if(result)
+         {
+            int c;
+            int start = 0;
+
+            for(c = 0; c<result; c++)
+            {
+               if(output[c] == '\n')
+               {
+                  int pos = dynamicBuffer.size;
+                  dynamicBuffer.size += c - start;
+                  memcpy(&dynamicBuffer[pos], output + start, c - start);
+                  if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
+                  // COMMENTED OUT DUE TO ISSUE #135, FIXED
+                  //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
+                     dynamicBuffer.size++;
+                  dynamicBuffer[dynamicBuffer.count - 1] = '\0';
+#ifdef _DEBUG
+                  // printf("%s\n", dynamicBuffer.array);
+#endif
+                  if(strstr(&dynamicBuffer[0], "vgdb me"))
+                     debugger.serialSemaphore.Release();
+                  ide.outputView.debugBox.Logf("%s\n", &dynamicBuffer[0]);
+                  dynamicBuffer.size = 0;
+                  start = c + 1;
+               }
+            }
+            if(c == result)
+            {
+               int pos = dynamicBuffer.size;
+               dynamicBuffer.size += c - start;
+               memcpy(&dynamicBuffer[pos], output + start, c - start);
+            }
+         }
+         else if(debugger.state == stopped)
+         {
+/*#ifdef _DEBUG
+            printf("Got end of file from GDB!\n");
+#endif*/
+            app.Unlock();
+            Sleep(0.2);
+            app.Lock();
+         }
+      }
+      delete dynamicBuffer;
+      ide.outputView.debugBox.Logf($"ValgrindLogThreadExit\n");
+      //if(oldValgrindHandle == vgLogFile)
+         debugger.GdbThreadExit/*ValgrindLogThreadExit*/();
+      delete oldValgrindHandle;
+      app.Unlock();
+      return 0;
+   }
+}
+
+class ValgrindTargetThread : Thread
+{
+   Debugger debugger;
+
+   unsigned int Main()
+   {
+      static char output[4096];
+      Array<char> dynamicBuffer { minAllocSize = 4096 };
+      DualPipe oldValgrindHandle = vgTargetHandle;
+      incref oldValgrindHandle;
+
+      app.Lock();
+      while(debugger.state != terminated && vgTargetHandle && !vgTargetHandle.Eof())
+      {
+         int result;
+         app.Unlock();
+         result = vgTargetHandle.Read(output, 1, sizeof(output));
+         app.Lock();
+         if(debugger.state == terminated || !vgTargetHandle || vgTargetHandle.Eof())
+            break;
+         if(result)
+         {
+            int c;
+            int start = 0;
+
+            for(c = 0; c<result; c++)
+            {
+               if(output[c] == '\n')
+               {
+                  int pos = dynamicBuffer.size;
+                  dynamicBuffer.size += c - start;
+                  memcpy(&dynamicBuffer[pos], output + start, c - start);
+                  if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
+                  // COMMENTED OUT DUE TO ISSUE #135, FIXED
+                  //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
+                     dynamicBuffer.size++;
+                  dynamicBuffer[dynamicBuffer.count - 1] = '\0';
+#ifdef _DEBUG
+                  // printf("%s\n", dynamicBuffer.array);
+#endif
+                  ide.outputView.debugBox.Logf("%s\n", &dynamicBuffer[0]);
+
+                  dynamicBuffer.size = 0;
+                  start = c + 1;
+               }
+            }
+            if(c == result)
+            {
+               int pos = dynamicBuffer.size;
+               dynamicBuffer.size += c - start;
+               memcpy(&dynamicBuffer[pos], output + start, c - start);
+            }
+         }
+         else
+         {
+#ifdef _DEBUG
+            printf("Got end of file from GDB!\n");
+#endif
+         }
+      }
+      delete dynamicBuffer;
+      //if(oldValgrindHandle == vgTargetHandle)
+         debugger.ValgrindTargetThreadExit();
+      delete oldValgrindHandle;
+      app.Unlock();
+      return 0;
+   }
+}
+
 class GdbThread : Thread
 {
    Debugger debugger;
index 379b7af..9799bd2 100644 (file)
@@ -191,16 +191,76 @@ class GDBDialog : Window
    hasMinimize = true;
    hasClose = true;
    stayOnTop = true;
-   size = { 424, 294 };
+   size = { 800, 600 };
    autoCreate = false;
 
    Command lastCommand;
    OldList commands;
 
-   Label commandLabel { this, position = { 8, 12 }, labeledWindow = command };
+   Stacker bg
+   {
+      this, direction = horizontal, gap = 0;
+      isActiveClient = true;
+      background = darkGray;//formColor
+      anchor = { left = 0, top = 0, right = 0, bottom = 0 };
+      flipSpring = true;
+      flipper = rightCol;
+   };
+
+   Stacker leftCol
+   {
+      bg, this, gap = 4, margin = 4 ;
+      isActiveClient = true;
+      background = darkGray;
+      size = { 200, 100 };
+      anchor = { top = 0, bottom = 0 };
+      flipSpring = true;
+      flipper = history;
+   };
+
+   PaneSplitter splitter
+   {
+      this, leftPane = leftCol, rightPane = rightCol, split = 200;
+   };
+
+   Stacker rightCol
+   {
+      bg, this, gap = 4, margin = 4;
+      isActiveClient = true;
+      background = darkGray;
+      size = { 800, 600 };
+      anchor = { top = 0, bottom = 0 };
+      flipSpring = true;
+      flipper = tree;
+   };
+
+   Label lhistory { leftCol, this, position = { 4, 4 }, labeledWindow = history };
+   ListBox history
+   {
+      leftCol, this, borderStyle = deep, hasVertScroll = true, hasHorzScroll = true;
+      // selectionColor = unfocusedSelectorColor;
+      fullRowSelect = true, alwaysHighLight = true;
+
+      size = { 180 };
+      anchor = { left = leftCol.margin, right = leftCol.margin };
+      text = $"Command History";
+
+      bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
+      {
+         if(row)
+         {
+            lastCommand = (Command)row.tag;
+            command.contents = lastCommand.command;
+            UpdateOutput();
+         }
+         return true;
+      }
+   };
+
+   Label commandLabel { rightCol, this, position = { 4, 4 }, labeledWindow = command };
    EditBox command
    {
-      this, text = $"Command:", size = { 328, 19 }, anchor = { left = 80, top = 8, right = 8 };
+      rightCol, this, text = $"Command:", size = { 328, 19 }, anchor = { left = rightCol.margin, right = rightCol.margin };
 
       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
       {
@@ -230,11 +290,20 @@ class GDBDialog : Window
       }
    };
 
-   TagButton infoLibs { this, text = "libs", tag = "info shared", anchor = { left = 80, top = 35 }, NotifyClicked = QuickCommandNotifyClicked; };
-   TagButton infoPaths { this, text = "paths", tag = "-environment-path", anchor = { left = 120, top = 35 }, NotifyClicked = QuickCommandNotifyClicked; };
-   TagButton infoWorkDir { this, text = "wd", tag = "-environment-pwd", anchor = { left = 170, top = 35 }, NotifyClicked = QuickCommandNotifyClicked; };
-   TagButton infoDirs { this, text = "pths", tag = "-environment-directory", anchor = { left = 200, top = 35 }, NotifyClicked = QuickCommandNotifyClicked; };
-   TagButton infoTemp { this, text = "pths", tag = "-environment-temp", anchor = { left = 200, top = 35 }, NotifyClicked = QuickCommandNotifyClicked; };
+   Stacker toolBar
+   {
+      rightCol, this, direction = horizontal, gap = 4;
+      isActiveClient = true;
+      background = darkGray;
+      size = { 200, 30 };
+      anchor = { left = rightCol.margin, right = rightCol.margin };
+   };
+
+   TagButton infoLibs { toolBar, this, text = "libs", tag = "info shared", NotifyClicked = QuickCommandNotifyClicked; };
+   TagButton infoPaths { toolBar, this, text = "paths", tag = "-environment-path", NotifyClicked = QuickCommandNotifyClicked; };
+   TagButton infoWorkDir { toolBar, this, text = "wd", tag = "-environment-pwd", NotifyClicked = QuickCommandNotifyClicked; };
+   TagButton infoDirs { toolBar, this, text = "pths", tag = "-environment-directory", NotifyClicked = QuickCommandNotifyClicked; };
+   TagButton infoTemp { toolBar, this, text = "pths", tag = "-environment-temp", NotifyClicked = QuickCommandNotifyClicked; };
 
    bool QuickCommandNotifyClicked(Button button, int x, int y, Modifiers mods)
    {
@@ -243,21 +312,22 @@ class GDBDialog : Window
       return true;
    }
 
-   Label treeLabel { this, position = { 8, 69 }, labeledWindow = tree };
-   ListBox tree
+   Label outputLabel { rightCol, this, position = { 4, 4 }, labeledWindow = output };
+   EditBox output
    {
-      this, text = $"Tree:";
-      multiSelect = false, fullRowSelect = false, hasVertScroll = true, hasHorzScroll = true;
-      borderStyle = deep, collapseControl = true, treeBranches = true;
-      anchor = Anchor { left = 80, right = 8, top = 65, bottom = 100 };
+      rightCol, this, text = $"Output:", multiLine = true, hasVertScroll = true, hasHorzScroll = true;
+      size = { 328, 80 };
+      anchor = { left = rightCol.margin, right = rightCol.margin };
       font = { panelFont.faceName, panelFont.size };
    };
 
-   Label outputLabel { this, position = { 8, 39 }, anchor = { left = 8, bottom = 73 }, labeledWindow = output };
-   EditBox output
+   Label treeLabel { rightCol, this, position = { 4, 4 }, labeledWindow = tree };
+   ListBox tree
    {
-      this, text = $"Output:", multiLine = true, hasVertScroll = true, hasHorzScroll = true;
-      size = { 328, 84 }, anchor = { left = 80, bottom = 8, right = 8 };
+      rightCol, this, text = $"Tree:";
+      multiSelect = false, fullRowSelect = false, hasVertScroll = true, hasHorzScroll = true;
+      borderStyle = deep, collapseControl = true, treeBranches = true;
+      anchor = { left = rightCol.margin, right = rightCol.margin };
       font = { panelFont.faceName, panelFont.size };
    };
 
@@ -583,7 +653,9 @@ class GDBDialog : Window
    {
       if(string && strlen(string))
       {
-         commands.Add(Command { command = CopyString(string) });
+         Command cmd = Command { command = CopyString(string) };
+         commands.Add(cmd);
+         history.AddString(string).tag = (uint64)cmd;
          lastCommand = commands.last;
 
          if(created)
index ddebb9f..41a49ab 100644 (file)
@@ -1922,7 +1922,8 @@ class CodeEditor : Window
                CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
                ProjectConfig config = projectView.project.config;
                int bitDepth = ide.workspace.bitDepth;
-               ide.debugger.RunToCursor(compiler, config, bitDepth, fileName, line, false, false);
+               bool useValgrind = ide.workspace.useValgrind;
+               ide.debugger.RunToCursor(compiler, config, bitDepth, useValgrind, fileName, line, false, false);
                delete compiler;
             }
          }
@@ -1941,7 +1942,8 @@ class CodeEditor : Window
             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
             ProjectConfig config = projectView.project.config;
             int bitDepth = ide.workspace.bitDepth;
-            ide.debugger.RunToCursor(compiler, config, bitDepth, fileName, line, true, false);
+            bool useValgrind = ide.workspace.useValgrind;
+            ide.debugger.RunToCursor(compiler, config, bitDepth, useValgrind, fileName, line, true, false);
             delete compiler;
          }
          return true;
@@ -1959,7 +1961,8 @@ class CodeEditor : Window
             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
             ProjectConfig config = projectView.project.config;
             int bitDepth = ide.workspace.bitDepth;
-            ide.debugger.RunToCursor(compiler, config, bitDepth, fileName, line, true, true);
+            bool useValgrind = ide.workspace.useValgrind;
+            ide.debugger.RunToCursor(compiler, config, bitDepth, useValgrind, fileName, line, true, true);
             delete compiler;
          }
          return true;
index 5034436..1cf2e00 100644 (file)
@@ -109,7 +109,7 @@ class CompilersDetectionDialog : Window
       // multiSelect = true, selectionColor = unfocusedSelectorColor;
       fullRowSelect = true;
       alwaysHighLight = true;
-      
+
       size = { 180 };
       anchor = Anchor { left = 8, top = 24, right = 8, bottom = 36 };
       text = $"Compilers";
index d0a46c6..2cc01ac 100644 (file)
@@ -1119,6 +1119,34 @@ class IDEWorkSpace : Window
          }
       }
       MenuDivider { debugMenu };
+      MenuItem debugUseValgrindItem
+      {
+         debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(ide.workspace)
+            {
+               ide.workspace.useValgrind = selection.checked;
+               ide.workspace.Save();
+            }
+            ide.AdjustValgrindChecks();
+            return true;
+         }
+      }
+      MenuItem debugValgrindFullLeakCheckItem
+      {
+         debugMenu, $"Valgrind: Full Leak Check", d, disabled = true, checkable = true;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(ide.workspace)
+            {
+               ide.workspace.vgFullLeakCheck = selection.checked;
+               ide.workspace.Save();
+            }
+            return true;
+         }
+      }
+      MenuDivider { debugMenu };
       MenuItem debugStepIntoItem
       {
          debugMenu, $"Step Into", i, f11, disabled = true;
@@ -1175,7 +1203,7 @@ class IDEWorkSpace : Window
          }
       }
       MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
-      MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", s };
+      MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", l };
       //MenuDivider { debugMenu };
       //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
    MenuPlacement imageMenu { menu, $"Image", i };
@@ -1485,7 +1513,7 @@ class IDEWorkSpace : Window
    GDBDialog gdbDialog
    {
       master = this, parent = this;
-      anchor = { left = 100, top = 100, right = 100, bottom = 100 };
+      //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
 
       void OnCommand(char * string)
       {
@@ -1822,12 +1850,20 @@ class IDEWorkSpace : Window
       toolBar.activeConfig.disabled       = unavailable;
       toolBar.activeCompiler.disabled     = unavailable;
       toolBar.activeBitDepth.disabled     = unavailable;
+      debugUseValgrindItem.disabled       = unavailable;
 
+      AdjustValgrindChecks();
       AdjustFileMenus();
       AdjustBuildMenus();
       AdjustDebugMenus();
    }
 
+   void AdjustValgrindChecks()
+   {
+      bool unavailable = !project || !debugUseValgrindItem.checked;
+      debugValgrindFullLeakCheckItem.disabled    = unavailable;
+   }
+
    property bool hasOpenedCodeEditors
    {
       get
@@ -1852,6 +1888,7 @@ class IDEWorkSpace : Window
    void AdjustBuildMenus()
    {
       bool unavailable = project && projectView.buildInProgress;
+      bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
 
       projectNewItem.disabled             = unavailable;
       toolBar.buttonNewProject.disabled   = unavailable;
@@ -1863,8 +1900,8 @@ class IDEWorkSpace : Window
       projectCloseItem.disabled           = unavailable;
       // toolBar.buttonCloseProject.disabled = unavailable;
 
-      projectRunItem.disabled    = unavailable || project.GetTargetType(project.config) != executable;
-      toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
+      projectRunItem.disabled    = naForRun;
+      toolBar.buttonRun.disabled = naForRun;
 
       projectBuildItem.disabled = false;
       projectBuildItem.text     = unavailable ? $"Stop Build" : $"Build";
@@ -2116,7 +2153,7 @@ class IDEWorkSpace : Window
                            return null;
                         //project = LoadProject(filePath, null);
                      }
-                     
+
                      if(workspace)
                      {
                         char absolutePath[MAX_LOCATION];
index 044a05d..c6b3fc0 100644 (file)
@@ -2316,11 +2316,10 @@ private:
       }
       else
          ChangeWorkingDir(topNode.path);
-      // ChangeWorkingDir(topNode.path);
       SetPath(true, compiler, config, bitDepth);
       if(executableLauncher)
       {
-         char * prefixedTarget = new char[strlen(executableLauncher) + strlen(target) + 2];
+         char * prefixedTarget = new char[strlen(executableLauncher) + strlen(target) + 8];
          prefixedTarget[0] = '\0';
          strcat(prefixedTarget, executableLauncher);
          strcat(prefixedTarget, " ");
index 13390d5..89f9931 100644 (file)
@@ -1508,6 +1508,7 @@ class ProjectView : Window
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
       TargetTypes targetType = project.GetTargetType(config);
       if(targetType == sharedLibrary || targetType == staticLibrary)
          MessageBox { master = ide, type = ok, text = $"Run", contents = $"Shared and static libraries cannot be run like executables." }.Modal();
@@ -1538,7 +1539,7 @@ class ProjectView : Window
             }
             else
             {
-               ide.debugger.Start(compiler, config, bitDepth);
+               ide.debugger.Start(compiler, config, bitDepth, useValgrind);
                result = true;
             }
          }
@@ -1909,6 +1910,7 @@ class ProjectView : Window
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
 
       bool result = false;
       if(/*!IsProjectModified() ||*/ BuildInterrim(project, restart, compiler, config, bitDepth, false))
@@ -1916,7 +1918,7 @@ class ProjectView : Window
          // For Restart, compiler and config will only be used if for
          // whatever reason (if at all possible) the Debugger is in a
          // 'terminated' or 'none' state
-         ide.debugger.Restart(compiler, config, bitDepth);
+         ide.debugger.Restart(compiler, config, bitDepth, useValgrind);
          result = true;
       }
 
@@ -1947,9 +1949,10 @@ class ProjectView : Window
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
 
       if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, bitDepth, false)))
-         ide.debugger.StepInto(compiler, config, bitDepth);
+         ide.debugger.StepInto(compiler, config, bitDepth, useValgrind);
       delete compiler;
       return true;
    }
@@ -1959,9 +1962,10 @@ class ProjectView : Window
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
       ProjectConfig config = project.config;
       int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
 
       if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, bitDepth, false)))
-         ide.debugger.StepOver(compiler, config, bitDepth, skip);
+         ide.debugger.StepOver(compiler, config, bitDepth, useValgrind, skip);
 
       delete compiler;
       return true;
index bdff439..aedad2f 100644 (file)
@@ -178,6 +178,8 @@ public:
 private:
    String compiler;
    int bitDepth;
+   bool useValgrind;
+   bool vgFullLeakCheck;
 
 public:
    void Save()