ide; fixed ide rendered useless at compiling when ide binary that's being run is...
[sdk] / ide / src / project / ProjectView.ec
index 5f75a85..57b7118 100644 (file)
@@ -70,6 +70,7 @@ static char * iconNames[] =
    "<:ecere>status/folderOpen.png",                /*openFolder*/
    "<:ecere>mimeTypes/textEcereSource.png",        /*ecFile*/
    "<:ecere>mimeTypes/textEcereHeader.png",        /*ehFile*/
+   "<:ecere>mimeTypes/textCSource.png",            /*sFile*/ // TODO: change sFile icon to differentiate from cFile icon
    "<:ecere>mimeTypes/textCSource.png",            /*cFile*/
    "<:ecere>mimeTypes/textCHeader.png",            /*hFile*/
    "<:ecere>mimeTypes/textC++Source.png",          /*cppFile*/
@@ -223,6 +224,8 @@ class ProjectView : Window
                      MenuItem { popupContent, $"Regenerate Makefile", m, NotifySelect = ProjectRegenerate }.disabled = buildMenuUnavailable;
                      MenuDivider { popupContent };
                   }
+                  MenuItem { popupContent, $"Debug Generate Symbols", l, NotifySelect = FileDebugGenerateSymbols }.disabled = buildMenuUnavailable;
+                  MenuDivider { popupContent };
                   MenuItem { popupContent, $"New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
                   MenuItem { popupContent, $"New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
                   MenuItem { popupContent, $"Import Folder...", i, NotifySelect = ProjectImportFolder };
@@ -236,7 +239,6 @@ class ProjectView : Window
                      MenuItem { popupContent, $"Remove project from workspace", r, NotifySelect = ProjectRemove }.disabled = buildMenuUnavailable;
                      MenuDivider { popupContent };
                   }
-                  MenuItem { popupContent, $"Active Configuration...", s, Key { f5, alt = true } , NotifySelect = MenuConfig };
                   MenuItem { popupContent, $"Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
                   MenuDivider { popupContent };
                   MenuItem { popupContent, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
@@ -259,8 +261,13 @@ class ProjectView : Window
                else if(node.type == file)
                {
                   MenuItem { popupContent, $"Open", o, NotifySelect = FileOpenFile };
+                  MenuDivider { popupContent };
+                  MenuItem { popupContent, $"Clean", l, NotifySelect = FileClean }.disabled = buildMenuUnavailable;
                   MenuItem { popupContent, $"Compile", c, Key { f7, ctrl = true}, NotifySelect = FileCompile }.disabled = buildMenuUnavailable;
                   MenuDivider { popupContent };
+                  MenuItem { popupContent, $"Debug Precompile", l, NotifySelect = FileDebugPrecompile }.disabled = buildMenuUnavailable;
+                  MenuItem { popupContent, $"Debug Compile", l, NotifySelect = FileDebugCompile }.disabled = buildMenuUnavailable;
+                  MenuDivider { popupContent };
                   MenuItem { popupContent, $"Remove", r, NotifySelect = FileRemoveFile };
                   MenuDivider { popupContent };
                   MenuItem { popupContent, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
@@ -290,6 +297,9 @@ class ProjectView : Window
                      MenuItem { popupContent, $"Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
                   }
                   MenuDivider { popupContent };
+                  MenuItem { popupContent, $"Clean", l, NotifySelect = FileClean }.disabled = buildMenuUnavailable;
+                  MenuItem { popupContent, $"Compile", c, Key { f7, ctrl = true}, NotifySelect = FileCompile }.disabled = buildMenuUnavailable;
+                  MenuDivider { popupContent };
                   MenuItem { popupContent, $"Remove", r, NotifySelect = FileRemoveFile };
                   MenuDivider { popupContent };
                   MenuItem { popupContent, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
@@ -316,6 +326,16 @@ class ProjectView : Window
          return true;
       }
 
+      bool NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch)
+      {
+         if(key == altUp || key == altDown)
+         {
+            SelectNextProject(key == altUp);
+            return false;
+         }
+         return true;
+      }
+
       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
       {
          if(row)
@@ -451,6 +471,35 @@ class ProjectView : Window
       }
       if(buildInProgress)
          return false;
+
+      if(modifiedDocument)
+      {
+         DialogResult dialogRes;
+         char msg[2048];
+         bool first = true;
+         strcpy(msg, $"You have modified projects.\nSave changes to ");
+         for(p : ide.workspace.projects)
+         {
+            if(p.topNode.modified)
+            {
+               if(!first) strcat(msg, ", ");
+               strcat(msg, p.name);
+               first = false;
+            }
+         }
+         strcat(msg, "?");
+
+         dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = msg }.Modal();
+
+         if(dialogRes == yes)
+         {
+            // TOFIX: Precomp error if brackets are taken out
+            return (DialogResult)MenuFileSave(null, 0) != cancel;
+         }
+         else if(dialogRes == cancel)
+            return false;
+         modifiedDocument = false;
+      }
       return true;
    }
 
@@ -473,12 +522,12 @@ class ProjectView : Window
    {
       for(prj : ide.workspace.projects)
       {
-         if(prj.topNode.modified && prj.Save(prj.filePath))
+         if(prj.topNode.modified)
          {
-            // ShowOutputBuildLog(true);
-            // DisplayCompiler(compiler, false);
-            // ProjectUpdateMakefileForAllConfigs(prj);
-            prj.topNode.modified = false;
+            prj.StopMonitoring();
+            if(prj.Save(prj.filePath))
+               prj.topNode.modified = false;
+            prj.StartMonitoring();
          }
       }
       modifiedDocument = false;
@@ -498,19 +547,36 @@ class ProjectView : Window
       return project.GetRelativePath(filePath, relativePath);
    }
 
-   ProjectNode GetNodeFromWindow(Window document, Project project)
+   ProjectNode GetNodeFromWindow(Window document, Project project, bool isCObject)
    {
       if(document.fileName)
       {
          char winFileName[MAX_LOCATION];
          char * documentFileName = GetSlashPathBuffer(winFileName, document.fileName);
-         for(p : ide.workspace.projects)
+         ProjectNode node;
+         Project prj;
+         if(isCObject)
          {
-            Project prj = project ? project : p;
-            ProjectNode node;
-            if((node = prj.topNode.FindByFullPath(documentFileName, false)))
-               return node;
-            if(project) break;
+            char name[MAX_FILENAME];
+            GetLastDirectory(documentFileName, name);
+            ChangeExtension(name, "ec", name);
+            for(p : ide.workspace.projects)
+            {
+               prj = project ? project : p;
+               if((node = prj.topNode.Find(name, false)))
+                  return node;
+               if(project) break;
+            }
+         }
+         else
+         {
+            for(p : ide.workspace.projects)
+            {
+               prj = project ? project : p;
+               if((node = prj.topNode.FindByFullPath(documentFileName, false)))
+                  return node;
+               if(project) break;
+            }
          }
       }
       return null;
@@ -525,6 +591,7 @@ class ProjectView : Window
    bool DisplayCompiler(CompilerConfig compiler, bool cleanLog)
    {
       ide.outputView.buildBox.Logf($"%s Compiler\n", compiler ? compiler.name : $"{problem with compiler selection}");
+      return true;
    }
 
    bool ProjectPrepareForToolchain(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler,
@@ -539,71 +606,90 @@ class ProjectView : Window
       if(displayCompiler)
          DisplayCompiler(compiler, false);
 
-      ProjectPrepareMakefile(project, method, false, false, compiler, config);
+      ProjectPrepareCompiler(project, compiler);
+      ProjectPrepareMakefile(project, method, compiler, config);
       return true;
    }
 
-   bool ProjectPrepareMakefile(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler,
-      CompilerConfig compiler, ProjectConfig config)
+   bool ProjectPrepareCompiler(Project project, CompilerConfig compiler)
    {
-      char makefilePath[MAX_LOCATION];
-      char makefileName[MAX_LOCATION];
-      bool exists;
-      LogBox logBox = ide.outputView.buildBox;
-      
-      if(displayCompiler)
-         DisplayCompiler(compiler, false);
-
-      strcpy(makefilePath, project.topNode.path);
-      project.CatMakeFileName(makefileName, config);
-      PathCatSlash(makefilePath, makefileName);
+      if(!project.GenerateCrossPlatformMk(app.includeFile) || !project.GenerateCompilerCf(compiler))
+         ide.outputView.buildBox.Logf($"Error generating compiler configuration (Is the project/config directory writable?)\n");
+      return true;
+   }
 
-      exists = FileExists(makefilePath);
-      if((method == normal && (!exists || config.makingModified/*|| project.topNode.modified*/)) ||
-            (method == forceExists && exists) || 
-            method == force) // || config.makingModified || makefileDirty
+   // Note: Compiler is only passed in to for VisualStudio support
+   bool ProjectPrepareMakefile(Project project, PrepareMakefileMethod method, CompilerConfig compiler, ProjectConfig config)
+   {
+      if(compiler.type.isVC)
       {
-         char * reason;
-         char * action;
-         ide.statusBar.text = $"Generating Makefile & Dependencies..."; // Dependencies?
+         // I'm guessing we'll want to support generating VS files on Linux as well...
+         ide.statusBar.text = $"Generating Visual Studio Solution...";
          app.UpdateDisplay();
+         //GenerateVSSolutionFile(project, compiler);
+         ide.statusBar.text = $"Generating Visual Studio Project...";
+         app.UpdateDisplay();
+         //GenerateVCProjectFile(project, compiler);
+         ide.statusBar.text = null;
+         app.UpdateDisplay();
+         return true;
+      }
+      else
+      {
+         char makefilePath[MAX_LOCATION];
+         char makefileName[MAX_LOCATION];
+         bool exists;
+         LogBox logBox = ide.outputView.buildBox;
          
-         if((method == normal && !exists) || (method == force && !exists))
-            action = $"Generating ";
-         else if(method == force)
-            action = $"Regenerating ";
-         else if(method == normal || method == forceExists)
-            action = $"Updating ";
-         else
-            action = "";
-         if(!exists)
-            reason = $"Makefile doesn't exist. ";
-         else if(project.topNode.modified)
-            reason = $"Project has been modified. ";
-         else
-            reason = "";
+         strcpy(makefilePath, project.topNode.path);
+         project.CatMakeFileName(makefileName, config);
+         PathCatSlash(makefilePath, makefileName);
+
+         exists = FileExists(makefilePath);
+         if(method == force ||
+           (method == forceExists && exists) ||
+           (method == normal && (!exists || (config && config.makingModified))))
+         {
+            char * reason;
+            char * action;
+            ide.statusBar.text = $"Generating Makefile & Dependencies..."; // Dependencies?
+            app.UpdateDisplay();
 
-         //logBox.Logf("%s\n", makefileName);
-         logBox.Logf($"%s - %s%smakefile for %s config...\n", makefileName, reason, action, GetConfigName(config));
+            if((method == normal && !exists) || (method == force && !exists))
+               action = $"Generating ";
+            else if(method == force)
+               action = $"Regenerating ";
+            else if(method == normal || method == forceExists)
+               action = $"Updating ";
+            else
+               action = "";
+            if(!exists)
+               reason = $"Makefile doesn't exist. ";
+            else if(project.topNode.modified)
+               reason = $"Project has been modified. ";
+            else
+               reason = "";
 
-         project.GenerateCrossPlatformCf();
-         project.GenerateDebugCf(compiler);
-         project.GenerateCompilerMk(compiler);
-         project.GenerateMakefile(null, false, null, compiler, config);
+            //logBox.Logf("%s\n", makefileName);
+            logBox.Logf($"%s - %s%smakefile for %s config...\n", makefileName, reason, action, GetConfigName(config));
 
-         ide.statusBar.text = null;
-         app.UpdateDisplay();
-         return true;
+            if(!project.GenerateMakefile(null, false, null, config))
+               ide.outputView.buildBox.Logf($"Error generating makefile (Is the project directory writable?)\n");
+
+            ide.statusBar.text = null;
+            app.UpdateDisplay();
+            return true;
+         }
       }
       return false;
    }
    
-   bool BuildInterrim(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config)
+   bool BuildInterrim(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config, bool justPrint)
    {
       if(ProjectPrepareForToolchain(prj, normal, true, true, compiler, config))
       {
          ide.outputView.buildBox.Logf($"Building project %s using the %s configuration...\n", prj.name, GetConfigName(config));
-         return Build(prj, buildType, compiler, config);
+         return Build(prj, buildType, compiler, config, justPrint);
       }
       return false;
    }
@@ -633,7 +719,7 @@ class ProjectView : Window
       return result;
    }
 
-   bool Build(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config)
+   bool Build(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config, bool justPrint)
    {
       bool result = true;
       Window document;
@@ -643,7 +729,7 @@ class ProjectView : Window
       {
          if(document.modifiedDocument)
          {
-            ProjectNode node = GetNodeFromWindow(document, prj);
+            ProjectNode node = GetNodeFromWindow(document, prj, false);
             if(node && !document.MenuFileSave(null, 0))
             {
                result = false;
@@ -659,7 +745,7 @@ class ProjectView : Window
 
          // TODO: Disabled until problems fixed... is it fixed?
          if(buildType == rebuild || (config && config.compilingModified))
-            prj.Clean(compiler, config, false);
+            prj.Clean(compiler, config, false, justPrint);
          else
          {
             if(buildType == relink || (config && config.linkingModified))
@@ -698,7 +784,7 @@ class ProjectView : Window
          ide.AdjustBuildMenus();
          ide.AdjustDebugMenus();
 
-         result = prj.Build(buildType == run, null, compiler, config);
+         result = prj.Build(buildType == run, null, compiler, config, justPrint, normal);
 
          if(config)
          {
@@ -740,14 +826,14 @@ class ProjectView : Window
       }
       else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, false);
          if(node)
             prj = node.project;
       }
       config = prj.config;
       if(/*prj != project || */!prj.GetConfigIsInDebugSession(config) || !ide.DontTerminateDebugSession($"Project Build"))
       {
-         BuildInterrim(prj, build, compiler, config);
+         BuildInterrim(prj, build, compiler, config, mods.ctrl && mods.shift);
       }
       delete compiler;
       return true;
@@ -766,7 +852,7 @@ class ProjectView : Window
       }
       else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, false);
          if(node)
             prj = node.project;
       }
@@ -779,7 +865,7 @@ class ProjectView : Window
             ide.outputView.buildBox.Logf($"Relinking project %s using the %s configuration...\n", prj.name, GetConfigName(config));
             if(config)
                config.linkingModified = true;
-            Build(prj, relink, compiler, config);
+            Build(prj, relink, compiler, config, mods.ctrl && mods.shift);
          }
       }
       delete compiler;
@@ -799,7 +885,7 @@ class ProjectView : Window
       }
       else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, false);
          if(node)
             prj = node.project;
       }
@@ -815,7 +901,7 @@ class ProjectView : Window
                config.compilingModified = true;
                config.makingModified = true;
             }*/ // -- should this still be used depite the new solution of BuildType?
-            Build(prj, rebuild, compiler, config);
+            Build(prj, rebuild, compiler, config, mods.ctrl && mods.shift);
          }
       }
       delete compiler;
@@ -835,7 +921,7 @@ class ProjectView : Window
       }
       else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, false);
          if(node)
             prj = node.project;
       }
@@ -851,7 +937,7 @@ class ProjectView : Window
             ide.AdjustBuildMenus();
             ide.AdjustDebugMenus();
 
-            prj.Clean(compiler, config, false);
+            prj.Clean(compiler, config, false, mods.ctrl && mods.shift);
             buildInProgress = none;
             ide.AdjustBuildMenus();
             ide.AdjustDebugMenus();
@@ -874,7 +960,7 @@ class ProjectView : Window
       }
       else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, false);
          if(node)
             prj = node.project;
       }
@@ -890,7 +976,7 @@ class ProjectView : Window
             ide.AdjustBuildMenus();
             ide.AdjustDebugMenus();
 
-            prj.Clean(compiler, config, true);
+            prj.Clean(compiler, config, true, mods.ctrl && mods.shift);
             buildInProgress = none;
             ide.AdjustBuildMenus();
             ide.AdjustDebugMenus();
@@ -914,102 +1000,126 @@ class ProjectView : Window
       }
       else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, false);
          if(node)
             prj = node.project;
       }
 
-      ProjectPrepareMakefile(prj, force, true, true, compiler, prj.config);
+      DisplayCompiler(compiler, false);
+      ProjectPrepareCompiler(project, compiler);
+      ProjectPrepareMakefile(prj, force, compiler, prj.config);
       delete compiler;
       return true;
    }
 
-   bool Compile(ProjectNode node)
+   bool Compile(Project project, List<ProjectNode> nodes, bool justPrint, SingleFileCompileMode mode)
    {
-      bool result = false;
+      bool result = true;
       char fileName[MAX_LOCATION];
       Window document;
-      Project prj = node.project;
-      ProjectConfig config = prj.config;
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
 
       stopBuild = false;
 
-      // Check if we have to save
-      strcpy(fileName, prj.topNode.path);
-      PathCatSlash(fileName, node.path);
-      PathCatSlash(fileName, node.name);
       for(document = ide.firstChild; document; document = document.next)
       {
          if(document.modifiedDocument)
          {
-            char documentFileName[MAX_LOCATION];
-            if(!fstrcmp(GetSlashPathBuffer(documentFileName, document.fileName), fileName))
-               if(!document.MenuFileSave(null, 0))
-                  return;
-         }
-      }
-
-      if(ProjectPrepareForToolchain(prj, normal, true, true, compiler, config))
-      {
-         if(!node.GetIsExcluded(config))
-         {
-            // Delete intermedaite files
+            ProjectNode n = GetNodeFromWindow(document, project, mode == cObject ? true : false);
+            for(node : nodes)
             {
-               char extension[MAX_EXTENSION];
-               DirExpression objDir = prj.GetObjDir(compiler, config);
-
-               strcpy(fileName, prj.topNode.path);
-               PathCatSlash(fileName, objDir.dir);
-               PathCatSlash(fileName, node.name);
-               StripExtension(fileName);
-               strcat(fileName, ".o");
-               if(FileExists(fileName))
-                  DeleteFile(fileName);
-
-               GetExtension(node.name, extension);
-               if(!strcmp(extension, "ec"))
+               if(n && n.IsInNode(node) && !document.MenuFileSave(null, 0))
                {
-                  // Delete generated C file
-                  strcpy(fileName, prj.topNode.path);
-                  PathCat(fileName, objDir.dir);
-                  PathCat(fileName, node.name);
-                  StripExtension(fileName);
-                  strcat(fileName, ".c");
-                  if(FileExists(fileName))
-                     DeleteFile(fileName);
-
-                  // Delete symbol file
-                  strcpy(fileName, prj.topNode.path);
-                  PathCat(fileName, node.path);
-                  PathCat(fileName, node.name);
-                  StripExtension(fileName);
-                  strcat(fileName, ".sym");
-                  if(FileExists(fileName))
-                     DeleteFile(fileName);
+                  ide.outputView.buildBox.Logf($"Unable to save %s file.\n", node.name);
+                  result = false;
+                  break;
                }
-
-               delete objDir;
             }
-            buildInProgress = compilingFile;
-            ide.AdjustBuildMenus();
+         }
+      }
 
-            //ide.outputView.ShowClearSelectTab(build);
-            // this stuff doesn't even appear
-            //ide.outputView.buildBox.Logf($"%s Compiler\n", compiler.name);
+      if(result)
+      {
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         result = false;
+         if(ProjectPrepareForToolchain(project, normal, true, true, compiler, config))
+         {
             if(config)
-               ide.outputView.buildBox.Logf($"Compiling single file %s in project %s using the %s configuration...\n", node.name, prj.name, config.name);
+               ide.outputView.buildBox.Logf($"%s specific file(s) in project %s using the %s configuration...\n",
+                     mode == normal ? $"Compiling" : $"Debug compiling", project.name, config.name);
             else
-               ide.outputView.buildBox.Logf($"Compiling single file %s in project %s...\n", node.name, prj.name);
+               ide.outputView.buildBox.Logf($"%s specific file(s) in project %s...\n",
+                     mode == normal ? $"Compiling" : $"Debug compiling", project.name);
 
-            prj.Compile(node, compiler, config);
+            buildInProgress = compilingFile;
+            ide.AdjustBuildMenus();
+            project.Compile(nodes, compiler, config, justPrint, mode);
             buildInProgress = none;
             ide.AdjustBuildMenus();
 
             result = true;
          }
+         delete compiler;
+      }
+      return result;
+   }
+
+   bool Clean(Project project, List<ProjectNode> nodes, bool justPrint)
+   {
+      bool result = true;
+      char fileName[MAX_LOCATION];
+      Window document;
+      ProjectConfig config = project.config;
+
+      stopBuild = false;
+
+      for(document = ide.firstChild; document; document = document.next)
+      {
+         if(document.modifiedDocument)
+         {
+            ProjectNode n = GetNodeFromWindow(document, project, false);
+            for(node : nodes)
+            {
+               if(n && n.IsInNode(node) && !document.MenuFileSave(null, 0))
+               {
+                  ide.outputView.buildBox.Logf($"Unable to save %s file.\n", node.name);
+                  result = false;
+                  break;
+               }
+            }
+         }
+      }
+
+      if(result)
+      {
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         result = false;
+         if(ProjectPrepareForToolchain(project, normal, true, true, compiler, config))
+         {
+            Map<String, NameCollisionInfo> namesInfo { };
+            project.topNode.GenMakefileGetNameCollisionInfo(namesInfo, config);
+            for(node : nodes)
+            {
+               if(node.GetIsExcluded(config))
+                  ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
+               else
+               {
+                  if(config)
+                     ide.outputView.buildBox.Logf($"Deleteing intermediate objects for %s %s in project %s using the %s configuration...\n",
+                           node.type == file ? $"single file" : $"folder", node.name, project.name, config.name);
+                  else
+                     ide.outputView.buildBox.Logf($"Deleteing intermediate objects for %s %s in project %s...\n",
+                           node.type == file ? $"single file" : $"folder", node.name, project.name);
+
+                  node.DeleteIntermediateFiles(compiler, config, namesInfo, false);
+                  result = true;
+               }
+            }
+            namesInfo.Free();
+            delete namesInfo;
+         }
+         delete compiler;
       }
-      delete compiler;
       return result;
    }
 
@@ -1108,42 +1218,13 @@ class ProjectView : Window
    {
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
 
+      // This call really does not belong here:
+      ide.UpdateToolBarActiveConfigs(false);
       for(config : project.configurations)
-      {
-         ProjectPrepareMakefile(project, forceExists, false, false,
-            compiler, config);
-      }
+         ProjectPrepareMakefile(project, forceExists, compiler, config);
 
       ide.Update(null);
       delete compiler;
-   }
-
-   bool MenuConfig(MenuItem selection, Modifiers mods)
-   {
-      if(ProjectActiveConfig { master = parent, project = project }.Modal() == ok)
-         ide.AdjustMenus();
-      return true;
-   }
-
-   bool MenuCompiler(MenuItem selection, Modifiers mods)
-   {
-      ActiveCompilerDialog compilerDialog
-      {
-         master = parent;
-         ideSettings = ideSettings, workspaceActiveCompiler = ide.workspace.compiler;
-      };
-      incref compilerDialog;
-      if(compilerDialog.Modal() == ok && strcmp(compilerDialog.workspaceActiveCompiler, ide.workspace.compiler))
-      {
-         CompilerConfig compiler = ideSettings.GetCompilerConfig(compilerDialog.workspaceActiveCompiler);
-         ide.workspace.compiler = compilerDialog.workspaceActiveCompiler;
-         ide.projectView.ShowOutputBuildLog(true);
-         ide.projectView.DisplayCompiler(compiler, false);
-         for(prj : ide.workspace.projects)
-            ide.projectView.ProjectUpdateMakefileForAllConfigs(prj);
-         delete compiler;
-      }
-      delete compilerDialog;
       return true;
    }
 
@@ -1185,16 +1266,103 @@ class ProjectView : Window
 
    bool FileCompile(MenuItem selection, Modifiers mods)
    {
-      DataRow row = fileList.currentRow;
-      if(row)
+      OldLink item;
+      OldList selectedRows;
+      Project project = null;
+      List<ProjectNode> nodes { };
+      fileList.GetMultiSelection(selectedRows);
+      for(item = selectedRows.first; item; item = item.next)
       {
+         OldLink i;
+         DataRow row = item.data;
          ProjectNode node = (ProjectNode)row.tag;
-         if(!Compile(node))
-            ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
+         if(!project)
+            project = node.project;
+         else if(node.project != project)
+         {
+            project = null;
+            break;
+         }
+         nodes.Add(node);
       }
+      selectedRows.Free(null);
+      if(project)
+         Compile(project, nodes, mods.ctrl && mods.shift, normal);
+      else
+         ide.outputView.buildBox.Logf($"Please select files from a single project.\n");
+      delete nodes;
       return true;
    }
 
+   bool FileClean(MenuItem selection, Modifiers mods)
+   {
+      OldLink item;
+      OldList selectedRows;
+      Project project = null;
+      List<ProjectNode> nodes { };
+      fileList.GetMultiSelection(selectedRows);
+      for(item = selectedRows.first; item; item = item.next)
+      {
+         OldLink i;
+         DataRow row = item.data;
+         ProjectNode node = (ProjectNode)row.tag;
+         if(!project)
+            project = node.project;
+         else if(node.project != project)
+         {
+            project = null;
+            break;
+         }
+         nodes.Add(node);
+      }
+      selectedRows.Free(null);
+      if(project)
+         Clean(project, nodes, mods.ctrl && mods.shift);
+      else
+         ide.outputView.buildBox.Logf($"Please select files from a single project.\n");
+      delete nodes;
+      return true;
+   }
+
+   bool FileDebugPrecompile(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      if(node)
+      {
+         List<ProjectNode> nodes { };
+         nodes.Add(node);
+         Compile(node.project, nodes, mods.ctrl && mods.shift, debugPrecompile);
+         delete nodes;
+      }
+   }
+
+   bool FileDebugCompile(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      if(node)
+      {
+         List<ProjectNode> nodes { };
+         nodes.Add(node);
+         Compile(node.project, nodes, mods.ctrl && mods.shift, debugCompile);
+         delete nodes;
+      }
+   }
+
+   bool FileDebugGenerateSymbols(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      if(node)
+      {
+         List<ProjectNode> nodes { };
+         nodes.Add(node);
+         Compile(node.project, nodes, mods.ctrl && mods.shift, debugGenerateSymbols);
+         delete nodes;
+      }
+   }
+
    Project GetSelectedProject(bool useSelection)
    {
       Project prj = project;
@@ -1208,6 +1376,24 @@ class ProjectView : Window
       return prj;
    }
    
+   void SelectNextProject(bool backwards)
+   {
+      DataRow row = fileList.currentRow;
+      DataRow currentRow = row;
+      ProjectNode node = (ProjectNode)row.tag;
+      if(node.type != project)
+         row = node.project.topNode.row;
+      else if(backwards)
+         row = row.previous ? row.previous : fileList.lastRow;
+      if(!backwards)
+         row = row.next ? row.next : fileList.firstRow;
+      if(row && row != currentRow)
+      {
+         fileList.SelectRow(row);
+         fileList.currentRow = row;
+      }
+   }
+
    ProjectNode GetSelectedNode(bool useSelection)
    {
       ProjectNode node = null;
@@ -1233,6 +1419,7 @@ class ProjectView : Window
       if(node != prj.topNode)
          PathCatSlash(folder, node.path);
       ShellOpen(folder);
+      return true;
    }
 
    bool Run(MenuItem selection, Modifiers mods)
@@ -1248,7 +1435,7 @@ class ProjectView : Window
          project.Run(args, compiler, config);
       /*else if(config.targetType == sharedLibrary || config.targetType == staticLibrary)
          MessageBox { master = ide, type = ok, text = "Run", contents = "Shared and static libraries cannot be run like executables." }.Modal();*/
-      else if(BuildInterrim(project, run, compiler, config))
+      else if(BuildInterrim(project, run, compiler, config, false))
          project.Run(args, compiler, config);
       delete args;
       delete compiler;
@@ -1268,7 +1455,7 @@ class ProjectView : Window
       else if(project.GetDebug(config) ||
          MessageBox { master = ide, type = okCancel, text = $"Starting Debug", contents = $"Attempting to debug non-debug configuration\nProceed anyways?" }.Modal() == ok)
       {
-         if(/*!IsProjectModified() ||*/ BuildInterrim(project, start, compiler, config))
+         if(/*!IsProjectModified() ||*/ BuildInterrim(project, start, compiler, config, false))
          {
             if(compiler.type.isVC)
             {
@@ -1283,7 +1470,6 @@ class ProjectView : Window
                ChangeWorkingDir(project.topNode.path);
 
                sprintf(command, "%s /useenv %s.sln /projectconfig \"%s|Win32\" /command \"%s\"" , "devenv", project.name, config.name, "Debug.Start");
-               //ide.outputView.buildBox.Logf("command: %s\n", command);
                Execute(command);
                ChangeWorkingDir(oldwd);
 
@@ -1438,7 +1624,7 @@ class ProjectView : Window
    {
       DataRow row = addTo ? addTo.AddRow() : fileList.AddRow();
 
-      row.tag = (int)node;
+      row.tag = (int64)node;
       node.row = row;
 
       if(node.type == resources)
@@ -1480,25 +1666,24 @@ class ProjectView : Window
       Project prj = node ? node.project : null;
       if(prj)
       {
+         prj.StopMonitoring();
          if(prj.Save(prj.filePath))
          {
-            // ShowOutputBuildLog(true);
-            // DisplayCompiler(compiler, false);
-            // ProjectUpdateMakefileForAllConfigs(prj);
+            Project modPrj = null;
             prj.topNode.modified = false;
-            prj = null;
             for(p : ide.workspace.projects)
             {
                if(p.topNode.modified)
                { 
-                  prj = p;
+                  modPrj = p;
                   break;
                }
             }
-            if(!prj)
+            if(!modPrj)
                modifiedDocument = false;
             Update(null);
          }
+         prj.StartMonitoring();
       }
       return true;
    }
@@ -1513,6 +1698,7 @@ class ProjectView : Window
          output.SelectTab(build);
          output.Show();
       }
+      return true;
    }
 
    bool DebugRestart()
@@ -1521,7 +1707,7 @@ class ProjectView : Window
       ProjectConfig config = project.config;
 
       bool result = false;
-      if(/*!IsProjectModified() ||*/ BuildInterrim(project, restart, compiler, config))
+      if(/*!IsProjectModified() ||*/ BuildInterrim(project, restart, compiler, config, false))
       {
          // For Restart, compiler and config will only be used if for
          // whatever reason (if at all possible) the Debugger is in a
@@ -1557,7 +1743,7 @@ class ProjectView : Window
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
       ProjectConfig config = project.config;
 
-      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config)))
+      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, false)))
          ide.debugger.StepInto(compiler, config);
       delete compiler;
       return true;
@@ -1568,7 +1754,7 @@ class ProjectView : Window
       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
       ProjectConfig config = project.config;
 
-      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config)))
+      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, false)))
          ide.debugger.StepOver(compiler, config, skip);
 
       delete compiler;
@@ -1638,7 +1824,7 @@ class ProjectView : Window
             }
             Update(null);
             folderNode.row = parentNode.row.AddRowAfter(after ? after.row : null);
-            folderNode.row.tag = (int)folderNode;
+            folderNode.row.tag = (int64)folderNode;
                
             folderNode.row.SetData(null, folderNode);
             fileList.currentRow = folderNode.row;
@@ -1767,7 +1953,7 @@ class ProjectView : Window
          }
          Update(null);
          result.row = parentNode.row.AddRowAfter(after ? after.row : null);
-         result.row.tag = (int)result;
+         result.row.tag = (int64)result;
          result.row.SetData(null, result);
       }
       return result;
@@ -1809,7 +1995,7 @@ class ProjectView : Window
          Update(null);
          project.ModifiedAllConfigs(true, false, false, true);
          projectNode.row = parentNode.row.AddRowAfter(after ? after.row : null);
-         projectNode.row.tag =(int)projectNode;
+         projectNode.row.tag =(int64)projectNode;
             
          projectNode.row.SetData(null, projectNode);
          fileList.currentRow = projectNode.row;