]> O.S.I.I.S - jp/crowedit.git/commitdiff
wip
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 12 Jul 2021 00:37:00 +0000 (02:37 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 12 Jul 2021 00:37:00 +0000 (02:37 +0200)
47 files changed:
CrowEdit.csproj
CrowEdit.style
CrowEditBase/src/CrowEditBase.cs
CrowEditBase/src/Debug/BreakPoint.cs [new file with mode: 0644]
CrowEditBase/src/Debug/Debugger.cs [new file with mode: 0644]
CrowEditBase/src/Debug/DebuggerObject.cs [new file with mode: 0644]
CrowEditBase/src/Debug/StackFrame.cs [new file with mode: 0644]
CrowEditBase/src/Debug/ThreadInfo.cs [new file with mode: 0644]
CrowEditBase/src/Debug/Watch.cs [new file with mode: 0644]
CrowEditBase/src/Editor.cs
CrowEditBase/src/IFileNode.cs [new file with mode: 0644]
CrowEditBase/src/LogViewerWidget.cs [new file with mode: 0644]
CrowEditBase/src/Plugin.cs
CrowEditBase/src/PluginsLoadContext.cs
CrowEditBase/src/Project.cs
CrowEditBase/src/SourceEditor.cs
CrowEditBase/ui/IDE.style
plugins/CECrowDebugLog/CECrowDebugLog.csproj
plugins/CECrowDebugLog/src/CrowService.cs
plugins/CENetcoreDbgPlugin/CENetcoreDbgPlugin.csproj [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/BreakPoint.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/CLRAddress.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/MIObjects.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/NetcoreDbgService.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/NetcoredbgDebugger.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/StackFrame.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/ThreadInfo.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/src/Watch.cs [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/ui/winConfiguration.crow [new file with mode: 0644]
plugins/CENetcoreDbgPlugin/ui/winSolution.crow [new file with mode: 0644]
plugins/CERoslynPlugin/CERoslynPlugin.csproj
plugins/CERoslynPlugin/src/CELogger.cs [new file with mode: 0644]
plugins/CERoslynPlugin/src/ConsoleLogger.cs
plugins/CERoslynPlugin/src/MSBuildProject.cs
plugins/CERoslynPlugin/src/ProjectTree/ProjectItemNodes.cs
plugins/CERoslynPlugin/src/RoslynService.cs
plugins/CERoslynPlugin/src/SolutionProject.cs
plugins/CERoslynPlugin/ui/winConfiguration.crow
src/CrowEdit.cs
src/DirectoryNode.cs [deleted file]
src/FileNode.cs [deleted file]
src/TreeNode.cs [deleted file]
ui/MenuItem.itmp
ui/windows/winEditor.crow
ui/windows/winLogs.crow [new file with mode: 0644]
ui/windows/winPlugins.crow
ui/windows/winProjects.crow

index ab850dab540cd640b7697272ca3feb535e5c1242..06689f952c54cb50c5acabf62ef0debfb65a23e9 100644 (file)
@@ -1,9 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
-               <TargetFramework>netcoreapp3.1</TargetFramework>
+               <TargetFramework>netcoreapp5</TargetFramework>
                <OutputType>WinExe</OutputType>
                <EnableDefaultItems>false</EnableDefaultItems>
-
        </PropertyGroup>
 
        <ItemGroup>
                <ProjectReference Include="CrowEditBase\CrowEditBase.csproj" />
                <ProjectReference Include="plugins\CECrowDebugLog\CECrowDebugLog.csproj" >
                        <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
-                       <PrivateAssets>all</PrivateAssets>
                </ProjectReference>
                <ProjectReference Include="plugins\CEXmlPlugin\CEXmlPlugin.csproj" >
                        <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
                </ProjectReference>
                <ProjectReference Include="plugins\CERoslynPlugin\CERoslynPlugin.csproj" >
                        <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
-                       <PrivateAssets>all</PrivateAssets>
+               </ProjectReference>
+               <ProjectReference Include="plugins\CENetcoreDbgPlugin\CENetcoreDbgPlugin.csproj" >
+                       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
                </ProjectReference>
                <ProjectReference Include="/mnt/devel/CrowIDE/Crow/Crow/Crow.csproj" />
 
index 50f7c1ff561da4c17bd52631437e698008e57b0c..ad8f71a9f840a0274a92a517fe1e1c8a69e507d7 100644 (file)
@@ -1,13 +1,27 @@
 SmallUIFont = "sans, 10";
+SmallFont = "consolas, 10";
 InactiveTabBackground = "DarkGrey";
 SelectedTabBackground = "Onyx";
 InactiveTabForeground = "Grey";
 SelectedTabForeground = "White";
 MenuIconSize = "14";
 
+ControlHighlight = "RoyalBlue";
+
+Splitter {
+       Thickness="1";
+       Background="Transparent";
+       Hover="{Background=White}";
+       Unhover="{Background=Transparent}";
+}
+DockStack {
+       Margin="0";
+       Spacing="0";
+}
 DockWindow {
        Template = "#CrowEdit.ui.DockWindow.template";
        Background = "DarkGrey";
+       Margin="0";
 }
 DockingTabView {
        Template = "#CrowEdit.ui.DockingTabView.template";
@@ -31,10 +45,3 @@ suggestionsListBox {
        UseLoadingThread = "false";
 }
 
-Editor {
-       Background="White";
-       Foreground="Black";
-       Text="";
-       Multiline="true";
-}
-
index f65f7867d37e7f6dcc84567977b61dbd800aeb99..c2329889193db2f84af3298ed6eadeba77d9faee 100644 (file)
@@ -17,6 +17,17 @@ namespace CrowEditBase
                        string defaultClass;
                }
                protected Dictionary<string, DocumentClientClassList> FileAssociations = new Dictionary<string, DocumentClientClassList> ();
+               ObservableList<LogEntry> logs = new ObservableList<LogEntry>();
+               public ObservableList<LogEntry> MainLog => logs;
+
+               public void Log(LogType type, string message) {
+                       lock (logs)
+                               logs.Add (new LogEntry(type, message));
+               }
+               public void ResetLog () {
+                       lock (logs)
+                               logs.Clear ();
+               }
 
                public void AddFileAssociation (string extension, Type clientClass) {
                        if (!FileAssociations.ContainsKey (extension))
diff --git a/CrowEditBase/src/Debug/BreakPoint.cs b/CrowEditBase/src/Debug/BreakPoint.cs
new file mode 100644 (file)
index 0000000..09a4df2
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System.Diagnostics;
+
+namespace CrowEditBase
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public class BreakPoint : CrowEditComponent
+       {
+               int index = -1;
+               public string Function;         
+               string fileFullPath;
+               int line;
+               bool isEnabled;
+
+               string type;
+               string disp;
+               string warning;
+               
+               public int Index {
+                       get => index;
+                       set {
+                               if (index == value)
+                                       return;
+                               index = value;
+                               NotifyValueChanged(index);
+                       }
+               }
+               public int Line {
+                       get => line;
+                       set {
+                               if (line == value)
+                                       return;
+                               line = value;
+                               NotifyValueChanged (line);
+                       }
+               }
+               public bool IsEnabled {
+                       get => isEnabled;
+                       set {
+                               if (isEnabled == value)
+                                       return;
+                               isEnabled = value;
+                               NotifyValueChanged (isEnabled);
+                       }
+               }
+               public string Type {
+                       get => type;
+                       set {
+                               if (type == value)
+                                       return;
+                               type = value;
+                               NotifyValueChanged (type);
+                       }
+               }
+               public string Disp {
+                       get => disp;
+                       set {
+                               if (disp == value)
+                                       return;
+                               disp = value;
+                               NotifyValueChanged (disp);
+                       }
+               }
+               public string Warning {
+                       get => warning;
+                       set {
+                               if (warning == value)
+                                       return;
+                               warning = value;
+                               NotifyValueChanged (warning);
+                       }
+               }               
+               public string FileFullPath {
+                       get => fileFullPath;
+                       set {
+                               if (fileFullPath == value)
+                                       return;
+                               fileFullPath = value;
+                               NotifyValueChanged (fileFullPath);
+                       }
+               }
+
+               protected BreakPoint(string fileFullPath, int line, bool isEnabled = true)
+               {
+                       FileFullPath = fileFullPath;
+                       Line = line;
+                       IsEnabled = isEnabled;
+               }
+
+               public void UpdateLocation (StackFrame frame) {
+                       //FileName = frame.File;
+                       FileFullPath = frame.FileFullPath;
+                       Function = frame.Function;
+                       Line = frame.Line - 1;
+               }
+               public override string ToString() => $"{Index}:{Type} {FileFullPath}:{Line} enabled:{IsEnabled}";
+               private string GetDebuggerDisplay() => ToString();
+       }
+}
diff --git a/CrowEditBase/src/Debug/Debugger.cs b/CrowEditBase/src/Debug/Debugger.cs
new file mode 100644 (file)
index 0000000..a6eadc8
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Runtime.CompilerServices;
+using Crow;
+
+namespace CrowEditBase
+{
+       public abstract class Debugger : CrowEditComponent
+       {
+               public enum Status
+               {
+                       /// <summary>debugger process created</summary>
+                       Init,
+                       /// <summary>request loading sent</summary>
+                       Starting,
+                       /// <summary>executable loaded, breakpoints requested</summary>
+                       Ready,
+                       /// <summary>running state received</summary>
+                       Running,
+                       /// <summary>stopped event received</summary>
+                       Stopped,
+               }
+
+               protected Project project;
+               public Command CMDDebugStart, CMDDebugPause, CMDDebugStop, CMDDebugStepIn, CMDDebugStepOver, CMDDebugStepOut;
+               public virtual CommandGroup Commands => new CommandGroup (
+                       CMDDebugStart, CMDDebugPause, CMDDebugStop, CMDDebugStepIn, CMDDebugStepOver, CMDDebugStepOut);
+               protected virtual void initCommands () {
+                       CMDDebugStart = new Command ("Start", Start, "#Icons.debug-play.svg");
+                       CMDDebugPause = new Command ("Pause", Pause, "#Icons.debug-pause.svg", false);
+                       CMDDebugStop = new Command ("Stop", Stop, "#Icons.debug-stop.svg", false);
+                       CMDDebugStepIn = new Command ("Step in", StepIn, "#Icons.debug-step-into.svg", false);
+                       CMDDebugStepOut = new Command ("Step out", StepOut, "#Icons.debug-step-out.svg", false);
+                       CMDDebugStepOver = new Command ("Step over", StepOver, "#Icons.debug-step-over.svg", false);
+               }
+
+
+               Status currentState = Status.Init;
+               bool breakOnStartup = false;
+
+               public Status CurrentState
+               {
+                       get => currentState;
+                       set
+                       {
+                               if (currentState == value)
+                                       return;
+                               currentState = value;
+
+                               CMDDebugStepIn.CanExecute = CMDDebugStepOut.CanExecute = CMDDebugStepOver.CanExecute =
+                                       (CurrentState == Status.Stopped);
+                               CMDDebugStart.CanExecute = (CurrentState == Status.Ready || CurrentState == Status.Stopped);
+                               CMDDebugPause.CanExecute = CMDDebugStop.CanExecute = (CurrentState == Status.Running);
+                       }
+               }
+               StackFrame executingFile;
+               int executingLine = -1;
+
+               public ObservableList<string> OutputLog = new ObservableList<string>();
+               public ObservableList<string> ErrorLog = new ObservableList<string>();
+               public ObservableList<string> DebuggerLog = new ObservableList<string>();
+
+               public ObservableList<StackFrame> Frames = new ObservableList<StackFrame>();
+               public ObservableList<ThreadInfo> Threads = new ObservableList<ThreadInfo>();
+               public ObservableList<Watch> Watches = new ObservableList<Watch>();
+               public ObservableList<BreakPoint> BreakPoints = new ObservableList<BreakPoint>();
+
+               ThreadInfo currentThread;
+               StackFrame currentFrame;
+               BreakPoint currentBreakPoint;
+
+               public ThreadInfo CurrentThread
+               {
+                       get => currentThread;
+                       set
+                       {
+                               if (currentThread == value)
+                                       return;
+                               currentThread = value;
+                               NotifyValueChanged(currentThread);
+                       }
+               }
+               public StackFrame CurrentFrame
+               {
+                       get => currentFrame;
+                       set
+                       {
+                               if (currentFrame == value)
+                                       return;
+                               currentFrame = value;
+                               NotifyValueChanged(currentFrame);
+                               onCurrentFrameChanged ();
+                       }
+               }
+               protected abstract void onCurrentFrameChanged ();
+               protected abstract void onCurrentThreadChanged ();
+               public BreakPoint CurrentBreakPoint
+               {
+                       get => currentBreakPoint;
+                       set
+                       {
+                               if (currentBreakPoint == value)
+                                       return;
+                               currentBreakPoint = value;
+                               NotifyValueChanged(currentBreakPoint);
+                               if (currentBreakPoint == null)
+                                       return;
+                               //tryGoTo(currentFrame);                                
+                       }
+               }
+
+               public bool BreakOnStartup
+               {
+                       get => breakOnStartup;
+                       set
+                       {
+                               if (BreakOnStartup == value)
+                                       return;
+                               breakOnStartup = value;
+                               NotifyValueChanged(breakOnStartup);
+                       }
+               }
+               public virtual Project Project
+               {
+                       get => project;
+                       set
+                       {
+                               if (project == value)
+                                       return;
+                               project = value;
+                               NotifyValueChanged(Project);
+                       }
+               }
+
+               public abstract void Start();
+               public abstract void Pause();
+               public abstract void Continue();
+               public abstract void Stop();
+
+               public abstract void StepIn();
+               public abstract void StepOver();
+               public abstract void StepOut();
+
+               public abstract void InsertBreakPoint(BreakPoint bp);
+               public abstract void DeleteBreakPoint(BreakPoint bp);
+
+               protected void ResetCurrentExecutingLocation() {
+
+               }
+
+
+       }
+}
diff --git a/CrowEditBase/src/Debug/DebuggerObject.cs b/CrowEditBase/src/Debug/DebuggerObject.cs
new file mode 100644 (file)
index 0000000..ccacdb7
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Runtime.CompilerServices;
+using Crow;
+
+namespace CrowEditBase
+{
+       public class DebuggerObject : IValueChange {
+               #region IValueChange implementation
+               public event EventHandler<ValueChangeEventArgs> ValueChanged;
+               public void NotifyValueChanged(string MemberName, object _value)                                
+                       => ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value));
+               
+               public void NotifyValueChanged(object _value, [CallerMemberName] string caller = null)
+                       => NotifyValueChanged(caller, _value);
+               #endregion              
+       }       
+}
\ No newline at end of file
diff --git a/CrowEditBase/src/Debug/StackFrame.cs b/CrowEditBase/src/Debug/StackFrame.cs
new file mode 100644 (file)
index 0000000..4a10d17
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System.Diagnostics;
+
+namespace CrowEditBase
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public abstract class StackFrame
+       {
+               public int Level;               
+               public string FileFullPath;
+               public int Line;
+               public int Column;
+               public int LineEnd;
+               public int ColumnEnd;
+               public string Function;
+               public string Address;
+
+               public bool IsDefined => !string.IsNullOrEmpty(FileFullPath);
+
+               public override string ToString() => $"{Level}:{FileFullPath}({Line},{Column} {Function})";
+               string GetDebuggerDisplay() => ToString();
+       }                       
+}
diff --git a/CrowEditBase/src/Debug/ThreadInfo.cs b/CrowEditBase/src/Debug/ThreadInfo.cs
new file mode 100644 (file)
index 0000000..01b1d18
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System.Diagnostics;
+
+namespace CrowEditBase
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public class ThreadInfo
+       {
+               public int Id;
+               public string Name;
+               public bool IsStopped;
+               public bool IsRunning => !IsStopped;
+
+               public override string ToString() => $"{Id}:{Name} Running:{IsRunning})";
+               string GetDebuggerDisplay() => ToString();
+       }
+}
diff --git a/CrowEditBase/src/Debug/Watch.cs b/CrowEditBase/src/Debug/Watch.cs
new file mode 100644 (file)
index 0000000..cf33260
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Diagnostics;
+using Crow;
+
+namespace CrowEditBase
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public abstract class Watch : CrowEditComponent {
+
+               Debugger dbg;
+               bool isExpanded;
+               string name;
+               string expression;
+               string value;
+               bool isEditable;
+               int numChild;
+               string type;
+               int threadId;
+
+               ObservableList<Watch> children = new ObservableList<Watch>();
+
+               public CommandGroup Commands => new CommandGroup (
+                       new Command ("Update Value", () => UpdateValue()),
+                       new Command ("Delete", () => Delete())
+               );
+
+               public bool HasChildren => NumChild > 0;
+
+               public bool IsExpanded {
+                       get => isExpanded;
+                       set {
+                               if (isExpanded == value)
+                                       return;
+                               isExpanded = value;
+                               NotifyValueChanged(isExpanded);
+
+                               if (isExpanded)
+                                       onExpand();
+                       }
+               }
+               protected abstract void onExpand();
+
+               public ObservableList<Watch> Children {
+                       get => children;
+                       set {
+                               if (children == value)
+                                       return;
+                               children = value;
+                               NotifyValueChanged (children);                          
+                       }
+               }
+               public string Name {
+                       get => name;
+                       set {
+                               if (name == value)
+                                       return;
+                               name = value;
+                               NotifyValueChanged(name);
+                       }
+               }
+               public string Expression {
+                       get => expression;
+                       set {
+                               if (expression == value)
+                                       return;
+                               expression = value;
+                               NotifyValueChanged(expression);
+                       }
+               }
+               public string Value {
+                       get => value;
+                       set {
+                               if (this.value == value)
+                                       return;
+                               this.value = value;
+                               NotifyValueChanged(this.value);
+                       }
+               }
+               public bool IsEditable {
+                       get => isEditable;
+                       set {
+                               if (isEditable == value)
+                                       return;
+                               isEditable = value;
+                               NotifyValueChanged(isEditable);
+                       }
+               }
+               public int NumChild {
+                       get => numChild;
+                       set {
+                               if (numChild == value)
+                                       return;
+                               numChild = value;
+                               NotifyValueChanged(numChild);
+                               NotifyValueChanged ("HasChildren", HasChildren);
+                       }
+               }
+               public string Type {
+                       get => type;
+                       set {
+                               if (type == value)
+                                       return;
+                               type = value;
+                               NotifyValueChanged(type);
+                       }
+               }
+               public int ThreadId {
+                       get => threadId;
+                       set {
+                               if (threadId == value)
+                                       return;
+                               threadId = value;
+                               NotifyValueChanged(threadId);
+                       }
+               }
+
+               public abstract void Create();
+               public abstract void Delete();
+               public abstract void UpdateValue ();
+
+
+               public override string ToString() => $"{Name}:{Expression} = {Value} [{Type}]";
+               string GetDebuggerDisplay() => ToString();
+       }
+}
index 8cff49ea50d441e9b83aa07c896d982db8b06619..d9e803f2025c7718582cc4a7b4065f83df4d198b 100644 (file)
@@ -14,17 +14,22 @@ using System.Reflection;
 using System.Collections;
 using CrowEditBase;
 using System.Threading;
+using System.ComponentModel;
 
 namespace Crow
 {
        public interface IDocumentClient {
 
        }
-       public class Editor : TextBox {
+       public class Editor : ScrollingObject, IEditableTextWidget {
                #region CTOR
                protected Editor () : base () {
+                       KeyEventsOverrides = true;//prevent scrollingObject moves by keyboard
+
                        initCommands ();
 
+                       getLines();
+
                        Thread t = new Thread (backgroundThreadFunc);
                        t.IsBackground = true;
                        t.Start ();
@@ -41,33 +46,7 @@ namespace Crow
 
                        ContextCommands = new CommandGroup (CMDCut, CMDCopy, CMDPaste);
                }
-               public override int CurrentColumn {
-                       get => base.CurrentColumn;
-                       set {
-                               if (CurrentColumn == value)
-                                       return;
-                               base.CurrentColumn = value; 
-                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
-                       }
-               }
-               public override int CurrentLine {
-                       get => base.CurrentLine;
-                       set {
-                               if (CurrentLine == value)
-                                       return;
-                               base.CurrentLine = value;
-                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
-                       }
-               }
-               protected override CharLocation? CurrentLoc {
-                       get => base.CurrentLoc;
-                       set {
-                               if (currentLoc == value)
-                                       return;
-                               base.CurrentLoc = value;
-                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
-                       }
-               }
+
                /*protected override CharLocation? SelectionStart {
                        get => base.SelectionStart;
                        set {
@@ -93,18 +72,12 @@ namespace Crow
                                RegisterForGraphicUpdate ();
                        }
                }
-               public override void OnTextChanged(object sender, TextChangeEventArgs e)
+               public event EventHandler<TextChangeEventArgs> TextChanged;
+               public virtual void OnTextChanged(object sender, TextChangeEventArgs e)
                {
                        if (disableTextChangedEvent)
                                return;                 
-                       base.OnTextChanged(sender, e);
-               }               
-               protected override void onFocused(object sender, EventArgs e)
-               {                       
-                       if (CurrentLoc == null)
-                               CurrentLoc = new CharLocation (0, 0);
-                       base.onFocused(sender, e);
-                       (IFace as CrowEditBase.CrowEditBase).CurrentEditor = this;
+                       TextChanged.Raise (this, e);
                }               
                protected void backgroundThreadFunc () {
                        while (true) {                          
@@ -117,5 +90,839 @@ namespace Crow
                                Thread.Sleep (200);                             
                        }       
                }               
+
+               #region Label
+               protected string _text = "";
+               int targetColumn = -1;//handle line changes with long->short->long line length sequence.                
+
+               protected CharLocation? hoverLoc = null;
+               protected CharLocation? currentLoc = null;
+               protected CharLocation? selectionStart = null;  //selection start (row,column)
+
+               protected virtual CharLocation? CurrentLoc {
+                       get => currentLoc;
+                       set {
+                               if (currentLoc == value)
+                                       return;
+                               currentLoc = value;
+                               NotifyValueChanged ("CurrentLine", CurrentLine);
+                               NotifyValueChanged ("CurrentColumn", CurrentColumn);
+
+                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
+            }
+        }
+               public virtual int CurrentLine {
+                       get => currentLoc.HasValue ? currentLoc.Value.Line : 0;
+                       set {
+                               if (currentLoc?.Line == value)
+                                       return;
+                               currentLoc = new CharLocation (value, currentLoc.Value.Column, currentLoc.Value.VisualCharXPosition);
+                               NotifyValueChanged ("CurrentLine", CurrentLine);
+
+                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
+                       }
+        }
+               public virtual int CurrentColumn {
+                       get => currentLoc.HasValue ? currentLoc.Value.Column < 0 ? 0 : currentLoc.Value.Column : 0;
+                       set {
+                               if (CurrentColumn == value)
+                                       return;
+                               currentLoc = new CharLocation (currentLoc.Value.Line, value);
+                               NotifyValueChanged ("CurrentColumn", CurrentColumn);
+
+                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
+                       }
+               }
+               /// <summary>
+               /// Set current cursor position in label.
+               /// </summary>
+               /// <param name="position">Absolute character position in text.</param>
+               public void SetCursorPosition (int position) {
+                       CharLocation loc = lines.GetLocation (position);
+                       loc.Column = Math.Min (loc.Column, lines[loc.Line].Length);
+                       CurrentLoc = loc;
+               }
+
+               Color selForeground, selBackground;
+               protected LineCollection lines;
+               protected bool textMeasureIsUpToDate = false;
+               protected object linesMutex = new object ();
+               protected string LineBreak = null;
+               protected Size cachedTextSize = default (Size);
+               protected bool mixedLineBreak = false;
+
+               protected FontExtents fe;
+               protected TextExtents te;               
+
+
+               /// <summary>
+               /// Background color for selected text inside this label.
+               /// </summary>
+               [DefaultValue ("SteelBlue")]
+               public virtual Color SelectionBackground {
+                       get { return selBackground; }
+                       set {
+                               if (selBackground == value)
+                                       return;
+                               selBackground = value;
+                               NotifyValueChangedAuto (selBackground);
+                               RegisterForRedraw ();
+                       }
+               }
+               /// <summary>
+               /// Selected text color inside this label.
+               /// </summary>
+               [DefaultValue("White")]
+               public virtual Color SelectionForeground {
+                       get { return selForeground; }
+                       set {
+                               if (selForeground == value)
+                                       return;
+                               selForeground = value;
+                               NotifyValueChangedAuto (selForeground);
+                               RegisterForRedraw ();
+                       }
+               }
+
+
+               /// <summary>
+               /// Moves cursor one char to the left.
+               /// </summary>
+               /// <returns><c>true</c> if move succeed</returns>              
+               public bool MoveLeft(){
+                       //targetColumn = -1;
+                       CharLocation loc = CurrentLoc.Value;
+                       if (loc.Column == 0) {
+                               if (loc.Line == 0)
+                                       return false;
+                               CurrentLoc = new CharLocation (loc.Line - 1, lines[loc.Line - 1].Length);
+            }else
+                               CurrentLoc = new CharLocation (loc.Line, loc.Column - 1);
+                       return true;
+               }
+               public bool MoveRight () {
+                       targetColumn = -1;
+                       CharLocation loc = CurrentLoc.Value;
+                       if (loc.Column == lines[loc.Line].Length) {
+                               if (loc.Line == lines.Count - 1)
+                                       return false;
+                               CurrentLoc = new CharLocation (loc.Line + 1, 0);
+                       } else
+                               CurrentLoc = new CharLocation (loc.Line, loc.Column + 1);
+                       return true;
+               }               
+               public bool LineMove (int lineDiff) {
+                       CharLocation loc = CurrentLoc.Value;
+                       int newLine = Math.Min (Math.Max (0, loc.Line + lineDiff), lines.Count - 1);
+
+                       if (newLine == loc.Line)
+                               return false;
+
+                       if (loc.Column > lines[newLine].Length) {
+                               if (targetColumn < 0)
+                                       targetColumn = loc.Column;
+                               CurrentLoc = new CharLocation (newLine, lines[newLine].Length);
+                       } else if (targetColumn < 0)
+                               CurrentLoc = new CharLocation (newLine, loc.Column);
+                       else if (targetColumn > lines[newLine].Length)
+                               CurrentLoc = new CharLocation (newLine, lines[newLine].Length);
+                       else
+                               CurrentLoc = new CharLocation (newLine, targetColumn);
+
+                       return true;
+        }
+               protected int visibleLines => (int)((double)ClientRectangle.Height / (fe.Ascent + fe.Descent));
+               public void GotoWordStart(){
+                       int pos = lines.GetAbsolutePosition (CurrentLoc.Value);                 
+                       //skip white spaces
+                       while (pos > 0 && !char.IsLetterOrDigit (_text[pos-1]))
+                               pos--;
+                       while (pos > 0 && char.IsLetterOrDigit (_text[pos-1]))
+                               pos--;
+                       CurrentLoc = lines.GetLocation (pos);
+               }
+               public void GotoWordEnd(){
+                       int pos = lines.GetAbsolutePosition (CurrentLoc.Value);
+                       //skip white spaces
+                       while (pos < _text.Length -1 && !char.IsLetterOrDigit (_text[pos]))
+                               pos++;
+                       while (pos < _text.Length - 1 && char.IsLetterOrDigit (_text[pos]))
+                               pos++;
+                       CurrentLoc = lines.GetLocation (pos);
+               }               
+
+               protected void detectLineBreak () {
+                       mixedLineBreak = false;
+
+                       if (lines.Count == 0 || lines[0].LineBreakLength == 0) {
+                               LineBreak = Environment.NewLine;
+                               return;
+            }
+                       LineBreak = _text.GetLineBreak (lines[0]).ToString ();
+
+                       for (int i = 1; i < lines.Count; i++) {
+                               ReadOnlySpan<char> lb = _text.GetLineBreak (lines[i]);
+                               if (!lb.SequenceEqual (LineBreak)) {
+                                       mixedLineBreak = true;
+                                       break;
+                }
+                       }
+        }
+               
+               protected void getLines () {                    
+                       if (lines == null)
+                               lines = new LineCollection (10);
+                       else
+                               lines.Clear ();
+
+                       if (string.IsNullOrEmpty (_text))
+                               lines.Add (new TextLine (0, 0, 0));
+                       else
+                               lines.Update (_text);
+               }
+               /// <summary>
+               /// Current Selected text span. May be used to set current position, or current selection.
+               /// </summary>
+               public TextSpan Selection {
+                       set {
+                               if (value.IsEmpty)
+                                       selectionStart = null;
+                               else
+                                       selectionStart = lines.GetLocation (value.Start);
+                               CurrentLoc = lines.GetLocation (value.End);
+                       }
+                       get {
+                               if (CurrentLoc == null)
+                                       return default;
+                               CharLocation selStart = CurrentLoc.Value, selEnd = CurrentLoc.Value;
+                               if (selectionStart.HasValue) {
+                                       if (CurrentLoc.Value.Line < selectionStart.Value.Line) {
+                                               selStart = CurrentLoc.Value;
+                                               selEnd = selectionStart.Value;
+                                       } else if (CurrentLoc.Value.Line > selectionStart.Value.Line) {
+                                               selStart = selectionStart.Value;
+                                               selEnd = CurrentLoc.Value;
+                                       } else if (CurrentLoc.Value.Column < selectionStart.Value.Column) {
+                                               selStart = CurrentLoc.Value;
+                                               selEnd = selectionStart.Value;
+                                       } else {
+                                               selStart = selectionStart.Value;
+                                               selEnd = CurrentLoc.Value;
+                                       }
+                               }
+                               return new TextSpan (lines.GetAbsolutePosition (selStart), lines.GetAbsolutePosition (selEnd));
+                       }
+        }
+               public string SelectedText {
+                       get {
+                               TextSpan selection = Selection;
+                               return selection.IsEmpty ? "" : _text.AsSpan (selection.Start, selection.Length).ToString ();
+                       }
+        }
+               public bool SelectionIsEmpty => selectionStart.HasValue ? Selection.IsEmpty : true;
+
+               protected virtual void measureTextBounds (Context gr) {
+                       fe = gr.FontExtents;
+                       te = new TextExtents ();
+
+                       cachedTextSize.Height = (int)Math.Ceiling ((fe.Ascent + fe.Descent) * Math.Max (1, lines.Count));
+
+                       TextExtents tmp = default;
+                       int longestLine = 0;
+                       for (int i = 0; i < lines.Count; i++) {
+                               if (lines[i].LengthInPixel < 0) {
+                                       if (lines[i].Length == 0)
+                                               lines.UpdateLineLengthInPixel (i, 0);// (int)Math.Ceiling (fe.MaxXAdvance);
+                                       else {
+                                               gr.TextExtents (_text.GetLine (lines[i]), Interface.TAB_SIZE, out tmp);
+                                               lines.UpdateLineLengthInPixel (i, (int)Math.Ceiling (tmp.XAdvance));
+                                       }
+                               }
+                               if (lines[i].LengthInPixel > lines[longestLine].LengthInPixel)
+                                       longestLine = i;
+                       }
+                       cachedTextSize.Width = lines[longestLine].LengthInPixel;
+                       textMeasureIsUpToDate = true;
+
+                       updateMaxScrolls (LayoutingType.Height);
+                       updateMaxScrolls (LayoutingType.Width);
+               }
+               protected virtual void drawContent (Context gr) {
+                       gr.Translate (-ScrollX, -ScrollY);
+
+                       Rectangle cb = ClientRectangle;
+                       fe = gr.FontExtents;
+                       double lineHeight = fe.Ascent + fe.Descent;
+
+                       CharLocation selStart = default, selEnd = default;
+                       bool selectionNotEmpty = false;
+
+                       if (HasFocus) {
+                               if (currentLoc?.Column < 0) {
+                                       updateLocation (gr, cb.Width, ref currentLoc);
+                                       NotifyValueChanged ("CurrentColumn", CurrentColumn);
+                               } else
+                                       updateLocation (gr, cb.Width, ref currentLoc);
+                               if (selectionStart.HasValue) {
+                                       updateLocation (gr, cb.Width, ref selectionStart);
+                                       if (CurrentLoc.Value != selectionStart.Value)
+                                               selectionNotEmpty = true;
+                               }
+                               if (selectionNotEmpty) {
+                                       if (CurrentLoc.Value.Line < selectionStart.Value.Line) {
+                                               selStart = CurrentLoc.Value;
+                                               selEnd = selectionStart.Value;
+                                       } else if (CurrentLoc.Value.Line > selectionStart.Value.Line) {
+                                               selStart = selectionStart.Value;
+                                               selEnd = CurrentLoc.Value;
+                                       } else if (CurrentLoc.Value.Column < selectionStart.Value.Column) {
+                                               selStart = CurrentLoc.Value;
+                                               selEnd = selectionStart.Value;
+                                       } else {
+                                               selStart = selectionStart.Value;
+                                               selEnd = CurrentLoc.Value;
+                                       }
+                               } else
+                                       IFace.forceTextCursor = true;
+                       }
+
+                       if (!string.IsNullOrEmpty (_text)) {
+                               Foreground?.SetAsSource (IFace, gr);
+
+                               TextExtents extents;
+                               Span<byte> bytes = stackalloc byte[128];
+                               double y = 0;
+
+                               for (int i = 0; i < lines.Count; i++) {
+                                       if (!cancelLinePrint (lineHeight, y, cb.Height)) {
+                                               int encodedBytes = -1;
+                                               if (lines[i].Length > 0) {
+                                                       int size = lines[i].Length * 4 + 1;
+                                                       if (bytes.Length < size)
+                                                               bytes = size > 512 ? new byte[size] : stackalloc byte[size];
+
+                                                       encodedBytes = Crow.Text.Encoding.ToUtf8 (_text.GetLine (lines[i]), bytes);
+                                                       bytes[encodedBytes++] = 0;
+
+                                                       if (lines[i].LengthInPixel < 0) {
+                                                               gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
+                                                               lines.UpdateLineLengthInPixel (i, (int)extents.XAdvance);
+                                                       }
+                                               }
+
+                                               RectangleD lineRect = new RectangleD (
+                                                       (int)cb.X,
+                                                       y + cb.Top, lines[i].LengthInPixel, lineHeight);
+
+                                               if (encodedBytes > 0) {
+                                                       gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
+                                                       gr.ShowText (bytes.Slice (0, encodedBytes));
+                                               }
+                                               /********** DEBUG TextLineCollection *************
+                                               gr.SetSource (Colors.Red);
+                                               gr.SetFontSize (9);
+                                               gr.MoveTo (700, lineRect.Y + fe.Ascent);
+                                               gr.ShowText ($"({lines[i].Start}, {lines[i].End}, {lines[i].EndIncludingLineBreak})");
+                                               gr.SetFontSize (Font.Size);
+                                               Foreground.SetAsSource (IFace, gr);
+                                               ********** DEBUG TextLineCollection *************/
+
+                                               if (HasFocus && selectionNotEmpty) {
+                                                       RectangleD selRect = lineRect;
+                                                       
+                                                       if (i >= selStart.Line && i <= selEnd.Line) {
+                                                               if (selStart.Line == selEnd.Line) {
+                                                                       selRect.X = selStart.VisualCharXPosition + cb.X;
+                                                                       selRect.Width = selEnd.VisualCharXPosition - selStart.VisualCharXPosition;
+                                                               } else if (i == selStart.Line) {
+                                                                       double newX = selStart.VisualCharXPosition + cb.X;
+                                                                       selRect.Width -= (newX - selRect.X) - 10.0;
+                                                                       selRect.X = newX;
+                                                               } else if (i == selEnd.Line) {
+                                                                       selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
+                                                               } else
+                                                                       selRect.Width += 10.0;
+                                                       } else {
+                                                               y += lineHeight;
+                                                               continue;
+                                                       }
+                                               
+                                                       gr.SetSource (selBackground);
+                                                       gr.Rectangle (selRect);
+                                                       if (encodedBytes < 0)
+                                                               gr.Fill ();
+                                                       else {
+                                                               gr.FillPreserve ();
+                                                               gr.Save ();
+                                                               gr.Clip ();
+                                                               gr.SetSource (SelectionForeground);
+                                                               gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
+                                                               gr.ShowText (bytes.Slice (0, encodedBytes));
+                                                               gr.Restore ();
+                                                       }
+                                                       Foreground.SetAsSource (IFace, gr);
+                                               }
+                                       }
+                                       y += lineHeight;
+                               }
+                       }
+
+                       gr.Translate (ScrollX, ScrollY);
+               }
+               protected virtual void updateHoverLocation (Point mouseLocalPos) {
+                       int hoverLine = (int)Math.Min (Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent + fe.Descent))), lines.Count - 1);
+                       hoverLoc = new CharLocation (hoverLine, -1, mouseLocalPos.X);
+                       using (Context gr = new Context (IFace.surf)) {
+                               setFontForContext (gr);
+                               updateLocation (gr, ClientRectangle.Width, ref hoverLoc);
+                       }
+               }
+               protected virtual bool cancelLinePrint (double lineHeght, double y, int clientHeight) => false;
+               RectangleD? textCursor = null;
+               public virtual bool DrawCursor (Context ctx, out Rectangle rect) {
+                       if (CurrentLoc == null) {
+                               rect = default;
+                               return false;
+                       }
+                       if (!CurrentLoc.Value.HasVisualX) {
+                               setFontForContext (ctx);
+                               lock (linesMutex) {                                     
+                                       if (currentLoc?.Column < 0) {
+                                               updateLocation (ctx, ClientRectangle.Width, ref currentLoc);
+                                               NotifyValueChanged ("CurrentColumn", CurrentColumn);
+                                       } else
+                                               updateLocation (ctx, ClientRectangle.Width, ref currentLoc);
+                               }
+                               textCursor = null;
+                       }
+
+
+                       int lineHeight = (int)(fe.Ascent + fe.Descent);
+                       textCursor = computeTextCursor (new RectangleD (CurrentLoc.Value.VisualCharXPosition, CurrentLoc.Value.Line * lineHeight, 1.0, lineHeight));
+
+                       if (textCursor == null) {
+                               rect = default;
+                               return false;
+                       }
+                       //}
+                       Rectangle c = ScreenCoordinates (textCursor.Value + Slot.Position + ClientRectangle.Position);
+                       ctx.ResetClip ();
+                       Foreground.SetAsSource (IFace, ctx, c);                 
+                       ctx.LineWidth = 1.0;
+                       ctx.MoveTo (0.5 + c.X, c.Y);
+                       ctx.LineTo (0.5 + c.X, c.Bottom);
+                       ctx.Stroke ();
+                       rect = c;
+                       return true;
+               }
+
+               protected void updateLocation (Context gr, int clientWidth, ref CharLocation? location) {
+                       if (location == null)
+                               return;
+                       CharLocation loc = location.Value;
+                       //Console.WriteLine ($"updateLocation: {loc} text:{_text.Length}");
+                       if (loc.HasVisualX)
+                               return;
+                       TextLine ls = lines[loc.Line];
+                       ReadOnlySpan<char> curLine = _text.GetLine (ls);
+                       double cPos = 0;
+
+                       if (loc.Column >= 0) {
+                               //int encodedBytes = Crow.Text.Encoding2.ToUtf8 (curLine.Slice (0, loc.Column), bytes);
+#if DEBUG
+                               if (loc.Column > curLine.Length) {
+                    System.Diagnostics.Debug.WriteLine ($"loc.Column: {loc.Column} curLine.Length:{curLine.Length}");
+                                       loc.Column = curLine.Length;
+                               }
+#endif
+                               loc.VisualCharXPosition = gr.TextExtents (curLine.Slice (0, loc.Column), Interface.TAB_SIZE).XAdvance + cPos;
+                               location = loc;
+                       } else {
+                               TextExtents te;
+                               Span<byte> bytes = stackalloc byte[5];//utf8 single char buffer + '\0'
+
+                               for (int i = 0; i < ls.Length; i++) {
+                                       int encodedBytes = Crow.Text.Encoding.ToUtf8 (curLine.Slice (i, 1), bytes);
+                                       bytes[encodedBytes] = 0;
+
+                                       gr.TextExtents (bytes, out te);
+                                       double halfWidth = te.XAdvance / 2;
+
+                                       if (loc.VisualCharXPosition <= cPos + halfWidth) {
+                                               loc.Column = i;
+                                               loc.VisualCharXPosition = cPos;
+                                               location = loc;
+                                               return;
+                                       }
+
+                                       cPos += te.XAdvance;
+                               }
+                               loc.Column = ls.Length;
+                               loc.VisualCharXPosition = cPos;
+                               location = loc;
+                       }
+               }
+
+               protected void checkShift () {
+                       if (IFace.Shift) {
+                               if (!selectionStart.HasValue)
+                                       selectionStart = CurrentLoc;
+                       } else
+                               selectionStart = null;
+               }
+
+               #region GraphicObject overrides
+               public override void OnLayoutChanges (LayoutingType layoutType) {
+                       base.OnLayoutChanges (layoutType);
+                       updateMaxScrolls (layoutType);
+               }
+               public override bool UpdateLayout (LayoutingType layoutType) {
+                       if ((LayoutingType.Sizing | layoutType) != LayoutingType.None) {
+                               if (!System.Threading.Monitor.TryEnter (linesMutex))
+                                       return false;
+                       }
+                       try {
+                               bool result = base.UpdateLayout (layoutType);                           
+                               return result;
+                       } finally {
+                               System.Threading.Monitor.Exit (linesMutex);
+                       }
+               }
+               public override int measureRawSize(LayoutingType lt)
+               {
+                       DbgLogger.StartEvent(DbgEvtType.GOMeasure, this, lt);
+
+                       if ((bool)lines?.IsEmpty)
+                               getLines ();
+
+                       if (!textMeasureIsUpToDate) {
+                               using (Context gr = new Context (IFace.surf)) {
+                                       setFontForContext (gr);
+                                       measureTextBounds (gr);
+                               }
+                       }
+                       DbgLogger.EndEvent(DbgEvtType.GOMeasure);
+                       return Margin * 2 + (lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width);
+               }
+               
+               protected override void onDraw (Context gr)
+               {
+                       base.onDraw (gr);
+
+                       setFontForContext (gr);
+                       
+                       if (!textMeasureIsUpToDate) {
+                               lock (linesMutex)
+                                       measureTextBounds (gr);
+            }
+                       
+                       if (ClipToClientRect) {
+                               gr.Save ();
+                               CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+                               gr.Clip ();
+                       }
+
+                       lock (linesMutex)
+                               drawContent (gr);
+                       
+                       if (ClipToClientRect)
+                               gr.Restore ();
+               }
+               #endregion
+
+               #region Mouse handling
+               protected override void onFocused (object sender, EventArgs e)
+               {
+                       base.onFocused (sender, e);
+
+                       if (CurrentLoc == null) {
+                               selectionStart = new CharLocation (0, 0);                               
+                               CurrentLoc = new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
+                       }
+
+                       RegisterForRedraw ();
+
+                       (IFace as CrowEditBase.CrowEditBase).CurrentEditor = this;
+               }
+               protected override void onUnfocused (object sender, EventArgs e)
+               {
+                       base.onUnfocused (sender, e);
+                       RegisterForRedraw ();
+               }
+        public override void onMouseEnter (object sender, MouseMoveEventArgs e) {
+            base.onMouseEnter (sender, e);
+                       if (Focusable)
+                               IFace.MouseCursor = MouseCursor.ibeam;                  
+               }
+        public override void onMouseMove (object sender, MouseMoveEventArgs e)
+               {
+                       base.onMouseMove (sender, e);
+
+                       updateHoverLocation (ScreenPointToLocal (e.Position));
+
+                       if (HasFocus && IFace.IsDown (MouseButton.Left)) {
+                               CurrentLoc = hoverLoc;                          
+                               RegisterForRedraw ();                           
+                       }
+               }               
+               public override void onMouseDown (object sender, MouseButtonEventArgs e)
+               {
+                       if (e.Button == Glfw.MouseButton.Left) {
+                               targetColumn = -1;
+                               if (HasFocus) {                                 
+                                       if (!IFace.Shift)                                                
+                                               selectionStart = hoverLoc;
+                                       else if (!selectionStart.HasValue)
+                                               selectionStart = CurrentLoc;
+                                       CurrentLoc = hoverLoc;
+                                       IFace.forceTextCursor = true;
+                                       RegisterForRedraw ();
+                                       e.Handled = true;
+                               }                                       
+                       }
+                       base.onMouseDown (sender, e);
+
+                       //done at the end to set 'hasFocus' value after testing it
+               }
+               public override void onMouseUp (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseUp (sender, e);
+                       if (e.Button != MouseButton.Left || !HasFocus || !selectionStart.HasValue)
+                               return;                 
+                       if (selectionStart.Value == CurrentLoc.Value)
+                               selectionStart = null;
+               }
+               public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseDoubleClick (sender, e);
+                       if (e.Button != MouseButton.Left || !HasFocus)
+                               return;
+
+                       GotoWordStart ();
+                       selectionStart = CurrentLoc;                    
+                       GotoWordEnd ();
+                       RegisterForRedraw ();
+               }
+               #endregion
+
+               #region Keyboard handling
+               public override void onKeyDown (object sender, KeyEventArgs e) {
+                       Key key = e.Key;
+                       TextSpan selection = Selection;
+                       switch (key) {
+                       case Key.Backspace:
+                               if (selection.IsEmpty) {
+                                       if (selection.Start == 0)
+                                               return;
+                                       if (CurrentLoc.Value.Column == 0) {
+                                               int lbLength = lines[CurrentLoc.Value.Line - 1].LineBreakLength;
+                                               update (new TextChange (selection.Start - lbLength, lbLength, ""));
+                                       }else
+                                               update (new TextChange (selection.Start - 1, 1, ""));
+                               } else
+                                       update (new TextChange (selection.Start, selection.Length, ""));
+                               break;
+                       case Key.Delete:
+                               if (selection.IsEmpty) {
+                                       if (selection.Start == _text.Length)
+                                               return;
+                                       if (CurrentLoc.Value.Column >= lines[CurrentLoc.Value.Line].Length) 
+                                               update (new TextChange (selection.Start, lines[CurrentLoc.Value.Line].LineBreakLength, ""));                        
+                                       else
+                                               update (new TextChange (selection.Start, 1, ""));
+                               } else {
+                                       if (IFace.Shift)
+                                               IFace.Clipboard = SelectedText;
+                                       update (new TextChange (selection.Start, selection.Length, ""));
+                               }
+                               break;
+                       case Key.Insert:
+                               if (IFace.Shift)
+                                       Paste ();
+                               else if (IFace.Ctrl)
+                                       Copy ();
+                               break;
+                       case Key.KeypadEnter:
+                       case Key.Enter:
+                               if (string.IsNullOrEmpty (LineBreak))
+                                       detectLineBreak ();
+                               update (new TextChange (selection.Start, selection.Length, LineBreak));
+                               break;
+                       case Key.Escape:
+                               selectionStart = null;
+                               CurrentLoc = lines.GetLocation (selection.Start);
+                               RegisterForRedraw ();
+                               break;
+                       case Key.Tab:
+                               update (new TextChange (selection.Start, selection.Length, "\t"));
+                               break;
+                       case Key.PageUp:
+                               checkShift ();
+                               LineMove (-visibleLines);
+                               RegisterForRedraw ();
+                               break;
+                       case Key.PageDown:
+                               checkShift ();
+                               LineMove (visibleLines);
+                               RegisterForRedraw ();
+                               break;
+                       case Key.Home:
+                               targetColumn = -1;
+                               checkShift ();
+                               if (IFace.Ctrl)
+                                       CurrentLoc = new CharLocation (0, 0);
+                               else
+                                       CurrentLoc = new CharLocation (CurrentLoc.Value.Line, 0);
+                               RegisterForRedraw ();
+                               break;
+                       case Key.End:
+                               checkShift ();
+                               int l = IFace.Ctrl ? lines.Count - 1 : CurrentLoc.Value.Line;
+                               CurrentLoc = new CharLocation (l, lines[l].Length);
+                               RegisterForRedraw ();
+                               break;
+                       case Key.Left:
+                               checkShift ();
+                               if (IFace.Ctrl)
+                                       GotoWordStart ();
+                               else
+                                       MoveLeft ();
+                               RegisterForRedraw ();
+                               break;
+                       case Key.Right:
+                               checkShift ();
+                               if (IFace.Ctrl)
+                                       GotoWordEnd ();
+                               else
+                                       MoveRight ();
+                               RegisterForRedraw ();
+                               break;
+                       case Key.Up:
+                               checkShift ();
+                               LineMove (-1);
+                               RegisterForRedraw ();
+                               break;
+                       case Key.Down:
+                               checkShift ();
+                               LineMove (1);
+                               RegisterForRedraw ();
+                               break;
+                       default:
+                               base.onKeyDown (sender, e);
+                               return;
+                       }
+                       autoAdjustScroll = true;
+                       IFace.forceTextCursor = true;
+                       e.Handled = true;                       
+               }
+               #endregion
+               #endregion
+
+
+               #region textBox
+               bool autoAdjustScroll = false;//if scrollXY is changed directly, dont try adjust scroll to cursor
+               internal RectangleD? computeTextCursor (Rectangle cursor) {
+                       Rectangle cb = ClientRectangle;
+                       cursor -= new Point (ScrollX, ScrollY);
+
+                       if (autoAdjustScroll) {
+                               autoAdjustScroll = false;
+                               int goodMsrs = 0;
+                               if (cursor.Right < 0)
+                                       ScrollX += cursor.Right;
+                               else if (cursor.X > cb.Width)
+                                       ScrollX += cursor.X - cb.Width;
+                               else
+                                       goodMsrs++;
+
+                               if (cursor.Y < 0)
+                                       ScrollY += cursor.Y;
+                               else if (cursor.Bottom > cb.Height)
+                                       ScrollY += cursor.Bottom - cb.Height;
+                               else
+                                       goodMsrs++;
+
+                               if (goodMsrs < 2)
+                                       return null;
+                       } else if (cursor.Right < 0 || cursor.X > cb.Width || cursor.Y < 0 || cursor.Bottom > cb.Height)
+                               return null;
+                       
+                       return cursor;            
+               }
+
+               void updateMaxScrolls (LayoutingType layout) {
+                       Rectangle cb = ClientRectangle;
+                       if (layout == LayoutingType.Width) {
+                               MaxScrollX = cachedTextSize.Width - cb.Width;
+                               NotifyValueChanged ("PageWidth", ClientRectangle.Width);
+                               if (cachedTextSize.Width > 0)
+                                       NotifyValueChanged ("ChildWidthRatio", Math.Min (1.0, (double)cb.Width / cachedTextSize.Width));
+                       } else if (layout == LayoutingType.Height) {
+                               MaxScrollY = cachedTextSize.Height - cb.Height;
+                               NotifyValueChanged ("PageHeight", ClientRectangle.Height);
+                               if (cachedTextSize.Height > 0)
+                                       NotifyValueChanged ("ChildHeightRatio", Math.Min (1.0, (double)cb.Height / cachedTextSize.Height));
+                       }
+               }
+               public virtual void Cut () {
+                       TextSpan selection = Selection;
+                       if (selection.IsEmpty)
+                               return;
+                       IFace.Clipboard = SelectedText;
+                       update (new TextChange (selection.Start, selection.Length, ""));
+               }
+               public virtual void Copy () {
+                       TextSpan selection = Selection;
+                       if (selection.IsEmpty)
+                               return;
+                       IFace.Clipboard = SelectedText;         
+               }
+               public virtual void Paste () {
+                       TextSpan selection = Selection;
+                       update (new TextChange (selection.Start, selection.Length, IFace.Clipboard));
+               }
+
+               #region Keyboard handling
+               public override void onKeyPress (object sender, KeyPressEventArgs e) {
+                       base.onKeyPress (sender, e);
+
+                       TextSpan selection = Selection;
+                       update (new TextChange (selection.Start, selection.Length, e.KeyChar.ToString ()));
+
+                       /*Insert (e.KeyChar.ToString());
+
+                       SelRelease = -1;
+                       SelBegin = new Point(CurrentColumn, SelBegin.Y);
+
+                       RegisterForGraphicUpdate();*/
+               }
+               #endregion
+
+               protected void update (TextChange change) {
+                       lock (linesMutex) {
+                               ReadOnlySpan<char> src = _text.AsSpan ();
+                               Span<char> tmp = stackalloc char[src.Length + (change.ChangedText.Length - change.Length)];
+                               //Console.WriteLine ($"{Text.Length,-4} {change.Start,-4} {change.Length,-4} {change.ChangedText.Length,-4} tmp:{tmp.Length,-4}");
+                               src.Slice (0, change.Start).CopyTo (tmp);
+                               change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
+                               src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
+                       
+                               _text = tmp.ToString ();
+                               lines.Update (change);
+                               //lines.Update (_text);
+                               selectionStart = null;
+
+                               CurrentLoc = lines.GetLocation (change.Start + change.ChangedText.Length);
+                               textMeasureIsUpToDate = false;
+                               IFace.forceTextCursor = true;
+                       }
+                       
+                       OnTextChanged (this, new TextChangeEventArgs (change));
+                       
+                       RegisterForGraphicUpdate ();
+               }
+                       
+               #endregion
+
        }
 }
\ No newline at end of file
diff --git a/CrowEditBase/src/IFileNode.cs b/CrowEditBase/src/IFileNode.cs
new file mode 100644 (file)
index 0000000..9f3077a
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright (c) 2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Crow;
+using CrowEditBase;
+using static CrowEditBase.CrowEditBase;
+
+namespace CrowEditBase
+{      
+       public interface IFileNode
+       {
+               string FullPath { get; }
+       }
+}
diff --git a/CrowEditBase/src/LogViewerWidget.cs b/CrowEditBase/src/LogViewerWidget.cs
new file mode 100644 (file)
index 0000000..f9bd3a5
--- /dev/null
@@ -0,0 +1,176 @@
+// Copyright (c) 2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Xml.Serialization;
+using System.ComponentModel;
+using System.Collections;
+using Crow.Cairo;
+
+namespace Crow
+{
+       public enum LogType {
+               Low,
+               Normal,
+               High,
+               Debug,
+               Warning,
+               Error,
+               Custom1,
+               Custom2,
+               Custom3,
+       }
+       public class LogEntry {
+               public LogType Type;
+               public string msg;
+               public LogEntry (LogType type, string message) {
+                       Type = type;
+                       msg = message;
+               }
+               public override string ToString() => msg;
+       }
+       public class LogViewerWidget : ScrollingObject
+       {
+               ObservableList<LogEntry> lines;
+               bool scrollOnOutput;
+               int visibleLines = 1;
+               FontExtents fe;
+
+               [DefaultValue(true)]
+               public virtual bool ScrollOnOutput {
+                       get { return scrollOnOutput; }
+                       set {
+                               if (scrollOnOutput == value)
+                                       return;
+                               scrollOnOutput = value;
+                               NotifyValueChanged ("ScrollOnOutput", scrollOnOutput);
+
+                       }
+               }
+               public virtual ObservableList<LogEntry> Lines {
+                       get { return lines; }
+                       set {
+                               if (lines == value)
+                                       return;
+                               if (lines != null) {
+                                       lines.ListAdd -= Lines_ListAdd;
+                                       lines.ListRemove -= Lines_ListRemove;
+                               }
+                               lines = value;
+                               if (lines != null) {
+                                       lines.ListAdd += Lines_ListAdd;
+                                       lines.ListRemove += Lines_ListRemove;
+                               }
+                               NotifyValueChanged ("Lines", lines);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+
+               void Lines_ListAdd (object sender, ListChangedEventArg e)
+               {
+                       // try
+                       // {
+                               MaxScrollY = lines.Count - visibleLines;
+                               if (scrollOnOutput)
+                                       ScrollY = MaxScrollY;
+                               
+                       // }
+                       // catch (System.Exception ex)
+                       // {
+                       //      Console.WriteLine ($"list add valueChange handler bug:{ex}");
+                       // }
+               }
+
+               void Lines_ListRemove (object sender, ListChangedEventArg e)
+               {
+                       MaxScrollY = lines.Count - visibleLines;
+               }
+
+
+               public override void OnLayoutChanges (LayoutingType layoutType)
+               {
+                       base.OnLayoutChanges (layoutType);
+
+                       if (layoutType == LayoutingType.Height) {
+                               using (ImageSurface img = new ImageSurface (Format.Argb32, 10, 10)) {
+                                       using (Context gr = new Context (img)) {
+                                               //Cairo.FontFace cf = gr.GetContextFontFace ();
+
+                                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                                               gr.SetFontSize (Font.Size);
+
+                                               fe = gr.FontExtents;
+                                       }
+                               }
+                               visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / fe.Height);
+                               MaxScrollY = lines == null ? 0 : lines.Count - visibleLines;
+                       }
+               }
+               protected override void onDraw (Cairo.Context gr)
+               {
+                       base.onDraw (gr);
+
+                       if (lines == null)
+                               return;
+
+                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                       gr.SetFontSize (Font.Size);
+
+                       Rectangle r = ClientRectangle;
+
+
+                       double y = ClientRectangle.Y;
+                       double x = ClientRectangle.X - ScrollX;
+
+                       lock (lines) {
+                               for (int i = 0; i < visibleLines; i++) {
+                                       if (i + ScrollY >= Lines.Count)
+                                               break;
+                                       //if ((lines [i + Scroll] as string).StartsWith ("error", StringComparison.OrdinalIgnoreCase)) {
+                                       //      errorFill.SetAsSource (gr);
+                                       //      gr.Rectangle (x, y, (double)r.Width, fe.Height);
+                                       //      gr.Fill ();
+                                       //      Foreground.SetAsSource (gr);
+                                       //}
+                                       LogEntry le = lines[i+ScrollY]; 
+                                       switch (le.Type) {
+                                               case LogType.Low:
+                                                       gr.SetSource (Colors.DimGrey);
+                                                       break;
+                                               case LogType.Normal:
+                                                       gr.SetSource (Colors.Grey);
+                                                       break;
+                                               case LogType.High:
+                                                       gr.SetSource (Colors.White);
+                                                       break;
+                                               case LogType.Debug:
+                                                       gr.SetSource (Colors.Yellow);
+                                                       break;
+                                               case LogType.Warning:
+                                                       gr.SetSource (Colors.Orange);
+                                                       break;
+                                               case LogType.Error:
+                                                       gr.SetSource (Colors.Red);
+                                                       break;
+                                               case LogType.Custom1:
+                                                       gr.SetSource (Colors.Cyan);
+                                                       break;
+                                               case LogType.Custom2:
+                                                       gr.SetSource (Colors.Green);
+                                                       break;
+                                               case LogType.Custom3:
+                                                       gr.SetSource (Colors.LightPink);
+                                                       break;
+                                       }
+                                       gr.MoveTo (x, y + fe.Ascent);
+                                       gr.ShowText (le.msg);
+                                       y += fe.Height;
+                                       gr.Fill ();
+                               }
+                       }
+               }
+
+       }
+}
+
index b2fe1b01a679d50049216c75e50eb70a3bf8c3ea..8639a95b8e3aad446bd72a87120622b911df0d7b 100644 (file)
@@ -21,6 +21,11 @@ namespace CrowEditBase
 
                public Assembly Load (AssemblyName assemblyName)
                        => loadContext.LoadFromAssemblyName (assemblyName);
+               
+               public bool TryGet (AssemblyName assemblyName, out Assembly assembly) {
+                       assembly = loadContext.Assemblies.FirstOrDefault (a=>a.GetName().Name == assemblyName.Name);
+                       return assembly != null;
+               }
                public virtual bool IsLoaded {
                        get { return isLoaded; }
                        set {
index 7e850faa889b13a13afd29951535efa4e749c952..682783936812bc6e0dcec83050af038ec79ff7f3 100644 (file)
@@ -25,15 +25,18 @@ namespace CrowEditBase
        }*/
        public class PluginsLoadContext : AssemblyLoadContext {
                public readonly Assembly MainAssembly;
-               string pluginDirectory;
-               public PluginsLoadContext (string pluginsDirectory)
-                       : base ($"CrowEditPluginsContext+{pluginsDirectory}", true) {
-                       this.pluginDirectory = pluginsDirectory;
-                       string pluginAssembly = Path.Combine (pluginsDirectory, $"{Path.GetFileName (pluginsDirectory)}.dll");
+               public readonly string Name;
+               readonly string fullPath;
+               public PluginsLoadContext (string pluginDirectory)
+                       : base (Path.GetFileName (pluginDirectory), false) {
+                       fullPath = pluginDirectory;
+                       Name = Path.GetFileName (pluginDirectory);
+
+                       string pluginAssembly = Path.Combine (fullPath, $"{Name}.dll");
                        MainAssembly = LoadFromAssemblyPath (pluginAssembly);
                }
                protected override Assembly Load(AssemblyName assemblyName) {                   
-                       string assemblyPath = Path.Combine (pluginDirectory, assemblyName.Name + ".dll");                       
+                       string assemblyPath = Path.Combine (fullPath, assemblyName.Name + ".dll");                      
                        return File.Exists (assemblyPath) ? LoadFromAssemblyPath (assemblyPath) : null;
                }
 
index 8c0017fb59fa9b446715fba9a73caf3767459f49..4c001ad5eef29605d7d927976f452ddc25d75c12 100644 (file)
@@ -45,10 +45,10 @@ namespace CrowEditBase
                        FullPath = fullPath;                    
                }
                public Command CMDLoad, CMDUnload, CMDReload;
-               public CommandGroup Commands => new CommandGroup (
+               public virtual CommandGroup Commands => new CommandGroup (
                        CMDLoad, CMDUnload, CMDReload);
                
-               protected virtual void initCommands () {
+               void initCommands () {
                        CMDLoad = new Command ("Load", Load, "#icons.reply.svg",  false);
                        CMDUnload = new Command ("Unload", Unload, "#icons.share-arrow.svg", false);
                        CMDReload = new Command ("Reload", () => { Unload(); Load();}, "#icons.refresh.svg", false);            
index 89abcef5414b4c2665883d18728d0584d7efaa9a..382a8d56a24d01ee44c8682174ae9f06017bb9e8 100644 (file)
@@ -163,11 +163,11 @@ namespace Crow
 
                                if (IFace.Shift) {
                                        for (int l = lineStart; l <= lineEnd; l++) {                            
-                                               if (Text[lines[l].Start] == '\t')
+                                               if (_text[lines[l].Start] == '\t')
                                                        update (new TextChange (lines[l].Start, 1, ""));
-                                               else if (Char.IsWhiteSpace (Text[lines[l].Start])) {
+                                               else if (Char.IsWhiteSpace (_text[lines[l].Start])) {
                                                        int i = 1;
-                                                       while (i < lines[l].Length && i < Interface.TAB_SIZE && Char.IsWhiteSpace (Text[i]))
+                                                       while (i < lines[l].Length && i < Interface.TAB_SIZE && Char.IsWhiteSpace (_text[i]))
                                                                i++;
                                                        update (new TextChange (lines[l].Start, i, ""));
                                                }
index f1a7cc77d95e6be3e160d95e1494f08f9f8e2101..e5ec8d4a003e064bf1902dd5f40d402a5570491d 100644 (file)
@@ -1,4 +1,11 @@
-icon {
+Editor {
+       Background="White";
+       Foreground="Black";
+       MouseWheelSpeed = "20";
+       BubbleMouseEvent ="None";
+}
+
+icon {
        Width="14";
        Height="14";
 }
index 127c3d0e730ef8c033d59bae56157af2f5d763c7..a20d97df1617ccf0ec5f4c22867cf528f3ab308c 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
-               <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
+               <TargetFrameworks>netcoreapp5</TargetFrameworks>
                <EnableDefaultItems>false</EnableDefaultItems>
        </PropertyGroup>
        
@@ -10,7 +10,6 @@
                <EmbeddedResource Include="ui\**\*.*" />
        </ItemGroup>
        <ItemGroup>
-               <ProjectReference Include="../CERoslynPlugin\CERoslynPlugin.csproj" />
-               
+               <ProjectReference Include="../CERoslynPlugin\CERoslynPlugin.csproj" />          
        </ItemGroup>
 </Project>
index 2a9f67093f96084bcc78f2ae6cd03876ffe36ccc..fd446d61abcdc6f8288f85ddca9bdac5a5044d0f 100644 (file)
@@ -28,7 +28,7 @@ namespace Crow
                        initCommands ();
 
                        //resolve other plugins dependencies
-                       AssemblyLoadContext.GetLoadContext (Assembly.GetExecutingAssembly ()).Resolving += resolvePluginRefs;
+                       //AssemblyLoadContext.GetLoadContext (Assembly.GetExecutingAssembly ()).Resolving += resolvePluginRefs;
                        
                        if (CrowEditBase.CrowEditBase.App.TryGetWindow ("#CECrowDebugLog.ui.winLogGraph.crow", out Window win))
                                win.DataSource = this;
@@ -497,8 +497,8 @@ namespace Crow
                                Events = events;
                                Widgets = widgets;
                                firstWidgetIndexToGet += widgets.Count;                         
-                               if (widgets.Count > 0 && firstWidgetIndexToGet != widgets.Last().InstanceIndex + 1)
-                                       Debugger.Break ();
+                               /*if (widgets.Count > 0 && firstWidgetIndexToGet != widgets.Last().InstanceIndex + 1)
+                                       Debugger.Break ();*/
                        }
                }
                void updateWidgetEvents (IList<DbgWidgetRecord> widgets, DbgEvent evt) {
diff --git a/plugins/CENetcoreDbgPlugin/CENetcoreDbgPlugin.csproj b/plugins/CENetcoreDbgPlugin/CENetcoreDbgPlugin.csproj
new file mode 100644 (file)
index 0000000..4540498
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+       <PropertyGroup>
+               <TargetFrameworks>netcoreapp5</TargetFrameworks>
+               <EnableDefaultItems>false</EnableDefaultItems>
+       </PropertyGroup>
+       
+       <ItemGroup>
+               <Compile Include="src\**\*.cs" />
+               <EmbeddedResource Include="ui\**\*.*" />
+       </ItemGroup>
+       <ItemGroup>
+               <ProjectReference Include="../CERoslynPlugin\CERoslynPlugin.csproj" />          
+       </ItemGroup>
+
+       
+</Project>
diff --git a/plugins/CENetcoreDbgPlugin/src/BreakPoint.cs b/plugins/CENetcoreDbgPlugin/src/BreakPoint.cs
new file mode 100644 (file)
index 0000000..3c19b3f
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System.Diagnostics;
+
+namespace NetcoreDbgPlugin
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public class BreakPoint : CrowEditBase.BreakPoint
+       {
+               public BreakPoint(string fileFullPath, int line, bool isEnabled = true) : base (fileFullPath, line, isEnabled) {
+               }
+
+               public void Update (MITupple bkpt) {
+                       Index = int.Parse (bkpt.GetAttributeValue("number"));
+                       Type = bkpt.GetAttributeValue("type");
+                       Disp = bkpt.GetAttributeValue("disp");
+                       IsEnabled = bkpt.GetAttributeValue("enabled") == "y";
+                       if (bkpt.TryGetAttributeValue("warning", out string warning))
+                               Warning = warning;
+                       else {
+                               Warning = null;
+                               Function = bkpt.GetAttributeValue("func");
+                               //FileName = bkpt.GetAttributeValue("file");
+                               FileFullPath = bkpt.GetAttributeValue("fullname")?.Replace("\\\\", "\\");
+                               Line = int.Parse (bkpt.GetAttributeValue("line")) - 1;
+
+                               /*if (project.TryGetProjectFileFromPath(FileFullName, out ProjectFileNode pf))
+                                       File = pf as CSProjectItem;*/
+
+                       }                       
+               }
+
+               public override string ToString() => $"{Index}:{Type} {FileFullPath}:{Line} enabled:{IsEnabled}";
+               private string GetDebuggerDisplay() => ToString();
+       }
+}
diff --git a/plugins/CENetcoreDbgPlugin/src/CLRAddress.cs b/plugins/CENetcoreDbgPlugin/src/CLRAddress.cs
new file mode 100644 (file)
index 0000000..ec4dc71
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System.Diagnostics;
+
+namespace NetcoreDbgPlugin
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public class CLRAddress
+       {
+               public string ModuleID;
+               public string MethodToken;
+               public long IlOffset;
+               public long NativeOffset;
+               public CLRAddress(MITupple clrAddress)
+               {
+                       ModuleID = clrAddress.GetAttributeValue("module-id");
+                       MethodToken = clrAddress.GetAttributeValue("method-token");
+                       IlOffset = long.Parse(clrAddress.GetAttributeValue("il-offset"));
+                       NativeOffset = long.Parse(clrAddress.GetAttributeValue("native-offset"));
+               }
+               public override string ToString() => $"Mod:{ModuleID} Meth:{MethodToken} IL:{IlOffset} Native:{NativeOffset}";
+               private string GetDebuggerDisplay() => ToString();
+       }
+}
diff --git a/plugins/CENetcoreDbgPlugin/src/MIObjects.cs b/plugins/CENetcoreDbgPlugin/src/MIObjects.cs
new file mode 100644 (file)
index 0000000..99d5ab9
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+
+namespace NetcoreDbgPlugin
+{
+               [DebuggerDisplay("{Name}")]
+               public class MIObject
+               {
+                       public string Name;
+                       public MIObject(ReadOnlySpan<char> name)
+                       {
+                               Name = name.ToString();
+                       }
+               }
+               [DebuggerDisplay("{Name}={Value}")]
+               public class MIAttribute : MIObject
+               {
+                       public string Value;
+                       public MIAttribute(ReadOnlySpan<char> name, ReadOnlySpan<char> value) : base(name)
+                       {
+                               Value = value.ToString();
+                       }
+                       public T GetValue<T>()
+                       {
+                               Type type = typeof(T);
+                               if (type == typeof(string))
+                                       return (T)(object)Value;
+                               if (type.IsEnum)
+                               {
+                                       return (T)Enum.Parse(typeof(T), Value);
+                               }
+                               else
+                               {
+                                       MethodInfo miParse = type.GetMethod("Parse", new Type[] { typeof(string) });
+                                       if (miParse != null)
+                                               return (T)miParse.Invoke(null, new object[] { Value });
+                               }
+                               return (T)Convert.ChangeType(Value, type);
+                       }
+               }
+               [DebuggerDisplay("{Name} ({Attributes.Count})")]
+               public class MITupple : MIObject
+               {
+                       public List<MIObject> Attributes = new List<MIObject>();
+                       public MITupple(ReadOnlySpan<char> name) : base(name) { }
+
+                       public MIObject this[string attributeName]
+                               => Attributes.FirstOrDefault(a => a.Name == attributeName);
+                       public MIObject this[int index]
+                               => Attributes[index];
+
+                       public string GetAttributeValue(string attributeName)
+                               => Attributes.OfType<MIAttribute>().FirstOrDefault(a => a.Name == attributeName)?.Value;
+                       public bool TryGetAttributeValue(string attributeName, out MIAttribute value)
+                       {
+                               value = Attributes.OfType<MIAttribute>().FirstOrDefault(a => a.Name == attributeName);
+                               return value != null;
+                       }
+                       public bool TryGetAttributeValue(string attributeName, out string value)
+                       {
+                               value = Attributes.OfType<MIAttribute>().FirstOrDefault(a => a.Name == attributeName)?.Value;
+                               return !string.IsNullOrEmpty (value);
+                       }
+
+                       public static MITupple Parse (ReadOnlySpan<char> data)
+                       {
+                               int tokStart = 0;
+                               int curPos = 0;
+
+                               Stack<MIObject> mistack = new Stack<MIObject>();
+                               mistack.Push(new MITupple("Root"));
+                               ReadOnlySpan<char> curName = null;
+                               MITupple tup = null;
+
+                               while (curPos < data.Length)
+                               {
+                                       switch (data[curPos])
+                                       {
+                                               case '[':
+                                                       mistack.Push(new MIList(curName));
+                                                       curName = null;
+                                                       break;
+                                               case '{':
+                                                       mistack.Push(new MITupple(curName));
+                                                       curName = null;
+                                                       break;
+                                               case '}':
+                                                       tup = mistack.Pop() as MITupple;
+                                                       if (mistack.Peek() is MITupple mit)
+                                                               mit.Attributes.Add(tup);
+                                                       else
+                                                               (mistack.Peek() as MIList).Items.Add(tup);
+                                                       break;
+                                               case ']':
+                                                       MIList list = mistack.Pop() as MIList;
+                                                       (mistack.Peek() as MITupple).Attributes.Add(list);
+                                                       break;
+                                               case ',':
+                                                       curName = null;
+                                                       break;
+                                               case '"':
+                                                       tup = mistack.Peek() as MITupple;
+                                                       tokStart = ++curPos;
+                                                       while (curPos < data.Length && !(data[curPos] == '"' && data[curPos-1] != '\\'))
+                                                               curPos++;
+                                                       
+                                                       tup.Attributes.Add(new MIAttribute(curName, data.Slice(tokStart, curPos - tokStart)));
+                                                       break;
+                                               case '=':
+                                                       curName = data.Slice(tokStart, curPos - tokStart);
+                                                       break;
+                                               default:
+                                                       curPos++;
+                                                       continue;
+                                       }
+                                       tokStart = ++curPos;
+                               }
+                               return mistack.Pop() as MITupple;
+                       }
+               }
+               [DebuggerDisplay("{Name} ({Items.Count})")]
+               public class MIList : MIObject
+               {
+                       public List<MITupple> Items = new List<MITupple>();
+                       public MIList(ReadOnlySpan<char> name) : base(name)
+                       {
+                       }
+               }
+
+               
+}
\ No newline at end of file
diff --git a/plugins/CENetcoreDbgPlugin/src/NetcoreDbgService.cs b/plugins/CENetcoreDbgPlugin/src/NetcoreDbgService.cs
new file mode 100644 (file)
index 0000000..639c030
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (c) 2013-2019  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using CrowEditBase;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using static CrowEditBase.CrowEditBase;
+using Crow;
+
+
+namespace NetcoreDbgPlugin
+{      
+       public class NetcoreDbgService : Service {
+               public NetcoreDbgService () : base () {
+               }
+               public string NetcoredbgPath {
+                       get => Configuration.Global.Get<string> ("NetcoredbgPath");
+                       set {
+                               if (value == NetcoredbgPath)
+                                       return;
+                               Configuration.Global.Set ("NetcoredbgPath", value);
+                               NotifyValueChanged (value);
+                       }
+               }
+               NetcoredbgDebugger dbg;
+               public override void Start() {
+                       if (CurrentState == Status.Running)
+                               return;
+                       dbg = new NetcoredbgDebugger ();
+                       CurrentState = Status.Running;
+               }
+               public override void Stop()
+               {
+                       if (CurrentState != Status.Running)
+                               return;
+
+                       dbg.Terminate ();
+                       dbg = null;
+                       CurrentState = Status.Stopped;
+               }
+               public override void Pause()
+               {
+                       if (CurrentState != Status.Running)
+                               return;
+
+                       dbg.Terminate ();
+                       CurrentState = Status.Paused;
+               }
+
+               public override string ConfigurationWindowPath => "#CENetcoreDbgPlugin.ui.winConfiguration.crow";
+       }
+}
\ No newline at end of file
diff --git a/plugins/CENetcoreDbgPlugin/src/NetcoredbgDebugger.cs b/plugins/CENetcoreDbgPlugin/src/NetcoredbgDebugger.cs
new file mode 100644 (file)
index 0000000..16cfdb2
--- /dev/null
@@ -0,0 +1,428 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using CrowEditBase;
+using Crow;
+using CERoslynPlugin;
+
+using static CrowEditBase.CrowEditBase;
+
+namespace NetcoreDbgPlugin
+{
+       public class NetcoredbgDebugger : Debugger
+       {
+               System.Diagnostics.Process procdbg;
+               public class Request {
+                       public readonly string Command;
+                       public Request (string command) {
+                               Command = command;
+                       }
+                       public override string ToString() => Command;
+               }
+               public class Request<T> : Request {
+                       public T RequestObject;
+                       public Request (T obj, string command) : base (command){
+                               RequestObject = obj;
+                       }
+               }
+               Queue<Request> pendingRequest = new Queue<Request>();
+               MSBuildProject msbProject => Project as MSBuildProject;
+
+               public override Project Project
+               {
+                       get => base.Project;
+                       set
+                       {
+                               if (base.Project == value || !(value is MSBuildProject msbProj))
+                                       return;
+                               base.Project = value;                           
+                       }
+               }
+               void initDebugSession () {
+                       if (CurrentState != Status.Init || msbProject == null)
+                               return;
+                       
+                       bool result = procdbg.Start();
+
+                       procdbg.BeginOutputReadLine();
+
+                       CreateNewRequest($"-file-exec-and-symbols {msbProject.OutputAssembly}");
+                       CreateNewRequest($"-environment-cd {Path.GetDirectoryName(msbProject.OutputAssembly)}");
+
+                       foreach (BreakPoint bp in BreakPoints)
+                               InsertBreakPoint(bp);
+
+                       CurrentState = Status.Starting;
+               }
+               #region CTOR
+               public NetcoredbgDebugger()
+               {
+                       procdbg = new System.Diagnostics.Process();
+                       procdbg.StartInfo.FileName = App.GetService<NetcoreDbgService>().NetcoredbgPath;
+                       procdbg.StartInfo.Arguments = "--interpreter=mi";
+                       procdbg.StartInfo.CreateNoWindow = true;
+                       procdbg.StartInfo.RedirectStandardInput = true;
+                       procdbg.StartInfo.RedirectStandardOutput = true;
+                       procdbg.StartInfo.RedirectStandardError = true;
+                       procdbg.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
+                       //procdbg.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8;
+                       procdbg.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
+
+                       procdbg.EnableRaisingEvents = true;
+                       procdbg.OutputDataReceived += Procdbg_OutputDataReceived;
+                       procdbg.ErrorDataReceived += Procdbg_ErrorDataReceived;
+                       procdbg.Exited += Procdbg_Exited;
+
+                       BreakPoints.ListAdd += BreakPoints_ListAdd;
+                       BreakPoints.ListRemove += BreakPoints_ListRemove;
+               }
+               #endregion
+
+               public void Terminate ()  {
+                       if (CurrentState == Status.Running || CurrentState == Status.Stopped)
+                               Stop ();
+                       procdbg?.Dispose();
+               }
+               /*protected override void ResetCurrentExecutingLocation()
+               {
+                       if (executingFile == null)
+                               return;
+                       executingFile.ExecutingLine = -1;
+                       executingFile = null;
+               }*/
+               /// <summary>
+               /// send request on netcoredbg process stdin
+               /// </summary>
+               void sendRequest(Request request)
+               {
+                       DebuggerLog.Add($"<- {request}");
+                       procdbg.StandardInput.WriteLine(request);
+               }
+
+               /// <summary>
+               /// enqueue new request, send it if no other request is pending
+               /// </summary>
+               public void CreateNewRequest(string request)
+               {
+                       lock (pendingRequest)
+                       {
+                               pendingRequest.Enqueue(new Request (request));
+                               if (pendingRequest.Count == 1)
+                                       sendRequest(pendingRequest.Peek());
+                       }
+               }
+               public void CreateNewRequest(Request request)
+               {
+                       lock (pendingRequest)
+                       {
+                               pendingRequest.Enqueue(request);
+                               if (pendingRequest.Count == 1)
+                                       sendRequest(pendingRequest.Peek());
+                       }
+               }
+
+               #region Debugger abstract class implementation
+               public override void Start()
+               {
+                       initDebugSession ();
+                       CreateNewRequest($"-exec-run");
+               }
+               public override void Pause()
+               {
+                       CreateNewRequest($"-exec-interrupt");
+               }
+               public override void Continue()
+               {
+                       CreateNewRequest($"-exec-continue");
+               }
+               public override void Stop()
+               {
+                       CreateNewRequest($"-exec-abort");                       
+               }
+
+               public override void StepIn()
+               {
+                       CreateNewRequest($"-exec-step");
+               }
+               public override void StepOver()
+               {
+                       CreateNewRequest($"-exec-next");
+               }
+               public override void StepOut()
+               {
+                       CreateNewRequest($"-exec-finish");
+               }
+
+               public override void InsertBreakPoint(CrowEditBase.BreakPoint bp)
+               {
+                       BreakPoint bk = bp as BreakPoint;
+                       CreateNewRequest (new Request<BreakPoint> (bk, $"-break-insert {bk.FileFullPath}:{bk.Line + 1}"));
+               }
+               public override void DeleteBreakPoint(CrowEditBase.BreakPoint bp)
+               {
+                       if (bp.Index < 0)
+                               return;
+                       CreateNewRequest($"-break-delete {bp.Index}");
+               }
+               protected override void onCurrentFrameChanged () {
+                               if (CurrentFrame == null)
+                                       return;
+                               tryGoTo((StackFrame)CurrentFrame);
+                               updateWatches ();
+               }
+               protected override void onCurrentThreadChanged () {
+                               if (CurrentThread == null)
+                                       return;
+                               getStackFrames((ThreadInfo)CurrentThread);
+                               updateWatches ();
+               }
+               #endregion
+
+               public void GetStackFrames(MIList list)
+               {
+
+               }
+
+               private void BreakPoints_ListRemove(object sender, ListChangedEventArg e)
+               {
+                       if (CurrentState == Status.Init)
+                               return;
+                       DeleteBreakPoint((BreakPoint)e.Element);
+               }
+               private void BreakPoints_ListAdd(object sender, ListChangedEventArg e)
+               {
+                       if (CurrentState == Status.Init)
+                               return;
+                       InsertBreakPoint((BreakPoint)e.Element);
+               }
+               private void Procdbg_Exited(object sender, EventArgs e)
+               {
+                       DebuggerLog.Add("GDB process Terminated.");
+                       
+                       CurrentState = Status.Init;
+               }
+               
+               void getStackFrames(ThreadInfo thread = null)
+               {
+                       if (thread == null)
+                               CreateNewRequest($"-stack-list-frames");
+                       else
+                               CreateNewRequest($"-stack-list-frames --thread {thread.Id}");
+               }
+               void getVariables(ThreadInfo thread = null, int stackLevel = 0)
+               {
+                       CreateNewRequest($"-stack-list-variables");
+               }
+               void updateWatches () {
+                       foreach (Watch w in Watches)
+                               w.UpdateValue ();                       
+               }
+
+               void tryGoTo(StackFrame frame)
+               {
+                       /*if (string.IsNullOrEmpty(frame.FileFullName))
+                               return;
+                       executingLine = frame.Line - 1;
+                       string strPath = frame.FileFullName;
+
+                       if (project.TryGetProjectFileFromPath(strPath, out ProjectFileNode pf))
+                       {
+                               if (!pf.IsOpened)
+                                       pf.Open();
+                               pf.IsSelected = true;
+
+                               executingFile = pf as CSProjectItem;
+                               executingFile.ExecutingLine = executingLine;
+                               executingFile.CurrentLine = executingLine;
+                       }
+                       else
+                       {
+                               ResetCurrentExecutingLocation();
+                               DebuggerLog.Add($"[ERROR]:current executing file ({strPath}) not found.");
+                       }*/
+               }
+               bool hasPendingRequest {
+                       get {
+                               lock (pendingRequest) {
+                                       return pendingRequest.Count > 0;
+                               }
+                       }
+               }
+
+               void Procdbg_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e) {
+                       DebuggerLog.Add($"-> Error: {e.Data}");
+               }               
+
+               void Procdbg_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e) {
+                       if (string.IsNullOrEmpty(e.Data))
+                               return;
+
+                       DebuggerLog.Add($"-> {e.Data}");
+
+                       char firstChar = e.Data[0];
+                       ReadOnlySpan<char> data = e.Data.AsSpan(1);
+
+                       if (firstChar == '(')
+                               return;
+
+                       int tokEnd = data.IndexOf(',');
+
+                       ReadOnlySpan<char> data_id = tokEnd < 0 ? data : data.Slice(0, tokEnd);
+                       if (tokEnd >= 0)
+                               data = data.Slice(tokEnd + 1);
+
+                       MITupple obj = MITupple.Parse (data);
+
+                       if (firstChar == '^')
+                       {
+                               Request request = null;
+                               lock (pendingRequest)
+                               {
+                                       if (pendingRequest.Count > 0)
+                                       {
+                                               request = pendingRequest.Dequeue();
+                                               if (pendingRequest.Count > 0)
+                                                       sendRequest(pendingRequest.Peek());
+                                       }
+                               }
+
+                               if (data_id.SequenceEqual("running"))
+                               {
+                                       CurrentState = Status.Running;
+                                       CurrentFrame = null;
+                                       CurrentThread = null;
+                                       Threads.Clear();
+                                       Frames.Clear();
+                               }
+                               else if (data_id.SequenceEqual("done"))
+                               {
+                                       if (obj.Attributes.Count > 0)
+                                       {
+                                               if (obj[0].Name == "threads") {
+                                                       MIList threads = obj[0] as MIList;
+                                                       Threads.Clear();
+                                                       foreach (MITupple t in threads.Items)
+                                                               Threads.Add(new ThreadInfo(t));
+                                               } else if (obj[0].Name == "stack") {
+                                                       MIList stack = obj[0] as MIList;
+                                                       Frames.Clear();
+                                                       foreach (MITupple f in stack.Items)
+                                                               Frames.Add(new StackFrame(f));
+                                               } else if (request is Request<Watch> w) {
+                                                       /*if (w.Command.StartsWith ("-var-delete")) {
+                                                               Watches.Remove (w.RequestObject);
+                                                       } else*/
+                                                       if (w.Command.StartsWith("-var-list-children")) {
+                                                               if (int.Parse (obj.GetAttributeValue ("numchild")) > 0) {
+                                                                       foreach (MITupple child in (obj["children"] as MIList).Items)
+                                                                               w.RequestObject.Children.Add(new Watch(this, child));
+                                                               }
+                                                       } else if (w.Command.StartsWith ("-var-evaluate"))
+                                                               w.RequestObject.Value = obj.GetAttributeValue("value");
+                                                       else
+                                                               w.RequestObject.Update (obj);
+                                               } else if (request is Request<BreakPoint> bpReq) {
+                                                       BreakPoint bp = bpReq.RequestObject;
+                                                       bp.Update (obj["bkpt"] as MITupple);
+                                                       
+                                               } else
+                                                       DebuggerLog.Add($"=> request result not handled: {request}");
+                                       }
+
+
+                               }
+                               else if (data_id.SequenceEqual("exit"))
+                               {
+                                       DebuggerLog.Add($"=> exit request done: {request}");
+                                       CreateNewRequest($"-gdb-exit");
+                               }
+                               else
+                                       print_unknown_datas($"requested: {request} data:{e.Data}");
+
+                       }
+                       else if (firstChar == '*')
+                       {
+                               if (data_id.SequenceEqual("stopped"))
+                               {
+                                       CurrentState = Status.Stopped;
+                                       string reason = obj.GetAttributeValue("reason");
+                                       if (reason == "exited")
+                                       {
+                                               CurrentState = Status.Ready;
+                                               DebuggerLog.Add($"Exited({obj.GetAttributeValue("exit-code")})");
+                                               //CreateNewRequest($"-gdb-exit");
+                                       }
+                                       else if (reason == "entry-point-hit" && !BreakOnStartup) {
+                                               Continue();
+                                       } else {
+                                               DebuggerLog.Add($"Stopped reason:{reason}");
+
+                                               StackFrame frame = new StackFrame(obj["frame"] as MITupple);
+                                               if (reason == "breakpoint-hit") {                                                       
+                                                       BreakPoint bp = (BreakPoint)BreakPoints.FirstOrDefault (bk=>bk.Index == int.Parse (obj.GetAttributeValue ("bkptno")));
+                                                       bp.UpdateLocation (frame);
+                                               }
+
+                                               tryGoTo(frame);
+
+                                               CreateNewRequest($"-thread-info");
+                                               getStackFrames();
+                                               getVariables();
+                                               updateWatches ();
+                                       }
+
+                               } else
+                                       print_unknown_datas(e.Data);
+                       } else if (firstChar == '=') {//EVENTS
+                               if (data_id.SequenceEqual("message")) {
+                                       OutputLog.Add(obj.GetAttributeValue("text").ToString().Replace(@"\0", ""));
+                               } else if (data_id.SequenceEqual("breakpoint-modified")) {
+                                       OutputLog.Add($"{e.Data}");
+                                       MITupple bkpt = obj["bkpt"] as MITupple;
+                                       BreakPoint bp = (BreakPoint)BreakPoints.FirstOrDefault (bk=>bk.Index == int.Parse (bkpt.GetAttributeValue("number")));
+                                       bp.Update (bkpt);
+                               }
+                       } else
+                               print_unknown_datas(e.Data);
+               }
+
+               void print_unknown_datas(string data)
+               {
+                       Console.ForegroundColor = ConsoleColor.Red;
+                       Console.WriteLine(data);
+                       Console.ResetColor();
+               }
+
+               public void WatchRequest(Watch w)
+               {
+                       string strThread = CurrentThread == null ? "" : $"--thread {CurrentThread.Id}";
+                       string strLevel = CurrentFrame == null ? "" : $"--frame {CurrentFrame.Level}";
+                       CreateNewRequest (new Request<Watch> (w, $"-var-create {w.Name} {w.Expression} {strThread} {strLevel}"));
+               }
+               public void WatchChildrenRequest(Watch w)
+               {                       
+                       string strThread = CurrentThread == null ? "" : $"--thread {CurrentThread.Id}";
+                       string strLevel = CurrentFrame == null ? "" : $"--frame {CurrentFrame.Level}";                  
+                       CreateNewRequest (new Request<Watch> (w, $"-var-list-children 1 {w.Name} {strThread} {strLevel}"));
+               }
+
+               public void OnValidateCommand(Object sender, ValidateEventArgs e)
+               {
+                       CreateNewRequest(e.ValidatedText);
+                       (sender as TextBox).Text = "";
+               }
+
+               public void OnValidateNewWatch(Object sender, ValidateEventArgs e)
+               {
+                       Watch w = new Watch(this, e.ValidatedText);
+                       Watches.Add(w);
+                       WatchRequest(w);
+                       (sender as TextBox).Text = "";
+               }
+
+       }
+}
diff --git a/plugins/CENetcoreDbgPlugin/src/StackFrame.cs b/plugins/CENetcoreDbgPlugin/src/StackFrame.cs
new file mode 100644 (file)
index 0000000..afa2e42
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System.Diagnostics;
+
+namespace NetcoreDbgPlugin
+{
+       [DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
+       public class StackFrame : CrowEditBase.StackFrame
+       {
+               public bool HasCLRAddress => ClrAddress != null;
+               public CLRAddress ClrAddress;
+
+               public StackFrame(MITupple frame)
+               {
+                       if (frame.TryGetAttributeValue("level", out MIAttribute level))
+                               this.Level = int.Parse(level.Value);
+                       //File = frame.GetAttributeValue("file");
+                       FileFullPath = frame.GetAttributeValue("fullname")?.Replace("\\\\", "\\");
+                       int.TryParse(frame.GetAttributeValue("line"), out Line);
+                       int.TryParse(frame.GetAttributeValue("col"), out Column);
+                       int.TryParse(frame.GetAttributeValue("end-line"), out LineEnd);
+                       int.TryParse(frame.GetAttributeValue("end-col"), out ColumnEnd);
+                       Function = frame.GetAttributeValue("func");
+                       Address = frame.GetAttributeValue("addr");
+                       MITupple clrAddrs = frame["clr-addr"] as MITupple;
+                       if (clrAddrs != null)
+                               ClrAddress = new CLRAddress(clrAddrs);
+               }
+               public override string ToString() => $"{Level}:{FileFullPath}({Line},{Column} {Function})";
+               string GetDebuggerDisplay() => ToString();
+       }                       
+}
diff --git a/plugins/CENetcoreDbgPlugin/src/ThreadInfo.cs b/plugins/CENetcoreDbgPlugin/src/ThreadInfo.cs
new file mode 100644 (file)
index 0000000..739c42b
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System.Diagnostics;
+
+namespace NetcoreDbgPlugin
+{
+       public class ThreadInfo : CrowEditBase.ThreadInfo
+       {
+               public ThreadInfo(MITupple frame)
+               {
+                       Id = int.Parse(frame.GetAttributeValue("id"));
+                       Name = frame.GetAttributeValue("name");
+                       IsStopped = frame.GetAttributeValue("state") == "stopped";
+               }
+       }
+}
diff --git a/plugins/CENetcoreDbgPlugin/src/Watch.cs b/plugins/CENetcoreDbgPlugin/src/Watch.cs
new file mode 100644 (file)
index 0000000..6ad2db4
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Diagnostics;
+//using static Crow.Coding.NetcoredbgDebugger;
+using Crow;
+
+namespace NetcoreDbgPlugin
+{      
+       public class Watch : CrowEditBase.Watch {
+               static int curId;
+
+               NetcoredbgDebugger dbg;
+       
+               protected override void onExpand() {
+                       if (HasChildren && Children.Count == 0)
+                               dbg.WatchChildrenRequest (this);
+               }
+
+
+               public override void Create()
+               {
+               }
+               public override void Delete()
+               {                       
+                       dbg.CreateNewRequest (new NetcoredbgDebugger.Request<Watch> (this, $"-var-delete {Name}"));
+                       dbg.Watches.Remove (this);
+               }
+               public override void UpdateValue () {
+                       string strThread = dbg.CurrentThread == null ? "" : $"--thread {dbg.CurrentThread.Id}";
+                       string strLevel = dbg.CurrentFrame == null ? "" : $"--frame {dbg.CurrentFrame.Level}";
+                       dbg.CreateNewRequest (new NetcoredbgDebugger.Request<Watch> (this, $"-var-evaluate-expression {Name} {strThread} {strLevel}"));
+                       foreach (Watch w in Children)
+                               w.UpdateValue ();
+               }
+               public Watch(NetcoredbgDebugger debugger, string expression)
+               {
+                       dbg = debugger;
+                       Name = $"watch_{curId++}";
+                       Expression = expression;
+               }
+               public Watch(NetcoredbgDebugger debugger, MITupple variable)
+               {
+                       dbg = debugger;
+                       Update (variable);
+               }
+               public void Update (MITupple variable)
+               {
+                       Name = variable.GetAttributeValue("name");
+                       Expression = variable.GetAttributeValue("exp");
+                       Value = variable.GetAttributeValue("value");
+                       IsEditable = variable.GetAttributeValue("attributes") == "editable";
+                       Type = variable.GetAttributeValue("type");
+                       NumChild = int.Parse(variable.GetAttributeValue("numchild"));
+                       ThreadId = int.Parse(variable.GetAttributeValue("thread-id"));
+                       NotifyValueChanged ("HasChildren", HasChildren);
+               }
+       }
+}
diff --git a/plugins/CENetcoreDbgPlugin/ui/winConfiguration.crow b/plugins/CENetcoreDbgPlugin/ui/winConfiguration.crow
new file mode 100644 (file)
index 0000000..b929424
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<DockWindow Caption="Roslyn plugin configuration"  Width="300" Height="400" Resizable="false">
+       <VerticalStack RootDataLevel="true" Margin="5">
+               <HorizontalStack Height="Fit">
+                       <Label Width="200" Text="DotNet SDK folder"/>
+                       <TextBox Width="Stretched" Text="{²SDKFolder}"/>
+                       <Button Command="{CMDOptions_SelectSDKFolder}" MinimumSize="0,0"/>
+               </HorizontalStack>
+               <HorizontalStack Height="Fit">
+                       <Label Width="200" Text="MSBuild root folder"/>
+                       <TextBox Width="Stretched" Text="{²MSBuildRoot}"/>
+                       <Button Command="{CMDOptions_SelectMSBuildRoot}" MinimumSize="0,0"/>
+               </HorizontalStack>
+               <HorizontalStack Height="Fit">
+                       <Label Width="200" Text="Netcoredbg path"/>
+                       <TextBox Width="Stretched" Text="{²NetcoredbgPath}"/>
+                       <Button Command="{CMDOptions_SelectNetcoredbgPath}" MinimumSize="0,0"/>
+               </HorizontalStack>
+       </VerticalStack>
+</DockWindow>
+
+
diff --git a/plugins/CENetcoreDbgPlugin/ui/winSolution.crow b/plugins/CENetcoreDbgPlugin/ui/winSolution.crow
new file mode 100644 (file)
index 0000000..c9ae6e5
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+
+
+
index 3f8e601898706ae438b3c14edf188917cd922d19..7bd9218f481f2b6fd05dc62dfd2f105b404a96c0 100644 (file)
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
-               <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
-               <EnableDefaultItems>false</EnableDefaultItems>
-               <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
+               <TargetFrameworks>netcoreapp5</TargetFrameworks>
+               <EnableDefaultItems>false</EnableDefaultItems>          
        </PropertyGroup>
        
        <ItemGroup>
                <Compile Include="src\**\*.cs" />
+               <EmbeddedResource Include="ui\**\*.*" />
                <EmbeddedResource Include="default.conf" />
        </ItemGroup>
        <ItemGroup>
        </ItemGroup>
        <ItemGroup>
                <PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
-               <PackageReference Include="Microsoft.Build" Version="16.8.*">
+               <PackageReference Include="Microsoft.Build" Version="15.1.*">
                        <PrivateAssets>all</PrivateAssets>
                        <Private>true</Private>
+                        <Visible>False</Visible>
                        <ExcludeAssets>runtime</ExcludeAssets>
                </PackageReference>
-               <PackageReference Include="Microsoft.Build.Framework" Version="16.8.*">
+               <PackageReference Include="Microsoft.Build.Framework" Version="15.1.*">
                        <PrivateAssets>all</PrivateAssets>
+                       <Visible>False</Visible>
                        <Private>true</Private>
                        <ExcludeAssets>runtime</ExcludeAssets>
                </PackageReference>
-               <PackageReference Include="Microsoft.Build.Tasks.Core" Version="16.8.*">
+               <PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.1.*">
                        <PrivateAssets>all</PrivateAssets>
+                       <Visible>False</Visible>
                        <Private>true</Private>
                        <ExcludeAssets>runtime</ExcludeAssets>
                </PackageReference>
-               <PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.8.*">
+               <PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.1.*">
                        <PrivateAssets>all</PrivateAssets>
+                       <Visible>False</Visible>
                        <Private>true</Private>
                        <ExcludeAssets>runtime</ExcludeAssets>
                </PackageReference>
        </ItemGroup>
 
        <ItemGroup>    
-               <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.8.0-5.final" >
-                       <IncludeAssets>all</IncludeAssets>
-               </PackageReference>
-               <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0-5.final" >
-                       <IncludeAssets>all</IncludeAssets>
-               </PackageReference>
-               <PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.8.0-5.final" >
-                       <IncludeAssets>all</IncludeAssets>
-               </PackageReference>
-               <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.8.0-5.final" >
+               <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.7.*" >
                        <IncludeAssets>all</IncludeAssets>
+                       <PrivateAssets>all</PrivateAssets>
+                       <ExcludeAssets>runtime</ExcludeAssets>
+                       <Visible>False</Visible>
                </PackageReference>
-               <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="3.8.0-5.final" >
+               <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.7.*" >
                        <IncludeAssets>all</IncludeAssets>
+                       <PrivateAssets>all</PrivateAssets>
+                       <ExcludeAssets>runtime</ExcludeAssets>
+                       <Visible>False</Visible>
                </PackageReference>
                <!--<PackageReference Include="Microsoft.VisualStudio.TestPlatform.ObjectModel" />-->
        </ItemGroup>    
diff --git a/plugins/CERoslynPlugin/src/CELogger.cs b/plugins/CERoslynPlugin/src/CELogger.cs
new file mode 100644 (file)
index 0000000..7d7a56c
--- /dev/null
@@ -0,0 +1,182 @@
+using System.Reflection;
+// Copyright (c) 2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Diagnostics;
+using System.Linq;
+using Crow;
+using System.Text.RegularExpressions;
+using Microsoft.Build.Framework;
+
+using static CrowEditBase.CrowEditBase;
+
+namespace CERoslynPlugin
+{
+       internal class CELogger : ILogger
+       {
+               IEventSource eventSource;
+               LoggerVerbosity verbosity;
+
+               public LoggerVerbosity Verbosity {
+                       get => verbosity;
+                       set {
+                               if (verbosity == value)
+                                       return;
+                               if (eventSource != null)
+                                       unregisterHandles ();
+                               verbosity = value;
+                               if (eventSource != null)
+                                       registerHandles ();
+                       }
+               } 
+               public string Parameters { get; set; }
+
+               public CELogger (LoggerVerbosity verbosity = LoggerVerbosity.Detailed)
+               {                       
+                       this.verbosity = verbosity;
+               }
+               public void Initialize (IEventSource eventSource) {
+                       this.eventSource = eventSource;
+                       registerHandles ();
+               }
+
+
+               void registerHandles () {
+                       eventSource.WarningRaised += EventSource_WarningRaised;
+                       eventSource.ErrorRaised += EventSource_ErrorRaised;
+                       eventSource.BuildStarted += EventSource_Progress_BuildStarted;
+                       eventSource.BuildFinished += EventSource_Progress_BuildFinished;
+
+                       switch (Verbosity) {
+                       case LoggerVerbosity.Minimal:
+                               eventSource.MessageRaised += EventSource_MessageRaised_Minimal;
+                               break;
+                       case LoggerVerbosity.Normal:
+                               eventSource.MessageRaised += EventSource_MessageRaised_Normal;
+                               eventSource.ProjectStarted += EventSource_ProjectStarted;
+                               eventSource.ProjectFinished += EventSource_ProjectFinished;
+                               break;
+                       case LoggerVerbosity.Detailed:
+                               eventSource.MessageRaised += EventSource_MessageRaised_All;
+                               eventSource.ProjectStarted += EventSource_ProjectStarted;
+                               eventSource.ProjectFinished += EventSource_ProjectFinished;
+                               eventSource.TargetStarted += EventSource_TargetStarted;
+                               eventSource.TargetFinished += EventSource_TargetFinished;
+                               eventSource.TaskStarted += EventSource_TaskStarted;
+                               eventSource.TaskFinished += EventSource_TaskFinished;
+                               break;
+                       case LoggerVerbosity.Diagnostic:
+                               eventSource.AnyEventRaised += EventSource_AnyEventRaised;
+                               break;
+                       }
+               }
+
+               void unregisterHandles () {
+                       eventSource.WarningRaised -= EventSource_WarningRaised;
+                       eventSource.ErrorRaised -= EventSource_ErrorRaised;
+
+
+                       switch (Verbosity) {
+                       case LoggerVerbosity.Minimal:
+                               eventSource.MessageRaised -= EventSource_MessageRaised_Minimal;
+                               break;
+                       case LoggerVerbosity.Normal:
+                               eventSource.MessageRaised -= EventSource_MessageRaised_Normal;
+                               eventSource.ProjectStarted -= EventSource_ProjectStarted;
+                               eventSource.ProjectFinished -= EventSource_ProjectFinished;
+                               break;
+                       case LoggerVerbosity.Detailed:
+                               eventSource.MessageRaised -= EventSource_MessageRaised_All;
+                               eventSource.ProjectStarted -= EventSource_ProjectStarted;
+                               eventSource.ProjectFinished -= EventSource_ProjectFinished;
+                               eventSource.TargetStarted -= EventSource_TargetStarted;
+                               eventSource.TargetFinished -= EventSource_TargetFinished;
+                               eventSource.TaskStarted -= EventSource_TaskStarted;
+                               eventSource.TaskFinished -= EventSource_TaskFinished;
+                               break;
+                       case LoggerVerbosity.Diagnostic:
+                               eventSource.AnyEventRaised -= EventSource_AnyEventRaised;
+                               break;
+                       }
+
+               }
+               void log (LogType type, string message) {
+                       string[] lines = Regex.Split (message, "\r\n|\r|\n");//|\r|\n|\\\\n");
+                       for     (int i=0; i<lines.Length;i++)
+                               App.Log (type, lines[i]);
+               }
+               void EventSource_Progress_BuildStarted (object sender, BuildStartedEventArgs e)
+               {
+                       App.ResetLog ();
+                       log (LogType.High, "Build starting.");
+               }
+               void EventSource_Progress_BuildFinished (object sender, BuildFinishedEventArgs e)
+               {
+                       log (LogType.High, "Build Finished.");
+                       //ide.CurrentSolution.RaiseDiagnosticsValueChanged();
+               }               
+
+        private void EventSource_TaskFinished (object sender, TaskFinishedEventArgs e) {
+                       log (LogType.Custom1, e.Message);
+               }
+
+               private void EventSource_TaskStarted (object sender, TaskStartedEventArgs e) {
+                       log (LogType.Custom1, e.Message);
+               }
+
+               private void EventSource_TargetFinished (object sender, TargetFinishedEventArgs e) {                    
+                       log (LogType.Custom2, e.Message);
+               }
+
+               private void EventSource_TargetStarted (object sender, TargetStartedEventArgs e) {
+                       log (LogType.Custom2, e.Message);
+               }
+               private void EventSource_MessageRaised (object sender, BuildMessageEventArgs e) {
+                       log (LogType.Normal, e.Message);
+               }
+        private void EventSource_AnyEventRaised (object sender, BuildEventArgs e) {
+                       log (LogType.Normal, e.Message);
+               }
+
+        private void EventSource_MessageRaised_Minimal (object sender, BuildMessageEventArgs e) {
+                       if (e.Importance == MessageImportance.High)
+                               log (LogType.High, e.Message);
+               }
+               private void EventSource_MessageRaised_Normal (object sender, BuildMessageEventArgs e) {
+                       if (e.Importance == MessageImportance.Normal)
+                               log (LogType.Normal, e.Message);
+                       else if(e.Importance == MessageImportance.High)
+                               log (LogType.High, e.Message);
+               }
+               private void EventSource_MessageRaised_All (object sender, BuildMessageEventArgs e) {                   
+                       if (e.Importance == MessageImportance.Low)
+                               log (LogType.Low, e.Message);
+                       else if(e.Importance == MessageImportance.Normal)
+                               log (LogType.Normal, e.Message);
+                       else if(e.Importance == MessageImportance.High)
+                               log (LogType.High, e.Message);
+               }
+               void EventSource_ProjectStarted (object sender, ProjectStartedEventArgs e)
+               {
+                       log (LogType.High, e.Message);
+               }
+               void EventSource_ProjectFinished (object sender, ProjectFinishedEventArgs e)
+               {
+                       log (LogType.High, e.Message);
+               }
+               void EventSource_ErrorRaised (object sender, BuildErrorEventArgs e)
+               {
+                       log (LogType.Error, e.Message);
+               }
+               private void EventSource_WarningRaised (object sender, BuildWarningEventArgs e) {
+                       log (LogType.Warning, e.Message);
+               }
+
+               public void Shutdown ()
+               {
+                       if (eventSource != null)
+                               unregisterHandles ();
+               }
+       }
+}
index 73c81f27de05b4d1a0cb7ee25220b119211cc0d8..6f033c174975316f4dad3b0c35b2aa45e06adbb0 100644 (file)
@@ -10,7 +10,7 @@ using Microsoft.Build.Framework;
 
 namespace CERoslynPlugin
 {
-       public class ConsoleLogger : ILogger
+       internal class ConsoleLogger : ILogger
        {
                IEventSource eventSource;
                LoggerVerbosity verbosity;
@@ -29,7 +29,7 @@ namespace CERoslynPlugin
                } 
                public string Parameters { get; set; }
 
-               public ConsoleLogger (LoggerVerbosity verbosity = LoggerVerbosity.Diagnostic)
+               public ConsoleLogger (LoggerVerbosity verbosity = LoggerVerbosity.Normal)
                {                       
                        this.verbosity = verbosity;
                }
@@ -140,10 +140,14 @@ namespace CERoslynPlugin
                }
                void EventSource_ErrorRaised (object sender, BuildErrorEventArgs e)
                {
+                       Console.ForegroundColor = ConsoleColor.DarkRed;
                        Console.WriteLine (e.Message);
+                       Console.ResetColor();
                }
                private void EventSource_WarningRaised (object sender, BuildWarningEventArgs e) {
+                       Console.ForegroundColor = ConsoleColor.DarkYellow;
                        Console.WriteLine (e.Message);
+                       Console.ResetColor();
                }
 
                public void Shutdown ()
index 0077bf7267b30d1648ef8ef0cb046827214dd393..084b25539f7b8df3c815ad5a3369698847c11aa5 100644 (file)
@@ -9,6 +9,7 @@ using System.Threading;
 using Crow;
 using System.Reflection;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Collections.Generic;
 
 using Microsoft.Build.Construction;
@@ -20,6 +21,7 @@ using CrowEditBase;
 using static CrowEditBase.CrowEditBase;
 
 using Project = CrowEditBase.Project;
+using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.CSharp;
 
 namespace CERoslynPlugin
@@ -29,52 +31,63 @@ namespace CERoslynPlugin
                SolutionProject solutionProject;
                Microsoft.Build.Evaluation.Project project;
                CSharpCompilationOptions compileOptions;
-               public CSharpParseOptions parseOptions;
-
-               public override string Name => projectInSolution.ProjectName;
+               CSharpParseOptions parseOptions;
+               
                public string RootDir => project.DirectoryPath;
 
-               public MSBuildProject (SolutionProject solution, ProjectInSolution projectInSolution) : base (projectInSolution.AbsolutePath) {
+               static string[] defaultTargets = { "Restore", "Build", "Rebuild", "Pack", "Publish"};
+
+               internal MSBuildProject (SolutionProject solution, ProjectInSolution projectInSolution) : base (projectInSolution.AbsolutePath) {
                        this.projectInSolution = projectInSolution;
                        this.solutionProject = solution;
 
                        Load ();
+
+                       commands = new CommandGroup (CMDLoad, CMDUnload, CMDReload);
+                       foreach (string target in defaultTargets)
+                               Commands.Add (new Crow.Command (target, () => Build (target)));
                }
 
+               CommandGroup commands;
+
+               public override CommandGroup Commands => commands;
+
                public override void Load () {
                        if (IsLoaded)
                                return;
                        try
                        {
-                               ProjectRootElement projectRootElt = ProjectRootElement.Open (projectInSolution.AbsolutePath);
-                               project = new Microsoft.Build.Evaluation.Project (projectInSolution.AbsolutePath, null, null, solutionProject.projectCollection);
+                               using (var ctx = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext (this.GetType().Assembly).EnterContextualReflection()) {
+                                       ProjectRootElement projectRootElt = ProjectRootElement.Open (projectInSolution.AbsolutePath);
+                                       project = new Microsoft.Build.Evaluation.Project (projectInSolution.AbsolutePath, null, null, solutionProject.projectCollection);
 
-                               ProjectProperty msbuildProjExtPath = project.GetProperty ("MSBuildProjectExtensionsPath");
-                               ProjectProperty msbuildProjFile = project.GetProperty ("MSBuildProjectFile");                   
+                                       ProjectProperty msbuildProjExtPath = project.GetProperty ("MSBuildProjectExtensionsPath");
+                                       ProjectProperty msbuildProjFile = project.GetProperty ("MSBuildProjectFile");                   
 
-                               string[] props = { "EnableDefaultItems", "EnableDefaultCompileItems", "EnableDefaultNoneItems", "EnableDefaultEmbeddedResourceItems" };
+                                       string[] props = { "EnableDefaultItems", "EnableDefaultCompileItems", "EnableDefaultNoneItems", "EnableDefaultEmbeddedResourceItems" };
 
-                               foreach (string pr in props) {
-                                       ProjectProperty pp = project.AllEvaluatedProperties.Where (ep => ep.Name == pr).FirstOrDefault ();
-                                       if (pp == null)
-                                               project.SetProperty (pr, "true");
-                               }
+                                       foreach (string pr in props) {
+                                               ProjectProperty pp = project.AllEvaluatedProperties.Where (ep => ep.Name == pr).FirstOrDefault ();
+                                               if (pp == null)
+                                                       project.SetProperty (pr, "true");
+                                       }
 
-                               project.ReevaluateIfNecessary ();
-                               
-                               parseOptions = CSharpParseOptions.Default;
+                                       project.ReevaluateIfNecessary ();
+                                       
+                                       parseOptions = CSharpParseOptions.Default;
 
-                               ProjectProperty langVersion = project.GetProperty ("LangVersion");
-                               if (langVersion != null && Enum.TryParse<LanguageVersion> (langVersion.EvaluatedValue, out LanguageVersion lv))
-                                       parseOptions = parseOptions.WithLanguageVersion (lv);
-                               else
-                                       parseOptions = parseOptions.WithLanguageVersion (LanguageVersion.Default);
+                                       ProjectProperty langVersion = project.GetProperty ("LangVersion");
+                                       if (langVersion != null && Enum.TryParse<LanguageVersion> (langVersion.EvaluatedValue, out LanguageVersion lv))
+                                               parseOptions = parseOptions.WithLanguageVersion (lv);
+                                       else
+                                               parseOptions = parseOptions.WithLanguageVersion (LanguageVersion.Default);
 
-                               ProjectProperty constants = project.GetProperty ("DefineConstants");
-                               if (constants != null)
-                                       parseOptions = parseOptions.WithPreprocessorSymbols (constants.EvaluatedValue.Split (';'));
+                                       ProjectProperty constants = project.GetProperty ("DefineConstants");
+                                       if (constants != null)
+                                               parseOptions = parseOptions.WithPreprocessorSymbols (constants.EvaluatedValue.Split (';'));
 
-                               populateTreeNodes ();
+                                       populateTreeNodes ();
+                               }
                                
                                IsLoaded = true;                        
                        }
@@ -90,9 +103,11 @@ namespace CERoslynPlugin
                public void Build () => Build ("Build");
                public void Build (params string[] targets)
                {
-                       ProjectInstance pi = BuildManager.DefaultBuildManager.GetProjectInstanceForBuild (project);                     
-                       BuildRequestData request = new BuildRequestData (pi, targets,null,BuildRequestDataFlags.ProvideProjectStateAfterBuild);                 
-                       BuildResult result = BuildManager.DefaultBuildManager.Build (solutionProject.buildParams, request);
+                       //using (var ctx = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext (this.GetType().Assembly).EnterContextualReflection()) {
+                               ProjectInstance pi = BuildManager.DefaultBuildManager.GetProjectInstanceForBuild (project);
+                               BuildRequestData request = new BuildRequestData (pi, targets,null,BuildRequestDataFlags.ProvideProjectStateAfterBuild);                 
+                               BuildResult result = BuildManager.DefaultBuildManager.Build (solutionProject.buildParams, request);
+                       //}
                }
 
                TreeNode rootNode;
@@ -106,7 +121,7 @@ namespace CERoslynPlugin
                                NotifyValueChanged ("Children", Children);
                        }
                }
-               public IList<TreeNode> Children => rootNode.Childs;
+               public IList<TreeNode> Children => rootNode?.Childs;
                public override string Icon {
                        get {
                                switch (Path.GetExtension (FullPath)) {
@@ -188,9 +203,9 @@ namespace CERoslynPlugin
 
                                        break;
                                default:
-                                       Console.ForegroundColor = ConsoleColor.Red;
+                                       /*Console.ForegroundColor = ConsoleColor.Grey;
                                        Console.WriteLine ($"Unhandled Item Type: {pn.ItemType} {pn.EvaluatedInclude}");
-                                       Console.ResetColor ();
+                                       Console.ResetColor ();*/
                                        break;
                                }
                        }
@@ -202,5 +217,44 @@ namespace CERoslynPlugin
                                item.Parent = this;
                        }*/
                }
+
+               public override string Name => project == null ? projectInSolution.ProjectName : project.GetProperty ("MSBuildProjectName").EvaluatedValue;
+               public string ToolsVersion => project.ToolsVersion;
+               public string DefaultTargets => project.Xml.DefaultTargets;             
+               public ICollection<ProjectProperty> Properties => project.Properties;
+               public ICollection<ProjectProperty> PropertiesSorted => project.Properties.OrderBy(p=>p.Name).ToList();
+               public string AssemblyName => project.GetProperty ("AssemblyName").EvaluatedValue;
+               public string OutputPath => project.GetProperty ("OutputPath").EvaluatedValue;
+               public string IntermediateOutputPath => project.GetProperty ("IntermediateOutputPath").EvaluatedValue;
+               public string OutputType => project.GetProperty ("OutputType").EvaluatedValue;
+               public string OutputAssembly =>
+                       Path.Combine (project.GetPropertyValue ("OutputPath"), project.GetPropertyValue ("TargetFrameworks"), AssemblyName + AssemblyExtension);
+               public string AssemblyExtension => RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? ".exe" : "";
+               public OutputKind OutputKind {
+                       get {
+                switch (OutputType) {
+                               case "Library":
+                                       return OutputKind.DynamicallyLinkedLibrary;
+                               case "Exe":
+                                       return OutputKind.ConsoleApplication;
+                               case "WinExe":
+                                       return OutputKind.WindowsApplication;
+                               default:
+                                       return OutputKind.ConsoleApplication;
+                }
+            }
+        }
+               public string RootNamespace => project.GetProperty ("RootNamespace").EvaluatedValue;
+               public bool AllowUnsafeBlocks => bool.Parse (project.GetProperty ("AllowUnsafeBlocks").EvaluatedValue);
+               public bool NoStdLib => bool.Parse (project.GetProperty ("NoStdLib").EvaluatedValue);
+               public bool TreatWarningsAsErrors => bool.Parse (project.GetProperty ("TreatWarningsAsErrors").EvaluatedValue);
+               public bool SignAssembly =>     bool.Parse (project.GetProperty ("SignAssembly").EvaluatedValue);
+               public string TargetFrameworkVersion => project.GetProperty ("TargetFrameworkVersion").EvaluatedValue;
+               public string Description => project.GetProperty ("Description").EvaluatedValue;
+               public string StartupObject => project.GetProperty ("StartupObject").EvaluatedValue;
+               public bool DebugSymbols => bool.Parse (project.GetProperty ("DebugSymbols").EvaluatedValue);
+               public int WarningLevel => int.Parse (project.GetProperty ("WarningLevel").EvaluatedValue);
+
+
        }
 }
\ No newline at end of file
index d995101b88cea16bf681f25b86647307b21b4015..b1bda942179b412b37944b096dccc3fd4e2d16d5 100644 (file)
@@ -18,7 +18,7 @@ namespace CERoslynPlugin
                Always,
                PreserveNewest
        }*/
-       public class ProjectItemNode  : TreeNode 
+       public class ProjectItemNode  : TreeNode, IFileNode 
        {
 
                ProjectItem projectItem;
@@ -62,6 +62,10 @@ namespace CERoslynPlugin
                                }
                        }
                }
+               public string FullPath => 
+                       NodeType == NodeType.EmbeddedResource || NodeType == NodeType.None || NodeType == NodeType.Compile ?
+                               Path.Combine (GetRoot<ProjectNode>().Project.RootDir, projectItem.EvaluatedInclude) : null;
+
                public override CommandGroup Commands {
                        get {
                                switch (NodeType) {
@@ -70,7 +74,7 @@ namespace CERoslynPlugin
                                case NodeType.Compile:
                                        return new CommandGroup (
                                                new Command ("Open", () => {
-                                                       App.OpenFile (Path.Combine (GetRoot<ProjectNode>().Project.RootDir, projectItem.EvaluatedInclude));
+                                                       App.OpenFile (FullPath);
                                                })
                                        );
                                default:
index 6f4f1a0ba80b6499826b650c13ddb94d2c6c6067..c105c2b3d824b550ef70b240a2b53bc37b3ab0d8 100644 (file)
@@ -18,19 +18,36 @@ using Crow;
 namespace CERoslynPlugin
 {      
        public class RoslynService : Service {
+               
                public RoslynService () : base () {
                        configureDefaultSDKPathes ();
                        //TODO static init to prevent rebinding on Service multiple instantiation
                        AssemblyLoadContext pluginCtx = AssemblyLoadContext.GetLoadContext (Assembly.GetExecutingAssembly());
                        pluginCtx.Resolving += msbuildResolve;
+
+                       foreach (string dll in Directory.GetFiles (MSBuildRoot, "*.dll"))
+                               pluginCtx.LoadFromAssemblyPath (dll);
+                       string capath = Path.Combine (MSBuildRoot, "Roslyn", "bincore");
+                       foreach (string dll in Directory.GetFiles (capath, "*.dll"))
+                               pluginCtx.LoadFromAssemblyPath (dll);
                }
                Assembly msbuildResolve (AssemblyLoadContext context, AssemblyName assemblyName) {
                        string assemblyPath = Path.Combine (MSBuildRoot, assemblyName.Name + ".dll");
-                       return File.Exists (assemblyPath) ? Assembly.LoadFrom (assemblyPath) : null;
+                       //return File.Exists (assemblyPath) ? context.LoadFromAssemblyPath (assemblyPath) : null;
+                       if (!File.Exists (assemblyPath))
+                               return null;
+                       Assembly a = context.LoadFromAssemblyPath (assemblyPath);
+                       Console.WriteLine ($"[MSBuildResolve]{a},{a.CodeBase}");
+                       return a;
                }
 
                public override void Start() {
-                       
+
+                       Environment.SetEnvironmentVariable ("MSBUILD_EXE_PATH", Path.Combine (MSBuildRoot, "MSBuild.dll"));
+                       Environment.SetEnvironmentVariable ("MSBuildSDKsPath", Path.Combine (MSBuildRoot, "Sdks"));
+
+                       if (Environment.OSVersion.Platform == PlatformID.Unix)
+                               Environment.SetEnvironmentVariable ("FrameworkPathOverride", "/usr/lib/mono/4.5/");                     
 
                        CurrentState = Status.Running;
 
index c7d65ef0f067450437611724ce86e8bf2553c931..e225e7ff0ccfa7b1e03c358ac4c774be199185af 100644 (file)
@@ -34,8 +34,8 @@ namespace CERoslynPlugin
 
                SolutionFile solutionFile;
 
-               public ProjectCollection projectCollection { get; private set; }
-               public BuildParameters buildParams { get; private set; }
+               internal ProjectCollection projectCollection { get; private set; }
+               internal BuildParameters buildParams { get; private set; }
                public Configuration UserConfig { get; private set; }
                public IEnumerable<string> Configurations => solutionFile.SolutionConfigurations.Select (sc => sc.ConfigurationName).Distinct ().ToList ();
                public IEnumerable<string> Platforms => solutionFile.SolutionConfigurations.Select (sc => sc.PlatformName).Distinct ().ToList ();
@@ -62,8 +62,8 @@ namespace CERoslynPlugin
 
                public override void Load () {
                        projectCollection = new ProjectCollection (
-                               null,   
-                               new ILogger [] { new ConsoleLogger () },
+                               null,
+                               new ILogger [] { new CELogger () },
                                ToolsetDefinitionLocations.Default
                        );
 
@@ -76,6 +76,11 @@ namespace CERoslynPlugin
                        ActiveConfiguration = solutionFile.GetDefaultConfigurationName ();
                        ActivePlatform = solutionFile.GetDefaultPlatformName ();
 
+                       projectCollection.SetGlobalProperty ("RestoreConfigFile", Path.Combine (
+                                                       Path.Combine (
+                                                               Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), ".nuget"), "NuGet"),
+                                                               "NuGet.Config"));
+
                        projectCollection.SetGlobalProperty ("SolutionDir", Path.GetDirectoryName (FullPath) + Path.DirectorySeparatorChar);                    
                        projectCollection.SetGlobalProperty ("DefaultItemExcludes", "obj/**/*;bin/**/*");
 
@@ -84,9 +89,9 @@ namespace CERoslynPlugin
                        //ide.projectCollection.HostServices
                        buildParams = new BuildParameters (projectCollection) {
                                Loggers = projectCollection.Loggers,
-                               LogInitialPropertiesAndItems = true,
-                               LogTaskInputs = true,                           
-                               /*UseSynchronousLogging = true*/
+                               LogInitialPropertiesAndItems = false,
+                               LogTaskInputs = false,                          
+                               UseSynchronousLogging = true
                        };
 
                        //projectCollection.IsBuildEnabled = false;
index b929424bc7c7c822d78341c95af42366737f0083..948632cba70499039184cad099d9fb8ceee11387 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<DockWindow Caption="Roslyn plugin configuration"  Width="300" Height="400" Resizable="false">
+<DockWindow Caption="Roslyn plugin configuration"  Width="80%" Height="400" Resizable="false">
        <VerticalStack RootDataLevel="true" Margin="5">
                <HorizontalStack Height="Fit">
                        <Label Width="200" Text="DotNet SDK folder"/>
index 2fb536c980bd846242f1b0c4992665eb0d14f971..5e4908e64391511e83425f80e40093f492ab06ed 100644 (file)
@@ -30,10 +30,23 @@ namespace CrowEdit
                        }
                        Console.WriteLine($"[UNRESOLVE] {assembly} {libraryName}");
                        return IntPtr.Zero;
+               }
+               
+               static Assembly last_chance_resolve (System.Runtime.Loader.AssemblyLoadContext context, AssemblyName assemblyName)
+               {
+                       foreach (Plugin plugin in App.Plugins) {
+                               if (plugin.TryGet (assemblyName, out Assembly assembly))
+                                       return assembly;
+                       }
+                       Console.ForegroundColor = ConsoleColor.Red;
+                       Console.WriteLine($"[UNRESOLVE] {assemblyName}");
+                       Console.ResetColor();
+                       return null;
                }               
                static CrowEdit()
                {
-                       System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).ResolvingUnmanagedDll += resolveUnmanaged;                    
+                       System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).ResolvingUnmanagedDll += resolveUnmanaged;
+                       System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).Resolving += last_chance_resolve;
                }
 #endif         
                static void Main ()
@@ -57,6 +70,7 @@ namespace CrowEdit
                        base.OnInitialized ();
 
                        loadPlugins ();                 
+                       reopenLastProjectList ();
 
                        SetWindowIcon ("#Crow.Icons.crow.png");
                
@@ -73,7 +87,6 @@ namespace CrowEdit
                        reloadWinConfigs ();
 
                        reopenLastDocumentList ();
-                       reopenLastProjectList ();
                }
                public override void Terminate()
                {
@@ -93,6 +106,7 @@ namespace CrowEdit
                        new Command("Explorer", (sender) => loadWindowWithThisDataSource (sender, "#CrowEdit.ui.windows.winFileExplorer.crow")),
                        new Command("Editors", (sender) => loadWindowWithThisDataSource (sender, "#CrowEdit.ui.windows.winEditor.crow")),
                        new Command("Projects", (sender) => loadWindowWithThisDataSource (sender, "#CrowEdit.ui.windows.winProjects.crow")),
+                       new Command("Logs", (sender) => loadWindowWithThisDataSource (sender, "#CrowEdit.ui.windows.winLogs.crow")),
                        new Command("Crow Preview", (sender) => loadWindowWithThisDataSource (sender, "#CECrowDebugLog.ui.winCrowPreview.crow")),
                        new Command("Services", (sender) => loadWindowWithThisDataSource (sender, "#CrowEdit.ui.windows.winServices.crow")),
                        new Command("Plugins", (sender) => loadWindowWithThisDataSource (sender, "#CrowEdit.ui.windows.winPlugins.crow"))
@@ -222,6 +236,24 @@ namespace CrowEdit
                        if (doc != null)
                                CurrentDocument = doc;
                }
+               void tv_projects_SelectedItemChanged (object sender, SelectionChangeEventArgs e) {
+                       if (e.NewValue is IFileNode fi) {
+                               if (string.IsNullOrEmpty (fi.FullPath) || ! File.Exists (fi.FullPath))
+                                       return;
+                               if (TryGetDefaultTypeForExtension (Path.GetExtension (fi.FullPath), out Type clientType)) {
+                                       if (typeof(Document).IsAssignableFrom (clientType))     {
+                                               if (OpenedDocuments.FirstOrDefault (d => d.FullPath == fi.FullPath) is Document doc)                                    
+                                                       CurrentDocument = doc;                                  
+                                       /*} else if (typeof(Service).IsAssignableFrom (clientType))
+                                               doc = GetService (clientType)?.OpenDocument (CurrentFilePath);*/
+                                       } else if (typeof(Project).IsAssignableFrom (clientType)) {
+                                               if (Projects.FirstOrDefault (p=>p.FullPath == fi.FullPath) is Project prj)
+                                                       CurrentProject = prj;
+                                       }
+                               }
+                       }                       
+               }
+                               
                void saveOpenedDocumentList () {
                        if (OpenedDocuments.Count == 0)
                                Configuration.Global.Set ("OpenedItems", "");
diff --git a/src/DirectoryNode.cs b/src/DirectoryNode.cs
deleted file mode 100644 (file)
index 87aa78a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.IO;
-using Crow;
-
-namespace CrowEditBase
-{
-       public class DirectoryNode : TreeNode
-       {
-               DirectoryInfo info;
-               public DirectoryInfo Info => info;
-               public DirectoryNode (DirectoryInfo info, TreeNode parent = null) : base (parent) {
-                       this.info = info;
-               }
-               public override string Name => info.Name;
-
-               public override CommandGroup Commands =>
-                       new CommandGroup(
-                               new Command ("Set as root", ()=> {CrowEditBase.App.CurrentDir = info.FullName;})                                
-                       );              
-               public TreeNode [] GetFileSystemTreeNodeOrdered () 
-                       => info.GetFileSystemInfos ().OrderBy (f => f.Attributes).ThenBy (f => f.Name)
-                       .Select (d=> d is DirectoryInfo dinfo ? (TreeNode)new DirectoryNode(dinfo, this) : (TreeNode)new FileNode (d as FileInfo, this)).ToArray ();
-
-       }
-
-
-}
diff --git a/src/FileNode.cs b/src/FileNode.cs
deleted file mode 100644 (file)
index 5f439dc..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.IO;
-using Crow;
-
-namespace CrowEditBase
-{
-       public class FileNode : TreeNode
-       {
-               FileInfo info;
-               Document doc;
-               public override CommandGroup Commands =>
-                       new CommandGroup(
-                               new Command ("Open", Open),                             
-                               new Command ("Delete", (sender0) => {
-                                       MessageBox.ShowModal (CrowEditBase.App, MessageBox.Type.YesNo, $"Delete {info.Name}?").Yes += (sender, e) => {
-                                               System.IO.File.Delete(info.FullName);
-                                               Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget;
-                                               (listContainer.Parent as Group).RemoveChild(listContainer);
-                                       };
-                               })
-                       );              
-               public FileNode (FileInfo info, TreeNode parent = null) : base (parent) {
-                       this.info = info;
-               }
-               public override string Name => info.Name;
-               
-               public bool IsOpen => doc != null;
-
-               public void Open () {
-                       doc = CrowEditBase.App.OpenFile (info.FullName);
-                       if (doc is TextDocument td)
-                               CrowEditBase.App.CurrentDocument = td;
-                       NotifyValueChanged ("IsOpen", IsOpen);
-               }
-               public void OnOpenClick (object sender, EventArgs e) => Open();
-       }
-
-
-}
diff --git a/src/TreeNode.cs b/src/TreeNode.cs
deleted file mode 100644 (file)
index 834efe0..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Linq;
-using Crow;
-
-namespace CrowEditBase
-{
-       public abstract class TreeNode : IValueChange, ISelectable
-       {
-               #region IValueChange implementation
-               public event EventHandler<ValueChangeEventArgs> ValueChanged;
-
-        public virtual void NotifyValueChanged (string MemberName, object _value)
-               {
-                       ValueChanged.Raise (this, new ValueChangeEventArgs (MemberName, _value));
-               }
-               #endregion
-
-               #region ISelectable implementation
-               public event EventHandler Selected;
-               public event EventHandler Unselected;
-               public virtual bool IsSelected {
-                       get { return isSelected; }
-                       set {
-                               if (value == isSelected)
-                                       return;
-
-                               Console.WriteLine ($"TreeNode({this}).IsSelected: {isSelected} -> {value}");
-
-                               isSelected = value;
-
-                               NotifyValueChanged ("IsSelected", isSelected);
-                       }
-               }
-               #endregion
-
-               ObservableList<TreeNode> childs = new ObservableList<TreeNode> ();
-               
-               public TreeNode () {}
-               public TreeNode (TreeNode parent) {
-                       Parent?.AddChild (this);
-               }
-               
-               protected bool isSelected, isExpanded;
-
-               public TreeNode Parent { get; protected set; }
-
-               public abstract string Name { get; }
-               public ObservableList<TreeNode> Childs {
-                       get => childs;
-                       set {
-                               if (childs == value)
-                                       return;
-                               childs = value;
-                               NotifyValueChanged ("Childs", childs);
-                       }
-               }
-               public abstract CommandGroup Commands { get; }
-
-               public void AddChild (TreeNode pn)
-               {
-                       childs.Add (pn);
-                       pn.Parent = this;
-               }
-               public void RemoveChild (TreeNode pn)
-               {
-                       pn.Parent = null;
-                       childs.Remove (pn);
-               }
-
-               public virtual bool IsExpanded {
-                       get { return isExpanded; }
-                       set {
-                               if (value == isExpanded)
-                                       return;
-                               isExpanded = value;
-                               NotifyValueChanged ("IsExpanded", isExpanded);
-                               NotifyValueChanged ("IconSub", IconSub);
-                       }
-               }
-               public virtual Picture Icon => new SvgPicture ("#Icons.Question.svg");
-               public virtual string IconSub => null;
-               
-               public override string ToString () => Name;
-
-               public IEnumerable<TreeNode> Flatten {
-                       get {
-                               yield return this;
-                               foreach (var node in childs.SelectMany (child => child.Flatten))
-                                       yield return node;
-                       }
-               }
-
-               public virtual void SortChilds ()
-               {
-                       foreach (TreeNode pn in Childs)
-                               pn.SortChilds ();
-                       Childs = new ObservableList<TreeNode> (Childs.OrderBy (c => c, new NodeComparer()));
-               }
-
-               public class NodeComparer : IComparer<TreeNode>
-               {
-                       public int Compare (TreeNode x, TreeNode y)
-                       {
-                               return string.Compare (x.Name, y.Name);
-                       }
-               }
-       }
-
-
-}
index d04d55b7bf6ad134f43591ff9b4bc39947ef292c..67a67c3692b697f1e54863bf2da1d2e1828a09d0 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <ItemTemplate DataType="Crow.Command" Path="#CrowEdit.ui.MenuButton.template"/>
 <ItemTemplate DataType="Crow.CommandGroup" Data="Commands">
-       <Popper PopDirection="Right" Caption="{Caption}" IsEnabled="{CanExecute}" Width="Stretched"
+       <Popper PopDirection="Right" Caption="{Caption}" Width="Stretched"
                        MouseEnter="{Background=${ControlHighlight}}"
                        MouseLeave="{Background=Transparent}">
                <Template>
index 6170eb6f6b68e0399c3796ee2d9c91f2e1deff48..4c3ea066af0fdfbbbf1cc0460a53d5888917ee25 100644 (file)
@@ -31,7 +31,7 @@
                        <ListItem IsVisible="{IsSelected}" IsSelected="{²IsSelected}" Selected="{/tb.HasFocus='true'}">
                                <VerticalStack Spacing="0">
                                        <HorizontalStack Spacing="0">
-                                               <Editor Name="tb" Multiline="true" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"
+                                               <Editor Name="tb" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"
                                                                Document="{}" TextChanged="onTextChanged"/>
                                                <ScrollBar Value="{²../tb.ScrollY}"
                                                                LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
diff --git a/ui/windows/winLogs.crow b/ui/windows/winLogs.crow
new file mode 100644 (file)
index 0000000..e32813d
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<DockWindow Caption="Logs"  Width="80%" >
+       <VerticalStack RootDataLevel="true" >
+               <HorizontalStack Spacing="0">
+                       <LogViewerWidget Name="log" Lines="{MainLog}" Font="${SmallFont}" MaxScrollX="1000"/>
+                       <ScrollBar Name="scrollbarY" Value="{²../log.ScrollY}" CursorRatio="{../log.ChildHeightRatio}" Maximum="{../log.MaxScrollY}" />
+               </HorizontalStack>
+               <ScrollBar Style="HScrollBar" Name="scrollbarX" Value="{²../log.ScrollX}" Maximum="{../log.MaxScrollX}" SmallIncrement="30"/>
+       </VerticalStack>
+</DockWindow>
+
+
index a341ab915ed897ffb60085aa9b2652ec311ba53f..0393cb71e92fa6b9161ac4ce09fa76a6b1fb6799 100644 (file)
@@ -1,8 +1,21 @@
 <?xml version="1.0"?>
-<DockWindow Caption="Services"  Width="60%" >
-       <VerticalStack>
-               <Label Fit="true" Text="Plugins directory path:"/>
+<DockWindow Caption="Available Plugins"  Width="200" >
+       <VerticalStack Margin="5">
+               <Label Fit="true" Text="Plugins directory path:" HorizontalAlignment="Left"/>
                <TextBox Height="Fit" Text="{²PluginsDirecory}" Margin="2"/>
+               <ListBox Data="{Plugins}" >
+                       <ItemTemplate>
+                               <HorizontalStack Height="Fit">
+                                       <Label Text="{Name}" Width="Stretched"/>
+                                       <ListBox Data="{Commands}" Fit="true">
+                                               <Template>
+                                                       <HorizontalStack Name="ItemsContainer" />
+                                               </Template>
+                                               <ItemTemplate Path="#CrowEditBase.ui.IconCommand.itmp"/>
+                                       </ListBox>
+                               </HorizontalStack>
+                       </ItemTemplate>
+               </ListBox>              
        </VerticalStack>
 </DockWindow>
 
index 5ecad115066c2a7a440f74a2f516fcc26d7f501a..760449587e6f92bb945c45696f8c59878481c093 100644 (file)
                </ItemTemplate>
        </ListBox>-->
 
-       <TreeView Name="treeview" IsRoot="true" RootDataLevel="true" Data="{Projects}" Background="Onyx" >
+       <TreeView Name="treeview" IsRoot="true" RootDataLevel="true" Data="{Projects}" Background="Onyx"
+                               SelectedItemChanged="tv_projects_SelectedItemChanged" >
+
                <ItemTemplate DataType="default" Data="Childs" Path="#CrowEditBase.ui.TreeExpandable.template" />
                <ItemTemplate DataType="CERoslynPlugin.MSBuildProject" Data="Children" Path="#CrowEditBase.ui.TreeExpandable.template" />
                <ItemTemplate DataType="CrowEditBase.Project" Data="SubProjects" Path="#CrowEditBase.ui.TreeExpandable.template" />
+
        </TreeView>     
 </DockWindow>