]> O.S.I.I.S - jp/crowedit.git/commitdiff
debug xml/iml parsing/suggestions/autocomplete
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Sat, 5 Jul 2025 22:46:26 +0000 (00:46 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Sat, 5 Jul 2025 22:46:26 +0000 (00:46 +0200)
CrowEditBase/src/Compiler/SourceDocument.cs
CrowEditBase/src/Compiler/SyntaxNodes/SingleTokenSyntax.cs
CrowEditBase/src/Compiler/SyntaxNodes/SyntaxNode.cs
CrowEditBase/src/SourceEditor.cs
plugins/CECrowPlugin/src/Parsing/IML/ImlDocument.cs
plugins/CECrowPlugin/src/Parsing/IML/ImlTokenizer.cs
plugins/CERoslynPlugin/src/Parsing/CsharpSyntaxWalkerBridge.cs
plugins/CEXmlPlugin/src/Parsing/XmlDocument.cs
plugins/CEXmlPlugin/src/Parsing/XmlSyntaxAnalyser.cs
plugins/CEXmlPlugin/src/Parsing/XmlSyntaxNodes.cs
plugins/CEXmlPlugin/src/Parsing/XmlTokenizer.cs

index cee7da6972051e350290b0ebfae081ed7013f84d..258e186eec8eccf9b3c93053423dbe7a4f60517e 100644 (file)
@@ -135,11 +135,11 @@ namespace CrowEditBase
                        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.HasFlag (TokenType.Trivia))
+                               return Colors.DimGrey;
                        if (tokType == TokenType.Keyword)
-                               return Colors.DarkSlateBlue;
+                               return Colors.Blue;
                        return Colors.Red;
                }
                public virtual string GetTokenTypeString (TokenType tokenType) => tokenType.ToString();
@@ -153,6 +153,8 @@ namespace CrowEditBase
 
                        cancelSource = new CancellationTokenSource();
                        backgroundCompilationTask = Task.Run(()=>parseAssync(cancelSource.Token));
+                       //TODO: to do
+                       await backgroundCompilationTask;
                        
                        //CurrentNode?.ExpandToTheTop();
                        
index 56c486f4e0c2f0e7d3910fc9dca870a079bec5d1..2df8fe7e53476af8aad9afa52eb7b75de7700350 100644 (file)
@@ -1,6 +1,8 @@
 // Copyright (c) 2021-2025  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using Drawing2D;
+
 namespace CrowEditBase
 {
        public class SingleTokenSyntax : SyntaxNode {
@@ -21,10 +23,10 @@ namespace CrowEditBase
         public override bool IsSimilar(object other)
         {
             return other is SingleTokenSyntax sts ?
-                               sts.Type == Type : other is TokenType tt ? Type == tt : false;
-
+                               sts.Type == Type : (int)other == (int)Type;
         }
         #endregion
 
+        public static implicit operator TokenType (SingleTokenSyntax sts) => sts == null ? TokenType.Unknown : sts.Type;
     }
 }
\ No newline at end of file
index bb639d62920ddc0594acc84e126beecd586e97ab..102721e5920d435052c9f8f0f1353ee80297fa0f 100644 (file)
@@ -66,6 +66,10 @@ namespace CrowEditBase
                                return null;
                        }
                }
+               public bool NextSiblingIs(TokenType tokType)
+                       => NextSibling is SingleTokenSyntax sts && sts.token.Type == tokType;
+               public bool PreviousSiblingIs(TokenType tokType) 
+                       => PreviousSibling is SingleTokenSyntax sts && sts.token.Type == tokType;
 
                protected Token getTokenByIndex (int idx) => Root.GetTokenByIndex(idx);
 
index 43a31e192b8800a55707748df1532e5ce661f6d7..a7553cedacbe6ee147f3cb9550acc4353b9b9aa1 100644 (file)
@@ -171,16 +171,20 @@ namespace CrowEditBase
                                        ");                                     
                                        overlay.DataSource = this;
                                        overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0;
-                               } else
+                               } else {
+                                       overlay.DataSource = this;
                                        overlay.IsVisible = true;
+                               }
                                overlay.RegisterForLayouting(LayoutingType.Sizing);
                        }
                }
                void hideOverlay () {
                        if (overlay == null)
                                return;
-                       lock(App.UpdateMutex)
+                       lock(App.UpdateMutex) {
                                overlay.IsVisible = false;
+                               overlay.DataSource = null;
+                       }
                }
                void completeToken () {
                        disableSuggestions = true;
@@ -464,7 +468,6 @@ namespace CrowEditBase
                                                        return;
                                        }
                                }
-
                                base.onKeyDown(sender, e);
                        /*} finally {
                                Document.ExitReadLock ();
@@ -837,7 +840,7 @@ namespace CrowEditBase
                                                gr.Stroke ();
                                        }
 
-                                       if (++tokPtr >= sourceDocument.Tokens.Length)
+                                       if (tokPtr >= sourceDocument.Tokens.Length)
                                                break;
                                        tok = sourceDocument.Tokens[tokPtr];
 
@@ -902,6 +905,7 @@ namespace CrowEditBase
 
                        updateCurrentTokAndNode();
 
+                       hideOverlay();
                        if (!disableSuggestions &&!disableTextChangedEvent && HasFocus)
                                tryGetSuggestions ();
 
index 11ac33831a43799e5d26118fa59c7f6dbed1ea93..34a684f975e32bd13414c35464f9d3837fa59fe7 100644 (file)
@@ -46,7 +46,7 @@ namespace CECrowPlugin
                        return crowType.GetMember (memberName, BindingFlags.Public | BindingFlags.Instance).FirstOrDefault ();
                }*/
 
-        protected override IEnumerable<Suggestion> getElementNameSuggestions(string curName, TextChange change)
+        protected override IEnumerable<Suggestion> getElementNameSuggestions(string curName, TextChange change, int finalPositionOffset = 0)
         {
                        CrowService srv = App.GetService<CrowService>();
                        if (srv == null || !srv.IsRunning)
@@ -62,13 +62,12 @@ namespace CECrowPlugin
                                widgetTypes = widgetTypes.Where(t=>t.Name.StartsWith(curName, StringComparison.OrdinalIgnoreCase));
                                curNameLength = curName.Length;
                        }
-                       int endPosOffset = change.HasNewText ? -change.ChangedText.Length : 0;
             return widgetTypes.Select (t
                                => new WidgetSuggestion(t,
-                                       new TextChange(change.Start, change.Length, t.Name + change.ChangedText), endPosOffset));
+                                       new TextChange(change.Start, change.Length, t.Name + change.ChangedText), finalPositionOffset));
         }
-        protected override IEnumerable<Suggestion> getAttributeNameSuggestions(string eltName, string curName, TextChange change) {
-                       int endPosOffset = change.HasNewText ? -1 : 0;
+        protected override IEnumerable<Suggestion> getAttributeNameSuggestions(string eltName, string curName, TextChange change, int finalPositionOffset = 0) {
+                       //int endPosOffset = change.HasNewText ? -1 : 0;
                        var members = App.GetService<CrowService>()?.GetAllCrowTypeMembers(eltName);
                        if (members != null) {
                                
@@ -77,7 +76,7 @@ namespace CECrowPlugin
 
                                var suggs = members?.Where(m=>m.MemberType == MemberTypes.Property)?.Select(p
                                        => new CrowPropertySuggestion(p as PropertyInfo,
-                                               new TextChange(change.Start, change.Length, p.Name + change.ChangedText), endPosOffset));
+                                               new TextChange(change.Start, change.Length, p.Name + change.ChangedText), finalPositionOffset));
 
                                foreach (var tmp in suggs.Where(s=>s.Category == "Divers"))
                                        yield return tmp;
@@ -92,46 +91,38 @@ namespace CECrowPlugin
                        }
                                
                }
-               protected override IEnumerable<Suggestion> getAttributeValueSuggestions(string eltName, string attribName, string attribValue, TextChange change) {
+               protected override IEnumerable<Suggestion> getAttributeValueSuggestions(string eltName, string attribName, string attribValue, TextChange change, int finalPositionOffset = 0) {
                        MemberInfo mi = App.GetService<CrowService>()?.GetAllCrowTypeMembers(eltName)?.Where(m=>m.Name.Equals(attribName, StringComparison.Ordinal)).FirstOrDefault();
                        if (mi is PropertyInfo pi) {
                                if (pi.Name == "Style")
                                        return App.Styling.Keys
                                                .Where (s => s.StartsWith (attribValue, StringComparison.OrdinalIgnoreCase))
                                                .Select(s=>new Suggestion(s,
-                                                       new TextChange(change.Start, change.Length, s + change.ChangedText)));
+                                                       new TextChange(change.Start, change.Length, s + change.ChangedText), finalPositionOffset));
                                if (pi.PropertyType.IsEnum)
                                        return Enum.GetNames (pi.PropertyType)
                                                .Where (s => s.StartsWith (attribValue, StringComparison.OrdinalIgnoreCase))
                                                .Select(s=>new Suggestion(s,
-                                                       new TextChange(change.Start, change.Length, s + change.ChangedText)));
+                                                       new TextChange(change.Start, change.Length, s + change.ChangedText), finalPositionOffset));
                                if (pi.PropertyType == typeof(bool))
                                        return  (new string[] {"true", "false"}).
                                                Where (s => s.StartsWith (attribValue, StringComparison.OrdinalIgnoreCase))
                                                .Select(s=>new Suggestion(s,
-                                                       new TextChange(change.Start, change.Length, s + change.ChangedText)));
+                                                       new TextChange(change.Start, change.Length, s + change.ChangedText), finalPositionOffset));
                                if (pi.PropertyType.Name == "Measure")
                                        return (new string[] {"Stretched", "Fit"}).
                                                Where (s => s.StartsWith (attribValue, StringComparison.OrdinalIgnoreCase))
                                                .Select(s=>new Suggestion(s,
-                                                       new TextChange(change.Start, change.Length, s + change.ChangedText)));
+                                                       new TextChange(change.Start, change.Length, s + change.ChangedText), finalPositionOffset));
                                if (pi.PropertyType.Name == "Fill")
                                        return  EnumsNET.Enums.GetValues<Colors> ()
                                                .Where (s => s.ToString().StartsWith (attribValue, StringComparison.OrdinalIgnoreCase))
                                                .Select(c=>new ColorSuggestion(c,
-                                                       new TextChange(change.Start, change.Length, c + change.ChangedText)));
+                                                       new TextChange(change.Start, change.Length, c + change.ChangedText), finalPositionOffset));
                        }
                        return null;
                }
-        public override IList GetSuggestions (int absoluteTextPos, int currentTokenIndex, SyntaxNode CurrentNode, CharLocation loc) {
-                       Token tok = GetTokenByIndex(currentTokenIndex);
-                       Console.Write($"{absoluteTextPos}({tok.Span}){tok.GetTokenType()}");
-                       if (currentTokenIndex > 0)
-                               Console.Write($" prev:{GetTokenByIndex(currentTokenIndex-1).GetTokenType()}");                  
-                       if (currentTokenIndex < Tokens.Length - 1)
-                               Console.Write($" next:{GetTokenByIndex(currentTokenIndex+1).GetTokenType()}");  
-                       Console.WriteLine($" node:{CurrentNode} ({loc})");
-                       
+        public override IList GetSuggestions (int absoluteTextPos, int currentTokenIndex, SyntaxNode CurrentNode, CharLocation loc) {          
                        IList sugs = base.GetSuggestions (absoluteTextPos, currentTokenIndex, CurrentNode, loc);
                        if (sugs != null)
                                return sugs;
index 378e9f347af693501506b4ea840d95c5eeabd319..dc62fe38b9214f982c30b72b4adac944f44fd25d 100644 (file)
@@ -139,6 +139,8 @@ namespace CECrowPlugin
                                }
                                reader.Read ();
                        }
+                       if (reader.EndOfSpan)//occurs when no closing quote
+                               addTok(ref reader, XmlTokenType.AttributeValue);
                }
 
        }
index c276670671625ce01727cb2f62261dbc16eb5a79..7918f783895b1edbe939d5eba0bf35f4f32c6e22 100644 (file)
@@ -47,10 +47,9 @@ namespace CERoslynPlugin
                        VisitLeadingTrivia (token);
 
                        Microsoft.CodeAnalysis.Text.TextSpan fs = token.Span;
-                       /*if (SyntaxFacts.IsLiteralExpression (token.Kind ()))
+                       if (SyntaxFacts.IsLiteralExpression (token.Kind ()))
                                addMultilineToken(token.ToString(), token.Span, (TokenType)token.RawKind);
-                       else*/
-                       if (fs.Length == 0)
+                       else if (fs.Length == 0)
                                Debug.WriteLine($"Empty token: {token}");
                        else {
                                Microsoft.CodeAnalysis.Text.TextSpan span = token.Span;
index 43a3d2d57ea91b85efaf5211c0e306632e3e7efb..eaac3c1658c1a2d2d4f9e30e8ade24681de34432 100644 (file)
@@ -11,6 +11,8 @@ using System;
 using Crow;
 using System.Linq;
 using System.Diagnostics;
+using System.Xml;
+using System.Text;
 
 namespace CrowEdit.Xml
 {
@@ -20,22 +22,25 @@ namespace CrowEdit.Xml
                protected override SyntaxAnalyser CreateSyntaxAnalyser() => new XmlSyntaxAnalyser (ImmutableBufferCopy);
                public override string GetTokenTypeString (TokenType tokenType) => ((XmlTokenType)tokenType).ToString();
 
-               protected virtual IEnumerable<Suggestion> getElementNameSuggestions(string curName, TextChange change) => null;
-               protected virtual IEnumerable<Suggestion> getAttributeNameSuggestions(string eltName, string attribName, TextChange change) => null;
-               protected virtual IEnumerable<Suggestion> getAttributeValueSuggestions(string eltName, string attribName, string attribValue, TextChange change) => null;
+               protected virtual IEnumerable<Suggestion> getElementNameSuggestions(string curName, TextChange change, int finalPositionOffset = 0) => null;
+               protected virtual IEnumerable<Suggestion> getAttributeNameSuggestions(string eltName, string attribName, TextChange change, int finalPositionOffset = 0) => null;
+               protected virtual IEnumerable<Suggestion> getAttributeValueSuggestions(string eltName, string attribName, string attribValue, TextChange change, int finalPositionOffset = 0) => null;
                public override IList GetSuggestions (int absoluteTextPos, int currentTokenIndex, SyntaxNode CurrentNode, CharLocation loc) {
-                       Console.WriteLine($"absPos:{absoluteTextPos} tokIdx:{currentTokenIndex} node:{CurrentNode} charLoc:{loc}");
                        Token tok = GetTokenByIndex(currentTokenIndex);
+                       Token nextTok = currentTokenIndex < Tokens.Length - 1 ? GetTokenByIndex(currentTokenIndex + 1) : null; 
+                       //Console.WriteLine($"absPos:{absoluteTextPos} {tok.GetTokenType()} tokIdx:{currentTokenIndex} node:{CurrentNode} parent:{CurrentNode?.Parent} charLoc:{loc}");
                        XmlTokenType tokType = tok.GetTokenType();
                        if (CurrentNode is SingleTokenSyntax sts) {
                                XmlTokenType tk = sts.token.GetTokenType();
+
                                if (CurrentNode.Parent is ElementTagSyntax ets) {
                                        if (ets is ElementEndTagSyntax eets) {
                                                if (eets.Parent is ElementSyntax es) {
                                                        string name = es.StartTag?.Name;
-                                                       if (!string.IsNullOrEmpty(name)){
+                                                       string eltName = sts.AsText();
+                                                       if (!string.IsNullOrEmpty(name) && !string.Equals(name, eltName)){
                                                                Suggestion sug = new Suggestion(name);
-                                                               if (tk == XmlTokenType.ElementName && name.StartsWith(sts.AsText(), StringComparison.OrdinalIgnoreCase))
+                                                               if (tk == XmlTokenType.ElementName && name.StartsWith(eltName, StringComparison.OrdinalIgnoreCase))
                                                                        sug.Change = new TextChange (tok.Start, tok.Length, sug.Caption);
                                                                else if (tk == XmlTokenType.EndElementOpen)
                                                                        sug.Change = new TextChange (tok.End, 0, sug.Caption);
@@ -46,209 +51,65 @@ namespace CrowEdit.Xml
                                                                return new List<Suggestion>([sug]);
                                                        } 
                                                }
-                                       } else {
-                                               string txtEnd = ets.HasClosingToken ? "" : ">";
-                                               if (tk == XmlTokenType.ElementOpen) {
-                                                       return getElementNameSuggestions("", new TextChange(tok.End, 0, txtEnd)).ToList();
+                                       } else {//startTag or empty element
+                                               StringBuilder txtEnd = new StringBuilder(10);
+                                               int offset = 0;
+                                               if (nextTok?.GetTokenType() != XmlTokenType.WhiteSpace)
+                                                       txtEnd.Append(" ");
+                                               if (!ets.HasClosingToken) {
+                                                       txtEnd.Append(">");
+                                                       offset = -1;
                                                }
-                                               if (tk == XmlTokenType.ElementName) {
-                                                       return getElementNameSuggestions(sts.AsText(), new TextChange(tok.Start, tok.Length, txtEnd)).ToList();
+                                               List<Suggestion> sugs;
+                                               if (tk == XmlTokenType.ElementOpen) {
+                                                       sugs = getElementNameSuggestions("", new TextChange(tok.End, 0, txtEnd.ToString()), offset).ToList();
+                                               }else if (tk == XmlTokenType.ElementName) {
+                                                       sugs = getElementNameSuggestions(sts.AsText(), new TextChange(tok.Start, tok.Length, txtEnd.ToString()), offset).ToList();
+                                               } else {
+                                                       return null;
                                                }
-                                       }
-                               } 
-                       }
-                       /*      
-                       if (tok.Start != absoluteTextPos //middle of edited tok
-                               && currentTokenIndex >= CurrentNode?.Root.TokenCount - 1) //occurs when curTok is last tok of text
-                       {
-                               return null;
-                       }
-                       Token prevTok = GetTokenByIndex(currentTokenIndex-1);
-
-                       if (CurrentNode is ElementEndTagSyntax eltEndTag) {
-                               //sug = corresponding eltName
-                               if (!tok.Is(XmlTokenType.ElementName) &&
-                                               eltEndTag.Parent is ElementSyntax elt &&
-                                               elt.StartTag?.Name != null) {
-
-                                       Suggestion sug = new Suggestion(elt.StartTag.Name);
-                                       string curEndName = null;
-                                       if (prevTok.Is(XmlTokenType.ElementName) && !elt.StartTag.Name.Equals(curEndName, StringComparison.Ordinal)) {
-                                               curEndName = root.GetTokenString(prevTok);
-                                               sug.Change = new TextChange (prevTok.Start, prevTok.Length, sug.Caption);
-                                       } else if (prevTok.Is(XmlTokenType.EndElementOpen)) {
-                                               curEndName = "";
-                                               sug.Change = new TextChange (prevTok.End, 0, sug.Caption);
-                                       } else 
-                                               return null;
-
-                                       //if (!tok.Is(XmlTokenType.ClosingSign))
-                                       if (!eltEndTag.close.HasValue)
-                                               sug.Change.ChangedText += ">";
-
-                                       if (elt.StartTag.Name.StartsWith (curEndName, StringComparison.OrdinalIgnoreCase))
-                                               return new List<Suggestion> ([sug]);
-                               }
-                       } else if (CurrentNode is ElementStartTagSyntax eltStartTag) {
-                               if (!tok.Is(XmlTokenType.ElementName)) {
-                                       TextChange change = default;
-                                       
-                                       if (prevTok.Is(XmlTokenType.ElementName))
-                                               change = new TextChange (prevTok.Start, prevTok.Length);
-                                       else if (prevTok.Is(XmlTokenType.ElementOpen))
-                                               change = new TextChange (prevTok.End, 0);
-                                       else if (eltStartTag.name.HasValue) {
-                                               string attribName = "";
-                                               if (prevTok.Type.HasFlag(TokenType.Trivia) ||
-                                                       (tok.Type.HasFlag(TokenType.Trivia) && GetTokenByIndex(currentTokenIndex+1).Type.HasFlag(TokenType.Trivia)))//attribute
-                                                       change = new TextChange(tok.Start, 0);
-                                               else if (prevTok.Is(XmlTokenType.AttributeName)) {
-                                                       change = new TextChange(prevTok.Start, prevTok.Length);
-                                                       attribName = prevTok.AsString(source);
-                                               } else
+                                               if (sugs.Count == 1 && sugs[0].Caption == sts.AsText())
                                                        return null;
-                                               if (!tok.Is(XmlTokenType.EqualSign))
-                                                       change.ChangedText += "=\"\"";
-                                               return getAttributeNameSuggestions(eltStartTag.Name, attribName, change).ToList();
-                                       } else
-                                               return null;
-
-                                       //if (!tok.Is(XmlTokenType.ClosingSign))
-                                       if (!eltStartTag.close.HasValue)
-                                               change.ChangedText = ">";
-                                       
-                                       return getElementNameSuggestions(eltStartTag.Name, change).ToList();
-
-                               }
-                       } else if (CurrentNode is AttributeSyntax attrib &&
-                                               attrib.Parent is ElementStartTagSyntax eltStart &&
-                                               eltStart.name.HasValue) {
-
-                               if (prevTok.Is(XmlTokenType.AttributeName)) {
-                                       TextChange change = new TextChange(prevTok.Start, prevTok.Length);
-                                       if (!tok.Is(XmlTokenType.EqualSign))
-                                               change.ChangedText += "=\"\"";
-                                       return getAttributeNameSuggestions(eltStart.Name, attrib.Name, change).ToList();                                        
-                               } else if (attrib.name.HasValue) {
-                                       if (prevTok.Is(XmlTokenType.AttributeValueOpen)) {
-                                               return getAttributeValueSuggestions(eltStart.Name, attrib.Name, "",
-                                                       tok.Is(XmlTokenType.AttributeValueClose) ?
-                                                               new TextChange(prevTok.End, 0)
-                                                               : new TextChange(prevTok.End, 0, "\""))?.ToList();
-                                       } else if (prevTok.Is(XmlTokenType.AttributeValue) && attrib.valueTok.HasValue) {
-                                               return getAttributeValueSuggestions(eltStart.Name, attrib.Name, attrib.Value,
-                                                       tok.Is(XmlTokenType.AttributeValueClose) ?
-                                                               new TextChange(prevTok.Start, prevTok.Length)
-                                                               : new TextChange(tok.Start, tok.Length, "\""))?.ToList();
+                                               return sugs;
                                        }
+                               } else if (CurrentNode.Parent is AttributeSyntax atts) {
                                        
-                               }
-
-                               *if (tokType == XmlTokenType.AttributeName) {
-                                       if (attrib.ValueToken.HasValue) {
-                                               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
-                                               );
+                                       if (tokType == XmlTokenType.WhiteSpace) {
+                                               Console.WriteLine($"*** {tk}");
+                                               //return getAttributeNameSuggestions(atts.Name, "", new TextChange(tok.End, 0)).ToList();
                                        } else {
-                                               change = new TextChange (tok.Start, tok.Length, selectedSugg + "=\"\"");
-                                               newSelection = TextSpan.FromStartAndLength (tok.Start + selectedSugg.Length + 2);
-                                       }
-                               } else {
-                                       int offset = 1;
-                                       if (!attrib.valueClose.HasValue) {
-                                               selectedSugg += root.GetTokenStringByIndex(attrib.valueClose.Value);
-                                               offset = 0;
-                                       }
-                                       if (tokType == XmlTokenType.AttributeValueOpen)
-                                               change = new TextChange (tok.End, 0, selectedSugg);
-                                       else if (tokType == XmlTokenType.AttributeValue)
-                                               change = new TextChange (tok.Start, tok.Length, selectedSugg);
-                                       newSelection = TextSpan.FromStartAndLength (change.End2 + offset);
-                               }*
-                       }*/
-
-                       return null;
-               }
-               /*
-               public override bool TryCompleteToken (Suggestion suggestion) {
-                       newSelection = null;
-                       change = default;
-
-                       string selectedSugg = suggestion?.ToString ();
-
-                       if (selectedSugg == null)
-                               return false;
-
-                       XmlTokenType tokType = tok.GetTokenType();
-
-                       if (tokType.HasFlag(XmlTokenType.WhiteSpace)) {
-                               
-                               if (typeof(ElementTagSyntax).IsAssignableFrom(node?.GetType())) {
-                                       ElementTagSyntax ets = node as ElementTagSyntax;
-                                       if (ets.name.HasValue) {
-                                               change = new TextChange (tok.End, 0, selectedSugg + "=\"\"");
-                                               newSelection = TextSpan.FromStartAndLength(change.End2 - 1);
-                                       } else
-                                               change = new TextChange (tok.End, 0, selectedSugg + " ");
-                               } else {
-                                       change = new TextChange (tok.End, 0, selectedSugg);
-                               }
-                       } else if (tokType == XmlTokenType.EndElementOpen) {
-                               change = new TextChange (tok.End, 0, selectedSugg + ">");
-                       } else if (tokType == XmlTokenType.ElementName) {
-                               if (node is ElementEndTagSyntax)
-                                       change = new TextChange (tok.Start, tok.Length, selectedSugg + ">");
-                               else {
-                                       change = new TextChange (tok.Start, tok.Length, selectedSugg + ">");
-                                       newSelection = TextSpan.FromStartAndLength (change.End2 - 1);
-                               }
-                       } else if (node is AttributeSyntax attrib) {
-                               
-                       } else if (tokType == XmlTokenType.ElementOpen) {
-                               change = new TextChange (tok.End, 0, selectedSugg + " ");
-                       } else
-                               change =  new TextChange (tok.Start, tok.Length, selectedSugg);
-
-                       return true;
-
+                                               if (atts.Parent is ElementTagSyntax et) {
+                                                       if (tokType == XmlTokenType.AttributeName) {
+                                                               string txtEnd = sts.NextSiblingIs(XmlTokenType.EqualSign) ? "" : "=\"\"";
+                                                               List<Suggestion> sugs = getAttributeNameSuggestions(et.Name, atts.Name, new TextChange(tok.Start, tok.Length, txtEnd), txtEnd.Length > 0 ? -1 : 0).ToList();
+                                                               if (sugs.Count == 0 || (sugs.Count == 1 && sugs[0].Caption == sts.AsText()))
+                                                                       return null;
 
-                       if (tok.GetTokenType() == XmlTokenType.ElementOpen ||
-                               tok.GetTokenType() == XmlTokenType.WhiteSpace ||
-                               tok.GetTokenType() == XmlTokenType.AttributeValueOpen) {
-                               change = new TextChange (tok.End, 0, selectedSugg);
-                               return true;
-                       }
-                       if (tok.GetTokenType() == XmlTokenType.AttributeName && CurrentNode is AttributeSyntax attrib) {
-                               if (attrib.ValueToken.HasValue) {
-                                       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 (tok.Start, tok.Length, selectedSugg + "=\"\"");
-                                       newSelection = TextSpan.FromStartAndLength (tok.Start + selectedSugg.Length + 2);
+                                                               return sugs;
+                                                       } else if (atts.HasName) {
+                                                               if(tokType == XmlTokenType.AttributeValueOpen) {
+                                                                       return getAttributeValueSuggestions(et.Name, atts.Name, "", new TextChange(tok.End, 0))?.ToList();
+                                                               } else if (tokType == XmlTokenType.AttributeValue) {
+                                                                       return getAttributeValueSuggestions(et.Name, atts.Name, CurrentNode.AsText(), new TextChange(tok.Start, tok.Length))?.ToList();
+                                                               }
+                                                       }
+                                               } else {
+                                                       System.Diagnostics.Debugger.Break();
+                                               }
+                                       }
                                }
-                               return true;
+                       } else if (CurrentNode is ElementTagSyntax ts) {
+                               string txtEnd = nextTok?.GetTokenType() == XmlTokenType.EqualSign ? "" : "=\"\"";
+                               return getAttributeNameSuggestions(ts.Name, "", new TextChange(tok.End, 0, txtEnd), txtEnd.Length > 0 ? -1 : 0).ToList();
                        }
-
-                       change = new TextChange (tok.Start, tok.Length, selectedSugg);
-                       return true;
-               }*/
+                       return null;
+               }
 
                public override Color GetColorForToken(Token token)
                {
                        TokenType tokType = token.Type;
                        XmlTokenType xmlTokType = (XmlTokenType)tokType;
-                       if (xmlTokType.HasFlag (XmlTokenType.Punctuation))
-                               return Colors.DarkGrey;
-                       if (tokType.HasFlag (TokenType.WhiteSpace))
-                               return Colors.Silver;                   
-                       if (xmlTokType.HasFlag (XmlTokenType.Trivia))
-                               return Colors.DimGrey;
-                       else if (xmlTokType == XmlTokenType.ElementName)
+                       if (xmlTokType == XmlTokenType.ElementName)
                                return Colors.Green;
                        if (xmlTokType == XmlTokenType.AttributeName)
                                return Colors.Blue;
@@ -258,9 +119,8 @@ namespace CrowEdit.Xml
                                return Colors.Black;
                        if (xmlTokType == XmlTokenType.PI_Target)
                                return Colors.DarkSlateBlue;
-                       return Colors.Red;
+                       return base.GetColorForToken(token);
 
                }
-               //protected bool previousTokHasFlag(XmlTokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
        }
 }
\ No newline at end of file
index e678241f0139f3e16d9aea276d9f48ef49ef14cf..9832636dcf12f0aea67000a469ce20004ec46f60 100644 (file)
@@ -19,6 +19,8 @@ namespace CrowEdit.Xml
                        tok.Type = (TokenType)type;
                }
                public static bool Is(this Token tok, XmlTokenType type) => (XmlTokenType)tok.Type == type;
+               public static bool NextSiblingIs(this SyntaxNode sts, XmlTokenType tt) => sts.NextSiblingIs((TokenType)tt);
+               public static bool PreviousSiblingIs(this SyntaxNode sts, XmlTokenType tt) => sts.PreviousSiblingIs((TokenType)tt);
        }       
        public class XmlSyntaxAnalyser : SyntaxAnalyser {
         public XmlSyntaxAnalyser (ReadOnlyTextBuffer document) : base (document) {}
@@ -32,10 +34,10 @@ namespace CrowEdit.Xml
                                                break;
                                        case XmlTokenType.BlockCommentStart:
                                                MultiNodeSyntax bc = new CommentTriviaSyntax(true);
-                                               bc.AddChild(new SingleTokenSyntax(Read()));
+                                               bc.AddChild(new XMLSingleTokenSyntax(Read()));
                                                while(tryPeek(out Token tok)) {
                                                        if (tok.Type == TokenType.BlockCommentEnd)      {
-                                                               bc.AddChild(new SingleTokenSyntax(Read()));
+                                                               bc.AddChild(new XMLSingleTokenSyntax(Read()));
                                                                break;
                                                        }
                                                        if (tok.Type == TokenType.LineBreak) {
@@ -43,7 +45,7 @@ namespace CrowEdit.Xml
                                                                        return true;
                                                                Read();
                                                        } else {
-                                                               bc.AddChild(new SingleTokenSyntax(Read()));
+                                                               bc.AddChild(new XMLSingleTokenSyntax(Read()));
                                                        }
                                                }
                                                currentNode.AddChild(bc);
@@ -56,28 +58,29 @@ namespace CrowEdit.Xml
 
                        return !EOF;
                }
-               bool accept(MultiNodeSyntax node, Enum tokenType) {
-                       if (EOF)
+               bool accept(MultiNodeSyntax node, Enum tokenType, bool skipTrivia = true, bool skipLineBreaks = true) {
+                       if (skipTrivia && !skipTriviaAndComments(node, skipLineBreaks))
                                return false;
                        if (Peek().Type == (TokenType)tokenType) {
-                               node.AddChild(new SingleTokenSyntax(Read()));
+                               node.AddChild(new XMLSingleTokenSyntax(Read()));
                                return true;
                        }
                        return false;
                }               
-               public virtual void ProcessAttributeValueSyntax(AttributeSyntax attrib) {
+               /*public virtual void ProcessAttributeValueSyntax(AttributeSyntax attrib) {
                        //attrib.valueTok = tokIdx - attrib.TokenIndexBase;
-               }
+               }*/
                AttributeSyntax processNode(AttributeSyntax attrib) {
-                       if (accept(attrib, XmlTokenType.EqualSign))
-                               if (accept(attrib, XmlTokenType.AttributeValueOpen))
-                                       if(accept(attrib, XmlTokenType.AttributeValue))
-                                               accept(attrib, XmlTokenType.AttributeValueClose);
+                       if (accept(attrib, XmlTokenType.EqualSign, true))
+                               if (accept(attrib, XmlTokenType.AttributeValueOpen, true)) {
+                                       accept(attrib, XmlTokenType.AttributeValue);
+                                       accept(attrib, XmlTokenType.AttributeValueClose);
+                               }
                        return attrib;
                }
                ElementEndTagSyntax processNode(ElementEndTagSyntax et) { 
                        if (accept(et, XmlTokenType.ElementName))
-                               accept(et, XmlTokenType.ClosingSign);
+                               accept(et, XmlTokenType.ClosingSign, true);
                        return et;
                }
                ProcessingInstructionSyntax processNode(ProcessingInstructionSyntax pi) {
@@ -85,7 +88,7 @@ namespace CrowEdit.Xml
                                pi.AddChild(new PITargetSyntax(Read()));
                                while (skipTriviaAndComments(pi, false)) {
                                        if (Peek().Is(XmlTokenType.PI_End)) {
-                                               pi.AddChild(new SingleTokenSyntax(Read()));
+                                               pi.AddChild(new XMLSingleTokenSyntax(Read()));
                                                break;
                                        }
                                        if (Peek().Is(XmlTokenType.AttributeName))
@@ -127,7 +130,13 @@ namespace CrowEdit.Xml
                                        if (accept (start, XmlTokenType.ClosingSign)) {
                                                elt = processElement(new ElementSyntax(start));
                                                break;
-                                       }                                       
+                                       }
+                                       //wouldd be better in tokenizer, and break on unexpected tok
+                                       if (Peek().Is(XmlTokenType.ElementOpen) || Peek().Is(XmlTokenType.EndElementOpen)) {
+                                               start.AddChild(new UnexpectedTokenSyntax(Read()));
+                                               break;
+                                       }
+
                                        if (Peek().Is(XmlTokenType.AttributeName))
                                                start.AddChild(processNode(new AttributeSyntax(Read())));
                                        else
index e877d5356eb33816b7daf44e8d197ce750725665..3404522eada8b9cc0626cad90406c593920177f1 100644 (file)
@@ -12,32 +12,33 @@ namespace CrowEdit.Xml
        public class XMLRootSyntax : SyntaxRootNode {
                public XMLRootSyntax (ReadOnlyTextBuffer buff, Token[] tokens) : base (buff, tokens) { }
        }
+       
        public class ProcessingInstructionSyntax : MultiNodeSyntax {
 //             public override bool IsComplete => base.IsComplete & name.HasValue & PIClose.HasValue;
                public ProcessingInstructionSyntax (Token openTok){
-                       AddChild(new SingleTokenSyntax(openTok));
+                       AddChild(new XMLSingleTokenSyntax(openTok));
                }
        }
-       public class PITargetSyntax : SingleTokenSyntax {
+       public class PITargetSyntax : XMLSingleTokenSyntax {
 //             public override bool IsComplete => base.IsComplete & name.HasValue & PIClose.HasValue;
                public PITargetSyntax (Token target) : base(target) { }
        }
 
-
+       public class XMLSingleTokenSyntax : SingleTokenSyntax {
+               public XMLSingleTokenSyntax(Token tok) : base(tok) { }
+        public static implicit operator XmlTokenType (XMLSingleTokenSyntax sts) => sts == null ? XmlTokenType.Unknown : (XmlTokenType)sts.Type;
+       }
        public abstract class ElementTagSyntax : MultiNodeSyntax {
 //             public override bool IsComplete => base.IsComplete & name.HasValue & close.HasValue;
                protected ElementTagSyntax (){}
                protected ElementTagSyntax (Token openTok) {
-                       AddChild(new SingleTokenSyntax(openTok));
+                       AddChild(new XMLSingleTokenSyntax(openTok));
                }
         public override bool IsComplete => ChildSequenceIs();
                public string Name => Children.ElementAtOrDefault(1) is SingleTokenSyntax sts &&
                                                          sts.token.GetTokenType() == XmlTokenType.ElementName ? sts.AsText(): "";
                public abstract bool HasClosingToken { get; }
        }
-       /*public class ElementNameSyntax : SingleTokenSyntax {
-               public ElementNameSyntax(Token name) : base(name) {}
-       }*/
        public class ElementStartTagSyntax : ElementTagSyntax {
                public ElementStartTagSyntax (Token openTok) : base(openTok) {}
                public override bool HasClosingToken => Children.LastOrDefault() is SingleTokenSyntax sts && sts.token.GetTokenType() == XmlTokenType.ClosingSign;
@@ -47,13 +48,12 @@ namespace CrowEdit.Xml
                public ElementEndTagSyntax (Token openTok) : base(openTok) {}
         public override bool HasClosingToken => Children.LastOrDefault() is SingleTokenSyntax sts && sts.token.GetTokenType() == XmlTokenType.ClosingSign;
        }
-
        public class EmptyElementSyntax : ElementTagSyntax {
                public EmptyElementSyntax (ElementStartTagSyntax startNode) {
                        foreach (var child in startNode.Children)
                                AddChild(child);
                }
-               public override bool HasClosingToken => Children.LastOrDefault() is SingleTokenSyntax sts && sts.token.GetTokenType() == XmlTokenType.EmptyElementClosing;
+               public override bool HasClosingToken => HasChilds && Children.LastOrDefault().IsSimilar(XmlTokenType.EmptyElementClosing);
         //public override bool IsComplete => base.IsComplete && StartTag != null;
     }
 
@@ -66,10 +66,22 @@ namespace CrowEdit.Xml
                public ElementStartTagSyntax StartTag => Children.ElementAtOrDefault(0) as ElementStartTagSyntax;
                public ElementEndTagSyntax EndTag => Children.LastOrDefault() as ElementEndTagSyntax;
        }
-       public class AttributeSyntax : MultiNodeSyntax {                        
-               //public override bool IsComplete => base.IsComplete & name.HasValue & equal.HasValue & valueTok.HasValue & valueOpen.HasValue & valueClose.HasValue;
+       public class AttributeSyntax : MultiNodeSyntax {
+               public override bool IsComplete => HasName && HasEquals;
                public AttributeSyntax(Token name) {
-                       AddChild (new SingleTokenSyntax(name));
+                       AddChild (new XMLSingleTokenSyntax(name));
+               }
+               public string Name => Children.FirstOrDefault() is SingleTokenSyntax sts &&
+                                                         sts.token.GetTokenType() == XmlTokenType.AttributeName ? sts.AsText(): "";
+               public bool HasName => HasChilds && Children.First().IsSimilar(XmlTokenType.AttributeName);
+               public bool HasEquals => HasChilds &&
+                       ((HasName && Children.First().NextSiblingIs(XmlTokenType.EqualSign)) ||
+                       (!HasName && Children.First().IsSimilar(XmlTokenType.EqualSign)));
+               
+       }
+       public class AttributeValueSyntax : MultiNodeSyntax {
+               public AttributeValueSyntax(Token openTok) {
+                       AddChild(new XMLSingleTokenSyntax(openTok));
                }
        }
 }
\ No newline at end of file
index c7fb88fb0a41f59076fcacd0f76df33cd9f7bddb..6fbf00dd832278e38a43cd5f1d48358e27b006e0 100644 (file)
@@ -195,7 +195,7 @@ namespace CrowEdit.Xml
                                        break;
                                }
                        }
-
+                       addTok (ref reader, XmlTokenType.Unknown);
                        return Toks.ToArray();
                }