]> O.S.I.I.S - jp/crowedit.git/commitdiff
Syntax analysis immutable copy of source and lineCollection
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Feb 2025 00:02:09 +0000 (01:02 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Feb 2025 00:02:09 +0000 (01:02 +0100)
27 files changed:
CrowEditBase/src/Compiler/SourceDocument.cs
CrowEditBase/src/Compiler/SyntaxAnalyser.cs
CrowEditBase/src/Compiler/SyntaxException.cs
CrowEditBase/src/Compiler/SyntaxNode.cs
CrowEditBase/src/Compiler/SyntaxRootNode.cs
CrowEditBase/src/CrowEditBase.cs
CrowEditBase/src/Document.cs
CrowEditBase/src/Editor.cs
CrowEditBase/src/SourceEditor.cs
CrowEditBase/src/TextBuffer.cs
CrowEditBase/src/TextDocument.cs
Directory.Build.props
plugins/CECrowPlugin/src/DebugInterfaceWidget.cs
plugins/CECrowPlugin/src/Parsing/IML/ImlDocument.cs
plugins/CECrowPlugin/src/Parsing/IML/ImlSyntaxAnalyser.cs
plugins/CECrowPlugin/src/Parsing/Styling/StyleDocument.cs
plugins/CECrowPlugin/src/Parsing/Styling/SyntaxAnalyser.cs
plugins/CECrowPlugin/src/Parsing/Styling/SyntaxNodes.cs
plugins/CEEbnfPlugin/src/Parsing/EbnfDocument.cs
plugins/CEEbnfPlugin/src/Parsing/EbnfSyntaxAnalyser.cs
plugins/CEEbnfPlugin/src/Parsing/EbnfSyntaxNodes.cs
plugins/CERoslynPlugin/src/CSDocument.cs
plugins/CERoslynPlugin/src/CSSyntaxAnalyser.cs
plugins/CEXmlPlugin/src/Parsing/XmlDocument.cs
plugins/CEXmlPlugin/src/Parsing/XmlSyntaxAnalyser.cs
plugins/CEXmlPlugin/src/Parsing/XmlSyntaxNodes.cs
ui/windows/winLogs.crow

index 32e75c236f771aa4b2f93cebab82adc97d40e057..d0b2ec4e614f08e1cc6b547073f694c3a3d56a51 100644 (file)
@@ -16,51 +16,30 @@ namespace CrowEditBase
                public SourceDocument (string fullPath, string editorPath = "#ui.sourceEditor.itmp")
                        : base (fullPath, editorPath) {
                }
-               protected Token[] tokens;
                protected SyntaxRootNode root;
-               protected int currentTokenIndex;
-               SyntaxNode currentNode;
-
-               protected Token currentToken => currentTokenIndex < 0 ? default : tokens[currentTokenIndex];
-               protected Token? previousToken {
-                       get {
-                               if (currentTokenIndex < 1) 
-                                       return null;
-                               return tokens[currentTokenIndex-1];
-                       }
-               }
-               public SyntaxNode CurrentNode {
-                       get => currentNode;
-                       set {
-                               if (currentNode == value)
-                                       return;
-                               currentNode = value;
-                               NotifyValueChanged ("CurrentNode", currentNode);
-                       }
-               }
-               public string CurrentTokenString => root?.GetTokenStringByIndex (currentTokenIndex);
-               public Token CurrentToken => currentToken;
-               public bool IsParsed => tokens.Length > 0 && root != null;
                public SyntaxRootNode Root => root;
+               public bool IsParsed => root != null && Tokens.Length > 0;
 
                //public SyntaxNode EditedNode { get; protected set; }
 
-               public Token[] Tokens => tokens;
+               public ReadOnlySpan<Token> Tokens => root.Tokens;
                public IEnumerable<SyntaxNode> SyntaxRootChildNodes => root?.children;
                public Token FindTokenIncludingPosition (int pos) {
-                       if (pos == 0 || tokens == null || tokens.Length == 0)
+                       if (!IsParsed || pos == 0 || Tokens.Length == 0)
                                return default;
-                       int idx = Array.BinarySearch (tokens, 0, tokens.Length, new  Token () {Start = pos});
-
-                       return idx == 0 ? tokens[0] : idx < 0 ? tokens[~idx - 1] : tokens[idx];
+                       int idx = Tokens.BinarySearch(new  Token () {Start = pos});
+                       return idx == 0 ? Tokens[0] : idx < 0 ? Tokens[~idx - 1] : Tokens[idx];
                }
+               public Token GetTokenByIndex(int tokIdx) => IsParsed && tokIdx >= 0 ?
+                                               Tokens[Math.Min(Tokens.Length - 1, tokIdx)] : default;
                public int FindTokenIndexIncludingPosition (int pos) {
-                       if (pos == 0 || tokens == null || tokens.Length == 0)
+                       if (!IsParsed || pos == 0 || Tokens.Length == 0)
                                return default;
-                       int idx = Array.BinarySearch (tokens, 0, tokens.Length, new  Token () {Start = pos});
-
+                       int idx = Tokens.BinarySearch(new  Token () {Start = pos});
                        return idx == 0 ? 0 : idx < 0 ? ~idx - 1 : idx - 1;
                }
+
+               
                /// <summary>
                /// if outermost is true, return oldest ancestor exept root node, useful for folding.
                /// </summary>
@@ -101,21 +80,14 @@ namespace CrowEditBase
 
                        base.apply(change);
 
-                       Tokenizer tokenizer = CreateTokenizer ();
                        SyntaxAnalyser syntaxAnalyser = CreateSyntaxAnalyser ();
-                       
-                       if (syntaxAnalyser == null) {
-                               root = null;
-                               return;
-                       }
+                       root = syntaxAnalyser?.Process ();
+
+                       NotifyValueChanged("Exceptions", syntaxAnalyser?.Exceptions);
 
                        //SyntaxNode changedNode = root.FindNodeIncludingSpan (TextSpan.FromStartAndLength (change.Start, change.ChangedText.Length));                  
                        
-                       tokens = tokenizer.Tokenize (buffer.Span);
-                       syntaxAnalyser.Process ();
-
-                       root = syntaxAnalyser.Root;
-                       NotifyValueChanged("Exceptions", syntaxAnalyser.Exceptions);
+                       
                        /*
                        SyntaxNode newNode = syntaxAnalyser.Root.FindNodeIncludingSpan (TextSpan.FromStartAndLength (change.Start, change.ChangedText.Length));
 
@@ -145,27 +117,14 @@ namespace CrowEditBase
 
                        //Console.WriteLine ($"CurrentToken: idx({currentTokenIndex}) {currentToken} {RootNode.Root.GetTokenStringByIndex(currentTokenIndex)}");
                }
-               static bool tryReplaceNode (SyntaxNode editedNode, SyntaxNode newNode) {
+               /*static bool tryReplaceNode (SyntaxNode editedNode, SyntaxNode newNode) {
                        if (newNode is SyntaxRootNode || editedNode is SyntaxRootNode)
                                return false;
                        editedNode.Replace (newNode);
                        return true;
                }
 
-               internal void updateCurrentTokAndNode (CharLocation loc) {
-                       int pos = buffer.GetAbsolutePosition(loc);
-                       if (tokens.Length > 0) {
-                               currentTokenIndex = FindTokenIndexIncludingPosition (pos);
-                               CurrentNode = root?.FindNodeIncludingSpan (currentToken.Span);
-                               NotifyValueChanged ("CurrentTokenString", (object)CurrentTokenString);
-                               //NotifyValueChanged ("CurrentTokenType", (uint)(currentToken.Type)>>8);
-                               NotifyValueChanged ("CurrentTokenType", (object)GetTokenTypeString(currentToken.Type));
-                       }else {
-                               currentTokenIndex = -1;
-                               CurrentNode = null;
-                               NotifyValueChanged ("CurrentTokenString", (object)"no token");
-                       }
-               }
+               */
 
                public virtual Color GetColorForToken (TokenType tokType) {
                        if (tokType.HasFlag (TokenType.Punctuation))
@@ -177,9 +136,9 @@ namespace CrowEditBase
                        return Colors.Red;
                }
                public virtual string GetTokenTypeString (TokenType tokenType) => tokenType.ToString();
-               protected abstract Tokenizer CreateTokenizer ();
+               //protected abstract Tokenizer CreateTokenizer ();
                protected abstract SyntaxAnalyser CreateSyntaxAnalyser ();
-               public abstract IList GetSuggestions (CharLocation loc);
+               public abstract IList GetSuggestions (Token currentToken, SyntaxNode currentNode, CharLocation loc);
 
                /// <summary>
                /// complete current token with selected item from the suggestion overlay.
@@ -189,23 +148,14 @@ namespace CrowEditBase
                /// /// <param name="change">the text change to apply</param>
                /// <param name="newSelection">new position or selection, null if normal position after text changes</param>
                /// <returns>true if successed</returns>
-               public abstract bool TryGetCompletionForCurrentToken (object suggestion, out TextChange change, out TextSpan? newSelection);
-               protected bool previousTokHasFlag(TokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
+               public abstract bool TryCompleteToken (Token CurrentToken, SyntaxNode CurrentNode, object suggestion, out TextChange change, out TextSpan? newSelection);
+               //protected bool previousTokHasFlag(TokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
                void parse () {
-                       Tokenizer tokenizer = CreateTokenizer ();
-                       tokens = tokenizer?.Tokenize (source);
                        SyntaxAnalyser syntaxAnalyser = CreateSyntaxAnalyser ();
-                       Stopwatch sw = Stopwatch.StartNew ();
-                       syntaxAnalyser?.Process ();
-                       sw.Stop();
-                       root = syntaxAnalyser?.Root;
+                       root = syntaxAnalyser?.Process ();
+                       NotifyValueChanged("Exceptions", syntaxAnalyser?.Exceptions);
 
                        //CrowEditBase.App.Log (LogType.Low, $"Syntax Analysis done in {sw.ElapsedMilliseconds}(ms) {sw.ElapsedTicks}(ticks)");
-                       if (syntaxAnalyser == null)
-                               return;
-                               /*foreach (Token t in Tokens)
-                                       Console.WriteLine ($"{t,-40} {Source.AsSpan(t.Start, t.Length).ToString()}");
-                               syntaxAnalyser.Root.Dump();*/
                }
 
        }
index cad6fe1b26ce749545634cd978afab53e8ed0565..3ebbd771bd85813dc0e85c1868018d9af84060d4 100644 (file)
@@ -4,22 +4,26 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using Crow.Text;
 
 namespace CrowEditBase
 {
        public abstract class SyntaxAnalyser {
                //protected abstract void Parse(SyntaxNode node);
-               protected SourceDocument source;
-               public SyntaxRootNode Root { get; protected set; }
+               protected ReadOnlyMemory<char> source;
+               protected LineCollection lines;
+               protected SyntaxRootNode Root;
                public IEnumerable<SyntaxException> Exceptions => Root?.GetAllExceptions();
-               public SyntaxAnalyser (SourceDocument source) {
-                       this.source = source;
+               public SyntaxAnalyser (SourceDocument document) {
+                       this.source = document.ImmutableBufferCopy;
+                       this.lines = document.Lines;
                }
-               public abstract void Process ();
+               public abstract SyntaxRootNode Process ();
                
                #region Token handling
                protected Token curTok => tokIdx < 0 ? default : tokens[tokIdx];
-               protected Token[] tokens;
+               protected ReadOnlySpan<char> curTokString => curTok.AsString(source.Span);
+               protected ReadOnlySpan<Token> tokens => Root.Tokens;
                protected bool EOF => tokIdx == tokens.Length;
                protected bool tryRead (out Token tok) {
                        if (EOF) {
@@ -68,7 +72,7 @@ namespace CrowEditBase
                #endregion
 
                #region parsing context
-               protected int currentLine, tokIdx;
+               protected int currentLine = 0, tokIdx = 0;
                protected SyntaxNode currentNode;
                #endregion
 
@@ -77,15 +81,23 @@ namespace CrowEditBase
                /// </summary>
                /// <param name="endToken">The final token of this node</param>
                /// <param name="endLine">the endline number of this node</param>
-               protected void setEndLineForCurrentNode (int endTokenOffsetFromCurrentTokIdx = 0) {
-                       currentNode.TokenCount = tokIdx - currentNode.TokenIndexBase + endTokenOffsetFromCurrentTokIdx;
+               protected void finishCurrentNode (int endTokenOffsetFromCurrentTokIdx = 0) {
+                       int count = tokIdx - currentNode.TokenIndexBase + endTokenOffsetFromCurrentTokIdx;
+                       currentNode.TokenCount = count < 0 ? null : count;
+                       if (endTokenOffsetFromCurrentTokIdx < 0) {
+                               Token lastTok = currentNode.LastTokenIndex.HasValue ?
+                                       Root.GetTokenByIndex(currentNode.LastTokenIndex.Value) :
+                                       Root.GetTokenByIndex(currentNode.TokenIndexBase);
+                               currentNode.EndLine = lines.GetLocation(lastTok.End).Line;
+                       }
+                       //currentNode.EndLine
                        currentNode.EndLine = currentLine;
                        currentNode = currentNode.Parent;
                }
-               protected void setEndOfNode (int endTokenOffsetFromCurrentTokIdx = 0, int endLineOffsetFromCurrentLine = 0) {
+               /*protected void setEndOfNode (int endTokenOffsetFromCurrentTokIdx = 0, int endLineOffsetFromCurrentLine = 0) {
                        currentNode.TokenCount = tokIdx - currentNode.TokenIndexBase + endTokenOffsetFromCurrentTokIdx;
                        currentNode.EndLine = currentLine + endLineOffsetFromCurrentLine;
-               }
+               }*/
                protected void setCurrentNodeEndLine (int endLine)
                        => currentNode.EndLine = endLine;
                protected bool skipTrivia(bool skipLineBreaks = true) {
@@ -100,7 +112,7 @@ namespace CrowEditBase
                        return !EOF;
                }
                protected void addException(string message) {
-                       currentNode.AddException(new SyntaxException(message, curTok));
+                       currentNode.AddException(new SyntaxException(message, curTok, source));
                }
 
 
index 3031acb3577b14c8281f15c166c28188c7ba6f8a..6da5a1aca8a38e786dad1f306a4fcfcecc954054 100644 (file)
@@ -7,13 +7,13 @@ namespace CrowEditBase
 {
        public class SyntaxException : Exception {
                public readonly Token Token;
-               public readonly SyntaxAnalyser SyntaxAnalyser;
-               public SyntaxException(string message, Token token = default, SyntaxAnalyser syntaxAnalyser = null, Exception innerException = null)
+               public readonly ReadOnlyMemory<char> SourceText;
+               public SyntaxException(string message, Token token = default, ReadOnlyMemory<char> textBuffer = default, Exception innerException = null)
                                : base (message, innerException) {
                        Token = token;
-                       SyntaxAnalyser = syntaxAnalyser;
+                       SourceText = textBuffer;
                }
-               public string TokenString => SyntaxAnalyser.Root.GetTokenString(Token);
+               public string TokenString => SourceText.Span.Slice(Token.Start,Token.Length).ToString();
         public override string ToString() => $"{Message}: {TokenString}";
     }
 }
\ No newline at end of file
index 4de25e48b758ded84119cc8ce47e3a17b7191d19..c9819731c691c9246e6a22760b77f103bc488147 100644 (file)
@@ -210,5 +210,6 @@ namespace CrowEditBase
                        return Span.Length < 0 ? "" : Root.GetText(Span).ToString();
                }
                public bool IsSimilar (SyntaxNode other) => this.GetType() == other?.GetType();
+
        }
 }
\ No newline at end of file
index 7955c3312c59defd851a4b0ff39ad4f664e2730c..17d41f0fe8cecc9109ae475946aaa1c471129b9f 100644 (file)
@@ -7,23 +7,27 @@ using Crow.Text;
 namespace CrowEditBase
 {
        public abstract class SyntaxRootNode : SyntaxNode {
-               protected readonly SourceDocument source;
-               public SyntaxRootNode (SourceDocument source) {
+               public SyntaxRootNode (ReadOnlyMemory<char> source, Token[] tokens) {
                        this.source = source;
+                       this.tokens = tokens;
                }
+               protected readonly ReadOnlyMemory<char> source;
+               protected Token[] tokens;
                public override int TokenIndexBase => 0;
-               public override int? TokenCount { get => Math.Max (0, source.Tokens.Length - 1); internal set {} }
+               public override int? TokenCount { get => tokens == null ? default : Math.Max (0, tokens.Length - 1); internal set {} }
                public override SyntaxRootNode Root => this;
                public override bool IsFoldable => false;
                public override SyntaxNode NextSiblingOrParentsNextSibling => null;
                public override void UnfoldToTheTop() {}
-               public string GetTokenStringByIndex (int idx) =>
-                       idx >= 0 && idx < source.Tokens.Length ? Root.GetText(source.Tokens[idx].Span).ToString() : null;
-               public Token GetTokenByIndex (int idx) =>
-                       idx >= 0 && idx < source.Tokens.Length ? source.Tokens[idx] : default;
+
+               public ReadOnlySpan<Token> Tokens => tokens;
+               public string GetTokenStringByIndex (int idx) => tokens != null ?
+                       idx >= 0 && idx < tokens.Length ? GetText(tokens[idx].Span).ToString() : null : null;
+               public Token GetTokenByIndex (int idx) => tokens != null ?
+                       idx >= 0 && idx < tokens.Length ? tokens[idx] : default : default;
                public ReadOnlySpan<char> GetText(TextSpan span) =>
-                       source.GetText(span);
+                       source.Span.Slice(span.Start, span.Length);
                public string GetTokenString(Token tok) =>
-                       source.GetText(tok.Span).ToString();
+                       GetText(tok.Span).ToString();
        }
 }
\ No newline at end of file
index 9ca47496081670cb1fb2cfc4fddc4039f2512430..b6c82db898aed0800c6f14c4451ad988d4d69a7d 100644 (file)
@@ -14,6 +14,20 @@ using Drawing2D;
 
 namespace CrowEditBase
 {
+       public static class Extensions {
+               public static bool TryCast<T>(this object o, out T result) {
+                       result = default;
+                       if (o != null) {
+                               Type tIn = o.GetType();
+                               Type tOut = typeof(T);
+                               if (tOut.IsAssignableFrom(tIn)) {
+                                       result = (T)o;
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+       }
        public abstract class CrowEditBase : Interface {
                public static CrowEditBase App;
                public CrowEditBase (int width, int height, bool singleThreaded = true) : base (width, height, singleThreaded) {
index 03db4e518b1b31a9cd905fcb1dcbfdebab2d765a..d4a032b51880aeb3b8c5150af0d606efefc40a85 100644 (file)
@@ -35,7 +35,7 @@ namespace CrowEditBase
                public void ExitWriteLock () => documentRWLock.ExitWriteLock ();
 
                public abstract bool TryGetState<T> (object client, out T state);
-               public abstract void RegisterClient (object client);
+               public abstract void RegisterClient (object client, bool initialState = false);
                public abstract void UnregisterClient (object client);
 
                DateTime accessTime;
index 00f2e37b9f3fd7b1004c01f65a095c129ef1cb15..d3b738137f8ddfae9e1b0ac18c111a76c25e5600 100644 (file)
@@ -125,8 +125,10 @@ namespace Crow
                /// </summary>
                /// <param name="position">Absolute character position in text.</param>
                public void SetCursorPosition (int position) {
+                       document.EnterReadLock();
                        CharLocation loc = document.GetLocation (position);
                        loc.Column = Math.Min (loc.Column, document.GetLine (loc.Line).Length);
+                       document.ExitReadLock();
                        CurrentLoc = loc;
                }
 
@@ -356,6 +358,7 @@ namespace Crow
                        bool selectionNotEmpty = false;
 
                        document.EnterReadLock();
+                       
                        try {
                                //if (HasFocus) {
                                        if (currentLoc?.Column < 0) {
@@ -555,9 +558,8 @@ namespace Crow
                protected void updateLocation (IContext gr, ref CharLocation loc) {
                        if (loc.HasVisualX)
                                return;
-                       TextLine ls = document.GetLine (loc.Line);
-                       ReadOnlySpan<char> curLine = document.GetText (ls);
-
+                       
+                       ReadOnlySpan<char> curLine = document.GetLineText (loc.Line);
                        if (loc.Column >= 0) {
                                //int encodedBytes = Crow.Text.Encoding2.ToUtf8 (curLine.Slice (0, loc.Column), bytes);
 #if DEBUG
@@ -575,7 +577,7 @@ namespace Crow
                                int totChar = 0;
                                double cPos = 0;
 
-                               for (int i = 0; i < ls.Length; i++) {
+                               for (int i = 0; i < curLine.Length; i++) {
                                        int encodedBytes = curLine.Slice (i, 1).ToUtf8 (bytes, ref totChar, tabSize);
                                        bytes[encodedBytes] = 0;
 
@@ -591,7 +593,7 @@ namespace Crow
 
                                        cPos += te.XAdvance;
                                }
-                               loc.Column = ls.Length;
+                               loc.Column = curLine.Length;
                                loc.VisualCharXPosition = cPos;
                                loc.TabulatedColumn = totChar;
                        }
index 9535d9e7a9613c886b917880c3734e672aea6d4c..9e87ebd3384a4c2afc6feb0c79901b1a24302a7b 100644 (file)
@@ -15,7 +15,7 @@ using System.Linq;
 namespace Crow
 {
        public class SourceEditor : Editor {
-               object TokenMutex = new object();
+               int currentTokenIndex = -1;
                SyntaxNode currentNode;
 #if DEBUG_NODE
                SyntaxNode _hoverNode;
@@ -36,9 +36,11 @@ namespace Crow
                                        return;
                                currentNode = value;
                                NotifyValueChanged ("CurrentNode", currentNode);
-                               RegisterForRedraw ();
                        }
                }
+               
+               public Token CurrentToken => typeof(SourceDocument).IsAssignableFrom(Document?.GetType()) ?
+                       (Document as SourceDocument).GetTokenByIndex(currentTokenIndex) : default;
 
                #region suggestions and autocomplete
                ListBox overlay;
@@ -59,10 +61,11 @@ namespace Crow
 
                protected void tryGetSuggestions () {
                        if (currentLoc.HasValue && Document is SourceDocument srcDoc && srcDoc.IsParsed) {
-                               IList suggs = srcDoc.GetSuggestions (CurrentLoc.Value);
+                               IList suggs = srcDoc.GetSuggestions (CurrentToken, currentNode, CurrentLoc.Value);
+                               Token tok = CurrentToken;
                                if (suggs != null && suggs.Count == 1 && (
-                                       (suggs[0] is System.Reflection.MemberInfo mi && mi.Name == srcDoc.CurrentTokenString) ||
-                                       (suggs[0].ToString() == srcDoc.CurrentTokenString)
+                                       (suggs[0] is System.Reflection.MemberInfo mi && mi.Name == srcDoc.GetText(tok.Span)) ||
+                                       (suggs[0].ToString() == srcDoc.GetText(tok.Span))
                                )){
                                        Suggestions = null;
                                }else
@@ -118,7 +121,7 @@ namespace Crow
                }
                void completeToken () {
                        if (Document is SourceDocument srcDoc) {
-                               if (srcDoc.TryGetCompletionForCurrentToken (overlay.SelectedItem, out TextChange change, out TextSpan? nextSelection)) {
+                               if (srcDoc.TryCompleteToken (CurrentToken, CurrentNode, overlay.SelectedItem, out TextChange change, out TextSpan? nextSelection)) {
                                        update (change);
                                        if (nextSelection.HasValue) {
                                                Selection = nextSelection.Value;
@@ -160,8 +163,7 @@ namespace Crow
                                        while (fold != null && fold.StartLine == currentLoc.Value.Line)
                                                fold = fold.Parent;
                                        fold?.UnfoldToTheTop();
-                                       if (Document is SourceDocument doc)
-                                               doc.updateCurrentTokAndNode (currentLoc.Value);
+                                       updateCurrentTokAndNode();
                                }
                                NotifyValueChanged ("CurrentLine", CurrentLine);
                                NotifyValueChanged ("CurrentColumn", CurrentColumn);
@@ -497,7 +499,7 @@ namespace Crow
 
                }
                protected override void drawContent (IContext gr) {
-                       if (!(Document is SourceDocument doc)) {
+                       if (!(Document is SourceDocument doc && doc.Root != null)) {
                                base.drawContent (gr);
                                return;
                        }
@@ -528,7 +530,6 @@ namespace Crow
                                marginRect.Height = lineHeight;
                                cb.Left += leftMargin;
 
-
                                CharLocation selStart = default, selEnd = default;
                                bool selectionNotEmpty = false;
                                CharLocation? nodeStart = null, nodeEnd = null;
@@ -660,7 +661,7 @@ namespace Crow
                                                                gr.ShowText (bytes.Slice (0, encodedBytes));
                                                        }
 
-                                                       if (doc.CurrentToken.Equals(tok)) {
+                                                       if (CurrentToken.Equals(tok)) {
                                                                /*CharLocation? tokloc = Document.GetLocation  (tok.Start);
                                                                updateLocation (gr, cb.Width, ref tokloc);*/
                                                                Rectangle r = new RectangleD(pixX, pixY, extents.Width, lineHeight);
@@ -800,8 +801,7 @@ namespace Crow
                protected override void update (TextChange change) {
                        base.update (change);
 
-                       if (Document is SourceDocument srcdoc)
-                               srcdoc.updateCurrentTokAndNode (CurrentLoc.Value);
+                       updateCurrentTokAndNode();
 
                        if (!disableSuggestions &&!disableTextChangedEvent && HasFocus)
                                tryGetSuggestions ();
@@ -817,6 +817,18 @@ namespace Crow
                        }
                        //Console.WriteLine ($"{pos}: {suggestionTok.AsString (_text)} {suggestionTok}");
                }
-               
+               void updateCurrentTokAndNode() {
+                       if (currentLoc.HasValue && Document is SourceDocument srcdoc) {
+                               currentTokenIndex = srcdoc.GetAbsolutePosition(currentLoc.Value);
+                               Token tok = srcdoc.FindTokenIncludingPosition(currentTokenIndex);
+                               CurrentNode = srcdoc.Root?.FindNodeIncludingSpan(tok.Span);
+                               
+                               NotifyValueChanged("CurrentToken",tok);
+                       } else {
+                               currentTokenIndex = -1;
+                               CurrentNode = null;
+                               NotifyValueChanged("CurrentToken",default);
+                       }
+               }
        }
 }
\ No newline at end of file
index 505098ef4bf7cd0f9e2761ee0000c0273fe7bd35..b4c6eb1dfe7d0fe76b67a75f8bb1191811cf7e73 100644 (file)
@@ -18,10 +18,11 @@ namespace CrowEditBase
                public bool mixedLineBreak = false;
                public string lineBreak = null;
 
+               internal LineCollection GetLineListCopy() => new LineCollection(lines.ToArray());
                public Span<char> Span => buffer.Span.Slice(0, length);
                public ReadOnlySpan<char> ReadOnlySpan => buffer.Span.Slice(0, length);
                public bool IsEmpty => length == 0;
-               public bool IsDirty => origBuffer.Span.Equals(buffer.Span, StringComparison.Ordinal);
+               public bool IsDirty => !origBuffer.Span.Equals(Span, StringComparison.Ordinal);
                public int LinesCount => lines.Count;
                public int Length => length;
                public ReadOnlyMemory<char> ReadOnlyCopy {
@@ -30,7 +31,7 @@ namespace CrowEditBase
                        }
                } 
                public void ResetDirtyState () {
-                       origBuffer = buffer.ToArray();
+                       origBuffer = Span.ToArray();
                }
                public TextBuffer(ReadOnlySpan<char> origText) {
                        length = origText.Length;
@@ -41,6 +42,7 @@ namespace CrowEditBase
                                lines.Add (new TextLine (0, 0, 0));
                        else
                                lines.Update (Span);
+                       ResetDirtyState ();
                }
                public void Update (TextChange change) {
                        ReadOnlySpan<char> orig = buffer.Span;
@@ -86,6 +88,8 @@ namespace CrowEditBase
                }
                public CharLocation GetLocation (int absolutePosition) => lines.GetLocation (absolutePosition);
                public TextLine GetLine (int index) => lines[index];
+               public ReadOnlySpan<char> GetText (TextLine line) => GetText(line.Span);
+               public ReadOnlySpan<char> GetText (TextSpan textSpan) => buffer.Span.Slice(textSpan.Start, textSpan.Length);
                public int GetAbsolutePosition (CharLocation loc) => lines.GetAbsolutePosition (loc);
                public CharLocation EndLocation => new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
         public override string ToString() => ReadOnlySpan.ToString();
index 43f14c27977c40e79459cfdcf6a11212215ad156..1843dee2315d53050f6904faa98a3a8ac484c760 100644 (file)
@@ -23,6 +23,8 @@ namespace CrowEditBase
 
                protected TextBuffer buffer;
                public ReadOnlySpan<char> source => buffer.ReadOnlySpan;
+               public ReadOnlyMemory<char> ImmutableBufferCopy => buffer.ReadOnlyCopy;
+               internal LineCollection Lines => buffer.GetLineListCopy();
                System.Text.Encoding encoding = System.Text.Encoding.UTF8;
 
                public override bool IsDirty => buffer.IsDirty;
@@ -40,18 +42,19 @@ namespace CrowEditBase
                        }
                        return state != null;
                }
-               public override void RegisterClient(object client)
+               public override void RegisterClient(object client, bool initState = false)
                {
-                       documentRWLock.EnterWriteLock ();
+                       EnterWriteLock();
                        registeredClients.Add (client, null);
-                       //notifyClient (client, new TextChange (0, 0, source));
-                       documentRWLock.ExitWriteLock ();
+                       if (initState)
+                               notifyClient (client,new TextChange (0, 0,source.ToString()));                          
+                       ExitWriteLock();
                }
                public override void UnregisterClient(object client)
                {
-                       documentRWLock.EnterWriteLock ();
+                       EnterWriteLock();
                        registeredClients.Remove (client);
-                       documentRWLock.ExitWriteLock ();
+                       ExitWriteLock();
                }
                void notifyClients (TextChange tc, object triggeringClient = null) {
                        object[] clients = registeredClients.Keys.ToArray ();
@@ -84,12 +87,6 @@ namespace CrowEditBase
                                        encoding = sr.CurrentEncoding;
                                }
                        }
-                       ReadOnlyMemory<char> testbuff = buffer.ReadOnlyCopy;
-                       
-                       buffer.Update(new TextChange(0,0,"test"));
-                       
-                       Debug.WriteLine($"buffer: {buffer.ToString()}");
-                       Debug.WriteLine($"testbuff: {testbuff.ToString()}");
                }
                protected override void initNewFile()
                {
@@ -253,10 +250,18 @@ namespace CrowEditBase
                                documentRWLock.ExitReadLock();
                        }
                }
+               public ReadOnlySpan<char> GetLineText (int index) {
+                       documentRWLock.EnterReadLock ();
+                       try {
+                               return buffer.GetText (buffer.GetLine(index));
+                       } finally {
+                               documentRWLock.ExitReadLock();
+                       }
+               }               
                public ReadOnlySpan<char> GetText (TextLine line) {
                        documentRWLock.EnterReadLock ();
                        try {
-                               return source.GetLine (line);
+                               return buffer.GetText (line);
                        } finally {
                                documentRWLock.ExitReadLock();
                        }
@@ -264,7 +269,7 @@ namespace CrowEditBase
                public ReadOnlySpan<char> GetText (TextSpan span) {
                        documentRWLock.EnterReadLock ();
                        try {
-                               return source.Slice (span.Start, span.Length);
+                               return buffer.GetText (span);
                        } finally {
                                documentRWLock.ExitReadLock();
                        }
index 01b6d2496a0c5942fe2683d83e20be1d77220e17..4321e719fe6705db676e5c0820856203907d9d74 100644 (file)
@@ -4,6 +4,6 @@
                <IntermediateOutputPath>$(SolutionDir)build\obj\$(Configuration)\</IntermediateOutputPath>
                <License>MIT</License>
                <Authors>Jean-Philippe Bruyère</Authors>
-               <LangVersion>7.2</LangVersion>
+               <!--<LangVersion>7.2</LangVersion>-->
        </PropertyGroup>
 </Project>
index 815cb3ac85d98afc56ff758134dc8cf87d63abbd..7b96840a4826a03f1e34769ba1335d0b92a62aee 100644 (file)
@@ -104,9 +104,9 @@ namespace Crow
 
                                if (value is ImlDocument imlDoc) {
                                        document?.UnregisterClient (this);
-                                       imlSource = "";
                                        document = imlDoc;
-                                       document?.RegisterClient (this);
+                                       imlSource = default;
+                                       document?.RegisterClient (this, true);
 
                                        NotifyValueChangedAuto (document);
                                        RegisterForGraphicUpdate ();
index 72988c68f365906c6e026d6fdd2130c3e5f15876..acb0487fcd7c3c0a9a55c7612a6a83390dc91c24 100644 (file)
@@ -31,7 +31,6 @@ namespace CECrowPlugin
                                if (msbp.IsCrowProject)
                        }*/
                }
-               protected override Tokenizer CreateTokenizer() => new ImlTokenizer ();
                protected override SyntaxAnalyser CreateSyntaxAnalyser() => new ImlSyntaxAnalyser (this);
                public override string GetTokenTypeString (TokenType tokenType) => ((ImlTokenType)tokenType).ToString();
 
@@ -49,20 +48,9 @@ namespace CECrowPlugin
                        Type crowType = IML.Instantiator.GetWidgetTypeFromName (crowTypeName);
                        return crowType.GetMember (memberName, BindingFlags.Public | BindingFlags.Instance).FirstOrDefault ();
                }
-               
-               protected bool previousTokHasFlag(ImlTokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
-               
-               protected bool tryCast<TOUT> (object objectToCast, out TOUT result) {
-                       result = default;
-                       if (typeof(TOUT).IsAssignableFrom(objectToCast.GetType())) {
-                               result = (TOUT)objectToCast;
-                               return true;
-                       }
 
-                       return false;
-               }
-               public override IList GetSuggestions (CharLocation loc) {
-                       IList sugs = base.GetSuggestions (loc);
+               public override IList GetSuggestions (Token currentToken, SyntaxNode CurrentNode, CharLocation loc) {
+                       IList sugs = base.GetSuggestions (currentToken, CurrentNode, loc);
                        if (sugs != null)
                                return sugs;
 
@@ -73,8 +61,7 @@ namespace CECrowPlugin
                                return new List<string> (allWidgetNames);
                        if (tok.GetTokenType() == XmlTokenType.ElementName)
                                return allWidgetNames.Where (s => s.StartsWith (root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
-                       if ((tok.Type.HasFlag(TokenType.WhiteSpace) || previousTokHasFlag(TokenType.WhiteSpace)) &&
-                                               tryCast(CurrentNode, out ElementTagSyntax ets)) {
+                       if (tok.Type.HasFlag(TokenType.WhiteSpace) && CurrentNode.TryCast(out ElementTagSyntax ets)) {
                                if (ets.name.HasValue)
                                        return getAllCrowTypeMembers (ets.Name).ToList();
                                return null;
@@ -139,8 +126,8 @@ namespace CECrowPlugin
                        }*/
                        return null;
                }
-               public override bool TryGetCompletionForCurrentToken (object suggestion, out TextChange change, out TextSpan? newSelection) {
-                       return base.TryGetCompletionForCurrentToken (suggestion is MemberInfo mi ? mi.Name : suggestion, out change, out newSelection);
+               public override bool TryCompleteToken (Token tok, SyntaxNode node, object suggestion, out TextChange change, out TextSpan? newSelection) {
+                       return base.TryCompleteToken (tok, node, suggestion is MemberInfo mi ? mi.Name : suggestion, out change, out newSelection);
                }
 
                public override Color GetColorForToken(TokenType tokType)
index db7aa17a0058da5d98d9bea922f477ad500d2700..e1b9047ac638e26cb6de68a9a8e196974bf83102 100644 (file)
@@ -10,14 +10,12 @@ using CrowEdit.Xml;
 namespace CECrowPlugin
 {
        public class ImlSyntaxAnalyser : XmlSyntaxAnalyser {
-               public ImlSyntaxAnalyser (ImlDocument source) : base (source) {
-                       this.source = source;
-               }
+               public ImlSyntaxAnalyser (ImlDocument document) : base (document) {}
 
 
-               public override void Process () {
+               public override SyntaxRootNode Process () {
 
-                       base.Process();
+                       return base.Process();
 
 /*
                        ImlDocument xmlDoc = source as ImlDocument;
index 215d7647f87bc3e44f14fadcc76edc784315545c..ac39b231102327d02fb2a88200991c5e2eee343b 100644 (file)
@@ -22,16 +22,15 @@ namespace CECrowPlugin.Style
                        }*/
                }
 
-               protected override Tokenizer CreateTokenizer() => new StyleTokenizer ();
                protected override SyntaxAnalyser CreateSyntaxAnalyser() => new StyleSyntaxAnalyser (this);
 
-               public override IList GetSuggestions (CharLocation loc) {
-                       Console.ForegroundColor = ConsoleColor.DarkYellow;
+               public override IList GetSuggestions (Token currentToken, SyntaxNode CurrentNode, CharLocation loc) {
+                       /*Console.ForegroundColor = ConsoleColor.DarkYellow;
                        Console.WriteLine ($"Tok: {this.CurrentTokenString} {((StyleTokenType)CurrentToken.Type).ToString()}");
-                       Console.ResetColor();
+                       Console.ResetColor();*/
                        return null;
                }
-               public override bool TryGetCompletionForCurrentToken(object suggestion, out TextChange change, out TextSpan? newSelection)
+               public override bool TryCompleteToken(Token tok, SyntaxNode node, object suggestion, out TextChange change, out TextSpan? newSelection)
                {
                        change = default;
                        newSelection = null;
index b4709b7ba0b4b12dc9a3d41dd73fb7b978590b53..a6045e55beb53e3b10f5493ea8b3731e31875f4b 100644 (file)
@@ -17,21 +17,21 @@ namespace CECrowPlugin.Style
                }
        }
        public class StyleSyntaxAnalyser : SyntaxAnalyser {
-               public StyleSyntaxAnalyser (StyleDocument source) : base (source) {
-                       this.source = source;
-               }
+               public StyleSyntaxAnalyser (StyleDocument document) : base (document) {}
+
+               public override SyntaxRootNode Process () {
+                       Tokenizer tokenizer = new StyleTokenizer();
+                       Token[] tokens = tokenizer.Tokenize(source.Span);
+
+                       currentNode = Root = new StyleRootSyntax (source, tokens);
 
-               public override void Process () {
-                       StyleDocument doc = source as StyleDocument;
-                       currentNode = Root = new StyleRootSyntax (doc);
                        currentLine = 0;
-                       Span<Token> toks = source.Tokens;
                        tokIdx = 0;
 
                        int firstNameIdx = -1;
 
-                       while (tokIdx < toks.Length) {
-                               Token curTok = toks[tokIdx];
+                       while (tokIdx < tokens.Length) {
+                               Token curTok = tokens[tokIdx];
                                if (curTok.Type == TokenType.LineBreak)
                                        currentLine++;
                                else if (!curTok.Type.HasFlag (TokenType.Trivia)) {
@@ -51,11 +51,13 @@ namespace CECrowPlugin.Style
                        }
                        while (currentNode.Parent != null) {
                                if (!currentNode.TokenCount.HasValue)
-                                       setEndLineForCurrentNode (-1);
+                                       finishCurrentNode (-1);
                                else
                                        currentNode = currentNode.Parent;
                        }
                        setCurrentNodeEndLine (currentLine);
+
+                       return Root;
                }
        }
 }
\ No newline at end of file
index c740e90b9fea54f5a14ab5c78376738cc3b557cd..0619d710672d69355fbfb490954b81f04dc69855 100644 (file)
@@ -11,9 +11,7 @@ namespace CECrowPlugin.Style
 {
 
        public class StyleRootSyntax : SyntaxRootNode {
-               public StyleRootSyntax (StyleDocument source)
-                       : base (source) {
-               }
+               public StyleRootSyntax (ReadOnlyMemory<char> source, Token[] tokens) : base (source, tokens) { }
        }
        public class ConstantDefinitionSyntax : SyntaxNode {
                internal int? name, equal, valueOpen, valueClose;
index 02d976b0db8d67e1d97301d059717b30906be0ca..e5494bf31775a44403597018bc648c1872ec5157 100644 (file)
@@ -2,6 +2,7 @@
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 
+using System;
 using Crow.Text;
 using System.Collections;
 using CrowEditBase;
@@ -22,13 +23,12 @@ namespace CrowEdit.Ebnf
                public EbnfDocument (string fullPath, string editorPath) : base (fullPath, editorPath) {
 
                }
-               protected override Tokenizer CreateTokenizer() => new EbnfTokenizer ();
                protected override SyntaxAnalyser CreateSyntaxAnalyser() => new EbnfSyntaxAnalyser (this);
 
-               public override IList GetSuggestions (CharLocation loc) {
+               public override IList GetSuggestions (Token currentToken, SyntaxNode CurrentNode, CharLocation loc) {
                        return null;
                }
-               public override bool TryGetCompletionForCurrentToken (object suggestion, out TextChange change, out TextSpan? newSelection) {
+               public override bool TryCompleteToken (Token tok, SyntaxNode node, object suggestion, out TextChange change, out TextSpan? newSelection) {
                        newSelection = null;
                        change = default;
                        return false;
index 382a3781af196fd606668b16d0c52475fed75583..d733ab3b3cd59937c6c315004b05a4b5c61c8e10 100644 (file)
@@ -10,9 +10,7 @@ namespace CrowEdit.Ebnf
 {
 
        public class EbnfSyntaxAnalyser : SyntaxAnalyser {
-               public EbnfSyntaxAnalyser  (EbnfDocument source) : base (source) {
-                       this.source = source;
-               }
+               public EbnfSyntaxAnalyser  (EbnfDocument document) : base (document) {}
                
                
                // ::= NCName '::=' Expression
@@ -22,14 +20,15 @@ namespace CrowEdit.Ebnf
                // Item ::= Primary ( '?' | '*' | '+' )?
                //NCName | StringLiteral | CharCode | CharClass | '(' Choice ')'
                // StringLiteral ::= '"' [^"]* '"' | "'" [^']* "'"      
-
-        public override void Process()
+               
+        public override SyntaxRootNode Process()
         {
-            EbnfDocument doc = source as EbnfDocument;
-                       currentNode = Root = new EbnfRootSyntax (doc);
+                       Tokenizer tokenizer = new EbnfTokenizer();
+                       Token[] tokens = tokenizer.Tokenize(source.Span);
+
+                       currentNode = Root = new EbnfRootSyntax (source, tokens);
                        currentLine = 0;
                        tokIdx = 0;
-                       tokens = doc.Tokens;
                        
                        /*while(tokIdx < tokens.Length) {
                                skipTrivia();
@@ -81,6 +80,7 @@ namespace CrowEdit.Ebnf
                                
 
                        setCurrentNodeEndLine (currentLine);
+                       return Root;
         }
                
 
index c6615d07bac78b1a66866ad5bb7c55af6e9f6151..b709ffde6204388e1be7cd89bfbf12720b016256 100644 (file)
@@ -11,9 +11,7 @@ namespace CrowEdit.Ebnf
 {
 
        public class EbnfRootSyntax : SyntaxRootNode {
-               public EbnfRootSyntax (EbnfDocument source)
-                       : base (source) {
-               }
+               public EbnfRootSyntax (ReadOnlyMemory<char> source, Token[] tokens) : base (source, tokens) { }
     }
        public class EbnfSyntaxNode : SyntaxNode {
                public EbnfSyntaxNode(int startLine, int tokenBase)
index efe786d484d073fe0d0fb1f7349b4179d836dbe5..6a68f3913f016aeca9e223b82373160c3e2867d0 100644 (file)
@@ -44,14 +44,13 @@ namespace CERoslynPlugin
                }
 
                #region SourceDocument abstract class implementation
-               protected override Tokenizer CreateTokenizer() => new CSTokenizer ();
                protected override SyntaxAnalyser CreateSyntaxAnalyser() => new CSSyntaxAnalyser (this);
 
-               public override IList GetSuggestions (CharLocation loc)
+               public override IList GetSuggestions (Token currentToken, SyntaxNode CurrentNode, CharLocation loc)
                {
                        throw new NotImplementedException();
                }
-               public override bool TryGetCompletionForCurrentToken (object suggestion, out TextChange change, out TextSpan? newSelection)
+               public override bool TryCompleteToken (Token tok, SyntaxNode node, object suggestion, out TextChange change, out TextSpan? newSelection)
                {
                        throw new NotImplementedException();
                }
index 761e47ea035a4bae0c0fa2627e9258562f32bfd6..1ac8b0e00baa1322020de55ee6d539b6c227efb3 100644 (file)
@@ -9,22 +9,23 @@ using CrowEditBase;
 namespace CERoslynPlugin
 {
        public class CSRootSyntax : SyntaxRootNode {
-               public CSRootSyntax (SourceDocument source)
-                       : base (source) {
-               }
+               public CSRootSyntax (ReadOnlyMemory<char> source, Token[] tokens) : base (source, tokens) {     }
        }
+       
        public class CSSyntaxAnalyser : SyntaxAnalyser {
         /*protected override void Parse(SyntaxNode node)
         {
             throw new NotImplementedException();
         }*/
 
-               public CSSyntaxAnalyser (CSDocument source) : base (source) {
-                       this.source = source;
-               }
+               public CSSyntaxAnalyser (CSDocument document) : base (document) {}
+
+               public override SyntaxRootNode Process () {
+                       Tokenizer tokenizer = new CSTokenizer();
+                       Token[] tokens = tokenizer.Tokenize(source.Span);
 
-               public override void Process () {
-                       currentNode = Root = new CSRootSyntax (source);
+                       currentNode = Root = new CSRootSyntax (source, tokens);
+                       return Root;
                }
        }
 }
\ No newline at end of file
index ecdb3d916de25ad32cf243c295e6eaeb402468ca..196825cfa2a840f01137c3743d6bb3c4e2ca6f36 100644 (file)
@@ -7,6 +7,7 @@ using System.Collections;
 using CrowEditBase;
 using Drawing2D;
 using System.Collections.Generic;
+using System;
 
 namespace CrowEdit.Xml
 {
@@ -17,16 +18,14 @@ namespace CrowEdit.Xml
                public static void SetTokenType (this Token tok, XmlTokenType type) {
                        tok.Type = (TokenType)type;
                }
+
        }
        public class XmlDocument : SourceDocument {
 
-               public XmlDocument (string fullPath, string editorPath) : base (fullPath, editorPath) {
-
-               }
-               protected override Tokenizer CreateTokenizer() => new XmlTokenizer ();
+               public XmlDocument (string fullPath, string editorPath) : base (fullPath, editorPath) { }
                protected override SyntaxAnalyser CreateSyntaxAnalyser() => new XmlSyntaxAnalyser (this);
                public override string GetTokenTypeString (TokenType tokenType) => ((XmlTokenType)tokenType).ToString();
-               public override IList GetSuggestions (CharLocation loc) {
+               public override IList GetSuggestions (Token currentToken, SyntaxNode CurrentNode, CharLocation loc) {
                        /*currentToken = FindTokenIncludingPosition (pos);
                        currentNode = FindNodeIncludingPosition (pos);*/
                        if (currentToken.GetTokenType() == XmlTokenType.EndElementOpen &&
@@ -37,7 +36,7 @@ namespace CrowEdit.Xml
                        }                       
                        return null;
                }
-               public override bool TryGetCompletionForCurrentToken (object suggestion, out TextChange change, out TextSpan? newSelection) {
+               public override bool TryCompleteToken (Token tok, SyntaxNode node, object suggestion, out TextChange change, out TextSpan? newSelection) {
                        newSelection = null;
                        change = default;
 
@@ -46,40 +45,40 @@ namespace CrowEdit.Xml
                        if (selectedSugg == null)
                                return false;
 
-                       Token tok = CurrentToken;
                        XmlTokenType tokType = tok.GetTokenType();
 
                        if (tokType.HasFlag(XmlTokenType.WhiteSpace)) {
-                               if (typeof(ElementTagSyntax).IsAssignableFrom(CurrentNode?.GetType())) {
-                                       ElementTagSyntax ets = CurrentNode as ElementTagSyntax;
+                               
+                               if (typeof(ElementTagSyntax).IsAssignableFrom(node?.GetType())) {
+                                       ElementTagSyntax ets = node as ElementTagSyntax;
                                        if (ets.name.HasValue) {
-                                               change = new TextChange (currentToken.End, 0, selectedSugg + "=\"\"");
+                                               change = new TextChange (tok.End, 0, selectedSugg + "=\"\"");
                                                newSelection = TextSpan.FromStartAndLength(change.End2 - 1);
                                        } else
-                                               change = new TextChange (currentToken.End, 0, selectedSugg + " ");
+                                               change = new TextChange (tok.End, 0, selectedSugg + " ");
                                } else {
-                                       change = new TextChange (currentToken.End, 0, selectedSugg);
+                                       change = new TextChange (tok.End, 0, selectedSugg);
                                }
                        } else if (tokType == XmlTokenType.EndElementOpen) {
-                               change = new TextChange (currentToken.End, 0, selectedSugg + ">");
+                               change = new TextChange (tok.End, 0, selectedSugg + ">");
                        } else if (tokType == XmlTokenType.ElementName) {
-                               if (CurrentNode is ElementEndTagSyntax)
-                                       change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg + ">");
+                               if (node is ElementEndTagSyntax)
+                                       change = new TextChange (tok.Start, tok.Length, selectedSugg + ">");
                                else {
-                                       change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg + ">");
+                                       change = new TextChange (tok.Start, tok.Length, selectedSugg + ">");
                                        newSelection = TextSpan.FromStartAndLength (change.End2 - 1);
                                }
-                       } else if (CurrentNode is AttributeSyntax attrib) {
+                       } else if (node is AttributeSyntax attrib) {
                                if (tokType == XmlTokenType.AttributeName) {
                                        if (attrib.ValueToken.HasValue) {
-                                               change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg);
+                                               change = new TextChange (tok.Start, tok.Length, selectedSugg);
                                                newSelection = new TextSpan(
                                                        attrib.ValueToken.Value.Start + change.CharDiff + 1,
                                                        attrib.ValueToken.Value.End + change.CharDiff - 1
                                                );
                                        } else {
-                                               change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg + "=\"\"");
-                                               newSelection = TextSpan.FromStartAndLength (currentToken.Start + selectedSugg.Length + 2);
+                                               change = new TextChange (tok.Start, tok.Length, selectedSugg + "=\"\"");
+                                               newSelection = TextSpan.FromStartAndLength (tok.Start + selectedSugg.Length + 2);
                                        }
                                } else {
                                        int offset = 1;
@@ -88,40 +87,40 @@ namespace CrowEdit.Xml
                                                offset = 0;
                                        }
                                        if (tokType == XmlTokenType.AttributeValueOpen)
-                                               change = new TextChange (currentToken.End, 0, selectedSugg);
+                                               change = new TextChange (tok.End, 0, selectedSugg);
                                        else if (tokType == XmlTokenType.AttributeValue)
-                                               change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg);
+                                               change = new TextChange (tok.Start, tok.Length, selectedSugg);
                                        newSelection = TextSpan.FromStartAndLength (change.End2 + offset);
                                }
                        } else if (tokType == XmlTokenType.ElementOpen) {
-                               change = new TextChange (currentToken.End, 0, selectedSugg + " ");
+                               change = new TextChange (tok.End, 0, selectedSugg + " ");
                        } else
-                               change =  new TextChange (currentToken.Start, currentToken.Length, selectedSugg);
+                               change =  new TextChange (tok.Start, tok.Length, selectedSugg);
 
                        return true;
 /***********************************************/
 
-                       /*if (currentToken.GetTokenType() == XmlTokenType.ElementOpen ||
-                               currentToken.GetTokenType() == XmlTokenType.WhiteSpace ||
-                               currentToken.GetTokenType() == XmlTokenType.AttributeValueOpen) {
-                               change = new TextChange (currentToken.End, 0, selectedSugg);
+                       /*if (tok.GetTokenType() == XmlTokenType.ElementOpen ||
+                               tok.GetTokenType() == XmlTokenType.WhiteSpace ||
+                               tok.GetTokenType() == XmlTokenType.AttributeValueOpen) {
+                               change = new TextChange (tok.End, 0, selectedSugg);
                                return true;
                        }
-                       if (currentToken.GetTokenType() == XmlTokenType.AttributeName && CurrentNode is AttributeSyntax attrib) {
+                       if (tok.GetTokenType() == XmlTokenType.AttributeName && CurrentNode is AttributeSyntax attrib) {
                                if (attrib.ValueToken.HasValue) {
-                                       change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg);
+                                       change = new TextChange (tok.Start, tok.Length, selectedSugg);
                                        newSelection = new TextSpan(
                                                attrib.ValueToken.Value.Start + change.CharDiff + 1,
                                                attrib.ValueToken.Value.End + change.CharDiff - 1
                                        );
                                } else {
-                                       change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg + "=\"\"");
-                                       newSelection = TextSpan.FromStartAndLength (currentToken.Start + selectedSugg.Length + 2);
+                                       change = new TextChange (tok.Start, tok.Length, selectedSugg + "=\"\"");
+                                       newSelection = TextSpan.FromStartAndLength (tok.Start + selectedSugg.Length + 2);
                                }
                                return true;
                        }
 
-                       change = new TextChange (currentToken.Start, currentToken.Length, selectedSugg);
+                       change = new TextChange (tok.Start, tok.Length, selectedSugg);
                        return true;*/
                }
 
@@ -145,6 +144,6 @@ namespace CrowEdit.Xml
                        return Colors.Red;
 
                }
-               protected bool previousTokHasFlag(XmlTokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
+               //protected bool previousTokHasFlag(XmlTokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
        }
 }
\ No newline at end of file
index d51c0855d2a3e6509649823850ae3f174f84a25d..4083aa9d9ff80d7f02245e2f6ca497f9707b8584 100644 (file)
@@ -4,23 +4,23 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection.Metadata.Ecma335;
 using CrowEditBase;
 
 namespace CrowEdit.Xml
 {
        public class XmlSyntaxAnalyser : SyntaxAnalyser {
-        public XmlSyntaxAnalyser (XmlDocument source) : base (source) {
-                       this.source = source;
-               }
+        public XmlSyntaxAnalyser (XmlDocument document) : base (document) {}
                public virtual void ProcessAttributeValueSyntax(AttributeSyntax attrib) {
                        attrib.valueTok = tokIdx - attrib.TokenIndexBase;
                }
-               public override void Process () {
-                       XmlDocument xmlDoc = source as XmlDocument;
-                       currentNode = Root = new XMLRootSyntax (xmlDoc);
+               public override SyntaxRootNode Process () {
+                       Tokenizer tokenizer = new XmlTokenizer();
+                       Token[] tokens = tokenizer.Tokenize(source.Span);
+
+                       currentNode = Root = new XMLRootSyntax (source, tokens);
                        currentLine = 0;
                        tokIdx = 0;
-                       tokens = source.Tokens;
 
                        while (tokIdx < tokens.Length) {
                                if (curTok.Type == TokenType.LineBreak)
@@ -35,18 +35,18 @@ namespace CrowEdit.Xml
                                                        tag.name = tokIdx - tag.TokenIndexBase;
                                                else if (curTok.GetTokenType() == XmlTokenType.ClosingSign) {
                                                        tag.close = tokIdx - tag.TokenIndexBase;
-                                                       setEndLineForCurrentNode ();
+                                                       finishCurrentNode ();
                                                        currentNode.RemoveChild (tag);
                                                        currentNode = currentNode.AddChild (new ElementSyntax (tag));
                                                } else if (curTok.GetTokenType() == XmlTokenType.EmptyElementClosing) {
-                                                       setEndLineForCurrentNode ();
+                                                       finishCurrentNode ();
                                                        currentNode.RemoveChild (tag);
                                                        currentNode = currentNode.AddChild (new EmptyElementSyntax (tag));
                                                        setCurrentNodeEndLine (currentLine);
                                                        currentNode = currentNode.Parent;
                                                } else {
                                                        addException ("Unexpected Token");
-                                                       setEndLineForCurrentNode (-1);
+                                                       finishCurrentNode (-1);
                                                        continue;
                                                }
                                        } else if (currentNode is ElementSyntax elt) {
@@ -55,6 +55,10 @@ namespace CrowEdit.Xml
                                                else if (curTok.GetTokenType() == XmlTokenType.EndElementOpen) {
                                                        elt.EndTag = new ElementEndTagSyntax (currentLine, tokIdx);
                                                        currentNode = elt.AddChild (elt.EndTag);
+                                                       /*} else {
+                                                               finishCurrentNode(-1);
+                                                               addException ("Unmatching open/closing element name");
+                                                       }*/
                                                }
                                        } else if (currentNode is AttributeSyntax attrib) {
                                                if (curTok.GetTokenType() == XmlTokenType.EqualSign)
@@ -68,10 +72,10 @@ namespace CrowEdit.Xml
                                                        ProcessAttributeValueSyntax (attrib);
                                                else if (curTok.GetTokenType() == XmlTokenType.AttributeValueClose) {
                                                        attrib.valueClose = tokIdx - attrib.TokenIndexBase;
-                                                       setEndLineForCurrentNode ();
+                                                       finishCurrentNode ();
                                                } else {
                                                        addException ("Unexpected Token");
-                                                       setEndLineForCurrentNode (-1);
+                                                       finishCurrentNode (-1);
                                                        continue;
                                                }
                                        } else if (currentNode is ElementEndTagSyntax eltEndTag) {
@@ -80,11 +84,11 @@ namespace CrowEdit.Xml
                                                else if (curTok.GetTokenType() == XmlTokenType.ClosingSign) {
                                                        eltEndTag.close = tokIdx - eltEndTag.TokenIndexBase;
                                                        //go up 2 times
-                                                       setEndLineForCurrentNode (); setEndLineForCurrentNode ();
+                                                       finishCurrentNode (); finishCurrentNode ();
                                                } else {
                                                        addException ("Unexpected Token");
-                                                       setEndLineForCurrentNode (-1);
-                                                       setEndLineForCurrentNode (-1);
+                                                       finishCurrentNode (-1);
+                                                       finishCurrentNode (-1);
                                                        continue;
                                                }
                                        } else if (currentNode is XMLRootSyntax) {
@@ -104,14 +108,14 @@ namespace CrowEdit.Xml
                                                        pi.name = tokIdx - pi.TokenIndexBase;
                                                else if (curTok.GetTokenType() == XmlTokenType.PI_End) {
                                                        pi.PIClose = tokIdx - pi.TokenIndexBase;
-                                                       setEndLineForCurrentNode ();
+                                                       finishCurrentNode ();
                                                } else if (curTok.GetTokenType() == XmlTokenType.AttributeName) {
                                                        AttributeSyntax attribute = new AttributeSyntax (currentLine, tokIdx);
                                                        attribute.name = 0;
                                                        currentNode = currentNode.AddChild (attribute);
                                                } else {
                                                        addException ("Unexpected Token");
-                                                       setEndLineForCurrentNode (-1);
+                                                       finishCurrentNode (-1);
                                                        continue;
                                                }
                                        }
@@ -120,11 +124,12 @@ namespace CrowEdit.Xml
                        }
                        while (currentNode.Parent != null) {
                                if (!currentNode.TokenCount.HasValue)
-                                       setEndLineForCurrentNode (-1);
+                                       finishCurrentNode (-1);
                                else
                                        currentNode = currentNode.Parent;
                        }
                        setCurrentNodeEndLine (currentLine);
+                       return Root;
                }
        }
 }
\ No newline at end of file
index 892347fd98837ed127d4d2975f6f48ea4d7b64cb..928b72202b359f71a618edcdb43015d61172fc85 100644 (file)
@@ -1,6 +1,7 @@
 // Copyright (c) 2013-2021  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.Linq;
 using Crow.Text;
 using CrowEditBase;
@@ -9,9 +10,7 @@ namespace CrowEdit.Xml
 {
 
        public class XMLRootSyntax : SyntaxRootNode {
-               public XMLRootSyntax (XmlDocument source)
-                       : base (source) {
-               }
+               public XMLRootSyntax (ReadOnlyMemory<char> source, Token[] tokens) : base (source, tokens) { }
        }
        public class ProcessingInstructionSyntax : SyntaxNode {
                public int? PIClose, name;
index 80cedd339f946295b11f02e7646020d62fbbd94f..98dc2f64ae4ec7f32bfcf811768227bd3098d639 100644 (file)
@@ -1,88 +1,87 @@
 <?xml version="1.0"?>
 <DockWindow Style="DockWindow" Caption="Logs"  Width="80%" Height="20%" >
        <VerticalStack>
-
-       <TabView Data="{OpenedLogs}" SelectedItem="{²CurrentLog}">
-               <Template>
-                       <VerticalStack Spacing="0" >
-                               <HorizontalStack Height="Fit">
-                                       <ListBox Data="{./Items}" >
-                                               <Template>
-                                                       <VerticalStack Spacing="0" >
-                                                               <ScrollBar Orientation="Horizontal" Foreground="RoyalBlue" Height="6" Width="Stretched" CornerRadius="3"
-                                                                       Value="{²../ItemsScroller.ScrollX}"
-                                                                       LargeIncrement="{../ItemsScroller.PageWidth}" SmallIncrement="1"
-                                                                       CursorRatio="{../ItemsScroller.ChildWidthRatio}" Maximum="{../ItemsScroller.MaxScrollX}">
-                                                                       <Template>
-                                                                               <Container Margin="1" Background="{./Background}">
-                                                                                       <Widget Name="Cursor" Background="{./Foreground}" CornerRadius="{./CornerRadius}"/>
-                                                                               </Container>
-                                                                       </Template>
-                                                               </ScrollBar>
-                                                               <Scroller Name="ItemsScroller" Height="Fit" Width="Stretched">
-                                                                       <HorizontalStack Name="ItemsContainer" Width="Fit" HorizontalAlignment="Left"/>
-                                                               </Scroller>
-                                                       </VerticalStack>
-                                               </Template>
-                                               <ItemTemplate>
-                                                       <ListItem RootDataLevel="true" Fit="true" Background="${InactiveTabBackground}" Foreground="${InactiveTabForeground}" IsSelected="{IsVisible}"
-                                                                       Selected="{.DataSource.IsVisible='true'};{Background=${SelectedTabBackground}};{Foreground=${SelectedTabForeground}}"
-                                                                       Unselected="{.DataSource.IsVisible='false'};{Background=${InactiveTabBackground}};{Foreground=${InactiveTabForeground}}"
-                                                                       BubbleEvents="MouseWheel">
-                                                               <HorizontalStack DataSource="{DataSource}" Margin="3" Spacing="5">
-                                                                       <!--<Image Style="TreeIcon" Path="{Icon}" SvgSub="{IconSub}"/> No icon in Document class-->
-                                                                       <Label Text="{Name}" ContextCommands="{TabCommands}" Foreground="{../../Foreground}" />
-                                                                       <Border CornerRadius="5" BorderWidth="1" Foreground="Transparent"  Height="12" Width="12"
-                                                                                               MouseEnter="{Foreground=White}" MouseLeave="{Foreground=Transparent}">
-                                                                               <Image Focusable="true" Name="Image" Margin="0" Width="Stretched" Height="Stretched" Path="#Crow.Icons.exit2.svg"
-                                                                                       MouseClick="OnQueryClose"/>
-                                                                       </Border>
-                                                               </HorizontalStack>
-                                                       </ListItem>
-                                               </ItemTemplate>
-                                       </ListBox>
-                                       <Popper Caption="Available Logs">
-                                               <ListBox Data="{Logs}" Style="ScrollingListBox" Height="100" Width="200" Background="Jet" BubbleEvents="none" >
+               <TabView Data="{OpenedLogs}" SelectedItem="{²CurrentLog}">
+                       <Template>
+                               <VerticalStack Spacing="0" >
+                                       <HorizontalStack Height="Fit">
+                                               <ListBox Data="{./Items}" >
+                                                       <Template>
+                                                               <VerticalStack Spacing="0" >
+                                                                       <ScrollBar Orientation="Horizontal" Foreground="RoyalBlue" Height="6" Width="Stretched" CornerRadius="3"
+                                                                               Value="{²../ItemsScroller.ScrollX}"
+                                                                               LargeIncrement="{../ItemsScroller.PageWidth}" SmallIncrement="1"
+                                                                               CursorRatio="{../ItemsScroller.ChildWidthRatio}" Maximum="{../ItemsScroller.MaxScrollX}">
+                                                                               <Template>
+                                                                                       <Container Margin="1" Background="{./Background}">
+                                                                                               <Widget Name="Cursor" Background="{./Foreground}" CornerRadius="{./CornerRadius}"/>
+                                                                                       </Container>
+                                                                               </Template>
+                                                                       </ScrollBar>
+                                                                       <Scroller Name="ItemsScroller" Height="Fit" Width="Stretched">
+                                                                               <HorizontalStack Name="ItemsContainer" Width="Fit" HorizontalAlignment="Left"/>
+                                                                       </Scroller>
+                                                               </VerticalStack>
+                                                       </Template>
                                                        <ItemTemplate>
-                                                               <Border CornerRadius="2" Margin="0" Height="Fit"
-                                                                               Foreground="Transparent"
-                                                                               MouseEnter="{Foreground=DimGrey}"
-                                                                               MouseLeave="{Foreground=Transparent}">
-                                                                               <CheckBox Caption="{Name}" Width="Stretched" IsChecked="{²IsOpened}"/>
-                                                               </Border>
+                                                               <ListItem RootDataLevel="true" Fit="true" Background="${InactiveTabBackground}" Foreground="${InactiveTabForeground}" IsSelected="{IsVisible}"
+                                                                               Selected="{.DataSource.IsVisible='true'};{Background=${SelectedTabBackground}};{Foreground=${SelectedTabForeground}}"
+                                                                               Unselected="{.DataSource.IsVisible='false'};{Background=${InactiveTabBackground}};{Foreground=${InactiveTabForeground}}"
+                                                                               BubbleEvents="MouseWheel">
+                                                                       <HorizontalStack DataSource="{DataSource}" Margin="3" Spacing="5">
+                                                                               <!--<Image Style="TreeIcon" Path="{Icon}" SvgSub="{IconSub}"/> No icon in Document class-->
+                                                                               <Label Text="{Name}" ContextCommands="{TabCommands}" Foreground="{../../Foreground}" />
+                                                                               <Border CornerRadius="5" BorderWidth="1" Foreground="Transparent"  Height="12" Width="12"
+                                                                                                       MouseEnter="{Foreground=White}" MouseLeave="{Foreground=Transparent}">
+                                                                                       <Image Focusable="true" Name="Image" Margin="0" Width="Stretched" Height="Stretched" Path="#Crow.Icons.exit2.svg"
+                                                                                               MouseClick="OnQueryClose"/>
+                                                                               </Border>
+                                                                       </HorizontalStack>
+                                                               </ListItem>
                                                        </ItemTemplate>
                                                </ListBox>
-                                       </Popper>                               
-                               </HorizontalStack>
-                               <Group Name="ItemsContainer" Background="${SelectedTabBackground}"/>
-                       </VerticalStack>
-               </Template>     
-               <ItemTemplate>
-                       <ListItem IsVisible="{IsSelected}" IsSelected="{²IsSelected}">
-                               <VerticalStack RootDataLevel="true" >
-                                       <HorizontalStack Height="Fit" Spacing="5" Margin="0">
-                                               <Widget Width="Stretched"/>
-                                               <EnumSelector Caption="Filter:" EnumValue="{²../../log.Filter}" />
-                                               <TextBox Background="Grey" Foreground="Black" Text="{²../../log.SearchString}" Width="200" KeyDown="../../log.onSearch" Font="${SmallUIFont}"/>
-                                               <CheckBox Fit="true" Caption="Case Sensitive" IsChecked="{²../../log.CaseSensitiveSearch}" Font="${SmallUIFont}"/>
-                                               <CheckBox Fit="true" Caption="All Word" IsChecked="{²../../log.AllWordSearch}" Font="${SmallUIFont}"/>
-                                               <Menu Style="DockWinTitleBarMenu" Data="{../../log.SearchCommands}" Fit="true" Background="Transparent"/>
-                                       </HorizontalStack>
-                                       <HorizontalStack Spacing="0">
-                                               <LogViewerWidget Name="log" Logger="{}" Font="${SmallFont}" MaxScrollX="6000" ContextCommands="{Commands}" CurrentEntryIndex="{²SelectedIndex}"/>
-                                               <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"/>
-                                       <HorizontalStack Height="Fit">
-                                               <Label Text="MaxScrollY:"/>
-                                               <Label Text="{../../log.MaxScrollY}"/>
-                                               <Label Text="ScrollY:"/>
-                                               <Label Text="{../../log.ScrollY}"/>
+                                               <Popper Caption="Available Logs">
+                                                       <ListBox Data="{Logs}" Style="ScrollingListBox" Height="100" Width="200" Background="Jet" BubbleEvents="none" >
+                                                               <ItemTemplate>
+                                                                       <Border CornerRadius="2" Margin="0" Height="Fit"
+                                                                                       Foreground="Transparent"
+                                                                                       MouseEnter="{Foreground=DimGrey}"
+                                                                                       MouseLeave="{Foreground=Transparent}">
+                                                                                       <CheckBox Caption="{Name}" Width="Stretched" IsChecked="{²IsOpened}"/>
+                                                                       </Border>
+                                                               </ItemTemplate>
+                                                       </ListBox>
+                                               </Popper>                               
                                        </HorizontalStack>
+                                       <Group Name="ItemsContainer" Background="${SelectedTabBackground}"/>
                                </VerticalStack>
-                       </ListItem>
-               </ItemTemplate>
-       </TabView>
+                       </Template>     
+                       <ItemTemplate>
+                               <ListItem IsVisible="{IsSelected}" IsSelected="{²IsSelected}">
+                                       <VerticalStack RootDataLevel="true" >
+                                               <HorizontalStack Height="Fit" Spacing="5" Margin="0">
+                                                       <Widget Width="Stretched"/>
+                                                       <EnumSelector Caption="Filter:" EnumValue="{²../../log.Filter}" />
+                                                       <TextBox Background="Grey" Foreground="Black" Text="{²../../log.SearchString}" Width="200" KeyDown="../../log.onSearch" Font="${SmallUIFont}"/>
+                                                       <CheckBox Fit="true" Caption="Case Sensitive" IsChecked="{²../../log.CaseSensitiveSearch}" Font="${SmallUIFont}"/>
+                                                       <CheckBox Fit="true" Caption="All Word" IsChecked="{²../../log.AllWordSearch}" Font="${SmallUIFont}"/>
+                                                       <Menu Style="DockWinTitleBarMenu" Data="{../../log.SearchCommands}" Fit="true" Background="Transparent"/>
+                                               </HorizontalStack>
+                                               <HorizontalStack Spacing="0">
+                                                       <LogViewerWidget Name="log" Logger="{}" Font="${SmallFont}" MaxScrollX="6000" ContextCommands="{Commands}" CurrentEntryIndex="{²SelectedIndex}"/>
+                                                       <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"/>
+                                               <HorizontalStack Height="Fit">
+                                                       <Label Text="MaxScrollY:"/>
+                                                       <Label Text="{../../log.MaxScrollY}"/>
+                                                       <Label Text="ScrollY:"/>
+                                                       <Label Text="{../../log.ScrollY}"/>
+                                               </HorizontalStack>
+                                       </VerticalStack>
+                               </ListItem>
+                       </ItemTemplate>
+               </TabView>
        </VerticalStack>
 </DockWindow>