From: Jean-Philippe Bruyère Date: Sun, 2 Mar 2025 07:31:23 +0000 (+0100) Subject: wip X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=d3c93f2d964245a71ea2d491b2c7c20a9c5f219a;p=jp%2Fcrowedit.git wip --- diff --git a/CrowEditBase/icons/at.svg b/CrowEditBase/icons/at.svg new file mode 100644 index 0000000..f8f8aae --- /dev/null +++ b/CrowEditBase/icons/at.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CrowEditBase/icons/automation.svg b/CrowEditBase/icons/automation.svg new file mode 100644 index 0000000..1f4c3ca --- /dev/null +++ b/CrowEditBase/icons/automation.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/CrowEditBase/icons/ban.svg b/CrowEditBase/icons/ban.svg new file mode 100644 index 0000000..6040dd7 --- /dev/null +++ b/CrowEditBase/icons/ban.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/binding.svg b/CrowEditBase/icons/binding.svg new file mode 100644 index 0000000..04f669e --- /dev/null +++ b/CrowEditBase/icons/binding.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CrowEditBase/icons/bolt.svg b/CrowEditBase/icons/bolt.svg new file mode 100644 index 0000000..1a84662 --- /dev/null +++ b/CrowEditBase/icons/bolt.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/bug-1.svg b/CrowEditBase/icons/bug-1.svg new file mode 100644 index 0000000..8c73946 --- /dev/null +++ b/CrowEditBase/icons/bug-1.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/CrowEditBase/icons/cancel-button.svg b/CrowEditBase/icons/cancel-button.svg new file mode 100644 index 0000000..5f52bb8 --- /dev/null +++ b/CrowEditBase/icons/cancel-button.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CrowEditBase/icons/coffee.svg b/CrowEditBase/icons/coffee.svg new file mode 100644 index 0000000..6ecefe6 --- /dev/null +++ b/CrowEditBase/icons/coffee.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CrowEditBase/icons/comment.svg b/CrowEditBase/icons/comment.svg new file mode 100644 index 0000000..d3bb799 --- /dev/null +++ b/CrowEditBase/icons/comment.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/computing-code.svg b/CrowEditBase/icons/computing-code.svg new file mode 100644 index 0000000..b5687ba --- /dev/null +++ b/CrowEditBase/icons/computing-code.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/CrowEditBase/icons/connect.svg b/CrowEditBase/icons/connect.svg new file mode 100644 index 0000000..51a39c7 --- /dev/null +++ b/CrowEditBase/icons/connect.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/dentist-chair.svg b/CrowEditBase/icons/dentist-chair.svg new file mode 100644 index 0000000..a567535 --- /dev/null +++ b/CrowEditBase/icons/dentist-chair.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/drop.svg b/CrowEditBase/icons/drop.svg new file mode 100644 index 0000000..164aaa6 --- /dev/null +++ b/CrowEditBase/icons/drop.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/earth-globe.svg b/CrowEditBase/icons/earth-globe.svg new file mode 100644 index 0000000..2d851cc --- /dev/null +++ b/CrowEditBase/icons/earth-globe.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/event.svg b/CrowEditBase/icons/event.svg new file mode 100644 index 0000000..cedebd5 --- /dev/null +++ b/CrowEditBase/icons/event.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/fill.svg b/CrowEditBase/icons/fill.svg new file mode 100644 index 0000000..afb6922 --- /dev/null +++ b/CrowEditBase/icons/fill.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CrowEditBase/icons/magic-wand.svg b/CrowEditBase/icons/magic-wand.svg new file mode 100644 index 0000000..8b40691 --- /dev/null +++ b/CrowEditBase/icons/magic-wand.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/CrowEditBase/icons/processing-file.svg b/CrowEditBase/icons/processing-file.svg new file mode 100644 index 0000000..c5bcbb5 --- /dev/null +++ b/CrowEditBase/icons/processing-file.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/CrowEditBase/icons/property.svg b/CrowEditBase/icons/property.svg new file mode 100644 index 0000000..de5dd37 --- /dev/null +++ b/CrowEditBase/icons/property.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/icons/recycling.svg b/CrowEditBase/icons/recycling.svg new file mode 100644 index 0000000..e86ca13 --- /dev/null +++ b/CrowEditBase/icons/recycling.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/CrowEditBase/icons/toolbox/Crow.Table.svg b/CrowEditBase/icons/toolbox/Crow.Table.svg new file mode 100644 index 0000000..0b42122 --- /dev/null +++ b/CrowEditBase/icons/toolbox/Crow.Table.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowEditBase/src/Compiler/SourceDocument.cs b/CrowEditBase/src/Compiler/SourceDocument.cs index f3a72bf..a341853 100644 --- a/CrowEditBase/src/Compiler/SourceDocument.cs +++ b/CrowEditBase/src/Compiler/SourceDocument.cs @@ -17,13 +17,19 @@ namespace CrowEditBase : base (fullPath, editorPath) { } protected SyntaxRootNode root; - public SyntaxRootNode Root => root; - public bool IsParsed => root != null && Tokens.Length > 0; - //public SyntaxNode EditedNode { get; protected set; } + public Command CMDRefreshSyntaxTree; + protected override void initCommands() + { + base.initCommands(); + CMDRefreshSyntaxTree = new ActionCommand ("Reparse", parse, "#icons.refresh.svg", true); + } + public SyntaxRootNode Root => root; + public bool IsParsed => root != null && Tokens.Length > 0; public ReadOnlySpan Tokens => root.Tokens; public IEnumerable SyntaxRootChildNodes => root?.children; + public Token FindTokenIncludingPosition (int pos) { if (!IsParsed || pos == 0 || Tokens.Length == 0) return default; @@ -38,8 +44,6 @@ namespace CrowEditBase int idx = Tokens.BinarySearch(new Token () {Start = pos}); return idx == 0 ? 0 : idx < 0 ? ~idx - 1 : idx; } - - /// /// if outermost is true, return oldest ancestor exept root node, useful for folding. /// @@ -117,18 +121,13 @@ namespace CrowEditBase //Console.WriteLine ($"CurrentToken: idx({currentTokenIndex}) {currentToken} {RootNode.Root.GetTokenStringByIndex(currentTokenIndex)}"); } - /*static bool tryReplaceNode (SyntaxNode editedNode, SyntaxNode newNode) { - if (newNode is SyntaxRootNode || editedNode is SyntaxRootNode) - return false; - editedNode.Replace (newNode); - return true; - } - */ public virtual Color GetColorForToken (TokenType tokType) { if (tokType.HasFlag (TokenType.Punctuation)) return Colors.DarkGrey; + if (tokType.HasFlag (TokenType.WhiteSpace)) + return Colors.Gainsboro; if (tokType.HasFlag (TokenType.Trivia)) return Colors.Silver; if (tokType == TokenType.Keyword) @@ -143,8 +142,13 @@ namespace CrowEditBase void parse () { SyntaxAnalyser syntaxAnalyser = CreateSyntaxAnalyser (); root = syntaxAnalyser?.Process (); - NotifyValueChanged("Exceptions", syntaxAnalyser?.Exceptions); + NotifyValueChanged("Exceptions", syntaxAnalyser?.Exceptions); + NotifyValueChanged ("SyntaxRootChildNodes", (object)null); + NotifyValueChanged ("SyntaxRootChildNodes", SyntaxRootChildNodes); + + //CurrentNode?.ExpandToTheTop(); + //CrowEditBase.App.Log (LogType.Low, $"Syntax Analysis done in {sw.ElapsedMilliseconds}(ms) {sw.ElapsedTicks}(ticks)"); } diff --git a/CrowEditBase/src/Compiler/SyntaxNode.cs b/CrowEditBase/src/Compiler/SyntaxNode.cs index 31b6f3b..226bdfe 100644 --- a/CrowEditBase/src/Compiler/SyntaxNode.cs +++ b/CrowEditBase/src/Compiler/SyntaxNode.cs @@ -201,7 +201,8 @@ namespace CrowEditBase foreach (SyntaxNode node in children) node.Dump (level + 1); } - public override string ToString() => $"l:({StartLine,3},{LineCount,3}) tks:{TokenIndexBase},{TokenCount} {this.GetType().Name}"; + //public override string ToString() => $"l:({StartLine,3},{LineCount,3}) tks:{TokenIndexBase},{TokenCount} {this.GetType().Name}"; + public override string ToString() => $"{this.GetType().Name}"; public string AsText() { return Span.Length < 0 ? "" : Root.GetText(Span).ToString(); } diff --git a/CrowEditBase/src/CrowEditBase.cs b/CrowEditBase/src/CrowEditBase.cs index b6c82db..9dd7833 100644 --- a/CrowEditBase/src/CrowEditBase.cs +++ b/CrowEditBase/src/CrowEditBase.cs @@ -541,6 +541,18 @@ namespace CrowEditBase CurrentEditor?.RegisterForGraphicUpdate (); } } + public bool ShowWhiteSpace { + get => Configuration.Global.Get ("ShowWhiteSpace", false); + set { + if (ShowWhiteSpace == value) + return; + Configuration.Global.Set ("ShowWhiteSpace", value); + NotifyValueChanged ("ShowWhiteSpace", ShowWhiteSpace); + + CurrentEditor?.RegisterForGraphicUpdate (); + } + } + public bool IndentWithSpace { get => Configuration.Global.Get ("IndentWithSpace", false); set { diff --git a/CrowEditBase/src/Editor.cs b/CrowEditBase/src/Editor.cs index 4767d0a..b79033f 100644 --- a/CrowEditBase/src/Editor.cs +++ b/CrowEditBase/src/Editor.cs @@ -8,12 +8,12 @@ using Crow.Text; using System.Collections.Generic; using Drawing2D; using System.Linq; -using CrowEditBase; using System.Threading; using System.ComponentModel; using static CrowEditBase.CrowEditBase; +using Crow; -namespace Crow +namespace CrowEditBase { public interface IDocumentClient { @@ -42,7 +42,7 @@ namespace Crow ContextCommands = new CommandGroup (CMDCut, CMDCopy, CMDPaste); } - public TextDocument Document { + public virtual TextDocument Document { get => document; set { if (document == value) @@ -742,7 +742,7 @@ namespace Crow RegisterForRedraw (); - (IFace as CrowEditBase.CrowEditBase).CurrentEditor = this; + (IFace as CrowEditBase).CurrentEditor = this; } public override void onMouseEnter (object sender, MouseMoveEventArgs e) { base.onMouseEnter (sender, e); diff --git a/CrowEditBase/src/Extensions.cs b/CrowEditBase/src/Extensions.cs new file mode 100644 index 0000000..581f4a7 --- /dev/null +++ b/CrowEditBase/src/Extensions.cs @@ -0,0 +1,19 @@ +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using Crow; +using Crow.Text; +using CrowEditBase; +using System.Reflection; + +namespace CrowEdit +{ + public static class Extensions + { + public static Picture GetIcon (this MemberInfo mi) + => mi is EventInfo ? new BmpPicture("#Icons.event.png") : new BmpPicture("#Icons.property.png"); + + } +} diff --git a/CrowEditBase/src/SourceEditor.cs b/CrowEditBase/src/SourceEditor.cs index aba2f95..ed51e45 100644 --- a/CrowEditBase/src/SourceEditor.cs +++ b/CrowEditBase/src/SourceEditor.cs @@ -7,27 +7,25 @@ using Glfw; using Crow.Text; using Drawing2D; using System.Collections; -using CrowEditBase; using static CrowEditBase.CrowEditBase; using System.Collections.Generic; using System.Linq; -using System.Collections.Frozen; +using Crow; +using System.Text.Unicode; +using System.Text; -namespace Crow +namespace CrowEditBase { - public class Suggestion { - public string Caption; - public TextChange Change; - public TextSpan? NextSelection; - - public Suggestion(string caption, TextChange change = default, int finalPositionOffset = 0) { - Caption = caption; - Change = change; - NextSelection = finalPositionOffset < 0 ? TextSpan.FromStartAndLength(change.End2 + finalPositionOffset) : null; - } - } public class SourceEditor : Editor { - int currentTokenIndex = -1; + SourceDocument sourceDocument; + public override TextDocument Document { + get => base.Document; + set { + base.Document = value; + sourceDocument = Document as SourceDocument; + } + } + int currentTokenIndex = -1; SyntaxNode currentNode; #if DEBUG_NODE SyntaxNode _hoverNode; @@ -51,8 +49,15 @@ namespace Crow } } - public Token CurrentToken => typeof(SourceDocument).IsAssignableFrom(Document?.GetType()) ? - (Document as SourceDocument).GetTokenByIndex(currentTokenIndex) : default; + public Token CurrentToken => sourceDocument != null && sourceDocument.IsParsed ? + sourceDocument.GetTokenByIndex(currentTokenIndex) : default; + +#if DEBUG + public string CurrentTokenString => sourceDocument != null && sourceDocument.IsParsed ? + CurrentToken.AsString(Document.source) : null; + public string CurrentTokenType => sourceDocument != null && sourceDocument.IsParsed ? + sourceDocument.GetTokenTypeString(CurrentToken.Type) : default; +#endif #region suggestions and autocomplete ListBox overlay; @@ -85,7 +90,33 @@ namespace Crow void showOverlay () { lock (IFace.UpdateMutex) { if (overlay == null) { - overlay = IFace.Load(@"#ui.SuggestionsOverlay.crow"); + //overlay = IFace.Load(@"#ui.SuggestionsOverlay.crow"); + overlay = IFace.LoadIMLFragment(@" + + + + + + + + + + + + + + + + + + + "); overlay.DataSource = this; overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0; } else @@ -96,9 +127,11 @@ namespace Crow void hideOverlay () { if (overlay == null) return; - overlay.IsVisible = false; + lock(App.UpdateMutex) + overlay.IsVisible = false; } void completeToken () { + disableSuggestions = true; if (Document is SourceDocument srcDoc) { if (overlay.SelectedItem is Suggestion sug) { update (sug.Change); @@ -107,7 +140,8 @@ namespace Crow } } hideOverlay (); - tryGetSuggestions (); + disableSuggestions = false; + //tryGetSuggestions (); } #endregion @@ -169,6 +203,8 @@ namespace Crow DbgLogger.EndEvent(DbgEvtType.GOMeasure); } } + + #region Mouse & Keyboard overrides public override void onMouseDown (object sender, MouseButtonEventArgs e) { hideOverlay (); if (mouseIsInMargin) { @@ -318,7 +354,24 @@ namespace Crow case Key.KeypadEnter: //doc.updateCurrentTokAndNode (Selection.Start); //Console.WriteLine ($"*** Current Token: {doc.CurrentToken} Current Node: {doc.CurrentNode}"); - update (new TextChange (selection.Start, selection.Length, Document.GetLineBreak ())); + if (currentLoc.HasValue) { + TextLine tl = doc.GetLine(currentLoc.Value.Line); + int firstTok = doc.FindTokenIndexIncludingPosition(tl.Start); + int i = firstTok; + Token tok = doc.GetTokenByIndex(i); + StringBuilder sb = new StringBuilder(20); + while (tok.End < tl.End && tok.Type.HasFlag(TokenType.WhiteSpace)) { + if (tok.Type == TokenType.Tabulation) + sb.Append(new string('\t', tok.Length)); + else if (tok.Type == TokenType.WhiteSpace) + sb.Append(new string(' ', tok.Length)); + else + break; + tok = doc.GetTokenByIndex(++i); + } + update (new TextChange (selection.Start, selection.Length, Document.GetLineBreak () + sb.ToString())); + } else + update (new TextChange (selection.Start, selection.Length, Document.GetLineBreak ())); autoAdjustScroll = true; IFace.forceTextCursor(); e.Handled = true; @@ -331,7 +384,7 @@ namespace Crow Document.ExitReadLock (); }*/ } - + #endregion SyntaxNode getFoldStartingAt (int line) { if (!(Document is SourceDocument doc)) @@ -583,6 +636,9 @@ namespace Crow Foreground.SetAsSource (IFace, gr); + bool showWhiteSpaces = App.ShowWhiteSpace; + string tabString = showWhiteSpaces ? + $"{new string(' ', (App.TabulationSize - 2) / 2)} \u2192{new string(' ', (App.TabulationSize - 2) / 2)}" : default; ReadOnlySpan sourceBytes = doc.source; Span bytes = stackalloc byte[128]; TextExtents extents; @@ -610,8 +666,20 @@ namespace Crow int tokPtr = doc.FindTokenIndexIncludingPosition(curTxtLine.Start); Token tok = doc.Tokens[tokPtr]; - while (tok.Start < curTxtLine.End) { - buff = sourceBytes.Slice (tok.Start, tok.Length); + while (tok.Start < (showWhiteSpaces ? curTxtLine.EndIncludingLineBreak : curTxtLine.End)) { + if (showWhiteSpaces && tok.Type.HasFlag(TokenType.WhiteSpace)) { + + if(tok.Type == TokenType.WhiteSpace) { + buff = new string('·', tok.Length); + } if(tok.Type == TokenType.Tabulation) { + buff = new StringBuilder(tok.Length*tabString.Length).Insert(0,tabString,tok.Length).ToString() ; + } else if (tok.Type == TokenType.LineBreak) { + buff = new string('\u204B', tok.Length); + } + /*gr.MoveTo (pixX, pixY + fe.Ascent); + gr.ShowText (buff);*/ + } else + buff = sourceBytes.Slice (tok.Start, tok.Length); gr.SetSource (doc.GetColorForToken (tok.Type)); int size = buff.Length * 4 + 1; @@ -758,15 +826,6 @@ namespace Crow tryGetSuggestions (); RegisterForGraphicUpdate(); - - lock (IFace.UpdateMutex) { - if (Document is SourceDocument doc) { - doc.NotifyValueChanged ("SyntaxRootChildNodes", (object)null); - doc.NotifyValueChanged ("SyntaxRootChildNodes", doc.SyntaxRootChildNodes); - CurrentNode?.ExpandToTheTop(); - } - } - //Console.WriteLine ($"{pos}: {suggestionTok.AsString (_text)} {suggestionTok}"); } void updateCurrentTokAndNode() { if (currentLoc.HasValue && Document is SourceDocument srcdoc) { @@ -776,6 +835,12 @@ namespace Crow CurrentNode = srcdoc.Root?.FindNodeIncludingSpan(tok.Span); NotifyValueChanged("CurrentToken",tok); +#if DEBUG + NotifyValueChanged("CurrentTokenString",CurrentTokenString); + NotifyValueChanged("CurrentTokenType",CurrentTokenType); +#endif + + } else { currentTokenIndex = -1; CurrentNode = null; diff --git a/CrowEditBase/src/Suggestions.cs b/CrowEditBase/src/Suggestions.cs new file mode 100644 index 0000000..645c1dc --- /dev/null +++ b/CrowEditBase/src/Suggestions.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2013-2025 Bruyère Jean-Philippe +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + +using System; +using Crow.Text; +using System.Reflection; +using Crow; + +namespace CrowEditBase +{ + public class Suggestion { + public string Caption; + public TextChange Change; + public TextSpan? NextSelection; + public virtual string Icon => "#icons.property.svg"; + + public Suggestion(string caption, TextChange change = default, int finalPositionOffset = 0) { + Caption = caption; + Change = change; + NextSelection = finalPositionOffset < 0 ? TextSpan.FromStartAndLength(change.End2 + finalPositionOffset) : null; + } + } + public class MemberInfoSuggestion : Suggestion { + public MemberInfo MemberInfo; + public MemberInfoSuggestion(MemberInfo memberInfo, TextChange change = default, int finalPositionOffset = 0) + : base(memberInfo.Name, change, finalPositionOffset) { + MemberInfo = memberInfo; + } + } + public class WidgetSuggestion : Suggestion { + public Type Type; + public override string Icon => $"#icons.{Type.FullName}.svg"; + public WidgetSuggestion(Type type, TextChange change = default, int finalPositionOffset = 0) + : base(type.Name, change, finalPositionOffset) { + Type = type; + } + } + public class ColorSuggestion : Suggestion { + public Fill Fill; + public override string Icon => $"#icons.fill.svg"; + public ColorSuggestion(Fill fill, TextChange change = default, int finalPositionOffset = 0) + : base(fill.ToString(), change, finalPositionOffset) { + Fill = fill; + } + } +} \ No newline at end of file diff --git a/CrowEditBase/ui/CrowEdit.style b/CrowEditBase/ui/CrowEdit.style index 47b6598..5ae11c4 100644 --- a/CrowEditBase/ui/CrowEdit.style +++ b/CrowEditBase/ui/CrowEdit.style @@ -77,6 +77,13 @@ TreeLabel { Foreground="White"; Margin = "1"; } +TreeLabel2 { + Foreground="Black"; + Background="LightGrey"; + Margin = "1"; + Font = "sans, 9"; +} + Splitter { Thickness="1"; Background="Transparent"; diff --git a/CrowEditBase/ui/Suggestions.template b/CrowEditBase/ui/Suggestions.template index 4928e26..350811b 100644 --- a/CrowEditBase/ui/Suggestions.template +++ b/CrowEditBase/ui/Suggestions.template @@ -8,6 +8,6 @@ + Width="12" /> diff --git a/CrowEditBase/ui/SuggestionsOverlay.crow b/CrowEditBase/ui/SuggestionsOverlay.crow index bc771da..6a8e3aa 100644 --- a/CrowEditBase/ui/SuggestionsOverlay.crow +++ b/CrowEditBase/ui/SuggestionsOverlay.crow @@ -7,17 +7,18 @@ \ No newline at end of file diff --git a/CrowEditBase/ui/sourceEditor.itmp b/CrowEditBase/ui/sourceEditor.itmp index 54967ac..5444c2d 100644 --- a/CrowEditBase/ui/sourceEditor.itmp +++ b/CrowEditBase/ui/sourceEditor.itmp @@ -1,7 +1,7 @@ - + +