pascalabcnet/VisualPascalABCNETLinux/Workbench/RunService.cs
Александр Земляк b23f9c96d0
Деактивация кнопок, связанных с Intellisense, для языков без Intellisense + разделение ILanguageInformation на два интерфейса (#3378)
* Refactor language information classes

* Implement SimpleLanguageInformation abstract class

* Move some properties to SimpleLanguageInformation

* Implement format and debug buttons disabling if Intellisense is not supported for current language

* Add Intellisense available check in FormsExtensions to deactivate menu items if needed

* Change function interfaces in VisibilityService

* Replace CodeCompletionController.CurrentParser null checks with IntellisenseAvailable method call

* Refactor IParser and BaseParser to deduplicate code

* Fix BuildTreeInSpecialMode in SPythonParser

* Add SimpleParser class for new languages without Intellisense

* Delete duplicate SetDebugButtonsEnabled function

* Add Intellisense available check in RunService when attaching debugger

* Delete inner check in SetDebugButtonsEnabled to improve architecture

* Change CurrentParser property in CodeCompletion to be CurrentLanguage

* Divide ILanguageInformation into two interfaces (creating new ILanguageIntellisenseSupport)

* Fix LanguageIntellisenseSupport initialization in BaseLanguage

* Fix RunService fictive_attach logic

* Disable Intellisense parsing for languages without Intellisense support

* Add DefaultLanguageInformation abstract class

* Add default implementation for SetSemanticConstants in BaseLanguage

* Simplify IParser interface

* Update developer guide documentation
2026-01-27 22:25:28 +03:00

344 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using VisualPascalABCPlugins;
namespace VisualPascalABC
{
public partial class WorkbenchRunService : IWorkbenchRunService
{
string RedirectIOModeModuleName = "__RedirectIOMode";
string RunModeModuleName = "__RunMode";
string RedirectIOModeName = "[REDIRECTIOMODE]";
string RunModeName = "[RUNMODE]";
private bool TerminateAllPrograms = false;
public RunManager RunnerManager;
private IWorkbench Workbench;
//private IWorkbenchDesignerService DesignerService;
private IWorkbenchBuildService BuildService;
private IWorkbenchDocumentService DocumentService;
private IWorkbenchDebuggerOperationsService DebuggerOperationsService;
private DebugHelper DebuggerManager;
private Dictionary<string, ICodeFileDocument> RunTabs = new Dictionary<string, ICodeFileDocument>();
private Dictionary<ICodeFileDocument, string> ReadRequests = new Dictionary<ICodeFileDocument, string>();
private Dictionary<string, string> RunArgumentsTable = new Dictionary<string, string>();
bool RunActiveTabPage = false;
// SSM 16/05/22 - добавил чтобы иметь возможность добавлять обработчики во внешнем плагине
public event RunnerManagerActionDelegate Starting
{
add
{
RunnerManager.Starting += value;
}
remove
{
RunnerManager.Starting -= value;
}
}
public event RunnerManagerActionDelegate Exited
{
add
{
RunnerManager.Exited += value;
}
remove
{
RunnerManager.Exited -= value;
}
}
public WorkbenchRunService()
{
Workbench = WorkbenchServiceFactory.Workbench;
RunnerManager = new RunManager(ReadStringRequest);
RunnerManager.Exited += new RunnerManagerActionDelegate(RunnerManager_Exited);
RunnerManager.Starting += new RunnerManagerActionDelegate(RunnerManager_Started);
RunnerManager.OutputStringReceived += new RunManager.TextRecivedDelegate(RunnerManager_OutputStringReceived);
RunnerManager.RunnerManagerUnhanledRuntimeException += new RunManager.RunnerManagerUnhanledRuntimeExceptionDelegate(RunnerManager_RunnerManagerUnhanledRuntimeException);
//DesignerService = WorkbenchServiceFactory.DesignerService;
this.DebuggerManager = WorkbenchServiceFactory.DebuggerManager;
BuildService = WorkbenchServiceFactory.BuildService;
DebuggerOperationsService = WorkbenchServiceFactory.DebuggerOperationsService;
DocumentService = WorkbenchServiceFactory.DocumentService;
}
public bool Run(bool RedirectConsoleIO)
{
Workbench.UserOptions.RedirectConsoleIO = RedirectConsoleIO;
if (Workbench.UserOptions.RedirectConsoleIO)
if (!DebuggerManager.IsRunning)
return Run(DocumentService.CurrentCodeFileDocument, true, false, false);
else if (DebuggerManager.IsRunAndInThisTabPage())
{
DebuggerManager.Continue();
return true;
}
return Run(DocumentService.CurrentCodeFileDocument);
}
public bool Run(bool forDebugging, bool startWithGoto, bool need_first_brpt)
{
return Run(DocumentService.CurrentCodeFileDocument, forDebugging, startWithGoto, need_first_brpt);
}
public void Run(string fileName, bool redirectIO, string ModeName, bool RunWithPause, string WorkingDirectory, string CommandLineArguments, bool attachDebugger, bool fictive_attach)
{
RunnerManager.Run(fileName,
Workbench.UserOptions.RedirectConsoleIO, RedirectIOModeName, RunWithPause,
Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.SourceFileDirectory,
CommandLineArguments, attachDebugger, fictive_attach);
}
public bool Run(ICodeFileDocument tabPage, bool forDebugging, bool startWithGoto, bool needFirstBreakpoint)
{
lock (o)
{
bool attachdbg = forDebugging || startWithGoto || needFirstBreakpoint; //|| WorkbenchServiceFactory.DebuggerManager.HasBreakpoints();
bool fictive_attach = false;
BuildService.CompilerOptions.UseDllForSystemUnits = false;
BuildService.CompilerOptions.OutputFileType = PascalABCCompiler.CompilerOptions.OutputType.ConsoleApplicaton;
if (ProjectFactory.Instance.ProjectLoaded)
tabPage = DocumentService.GetTabPageForMainFile();
if (attachdbg && !Workbench.UserOptions.AlwaysAttachDebuggerAtStart)
fictive_attach = !startWithGoto && !needFirstBreakpoint && !DebuggerManager.HasBreakpoints() || !CodeCompletion.CodeCompletionController.IntellisenseAvailable();
WorkbenchServiceFactory.OperationsService.ClearOutputTextBoxForTabPage(tabPage);
Workbench.ErrorsListWindow.ClearErrorList();
//DesignerService.GenerateAllDesignersCode();
string runtimeModule;
string ModeName;
bool RunWithPause = false;
if (Workbench.UserOptions.RedirectConsoleIO || forDebugging)
{
runtimeModule = RedirectIOModeModuleName;
ModeName = RedirectIOModeName;
if (Workbench.UserOptions.UseDllForSystemUnits && !Workbench.UserOptions.PABCDllChecked)
{
if (typeof(System.Runtime.CompilerServices.ExtensionAttribute).Assembly != typeof(int).Assembly || PascalABCCompiler.Compiler.get_assembly_path("PABCRtl.dll", false) == null)
Workbench.UserOptions.UseDllForSystemUnits = false;
Workbench.UserOptions.PABCDllChecked = true;
}
// SSM 09.02.20 - UseDllForSystemUnits включать когда флаг установлен - безо всяких доп. условий
if (/*Workbench.UserOptions.DeleteEXEAfterExecute &&*/ Workbench.UserOptions.UseDllForSystemUnits && !startWithGoto && !needFirstBreakpoint)
BuildService.CompilerOptions.UseDllForSystemUnits = true;
}
else
{
runtimeModule = RunModeModuleName;
ModeName = RunModeName;
RunWithPause = Workbench.UserOptions.PauseInRunModeIfConsole;
}
bool debug = BuildService.CompilerOptions.Debug;
if (forDebugging)
{
BuildService.CompilerOptions.Debug = true;
BuildService.CompilerOptions.ForDebugging = true;
Workbench.UserOptions.RedirectConsoleIO = true;
}
string OutputFileName = null;
if (!forDebugging)
{
if (!ProjectFactory.Instance.ProjectLoaded)
OutputFileName = BuildService.Compile(tabPage.FileName, false, runtimeModule, true, Workbench.UserOptions.RedirectConsoleIO);
else
OutputFileName = BuildService.Compile(ProjectFactory.Instance.CurrentProject, false, runtimeModule, true, Workbench.UserOptions.RedirectConsoleIO);
}
else
{
if (!ProjectFactory.Instance.ProjectLoaded)
OutputFileName = BuildService.Compile(tabPage.FileName, false, runtimeModule, true, true);
else
OutputFileName = BuildService.Compile(ProjectFactory.Instance.CurrentProject, false, runtimeModule, true, true);
}
if (RunWithPause)
RunWithPause = RunWithPause && Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.OutputFileType == PascalABCCompiler.CompilerOptions.OutputType.ConsoleApplicaton;
if (OutputFileName != null)
{
switch (Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.OutputFileType)
{
case PascalABCCompiler.CompilerOptions.OutputType.ClassLibrary:
if (DocumentService.ActiveCodeFileDocument != null && DocumentService.ActiveCodeFileDocument != DocumentService.CurrentCodeFileDocument && !DocumentService.ActiveCodeFileDocument.Run)
if (!RunActiveTabPage)
{
RunActiveTabPage = true;
return Run(DocumentService.ActiveCodeFileDocument, forDebugging, startWithGoto, needFirstBreakpoint);
}
MessageBox.Show(Form1StringResources.Get("RUN_DLL_WARNING_TEXT"), PascalABCCompiler.StringResources.Get("!WARNING"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
RunActiveTabPage = false;
break;
case PascalABCCompiler.CompilerOptions.OutputType.PascalCompiledUnit:
if (DocumentService.ActiveCodeFileDocument != null && DocumentService.ActiveCodeFileDocument != DocumentService.CurrentCodeFileDocument && !DocumentService.ActiveCodeFileDocument.Run)
if (!RunActiveTabPage)
{
RunActiveTabPage = true;
return Run(DocumentService.ActiveCodeFileDocument, forDebugging, startWithGoto, needFirstBreakpoint);
}
RunActiveTabPage = false;
MessageBox.Show(Form1StringResources.Get("RUN_PCU_WARNING_TEXT"), PascalABCCompiler.StringResources.Get("!WARNING"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
break;
case PascalABCCompiler.CompilerOptions.OutputType.ConsoleApplicaton:
case PascalABCCompiler.CompilerOptions.OutputType.WindowsApplication:
if (forDebugging)
{
BuildService.CompilerOptions.Debug = debug;
BuildService.CompilerOptions.ForDebugging = false;
if (startWithGoto)
{
DebuggerManager.ShowDebugTabs = true;
DebuggerManager.UpdateBreakpoints();
DebuggerManager.CurrentBreakpoint = DebuggerManager.AddBreakPoint(DocumentService.CurrentCodeFileDocument.FileName, DocumentService.CurrentCodeFileDocument.TextEditor.ActiveTextAreaControl.Caret.Line + 1, false);
DebuggerManager.AddGoToBreakPoint(DebuggerManager.CurrentBreakpoint);
}
else if (needFirstBreakpoint)
{
DebuggerManager.ShowDebugTabs = true;
DebuggerManager.UpdateBreakpoints();
if (Workbench.VisualEnvironmentCompiler.Compiler.VarBeginOffset != 0)
{
DebuggerManager.SetFirstBreakpoint(tabPage.FileName, Workbench.VisualEnvironmentCompiler.Compiler.VarBeginOffset);
DebuggerManager.AddGoToBreakPoint(tabPage.FileName, Workbench.VisualEnvironmentCompiler.Compiler.BeginOffset);
}
else
DebuggerManager.SetFirstBreakpoint(tabPage.FileName, Workbench.VisualEnvironmentCompiler.Compiler.BeginOffset);
}
else
{
DebuggerManager.UpdateBreakpoints();
DebuggerManager.ShowDebugTabs = false;
}
}
RunActiveTabPage = false;
try
{
RunTabsAdd(Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.OutputFileName, tabPage);
RunnerManager.Run(Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.OutputFileName,
Workbench.UserOptions.RedirectConsoleIO, ModeName, RunWithPause,
// Path.GetDirectoryName(Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.OutputFileName), // SSM 21.05.19 - исправил. Теперь текущим является каталог, в котором расположен исходник.
// Если компилировать программы на сетевом диске, а exe создавать локально, то работает шустро
Workbench.VisualEnvironmentCompiler.Compiler.CompilerOptions.SourceFileDirectory,
RunArgumentsTable[tabPage.FileName.ToLower()], attachdbg, fictive_attach);
}
catch (System.Exception e)
{
// SSM 22/04/19 - исправляю вылет оболочки при отсутствии exe файла
// this.RunnerManager_Exited(OutputFileName); // - это всё равно не срабатывает. Кнопки оказываются в заблокированном состоянии
Console.WriteLine(e.Message+" "+e.StackTrace);
WorkbenchServiceFactory.OperationsService.AddTextToOutputWindowSync(OutputFileName, "Произошла непредвиденная ошибка. Вероятно, на диске отсутствует .exe-файл. Повторите запуск");
//throw;
return false;
}
if (!ProjectFactory.Instance.ProjectLoaded)
DocumentService.ActiveCodeFileDocument = tabPage;
if (forDebugging)
{
DebuggerOperationsService.AddDebugPage(tabPage);
}
WorkbenchStorage.SetCurrentTabPageIfWriteToOutputWindow = Workbench.UserOptions.RedirectConsoleIO;
//if (UserOptions1.ConsoleOutput)
//AddTextToOutputWindow("Ïðîãðàììà çàïóùåíà");
return true;
}
}
RunActiveTabPage = false;
return false;
}
}
public bool Run(ICodeFileDocument tabPage)
{
return Run(tabPage, false, false, false);
}
private bool __runInThreadDebug;
private void __runInThread(object state)
{
Run(__runInThreadDebug);
}
private void runInThread(bool debug)
{
__runInThreadDebug = debug;
if (!ThreadPool.QueueUserWorkItem(new WaitCallback(__runInThread)))
Run(debug);
}
public bool Stop() // Èíòåðåñíî, çà÷åì ñäåëàëè private
{
if (RunnerManager.IsRun(Workbench.CurrentEXEFileName))
{
RunnerManager.Stop(Workbench.CurrentEXEFileName);
return true;
}
return true;
}
void RunTabsAdd(string name, ICodeFileDocument p)
{
name = Tools.FileNameToLower(name);
if (RunTabs.ContainsKey(name))
RunTabs[name] = p;
else
RunTabs.Add(name, p);
}
public void SendInputTextToProcess()
{
ReadRequests.Remove(DocumentService.CurrentCodeFileDocument);
RunnerManager.WritelnStringToProcess(Workbench.CurrentEXEFileName, Workbench.OutputWindow.InputTextBoxText);
Workbench.OutputWindow.AppendTextToOutputBox(Environment.NewLine);
WorkbenchServiceFactory.OperationsService.SendNewLineToInputTextBox();
Workbench.OutputWindow.InputPanelVisible = false;
}
public bool IsRun()
{
return RunnerManager.IsRun();
}
public bool IsRun(string FileName)
{
return RunnerManager.IsRun(FileName);
}
public void Stop(string FileName)
{
RunnerManager.Stop(FileName);
}
public bool HasRunArgument(string FileName)
{
return RunArgumentsTable.ContainsKey(FileName);
}
public void AddRunArgument(string FileName, string argument)
{
RunArgumentsTable[FileName] = argument;
}
public ICodeFileDocument GetRunTab(string FileName)
{
return RunTabs[FileName];
}
public string GetRunArgument(string FileName)
{
return RunArgumentsTable[FileName];
}
public void KillAll()
{
TerminateAllPrograms = true;
RunnerManager.KillAll();
TerminateAllPrograms = false;
}
}
}