using System.Reflection.PortableExecutable; // Copyright (c) 2013-2021 Bruyère Jean-Philippe // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using Crow; using System.IO; using Glfw; using Crow.Text; using System.Collections.Generic; using Encoding = System.Text.Encoding; using Crow.DebugLogger; namespace DebugLogAnalyzer { public class Program : SampleBase { public static Program CurrentProgramInstance; static void Main (string [] args) { DbgLogger.IncludeEvents = DbgEvtType.None; DbgLogger.DiscardEvents = DbgEvtType.All; using (Program app = new Program ()) { CurrentProgramInstance = app; app.Run (); } } protected override void OnInitialized () { initCommands (); base.OnInitialized (); if (string.IsNullOrEmpty (CurrentDir)) CurrentDir = Path.Combine (Directory.GetCurrentDirectory (), "Interfaces"); Load ("#Dbg.main.crow").DataSource = this; //crowContainer = FindByName ("CrowContainer") as Container; editor = FindByName ("tb") as TextBox; /*TreeView tv = FindByName("dbgTV") as TreeView; dbgTreeViewScroller = tv.FindByNameInTemplate ("scroller1") as Scroller;*/ if (!File.Exists (CurrentFile)) newFile (); //I set an empty object as datasource at this level to force update when new //widgets are added to the interface reloadFromFile (); } List events = new List(); List widgets = new List(); DbgEvent curEvent = new DbgEvent(); DbgWidgetRecord curWidget = new DbgWidgetRecord(); bool debugLogRecording; Scroller dbgTreeViewScroller; int targetTvScroll = -1; public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, CMDShowLeftPane, CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions; public CommandGroup EventCommands, DirectoryCommands; public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs); void initCommands () { CMDNew = new Command ("New", new Action (onNewFile), "#Icons.blank-file.svg"); CMDSave = new Command ("Save", new Action (onSave), "#Icons.save.svg", false); CMDSaveAs = new Command ("Save As...", new Action (onSaveAs), "#Icons.save.svg"); CMDQuit = new Command ("Quit", new Action (() => base.Quit ()), "#Icons.exit.svg"); CMDUndo = new Command ("Undo", new Action (undo),"#Icons.undo.svg", false); CMDRedo = new Command ("Redo", new Action (redo),"#Icons.redo.svg", false); CMDCut = new Command ("Cut", new Action (() => cut ()), "#Icons.scissors.svg", false); CMDCopy = new Command ("Copy", new Action (() => copy ()), "#Icons.copy-file.svg", false); CMDPaste= new Command ("Paste", new Action (() => paste ()), "#Icons.paste-on-document.svg", false); EventCommands = new CommandGroup( new Command("Goto parent event", ()=> { CurrentEvent = CurrentEvent?.parentEvent; }) ); DirectoryCommands = new CommandGroup( new Command("Set as root directory", ()=> { CurrentEvent = CurrentEvent?.parentEvent; }) ); } public string CrowDbgAssemblyLocation { get => Configuration.Global.Get("CrowDbgAssemblyLocation"); set { if (CrowDbgAssemblyLocation == value) return; Configuration.Global.Set ("CrowDbgAssemblyLocation", value); NotifyValueChanged(CrowDbgAssemblyLocation); } } public List Events { get => events; set { if (events == value) return; events = value; NotifyValueChanged (nameof (Events), events); } } public List Widgets { get => widgets; set { if (widgets == value) return; widgets = value; NotifyValueChanged (nameof (Widgets), widgets); } } public DbgEvent CurrentEvent { get => curEvent; set { if (curEvent == value) return; curEvent = value; NotifyValueChanged (nameof (CurrentEvent), curEvent); NotifyValueChanged ("CurEventChildEvents", curEvent?.Events); } } public DbgWidgetRecord CurrentWidget { get => curWidget; set { if (curWidget == value) return; curWidget = value; NotifyValueChanged (nameof (CurrentWidget), curWidget); NotifyValueChanged ("CurWidgetRootEvents", curWidget?.RootEvents); NotifyValueChanged ("CurWidgetEvents", curWidget?.Events); } } public List CurWidgetRootEvents => curWidget == null? new List() : curWidget.RootEvents; public DbgEvtType RecordedEvents { get => Configuration.Global.Get (nameof (RecordedEvents)); set { if (RecordedEvents == value) return; Configuration.Global.Set (nameof (RecordedEvents), value); if (DebugLogRecording) DbgLogger.IncludeEvents = RecordedEvents; NotifyValueChanged(RecordedEvents); } } public DbgEvtType DiscardedEvents { get => Configuration.Global.Get (nameof (DiscardedEvents)); set { if (DiscardedEvents == value) return; Configuration.Global.Set (nameof (DiscardedEvents), value); if (DebugLogRecording) DbgLogger.DiscardEvents = DiscardedEvents; NotifyValueChanged(DiscardedEvents); } } public bool DebugLoggingEnabled => DbgLogger.IsEnabled; public bool DebugLogToFile { get => Configuration.Global.Get (nameof(DebugLogToFile)); set { if (DbgLogger.ConsoleOutput != value) return; Configuration.Global.Set (nameof(DebugLogToFile), value); NotifyValueChanged(DebugLogToFile); } } public string DebugLogFilePath { get => Configuration.Global.Get (nameof (DebugLogFilePath)); set { if (CurrentFile == value) return; Configuration.Global.Set (nameof (DebugLogFilePath), value); NotifyValueChanged (DebugLogFilePath); } } public bool DebugLogRecording { get => debugLogRecording; set { if (debugLogRecording == value) return; debugLogRecording = value; NotifyValueChanged(debugLogRecording); } } const string _defaultFileName = "unnamed.txt"; string source = "", origSource; TextBox editor; Stack undoStack = new Stack (); Stack redoStack = new Stack (); TextSpan selection; Exception currentException; public string CurrentDir { get => Configuration.Global.Get (nameof (CurrentDir)); set { if (CurrentDir == value) return; Configuration.Global.Set (nameof (CurrentDir), value); NotifyValueChanged (CurrentDir); } } public string CurrentFile { get => Configuration.Global.Get (nameof (CurrentFile)); set { if (CurrentFile == value) return; Configuration.Global.Set (nameof (CurrentFile), value); NotifyValueChanged (CurrentFile); } } public new bool IsDirty => source != origSource; public string Source { get => source; set { if (source == value) return; source = value; CMDSave.CanExecute = IsDirty; NotifyValueChanged (source); NotifyValueChanged ("IsDirty", IsDirty); } } string SelectedText => selection.IsEmpty ? "" : Source.AsSpan (selection.Start, selection.Length).ToString (); public Exception CurrentException { get => currentException; set { if (currentException == value) return; currentException = value; NotifyValueChanged ("ShowError", ShowError); NotifyValueChanged ("CurrentExceptionMSG", (object)CurrentExceptionMSG); NotifyValueChanged (currentException); } } public bool ShowError => currentException != null; public string CurrentExceptionMSG => currentException == null ? "" : currentException.Message; void undo () { if (undoStack.TryPop (out TextChange tch)) { redoStack.Push (tch.Inverse (source)); CMDRedo.CanExecute = true; apply (tch); editor.SetCursorPosition (tch.End + tch.ChangedText.Length); } if (undoStack.Count == 0) CMDUndo.CanExecute = false; } void redo () { if (redoStack.TryPop (out TextChange tch)) { undoStack.Push (tch.Inverse (source)); CMDUndo.CanExecute = true; apply (tch); editor.SetCursorPosition (tch.End + tch.ChangedText.Length); } if (redoStack.Count == 0) CMDRedo.CanExecute = false; } void cut () { copy (); applyChange (new TextChange (selection.Start, selection.Length, "")); } void copy () { Clipboard = SelectedText; } void paste () { applyChange (new TextChange (selection.Start, selection.Length, Clipboard)); } bool disableTextChangedEvent = false; void apply (TextChange change) { Span tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)]; ReadOnlySpan src = source.AsSpan (); src.Slice (0, change.Start).CopyTo (tmp); if (!string.IsNullOrEmpty (change.ChangedText)) change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start)); src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length)); disableTextChangedEvent = true; Source = tmp.ToString (); disableTextChangedEvent = false; } void applyChange (TextChange change) { undoStack.Push (change.Inverse (source)); redoStack.Clear (); CMDUndo.CanExecute = true; CMDRedo.CanExecute = false; apply (change); } void resetUndoRedo () { undoStack.Clear (); redoStack.Clear (); CMDUndo.CanExecute = false; CMDRedo.CanExecute = false; } void onNewFile () { if (IsDirty) { MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?").Yes += (sender, e) => newFile (); } else newFile (); } void onSave () { if (!File.Exists (CurrentFile)) { onSaveAs (); return; } save (); } void onSaveAs () { string dir = Path.GetDirectoryName (CurrentFile); if (string.IsNullOrEmpty (dir)) dir = Directory.GetCurrentDirectory (); LoadIMLFragment (@"").DataSource = this; } void saveFileDialog_OkClicked (object sender, EventArgs e) { FileDialog fd = sender as FileDialog; if (string.IsNullOrEmpty (fd.SelectedFileFullPath)) return; if (File.Exists(fd.SelectedFileFullPath)) { MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "File exists, overwrite?"); mb.Yes += (sender2, e2) => { CurrentFile = fd.SelectedFileFullPath; save (); }; return; } CurrentFile = fd.SelectedFileFullPath; save (); } void newFile() { disableTextChangedEvent = true; Source = @"