diff --git a/External/Plugins/ConsolePanel/ConsolePanel.csproj b/External/Plugins/ConsolePanel/ConsolePanel.csproj
new file mode 100644
index 0000000000..8a24ee50d2
--- /dev/null
+++ b/External/Plugins/ConsolePanel/ConsolePanel.csproj
@@ -0,0 +1,94 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}
+ Library
+ Properties
+ ConsolePanel
+ ConsolePanel
+ v4.8
+
+
+ true
+ full
+ false
+ ..\..\..\FlashDevelop\Bin\Debug\Plugins\
+ DEBUG;TRACE
+ prompt
+ 4
+ preview
+
+
+ pdbonly
+ true
+ ..\..\..\FlashDevelop\Bin\Debug\Plugins\
+ TRACE
+ prompt
+ 4
+ AnyCPU
+ preview
+
+
+
+
+
+
+
+
+
+
+
+ UserControl
+
+
+ ConsoleControl.cs
+
+
+ UserControl
+
+
+ TabbedConsole.cs
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+ {61885f70-b4dc-4b44-852d-5d6d03f2a734}
+ PluginCore
+ False
+
+
+ {78101c01-e186-4954-b1dd-debb7905fad8}
+ ProjectManager
+ False
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
\ No newline at end of file
diff --git a/External/Plugins/ConsolePanel/Gui/TabbedConsole.Designer.cs b/External/Plugins/ConsolePanel/Gui/TabbedConsole.Designer.cs
new file mode 100644
index 0000000000..c88c91519a
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Gui/TabbedConsole.Designer.cs
@@ -0,0 +1,87 @@
+namespace ConsolePanel.Gui
+{
+ partial class TabbedConsole
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.tabConsoles = new System.Windows.Forms.TabControl();
+ this.btnNew = new System.Windows.Forms.Button();
+ this.pnlContainer = new System.Windows.Forms.Panel();
+ this.pnlContainer.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // tabConsoles
+ //
+ this.tabConsoles.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tabConsoles.Location = new System.Drawing.Point(0, 0);
+ this.tabConsoles.Name = "tabConsoles";
+ this.tabConsoles.SelectedIndex = 0;
+ this.tabConsoles.Size = new System.Drawing.Size(398, 199);
+ this.tabConsoles.TabIndex = 0;
+ this.tabConsoles.MouseClick += new System.Windows.Forms.MouseEventHandler(this.tabConsoles_MouseClick);
+ //
+ // btnNew
+ //
+ this.btnNew.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnNew.FlatAppearance.BorderSize = 0;
+ this.btnNew.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.btnNew.Location = new System.Drawing.Point(379, 3);
+ this.btnNew.Name = "btnNew";
+ this.btnNew.Size = new System.Drawing.Size(16, 16);
+ this.btnNew.TabIndex = 0;
+ this.btnNew.UseVisualStyleBackColor = false;
+ this.btnNew.Click += new System.EventHandler(this.btnNew_Click);
+ //
+ // pnlContainer
+ //
+ this.pnlContainer.Controls.Add(this.btnNew);
+ this.pnlContainer.Controls.Add(this.tabConsoles);
+ this.pnlContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.pnlContainer.Location = new System.Drawing.Point(0, 0);
+ this.pnlContainer.Name = "pnlContainer";
+ this.pnlContainer.Size = new System.Drawing.Size(398, 199);
+ this.pnlContainer.TabIndex = 1;
+ //
+ // TabbedConsole
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.pnlContainer);
+ this.Name = "TabbedConsole";
+ this.Size = new System.Drawing.Size(398, 199);
+ this.pnlContainer.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TabControl tabConsoles;
+ private System.Windows.Forms.Button btnNew;
+ private System.Windows.Forms.Panel pnlContainer;
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Gui/TabbedConsole.cs b/External/Plugins/ConsolePanel/Gui/TabbedConsole.cs
new file mode 100644
index 0000000000..315db4abab
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Gui/TabbedConsole.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ConsolePanel.Gui
+{
+ public partial class TabbedConsole : UserControl
+ {
+ readonly PluginMain main;
+
+ public ICollection Consoles => consoleTabMap.Keys;
+
+ readonly Dictionary consoleTabMap;
+ readonly Dictionary tabConsoleMap;
+
+ public TabbedConsole(PluginMain plugin)
+ {
+ InitializeComponent();
+ main = plugin;
+ consoleTabMap = new Dictionary();
+ tabConsoleMap = new Dictionary();
+ btnNew.Image = PluginCore.PluginBase.MainForm.FindImage16("33");
+ }
+
+ public void AddConsole(IConsole console)
+ {
+ var tab = new TabPage(console.ConsoleControl.Text);
+ console.ConsoleControl.Dock = DockStyle.Fill;
+ tab.Controls.Add(console.ConsoleControl);
+
+ tabConsoles.TabPages.Add(tab);
+ tabConsoles.SelectTab(tab);
+ consoleTabMap.Add(console, tabConsoles.SelectedTab);
+ tabConsoleMap.Add(tabConsoles.SelectedTab, console);
+ }
+
+ public void RemoveConsole(IConsole console)
+ {
+ if (!consoleTabMap.ContainsKey(console)) return;
+ console.Cancel();
+ var page = consoleTabMap[console];
+ tabConsoles.TabPages.Remove(page);
+ consoleTabMap.Remove(console);
+ tabConsoleMap.Remove(page);
+ }
+
+ void tabConsoles_MouseClick(object sender, MouseEventArgs e)
+ {
+ if (e.Button != MouseButtons.Middle) return;
+ for (int i = 0; i < tabConsoles.TabCount; i++)
+ {
+ if (tabConsoles.GetTabRect(i).Contains(e.Location))
+ {
+ RemoveConsole(tabConsoleMap[tabConsoles.TabPages[i]]);
+ }
+ }
+ }
+
+ void btnNew_Click(object sender, EventArgs e) => main.CreateConsolePanel();
+ }
+}
diff --git a/External/Plugins/ConsolePanel/IConsole.cs b/External/Plugins/ConsolePanel/IConsole.cs
new file mode 100644
index 0000000000..cc92356329
--- /dev/null
+++ b/External/Plugins/ConsolePanel/IConsole.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Windows.Forms;
+
+namespace ConsolePanel
+{
+ ///
+ /// Interface to implement a different way of embedding a console window
+ ///
+ public interface IConsole
+ {
+ event EventHandler Exited;
+
+ ///
+ /// The Control that is added to the FlashDevelop form
+ ///
+ Control ConsoleControl { get; }
+
+ string WorkingDirectory { set; }
+
+ void Clear();
+
+ void Cancel();
+
+ ///
+ /// Sends a string to the command line
+ ///
+ ///
+ void SendString(string str);
+ }
+}
diff --git a/External/Plugins/ConsolePanel/IConsoleProvider.cs b/External/Plugins/ConsolePanel/IConsoleProvider.cs
new file mode 100644
index 0000000000..1a8304da01
--- /dev/null
+++ b/External/Plugins/ConsolePanel/IConsoleProvider.cs
@@ -0,0 +1,8 @@
+namespace ConsolePanel
+{
+ public interface IConsoleProvider
+ {
+ IConsole GetConsole();
+ IConsole GetConsole(string workingDirectory);
+ }
+}
\ No newline at end of file
diff --git a/External/Plugins/ConsolePanel/Implementation/CmdProcess/CmdConsole.cs b/External/Plugins/ConsolePanel/Implementation/CmdProcess/CmdConsole.cs
new file mode 100644
index 0000000000..1f772c3117
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Implementation/CmdProcess/CmdConsole.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Windows.Forms;
+
+namespace ConsolePanel.Implementation.CmdProcess
+{
+ class CmdConsole : IConsole
+ {
+ readonly ConsoleControl cmd;
+
+ public CmdConsole() : this(null)
+ {
+ }
+
+ public CmdConsole(string workingDirectory)
+ {
+ cmd = new ConsoleControl(true, workingDirectory) { Text = "cmd" };
+ cmd.Exited += (sender, e) => Exited?.Invoke(sender, e);
+ }
+
+ public Control ConsoleControl => cmd;
+
+ public string WorkingDirectory
+ {
+ set => cmd.WorkingDirectory = value;
+ }
+
+ public event EventHandler Exited;
+
+ public void Clear() => cmd.SendString("cls");
+
+ public void Cancel() => cmd.Cancel();
+
+ public void SendString(string str) => cmd.SendString(str, false);
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Implementation/CmdProcess/CmdConsoleProvider.cs b/External/Plugins/ConsolePanel/Implementation/CmdProcess/CmdConsoleProvider.cs
new file mode 100644
index 0000000000..5f55d6e35b
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Implementation/CmdProcess/CmdConsoleProvider.cs
@@ -0,0 +1,8 @@
+namespace ConsolePanel.Implementation.CmdProcess
+{
+ class CmdConsoleProvider : IConsoleProvider
+ {
+ public IConsole GetConsole() => GetConsole(null);
+ public IConsole GetConsole(string workingDirectory) => new CmdConsole(workingDirectory);
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Implementation/CmdProcess/ConsoleControl.Designer.cs b/External/Plugins/ConsolePanel/Implementation/CmdProcess/ConsoleControl.Designer.cs
new file mode 100644
index 0000000000..3b832d795a
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Implementation/CmdProcess/ConsoleControl.Designer.cs
@@ -0,0 +1,48 @@
+namespace ConsolePanel.Implementation.CmdProcess
+{
+ partial class ConsoleControl
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.pnlClipping = new System.Windows.Forms.Panel();
+ this.SuspendLayout();
+ //
+ // pnlClipping
+ //
+ this.pnlClipping.Location = new System.Drawing.Point(0, 0);
+ this.pnlClipping.Name = "pnlClipping";
+ this.pnlClipping.Size = new System.Drawing.Size(128, 103);
+ this.pnlClipping.TabIndex = 0;
+ this.pnlClipping.Enter += new System.EventHandler(this.CmdPanel_Enter);
+ //
+ // ConsoleControl
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.pnlClipping);
+ this.ForeColor = System.Drawing.Color.White;
+ this.Name = "ConsoleControl";
+ this.Size = new System.Drawing.Size(246, 149);
+ this.Paint += new System.Windows.Forms.PaintEventHandler(this.ConsoleControl_Paint);
+ this.Enter += new System.EventHandler(this.CmdPanel_Enter);
+ this.Resize += new System.EventHandler(this.CmdPanel_Resize);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Panel pnlClipping;
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Implementation/CmdProcess/ConsoleControl.cs b/External/Plugins/ConsolePanel/Implementation/CmdProcess/ConsoleControl.cs
new file mode 100644
index 0000000000..90d7d2b08f
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Implementation/CmdProcess/ConsoleControl.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Windows.Forms;
+using System.Diagnostics;
+using System.Drawing;
+using System.Collections.Generic;
+using System.Windows.Automation;
+using ConsoleControl;
+
+namespace ConsolePanel.Implementation.CmdProcess
+{
+ public partial class ConsoleControl : UserControl
+ {
+ IntPtr cmdHandle;
+ AutomationElement window;
+ Size realSize;
+
+ ConsoleColor backColor = ConsoleColor.Black;
+ ConsoleColor foreColor = ConsoleColor.White;
+ readonly List commandsToDo = new List();
+ string lastWorkingDir;
+
+ public event EventHandler Exited;
+
+ public string WorkingDirectory
+ {
+ set
+ {
+ lastWorkingDir = value;
+ if (Process == null) Create();
+ else
+ {
+ SendString("cd \"" + value + "\"");
+ SendString("cls");
+ }
+ }
+ }
+
+ public ConsoleColor ConsoleBackColor
+ {
+ get => backColor;
+ set
+ {
+ if (value == backColor) return;
+ backColor = value;
+ var trimmedFore = foreColor.ToString("X").TrimStart('0');
+ if (trimmedFore.Length == 0) trimmedFore = "0";
+ var trimmedBack = backColor.ToString("X").TrimStart('0');
+ if (trimmedBack.Length == 0) trimmedBack = "0";
+ SendString("color " + trimmedBack + trimmedFore);
+ SendString("cls");
+ }
+ }
+
+ public ConsoleColor ConsoleForeColor
+ {
+ get => foreColor;
+ set
+ {
+ if (value == foreColor) return;
+ foreColor = value;
+ var trimmedFore = foreColor.ToString("X").TrimStart('0');
+ if (trimmedFore.Length == 0) trimmedFore = "0";
+ var trimmedBack = backColor.ToString("X").TrimStart('0');
+ if (trimmedBack.Length == 0) trimmedBack = "0";
+ SendString("color " + trimmedBack + trimmedFore);
+ SendString("cls");
+ }
+ }
+
+ ///
+ /// Returns the actual size of the console window's client area
+ /// (the width of a console window only changes by specific values)
+ ///
+ public Size ActualSize => realSize;
+
+ public Process Process { get; set; }
+
+ ///
+ /// Creates a new ConsoleControl
+ ///
+ ///
+ ///
+ public ConsoleControl(bool init = true, string workingDirectory = null)
+ {
+ InitializeComponent();
+ SetStyle(ControlStyles.Selectable, true);
+ lastWorkingDir = workingDirectory;
+ if (init) Create();
+ }
+
+ ///
+ /// Cancel the currently running process
+ ///
+ public void Cancel()
+ {
+ if (Process is null) return;
+ if (!Process.HasExited)
+ {
+ SendString("^(c)", false);
+ try
+ {
+ Process.Kill();
+ }
+ catch { }
+
+ }
+ Process = null;
+ }
+
+ ///
+ /// Creates the console window if it was closed / not created yet
+ ///
+ public void Create()
+ {
+ if (Process is not null && !Process.HasExited) return;
+ try
+ {
+ Process = new Process
+ {
+ StartInfo =
+ {
+ FileName = "cmd",
+ UseShellExecute = false,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ },
+ EnableRaisingEvents = true
+ };
+ if (lastWorkingDir is not null) Process.StartInfo.WorkingDirectory = lastWorkingDir;
+ Process.Exited += Process_Exited;
+ Process.Start();
+
+ //Wait for cmd window
+ while (Process.MainWindowHandle == IntPtr.Zero)
+ {
+ Process.Refresh();
+ }
+ cmdHandle = Process.MainWindowHandle;
+ window = AutomationElement.FromHandle(cmdHandle);
+ WinApi.SetParent(cmdHandle, pnlClipping.Handle);
+ SendString(" ",false);
+ ResizeConsole();
+ }
+ catch
+ {
+ }
+
+ GotFocus += (sender, args) =>
+ {
+ pnlClipping.Focus();
+ };
+ }
+
+ ///
+ /// Sends a String to the embedded console window
+ ///
+ /// The string to send
+ /// if true, a "\r" is appended to the given string
+ public void SendString(string str, bool execute = true)
+ {
+ if (execute) str += "\r";
+ ProcessCommandCache();
+ try
+ {
+ RunCommandWithoutCache(str);
+ }
+ catch
+ {
+ commandsToDo.Add(str);
+ }
+ }
+
+ void ProcessCommandCache()
+ {
+ while (commandsToDo.Count > 0)
+ {
+ var toDo = commandsToDo[0];
+ try
+ {
+ RunCommandWithoutCache(toDo);
+ commandsToDo.RemoveAt(0);
+ }
+ catch
+ {
+ break;
+ }
+ }
+ }
+
+ void RunCommandWithoutCache(string cmd)
+ {
+ window.SetFocus();
+ //TODO: prevent user from clicking around while doing this
+ SendKeys.SendWait(cmd);
+ Focus();
+ }
+
+ void ResizeConsole()
+ {
+ WinApi.ShowWindow(cmdHandle, WinApi.SW_SHOWMAXIMIZED);
+ WinApi.ResizeClientRectTo(cmdHandle, new Rectangle(Point.Empty, Size));
+ SetRealConsoleSize();
+ var tooWide = realSize.Width > Width;
+ var tooHigh = realSize.Height > Height;
+ if (tooWide || tooHigh)
+ {
+ int newWidth = realSize.Width;
+ int newHeight = realSize.Height;
+ if (tooWide) newWidth -= 8;
+ if (tooHigh) newHeight -= 12;
+ WinApi.ResizeClientRectTo(cmdHandle, new Rectangle(0, 0, newWidth, newHeight));
+ SetRealConsoleSize();
+ }
+ pnlClipping.Size = realSize;
+ }
+
+ void SetRealConsoleSize()
+ {
+ WinApi.GetWindowInfo(cmdHandle, out var info);
+ var leftBorder = info.rcClient.Left - info.rcWindow.Left;
+ var topBorder = info.rcClient.Top - info.rcWindow.Top;
+ var rightBorder = (int)info.cxWindowBorders;
+ var bottomBorder = (int)info.cyWindowBorders;
+ var width = info.rcWindow.Right - info.rcWindow.Left;
+ var height = info.rcWindow.Bottom - info.rcWindow.Top;
+
+ realSize.Width = width - leftBorder - rightBorder;
+ realSize.Height = height - topBorder - bottomBorder;
+ }
+
+ void CmdPanel_Resize(object sender, EventArgs e) => ResizeConsole();
+
+ void Process_Exited(object sender, EventArgs e)
+ {
+ cmdHandle = IntPtr.Zero;
+ Exited?.Invoke(sender, e);
+ }
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing) components?.Dispose();
+ Cancel();
+ base.Dispose(disposing);
+ }
+
+ void CmdPanel_Enter(object sender, EventArgs e)
+ {
+ try
+ {
+ window.SetFocus();
+ }
+ catch { }
+ ProcessCommandCache();
+ }
+
+ void ConsoleControl_Paint(object sender, PaintEventArgs e) => ResizeConsole();
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Managers/ConsoleManager.cs b/External/Plugins/ConsolePanel/Managers/ConsoleManager.cs
new file mode 100644
index 0000000000..6217736a67
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Managers/ConsoleManager.cs
@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+
+namespace ConsolePanel.Managers
+{
+ public class ConsoleManager
+ {
+ static PluginMain main;
+
+ static readonly List CommandList = new List();
+ static IConsoleProvider cachedProvider;
+
+ ///
+ /// Creates a new console panel and sends the given string to it.
+ ///
+ /// the command to send
+ public static void CreateConsole(string command)
+ {
+ if (main != null)
+ {
+ ProcessCommandList();
+ main.CreateConsolePanel().SendString(command);
+ }
+ else
+ {
+ CommandList.Add(command);
+ }
+ }
+
+ public static void SetConsoleProvider(IConsoleProvider provider)
+ {
+ if (main != null)
+ {
+ main.ConsoleProvider = provider;
+ }
+ else
+ {
+ cachedProvider = provider;
+ }
+ }
+
+ public static void Init(PluginMain plugin)
+ {
+ main = plugin;
+ ProcessCachedProvider();
+ ProcessCommandList();
+ }
+
+ static void ProcessCommandList()
+ {
+ while (CommandList.Count > 0)
+ {
+ main.CreateConsolePanel().SendString(CommandList[0]);
+ CommandList.RemoveAt(0);
+ }
+ }
+
+ static void ProcessCachedProvider()
+ {
+ if (cachedProvider is null) return;
+ main.ConsoleProvider = cachedProvider;
+ }
+ }
+}
diff --git a/External/Plugins/ConsolePanel/PluginMain.cs b/External/Plugins/ConsolePanel/PluginMain.cs
new file mode 100644
index 0000000000..0add6c4a51
--- /dev/null
+++ b/External/Plugins/ConsolePanel/PluginMain.cs
@@ -0,0 +1,142 @@
+using System;
+using PluginCore;
+using System.ComponentModel;
+using PluginCore.Managers;
+using PluginCore.Utilities;
+using System.IO;
+using PluginCore.Helpers;
+using System.Windows.Forms;
+using WeifenLuo.WinFormsUI.Docking;
+using System.Drawing;
+
+namespace ConsolePanel
+{
+ public class PluginMain : IPlugin
+ {
+ string settingFilename;
+ Settings settingObject;
+ DockContent pluginPanel;
+ Gui.TabbedConsole tabView;
+ Image image;
+
+ #region Required Properties
+
+ public int Api => 1;
+
+ public string Author { get; } = "Christoph Otter";
+
+ public string Description { get; } = "Plugin that adds an embedded console window to FlashDevelop.";
+
+ public string Guid { get; } = "AEDE556E-54C3-4EFB-8EF3-54E85DC37D1E";
+
+ public string Help { get; } = "www.flashdevelop.org/community/";
+
+ public string Name { get; } = nameof(ConsolePanel);
+
+ [Browsable(false)]
+ public object Settings => settingObject;
+
+ #endregion
+
+ public IConsoleProvider ConsoleProvider { get; set; }
+
+ public void Initialize()
+ {
+ InitBasics();
+ LoadSettings();
+ CreatePluginPanel();
+ CreateMenuItem();
+ CreateDefaultConsoleProvider();
+ AddEventHandlers();
+ }
+
+ public void HandleEvent(object sender, NotifyEvent e, HandlingPriority priority)
+ {
+ switch (e.Type)
+ {
+ case EventType.Command:
+ var data = (DataEvent)e;
+ if (data.Action == "ProjectManager.Project")
+ {
+ foreach (var panel in tabView.Consoles)
+ {
+ panel.WorkingDirectory = PluginBase.CurrentProject.GetAbsolutePath(string.Empty);
+ }
+ }
+ break;
+ case EventType.UIStarted:
+ CreateConsolePanel();
+ break;
+ }
+ }
+
+ public void Dispose() => SaveSettings();
+
+ void InitBasics()
+ {
+ var path = Path.Combine(PathHelper.DataDir, Name);
+ if (!Directory.Exists(path)) Directory.CreateDirectory(path);
+ settingFilename = Path.Combine(path, "Settings.fdb");
+ image = PluginBase.MainForm.FindImage("57");
+ Managers.ConsoleManager.Init(this);
+ }
+
+ void LoadSettings()
+ {
+ settingObject = new Settings();
+ if (!File.Exists(settingFilename)) SaveSettings();
+ else settingObject = ObjectSerializer.Deserialize(settingFilename, settingObject);
+ }
+
+ void AddEventHandlers()
+ {
+ EventManager.AddEventHandler(this, EventType.Command);
+ EventManager.AddEventHandler(this, EventType.UIStarted, HandlingPriority.Low);
+ }
+
+ void SaveSettings() => ObjectSerializer.Serialize(settingFilename, settingObject);
+
+ void CreatePluginPanel()
+ {
+ tabView = new Gui.TabbedConsole(this);
+ pluginPanel = PluginBase.MainForm.CreateDockablePanel(tabView, Guid, image, DockState.DockBottom);
+ pluginPanel.Text = "Console";
+ }
+
+ void CreateMenuItem()
+ {
+ var label = "Console Panel";
+ var viewMenu = (ToolStripMenuItem)PluginBase.MainForm.FindMenuItem("ViewMenu");
+ var cmdItem = new ToolStripMenuItem(label, image, OpenPanel);
+ viewMenu.DropDownItems.Add(cmdItem);
+ }
+
+ void OpenPanel(object sender, EventArgs e)
+ {
+ if (tabView.Consoles.Count == 0) CreateConsolePanel();
+ pluginPanel.Show();
+ }
+
+ void CreateDefaultConsoleProvider() => ConsoleProvider = new Implementation.CmdProcess.CmdConsoleProvider();
+
+ public IConsole CreateConsolePanel()
+ {
+ var workingDirectory = PluginBase.CurrentProject?.GetAbsolutePath(string.Empty);
+ var console = ConsoleProvider.GetConsole(workingDirectory);
+ console.Exited += (sender, args) =>
+ {
+ if (tabView.InvokeRequired) tabView.Invoke((MethodInvoker) RemoveConsole);
+ else RemoveConsole();
+ };
+ tabView.AddConsole(console);
+ return console;
+ // Utils
+ void RemoveConsole()
+ {
+ if (PluginBase.MainForm.ClosingEntirely) return;
+ tabView.RemoveConsole(console);
+ if (tabView.Consoles.Count == 0) pluginPanel.Hide();
+ }
+ }
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Properties/AssemblyInfo.cs b/External/Plugins/ConsolePanel/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..5a3fb3d221
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("EmbeddedCmd")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("EmbeddedCmd")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("AEDE556E-54C3-4EFB-8EF3-54E85DC37D1E")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/External/Plugins/ConsolePanel/Properties/Resources.Designer.cs b/External/Plugins/ConsolePanel/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000..e0c93530ef
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ConsolePanel.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConsolePanel.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/External/Plugins/ConsolePanel/Properties/Resources.resx b/External/Plugins/ConsolePanel/Properties/Resources.resx
new file mode 100644
index 0000000000..4fdb1b6aff
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Properties/Resources.resx
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/External/Plugins/ConsolePanel/Settings.cs b/External/Plugins/ConsolePanel/Settings.cs
new file mode 100644
index 0000000000..f7fc36e2d2
--- /dev/null
+++ b/External/Plugins/ConsolePanel/Settings.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace ConsolePanel
+{
+ [Serializable]
+ class Settings
+ {
+ }
+}
\ No newline at end of file
diff --git a/External/Plugins/ConsolePanel/WinApi.cs b/External/Plugins/ConsolePanel/WinApi.cs
new file mode 100644
index 0000000000..ed179804c5
--- /dev/null
+++ b/External/Plugins/ConsolePanel/WinApi.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace ConsoleControl
+{
+ [StructLayout(LayoutKind.Sequential)]
+ struct RECT
+ {
+ public int Left;
+ public int Top;
+ public int Right;
+ public int Bottom;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct WINDOWINFO
+ {
+ public uint cbSize;
+ public RECT rcWindow;
+ public RECT rcClient;
+ public uint dwStyle;
+ public uint dwExStyle;
+ public uint dwWindowStatus;
+ public uint cxWindowBorders;
+ public uint cyWindowBorders;
+ public ushort atomWindowType;
+ public ushort wCreatorVersion;
+
+ public WINDOWINFO(Boolean? filler) : this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
+ {
+ cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
+ }
+ }
+
+ class WinApi
+ {
+ public const int GWL_STYLE = -16;
+ public const int SW_SHOWMAXIMIZED = 3;
+
+ [DllImport("user32.dll")]
+ public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32.dll")]
+ public static extern bool GetWindowInfo(IntPtr hwnd, out WINDOWINFO wi);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
+
+ [DllImport("user32.dll")]
+ public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+
+ [DllImport("user32.dll")]
+ public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("user32.dll")]
+ public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
+
+ [DllImport("user32.dll")]
+ public static extern bool AdjustWindowRect(ref RECT lpRect, int dwStyle, bool bMenu);
+
+ public static Rectangle GetClientRect(IntPtr hWnd)
+ {
+ GetClientRect(hWnd, out var rc);
+ return new Rectangle(rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top);
+ }
+
+ public static void ResizeClientRectTo(IntPtr hWnd, Rectangle desired)
+ {
+ RECT size;
+ size.Top = desired.Top;
+ size.Left = desired.Left;
+ size.Bottom = desired.Bottom;
+ size.Right = desired.Right;
+
+ var style = GetWindowLong(hWnd, GWL_STYLE);
+ AdjustWindowRect(ref size, style, false);
+ MoveWindow(hWnd, size.Left, size.Top, size.Right - size.Left, size.Bottom - size.Top, true);
+ }
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr SetFocus(IntPtr hWnd);
+ }
+}
diff --git a/External/Plugins/CssCompletion/Helpers/CssMinify.cs b/External/Plugins/CssCompletion/Helpers/CssMinify.cs
index 8c76021264..bc5d055e05 100644
--- a/External/Plugins/CssCompletion/Helpers/CssMinify.cs
+++ b/External/Plugins/CssCompletion/Helpers/CssMinify.cs
@@ -111,7 +111,7 @@ public static string Minify(string theCss)
/// The current CSS parsing state.
///
/// The future CSS parsing state.
- private static CssState GetState(string theCss, ref int thePos, CssState theCurState)
+ static CssState GetState(string theCss, ref int thePos, CssState theCurState)
{
int aLen = theCss.Length;
int i = thePos;
@@ -181,19 +181,18 @@ private static CssState GetState(string theCss, ref int thePos, CssState theCurS
thePos = i;
char c = theCss[i];
- if (IsTokenChar(c))
- return CssState.Token;
-
- if (c == '\"')
- return CssState.StringD;
- if (c == '\'')
- return CssState.StringS;
- return CssState.Punctuation;
+ if (IsTokenChar(c)) return CssState.Token;
+ return c switch
+ {
+ '\"' => CssState.StringD,
+ '\'' => CssState.StringS,
+ _ => CssState.Punctuation
+ };
}
- private static bool IsWhitespaceChar(char p) => p == '\t' || p == '\r' || p == '\n' || p == ' ';
+ static bool IsWhitespaceChar(char p) => p == '\t' || p == '\r' || p == '\n' || p == ' ';
- private static bool IsTokenChar(char theChar)
+ static bool IsTokenChar(char theChar)
{
if (theChar >= 'a' && theChar <= 'z') return true;
if (theChar >= '0' && theChar <= '9') return true;
diff --git a/FlashDevelop.sln b/FlashDevelop.sln
index c06495d1d4..2b7c577cce 100644
--- a/FlashDevelop.sln
+++ b/FlashDevelop.sln
@@ -74,6 +74,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicCompletion", "External
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CssCompletion", "External\Plugins\CssCompletion\CssCompletion.csproj", "{DCA7613E-7BC3-4610-A95E-73C0D64C5B98}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsolePanel", "External\Plugins\ConsolePanel\ConsolePanel.csproj", "{2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FDBuild", "External\Tools\FDBuild\FDBuild.csproj", "{FF680DE0-9CB7-45F4-BAFA-6EFFAAFD9C09}"
ProjectSection(ProjectDependencies) = postProject
{61885F70-B4DC-4B44-852D-5D6D03F2A734} = {61885F70-B4DC-4B44-852D-5D6D03F2A734}
@@ -603,6 +605,22 @@ Global
{DCA7613E-7BC3-4610-A95E-73C0D64C5B98}.Release+Tests|Any CPU.Build.0 = Release|Any CPU
{DCA7613E-7BC3-4610-A95E-73C0D64C5B98}.Release+Tests|x86.ActiveCfg = Release|Any CPU
{DCA7613E-7BC3-4610-A95E-73C0D64C5B98}.Release+Tests|x86.Build.0 = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug|x86.Build.0 = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug+Tests|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug+Tests|Any CPU.Build.0 = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug+Tests|x86.ActiveCfg = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Debug+Tests|x86.Build.0 = Debug|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release|x86.ActiveCfg = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release|x86.Build.0 = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release+Tests|Any CPU.ActiveCfg = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release+Tests|Any CPU.Build.0 = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release+Tests|x86.ActiveCfg = Release|Any CPU
+ {2A36ADDC-B30E-472B-BDD6-0E6E35649FAA}.Release+Tests|x86.Build.0 = Release|Any CPU
{FF680DE0-9CB7-45F4-BAFA-6EFFAAFD9C09}.Debug|Any CPU.ActiveCfg = Debug|x86
{FF680DE0-9CB7-45F4-BAFA-6EFFAAFD9C09}.Debug|Any CPU.Build.0 = Debug|x86
{FF680DE0-9CB7-45F4-BAFA-6EFFAAFD9C09}.Debug|x86.ActiveCfg = Debug|x86