}
#endregion
- protected Token token;
+ public readonly Token token;
#region SyntaxNode implementation
public override TokenType Type => token.Type;
public override int SpanStart => token.Start;
public override int SpanEnd => token.End;
public override bool IsComplete => token.Type != TokenType.Unknown && token.Length > 0;
- #endregion
- }
+ public override bool IsSimilar(object other)
+ {
+ return other is SingleTokenSyntax sts ?
+ sts.Type == Type : other is TokenType tt ? Type == tt : false;
+
+ }
+ #endregion
+
+ }
}
\ No newline at end of file
//
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System.Collections.Generic;
+using System.ComponentModel;
using Crow.Text;
namespace CrowEditBase
public string AsText() {
return Span.Length < 0 ? "" : Root.GetText(Span).ToString();
}
- public bool IsSimilar (SyntaxNode other) => this.GetType() == other?.GetType();
+ public virtual bool IsSimilar (object other) => this.GetType() == other?.GetType();
public class CompareOnStartLine : IComparer<SyntaxNode>
{
public int Compare(SyntaxNode x, SyntaxNode y) => x.StartLocation.Line - y.StartLocation.Line;
}
public override string ToString() => $"{this.GetType().Name}";
-
- #region to clean
- /*public int StartLine { get; private set; }
- public virtual int LineCount => lineCount;*/
-
- /*List<SyntaxException> exceptions = new List<SyntaxException>();
- public IEnumerable<SyntaxException> Exceptions => exceptions;
- public void AddException(SyntaxException e) => exceptions.Add(e);
- public void ResetExceptions(SyntaxException e) => exceptions.Clear();
- public IEnumerable<SyntaxException> GetAllExceptions() {
- foreach (SyntaxException e in exceptions)
- yield return e;
- foreach (SyntaxNode n in Children) {
- foreach (SyntaxException ce in n.GetAllExceptions())
- yield return ce;
- }
- }*/
-
- //public int IndexOf (SyntaxNode node) => children.IndexOf (node);
-
- /*public virtual int TokenIndexBase { get; private set; }
- public virtual int TokenCount => lastTokenOfset.HasValue ? lastTokenOfset.Value + 1 : 0;
- public int? LastTokenIndex => lastTokenOfset.HasValue ? TokenIndexBase + lastTokenOfset.Value : null;
-
- public int EndLine {
- set {
- lineCount = value - StartLine + 1;
- }
- get => StartLine + lineCount - 1;
- }*/
-
- /*
- public void Replace (SyntaxNode newNode) {
- Parent.replaceChild (this, newNode);
- }
- void replaceChild (SyntaxNode oldNode, SyntaxNode newNode) {
- int idx = children.IndexOf (oldNode);
- children[idx] = newNode;
- newNode.Parent = this;
- int tokIdxDiff = newNode.TokenCount - oldNode.TokenCount;
- int lineDiff = newNode.EndLine - oldNode.EndLine;
- if (tokIdxDiff == 0 && lineDiff == 0)
- return;
-
- SyntaxNode curNode = this;
- while (curNode != null) {
- curNode.lineCount += lineDiff;
- curNode.TokenCount += tokIdxDiff;
- if (curNode is SyntaxRootNode)
- break;
- while (++idx < curNode.children.Count)
- curNode.children[idx].offset (tokIdxDiff, lineDiff);
- idx = curNode.Parent.children.IndexOf (curNode);
- curNode = curNode.Parent;
- }
- }*/
- /*void offset (int tokenOffset, int lineOffset) {
- TokenIndexBase += tokenOffset;
- StartLine += lineOffset;
- foreach (SyntaxNode child in children) {
- child.offset (tokenOffset, lineOffset);
- }
- }*/
-/*
- public T FindNodeIncludingPosition<T> (int pos) {
- foreach (SyntaxNode node in children) {
- if (node.Contains (pos))
- return node.FindNodeIncludingPosition<T> (pos);
- }
-
- return this is T tt ? tt : default;
- }*/
- /*public void Dump (int level = 0) {
- Console.WriteLine ($"{new string('\t', level)}{this}");
- foreach (SyntaxNode node in children)
- node.Dump (level + 1);
- }*/
- //public override string ToString() => $"l:({StartLine,3},{LineCount,3}) tks:{TokenIndexBase},{TokenCount} {this.GetType().Name}";
- #endregion
}
}
\ No newline at end of file
protected void tryGetSuggestions () {
if (currentLoc.HasValue && Document is SourceDocument srcDoc && srcDoc.IsParsed) {
int pos = srcDoc.GetAbsolutePosition(CurrentLoc.Value);
- var tmp = srcDoc.GetSuggestions (pos, currentTokenIndex, currentNode, CurrentLoc.Value);
- if (tmp?.Count == 1 && tmp[0].TryCast(out Suggestion sug) && sug.Change.HasNoEffect(srcDoc.source))
- Suggestions = null;
- else
- Suggestions = tmp;
- } else
- Suggestions = null;
+ if (pos > 0) {
+ SyntaxNode node = srcDoc.FindNodeIncludingPosition(pos-1);
+ if (node != null) {
+ var tmp = srcDoc.GetSuggestions (pos,
+ srcDoc.FindTokenIndexIncludingPosition(pos -1), node, CurrentLoc.Value);
+ if (!(tmp?.Count == 1 && tmp[0].TryCast(out Suggestion sug) && sug.Change.HasNoEffect(srcDoc.source)))
+ Suggestions = tmp;
+ return;
+ }
+ }
+ }
+ Suggestions = null;
}
void showOverlay () {
lock (IFace.UpdateMutex) {
return;
}
- if (Document is SourceDocument doc) {
+ if (Document is SourceDocument doc && doc.IsParsed) {
switch (e.Key) {
/*case Key.F3:
doc.Root?.Dump();
}
protected override void drawContent (IContext gr) {
+ sourceDocument.EnterReadLock ();
+
+ double lineHeight = fe.Ascent + fe.Descent;
+ updateMargin ();
+
+ bool printLineNumbers = App.PrintLineNumbers;
+ Color marginBG = App.MarginBackground;
+ Color marginFG = Colors.Ivory;
+ Rectangle cb = ClientRectangle;
+ RectangleD marginRect = new RectangleD (cb.X, cb.Y, leftMargin - leftMarginRightGap, cb.Height);
+
+ gr.SetSource (marginBG);
+ gr.Rectangle (marginRect);
+ gr.Fill();
+
if (!parsingOk) {
base.drawContent (gr);
+ sourceDocument.ExitReadLock ();
return;
}
- sourceDocument.EnterReadLock ();
try {
- double lineHeight = fe.Ascent + fe.Descent;
- updateMargin ();
-
- bool printLineNumbers = App.PrintLineNumbers;
- Color marginBG = App.MarginBackground;
- Color marginFG = Colors.Ivory;
- Rectangle cb = ClientRectangle;
- RectangleD marginRect = new RectangleD (cb.X, cb.Y, leftMargin - leftMarginRightGap, cb.Height);
-
- gr.SetSource (marginBG);
- gr.Rectangle (marginRect);
- gr.Fill();
-
gr.Translate (-ScrollX, 0);
double lineNumWidth = gr.TextExtents (Document.LinesCount.ToString()).Width;
RegisterForGraphicUpdate();
}
void updateCurrentTokAndNode() {
- if (currentLoc.HasValue && Document is SourceDocument srcdoc) {
+ if (currentLoc.HasValue && Document is SourceDocument srcdoc && srcdoc.Tokens.Length > 0) {
int pos = srcdoc.GetAbsolutePosition(currentLoc.Value);
currentTokenIndex = srcdoc.FindTokenIndexIncludingPosition(pos);
Token tok = srcdoc.GetTokenByIndex(currentTokenIndex);
using System;
using System.Linq;
using Crow.Text;
+using System.Collections;
using System.Collections.Generic;
using Crow;
using IML = Crow.IML;
namespace CECrowPlugin
{
+ public static class Extensions {
+ public static ImlTokenType GetTokenType (this Token tok) {
+ return (ImlTokenType)tok.Type;
+ }
+ public static void SetTokenType (this Token tok, ImlTokenType type) {
+ tok.Type = (TokenType)type;
+ }
+ public static bool Is(this Token tok, ImlTokenType type) => (ImlTokenType)tok.Type == type;
+ }
public class ImlDocument : XmlDocument {
-
-
public ImlDocument (string fullPath, string editorPath) : base (fullPath, editorPath) {
App.GetService<CrowService> ()?.Start ();
if (msbp.IsCrowProject)
}*/
}
+
protected override SyntaxAnalyser CreateSyntaxAnalyser() => new ImlSyntaxAnalyser (ImmutableBufferCopy);
public override string GetTokenTypeString (TokenType tokenType) => ((ImlTokenType)tokenType).ToString();
if (widgetType == null)
return null;
- IEnumerable<Type> widgetTypes = widgetType.Assembly.GetExportedTypes ().Where(t=>
- widgetType.IsAssignableFrom (t) && !t.IsAbstract);
+ IEnumerable<Type> widgetTypes = widgetType.Assembly.GetExportedTypes ().Where(
+ t=>!t.IsAbstract && widgetType.IsAssignableFrom (t));
int curNameLength = 0;
if (!string.IsNullOrEmpty(curName)) {
widgetTypes = widgetTypes.Where(t=>t.Name.StartsWith(curName, StringComparison.OrdinalIgnoreCase));
}
return null;
}
- /*public override IList GetSuggestions (int absoluteTextPos, int currentTokenIndex, SyntaxNode CurrentNode, CharLocation loc) {
+ 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})");
+
IList sugs = base.GetSuggestions (absoluteTextPos, currentTokenIndex, CurrentNode, loc);
if (sugs != null)
return sugs;
-
+/*
+
- Token tok = GetTokenByIndex(currentTokenIndex);
if (tok.GetTokenType() == XmlTokenType.ElementOpen)
return new List<string> (allWidgetNames);
//else if (tok.Type == TokenType.ElementName)
// Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (Source)).ToList ();
} else {
- }
+ }*/
return null;
- }*/
+ }
public override Color GetColorForToken(Token token)
{
-// Copyright (c) 2021-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+// 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 System;
-using System.Collections.Generic;
-using System.Linq;
using CrowEditBase;
using CrowEdit.Xml;
-using System.Threading.Tasks;
-using System.Threading;
namespace CECrowPlugin
{
public class ImlSyntaxAnalyser : XmlSyntaxAnalyser {
public ImlSyntaxAnalyser (ReadOnlyTextBuffer document) : base (document) {}
-
- public override async Task<SyntaxRootNode> Process (CancellationToken cancel = default) {
-
- return await base.Process();
-
-/*
- ImlDocument xmlDoc = source as ImlDocument;
- Exceptions = new List<SyntaxException> ();
- currentNode = new XMLRootSyntax (xmlDoc);
- currentLine = 0;
- Span<Token> toks = source.Tokens;
- tokIdx = 0;
-
- while (tokIdx < toks.Length) {
- Token curTok = toks[tokIdx];
- if (curTok.Type == TokenType.LineBreak)
- currentLine++;
- else if (!curTok.Type.HasFlag (TokenType.Trivia)) {
- if (currentNode is ElementStartTagSyntax tag) {
- if (curTok.GetTokenType() == XmlTokenType.AttributeName) {
- AttributeSyntax attribute = new AttributeSyntax (currentLine, tokIdx);
- attribute.name = 0;
- currentNode = currentNode.AddChild (attribute);
- } else if (curTok.GetTokenType() == XmlTokenType.ElementName)
- tag.name = tokIdx - tag.TokenIndexBase;
- else if (curTok.GetTokenType() == XmlTokenType.ClosingSign) {
- storeCurrentNode ();
- currentNode.RemoveChild (tag);
- currentNode = currentNode.AddChild (new ElementSyntax (tag));
- } else if (curTok.GetTokenType() == XmlTokenType.EmptyElementClosing) {
- storeCurrentNode ();
- currentNode.RemoveChild (tag);
- currentNode = currentNode.AddChild (new EmptyElementSyntax (tag));
- setCurrentNodeEndLine (currentLine);
- currentNode = currentNode.Parent;
- } else {
- Exceptions.Add (new SyntaxException ("Unexpected Token", curTok));
- storeCurrentNode (-1);
- continue;
- }
- } else if (currentNode is ElementSyntax elt) {
- if (curTok.GetTokenType() == XmlTokenType.ElementOpen)
- currentNode = currentNode.AddChild (new ElementStartTagSyntax (currentLine, tokIdx));
- else if (curTok.GetTokenType() == XmlTokenType.EndElementOpen) {
- elt.EndTag = new ElementEndTagSyntax (currentLine, tokIdx);
- currentNode = elt.AddChild (elt.EndTag);
- }
- } else if (currentNode is AttributeSyntax attrib) {
- if (curTok.GetTokenType() == XmlTokenType.EqualSign)
- if (attrib.equal.HasValue)
- Exceptions.Add (new SyntaxException ("Extra equal sign in attribute syntax", curTok));
- else
- attrib.equal = tokIdx - attrib.TokenIndexBase;
- else if (curTok.GetTokenType() == XmlTokenType.AttributeValueOpen)
- attrib.valueOpen = tokIdx - attrib.TokenIndexBase;
- else if (curTok.GetTokenType() == XmlTokenType.AttributeValue)
- attrib.valueTok = tokIdx - attrib.TokenIndexBase;
- else if (curTok.GetTokenType() == XmlTokenType.AttributeValueClose) {
- attrib.valueClose = tokIdx - attrib.TokenIndexBase;
- storeCurrentNode ();
- } else {
- Exceptions.Add (new SyntaxException ("Unexpected Token", curTok));
- storeCurrentNode (-1);
- continue;
- }
- } else if (currentNode is ElementEndTagSyntax eltEndTag) {
- if (curTok.GetTokenType() == XmlTokenType.ElementName)
- eltEndTag.name = tokIdx - eltEndTag.TokenIndexBase;
- else if (curTok.GetTokenType() == XmlTokenType.ClosingSign) {
- //go up 2 times
- storeCurrentNode (); storeCurrentNode ();
- } else {
- Exceptions.Add (new SyntaxException ("Unexpected Token", curTok));
- storeCurrentNode (-1);
- storeCurrentNode (-1);
- continue;
- }
- } else if (currentNode is XMLRootSyntax) {
- switch (curTok.GetTokenType()) {
- case XmlTokenType.ElementOpen:
- currentNode = currentNode.AddChild (new ElementStartTagSyntax (currentLine, tokIdx));
- break;
- case XmlTokenType.PI_Start:
- currentNode = currentNode.AddChild (new ProcessingInstructionSyntax (currentLine, tokIdx));
- break;
- default:
- Exceptions.Add (new SyntaxException ("Unexpected Token", curTok));
- break;
- }
- } else if (currentNode is ProcessingInstructionSyntax pi) {
- if (curTok.GetTokenType() == XmlTokenType.PI_Target)
- pi.name = tokIdx - pi.TokenIndexBase;
- else if (curTok.GetTokenType() == XmlTokenType.PI_End) {
- storeCurrentNode ();
- } else if (curTok.GetTokenType() == XmlTokenType.AttributeName) {
- AttributeSyntax attribute = new AttributeSyntax (currentLine, tokIdx);
- attribute.name = 0;
- currentNode = currentNode.AddChild (attribute);
- } else {
- Exceptions.Add (new SyntaxException ("Unexpected Token", curTok));
- storeCurrentNode (-1);
- continue;
- }
- }
- }
- tokIdx++;
- }
- while (currentNode.Parent != null) {
- if (!currentNode.LastTokenOffset.HasValue)
- storeCurrentNode (-1);
- else
- currentNode = currentNode.Parent;
- }
- setCurrentNodeEndLine (currentLine);
- */
- }
+ protected override Token[] tokenize()
+ {
+ Tokenizer tokenizer = new ImlTokenizer();
+ return tokenizer.Tokenize(source.Source.Span);
+ }
}
}
\ No newline at end of file
-// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+// Copyright (c) 2013-2025 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 Crow;
using System.Linq;
+using System.Diagnostics;
namespace CrowEdit.Xml
{
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;
public override IList GetSuggestions (int absoluteTextPos, int currentTokenIndex, SyntaxNode CurrentNode, CharLocation loc) {
- /*Token tok = GetTokenByIndex(currentTokenIndex);
+ Console.WriteLine($"absPos:{absoluteTextPos} tokIdx:{currentTokenIndex} node:{CurrentNode} charLoc:{loc}");
+ Token tok = GetTokenByIndex(currentTokenIndex);
+ 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)){
+ Suggestion sug = new Suggestion(name);
+ if (tk == XmlTokenType.ElementName && name.StartsWith(sts.AsText(), 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);
+ else
+ return null;
+ if (!eets.HasClosingToken)
+ sug.Change.ChangedText += ">";
+ return new List<Suggestion>([sug]);
+ }
+ }
+ } else {
+ string txtEnd = ets.HasClosingToken ? "" : ">";
+ if (tk == XmlTokenType.ElementOpen) {
+ return getElementNameSuggestions("", new TextChange(tok.End, 0, txtEnd)).ToList();
+ }
+ if (tk == XmlTokenType.ElementName) {
+ return getElementNameSuggestions(sts.AsText(), new TextChange(tok.Start, tok.Length, txtEnd)).ToList();
+ }
+ }
+ }
+ }
+ /*
if (tok.Start != absoluteTextPos //middle of edited tok
&& currentTokenIndex >= CurrentNode?.Root.TokenCount - 1) //occurs when curTok is last tok of text
{
}
void processElementNode(MultiNodeSyntax node) {
ElementStartTagSyntax start = new ElementStartTagSyntax(Read());
+ MultiNodeSyntax elt = null;
if (accept (start, XmlTokenType.ElementName)) {
while (skipTriviaAndComments(node)) {
if (accept (start, XmlTokenType.EmptyElementClosing)) {
- node.AddChild(new EmptyElementSyntax(start));
+ elt = new EmptyElementSyntax(start);
break;
}
if (accept (start, XmlTokenType.ClosingSign)) {
- node.AddChild(processElement(new ElementSyntax(start)));
+ elt = processElement(new ElementSyntax(start));
break;
}
if (Peek().Is(XmlTokenType.AttributeName))
start.AddChild(new UnexpectedTokenSyntax(Read()));
}
} else {
- start.AddChild(new UnexpectedTokenSyntax(Read()));
- node.AddChild(new ElementSyntax(start));
+ if (!EOF)
+ start.AddChild(new UnexpectedTokenSyntax(Read()));
+ elt = new ElementSyntax(start);
}
- }
- public override async Task<SyntaxRootNode> Process (CancellationToken cancel = default) {
+ if (elt == null)
+ elt = new ElementSyntax(start);
+ node.AddChild(elt);
+ }
+ protected virtual Token[] tokenize() {
Tokenizer tokenizer = new XmlTokenizer();
- Token[] tokens = tokenizer.Tokenize(source.Source.Span);
+ return tokenizer.Tokenize(source.Source.Span);
+ }
+
+ public override async Task<SyntaxRootNode> Process (CancellationToken cancel = default) {
+ Token[] tokens = tokenize();
tokIdx = 0;
this.cancel = cancel;//?
Root = new XMLRootSyntax (source, tokens);
+
while (!EOF) {
if (cancel.IsCancellationRequested)
break;
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));
}
+ 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;
+
}
public class ElementEndTagSyntax : ElementTagSyntax {
public ElementEndTagSyntax (Token openTok) : base(openTok) {}
+ public override bool HasClosingToken => Children.LastOrDefault() is SingleTokenSyntax sts && sts.token.GetTokenType() == XmlTokenType.ClosingSign;
}
- public class EmptyElementSyntax : MultiNodeSyntax {
+ 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 IsComplete => base.IsComplete && StartTag != null;
}
public class ElementSyntax : MultiNodeSyntax {
-
- public override bool IsComplete => base.IsComplete;// & StartTag.IsComplete & (EndTag != null && EndTag.IsComplete);
-
+ public override bool IsComplete => StartTag != null && EndTag != null && StartTag.IsComplete && EndTag.IsComplete && StartTag.Name == EndTag.Name;
public ElementSyntax (ElementStartTagSyntax startNode) {
AddChild (startNode);
}
+
+ 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;