namespace CrowEditBase
{
public abstract class SourceDocument : TextDocument {
+ #region CTOR
public SourceDocument (string fullPath, string editorPath = "#ui.sourceEditor.itmp")
: base (fullPath, editorPath) {
}
+ #endregion
+
protected SyntaxRootNode root;
+ CancellationTokenSource cancelSource;
+ Task backgroundCompilationTask;
+ public SyntaxRootNode Root {
+ get => root;
+ }
+ public bool IsParsed => root != null && Tokens.Length > 0;
+ public ReadOnlySpan<Token> Tokens => root.Tokens;
+ public IEnumerable<SyntaxNode> SyntaxRootChildNodes => root?.children;
+ public SyntaxException CurrentException {
+ get => CrowEditBase.App.CurrentException;
+ set {
+ CrowEditBase.App.CurrentException = value;
+ SetLocation(value.Location);
+ }
+ }
+
+ #region commands
public Command CMDRefreshSyntaxTree;
-
protected override void initCommands()
{
base.initCommands();
CMDRefreshSyntaxTree = new ActionCommand ("Reparse", parse, "#icons.refresh.svg", true);
}
- public SyntaxRootNode Root {
- get => root;
- }
-
- public bool IsParsed => root != null && Tokens.Length > 0;
- public ReadOnlySpan<Token> Tokens => root.Tokens;
- public IEnumerable<SyntaxNode> SyntaxRootChildNodes => root?.children;
+ #endregion
+ #region token & node searching
+ public Token GetTokenByIndex(int tokIdx) => IsParsed && tokIdx >= 0 ?
+ Tokens[Math.Min(Tokens.Length - 1, tokIdx)] : default;
public Token FindTokenIncludingPosition (int pos) {
if (!IsParsed || pos == 0 || Tokens.Length == 0)
return default;
int idx = Tokens.BinarySearch(new Token (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 (!IsParsed || pos == 0 || Tokens.Length == 0)
return default;
/// if outermost is true, return oldest ancestor exept root node, useful for folding.
/// </summary>
public SyntaxNode FindNodeIncludingPosition (int pos, bool outerMost = false) {
+
if (root == null)
return null;
if (!root.Contains (pos))
}
return sn;
}
- /*public T FindNodeIncludingPosition<T> (int pos) {
- if (root == null)
- return default;
- if (!root.Contains (pos))
- return default;
- return root.FindNodeIncludingPosition<T> (pos);
- }
- public SyntaxNode FindNodeIncludingSpan (TextSpan span) {
- if (root == null)
- return null;
- if (!root.Contains (span))
- return null;
- return root.FindNodeIncludingSpan (span);
- }*/
+ #endregion
+ #region TextDocument implementation
protected override void reloadFromFile () {
base.reloadFromFile ();
parse ();
//Console.WriteLine ($"CurrentToken: idx({currentTokenIndex}) {currentToken} {RootNode.Root.GetTokenStringByIndex(currentTokenIndex)}");
}
-
+ #endregion
public virtual Color GetColorForToken (Token token)
{
//protected abstract Tokenizer CreateTokenizer ();
protected abstract SyntaxAnalyser CreateSyntaxAnalyser ();
public abstract IList GetSuggestions (int absoluteTextPos, int currentTokenIndex, SyntaxNode currentNode, CharLocation loc);
- CancellationTokenSource cancelSource;
- Task backgroundCompilationTask;
protected virtual async void parse () {
if (backgroundCompilationTask != null && !backgroundCompilationTask.IsCompleted) {
cancelSource.Cancel();
NotifyValueChanged ("SyntaxRootChildNodes", SyntaxRootChildNodes);
}
- public SyntaxException CurrentException {
- get => CrowEditBase.App.CurrentException;
- set {
- CrowEditBase.App.CurrentException = value;
- SetLocation(value.Location);
- }
- }
}
}
\ No newline at end of file
+++ /dev/null
-// 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 Crow.Text;
-using Crow;
-using System.Diagnostics;
-
-namespace CrowEditBase
-{
- public class UnexpectedTokenSyntax : SingleTokenSyntax {
- public UnexpectedTokenSyntax(Token tok) : base (tok) { }
- }
- public class SingleTokenSyntax : SyntaxNode {
- protected Token token;
- 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;
- public SingleTokenSyntax(Token tok) {
- token = tok;
- token.syntaxNode = this;
- }
- }
- public class CommentTriviaSyntax : MultiNodeSyntax {
- bool block;
- public CommentTriviaSyntax(bool block) {
- this.block = block;
- }
- public override bool IsComplete => true;
-
- }
- public abstract class MultiNodeSyntax : SyntaxNode {
- public MultiNodeSyntax() { }
- internal List<SyntaxNode> children = new List<SyntaxNode> ();
- public IEnumerable<SyntaxNode> Children => children;
- public SyntaxNode AddChild (SyntaxNode child) {
- children.Add (child);
- child.Parent = this;
- return child;
- }
- public void RemoveChild (SyntaxNode child) {
- children.Remove (child);
- child.Parent = null;
- }
- public IEnumerable<T> GetChilds<T> () => children.OfType<T>();
-
- public bool ChildIs<T> (int idx) => children.Count() <= idx ? false : children[idx] is T;
- public bool ChildSequenceIs(params object[] sequ) {
- if (children.Count != sequ.Length)
- return false;
- for (int i = 0; i < sequ.Length; i++) {
- if (typeof(Type).IsAssignableFrom(sequ[i].GetType())) {
- if ((sequ[i] as Type) != children[i].GetType())
- return false;
- } else if (sequ[i].GetType().IsEnum) {
- if (!(children[i] is SingleTokenSyntax tok) || (TokenType)sequ[i] != tok.Type)
- return false;
- } else
- return false;
- if (!children[i].IsComplete)
- return false;
-
- }
- return true;
- }
- public override bool IsComplete {
- get {
- for (int i = 0; i < children.Count(); i++) {
- if (!children[i].IsComplete)
- return false;
- }
- return true;
- }
- }
- public override bool HasChilds => children.Count > 0;
- public override int SpanStart => HasChilds ? children[0].SpanStart : 0;
- public override int SpanEnd => HasChilds ? children[children.Count - 1].SpanEnd : 0;
- /*public override int SpanEnd {//to be removed, used for debugging
- get {
- if (HasChilds) {
-
- if (children[children.Count - 1] == this)
- System.Diagnostics.Debugger.Break();
- return children[children.Count - 1].SpanEnd;
- } else return 0;
- }
- } */
-
- internal bool isFolded;
- public virtual bool IsFoldable => IsComplete && !(Parent != Root && Parent.StartLocation.Line == StartLocation.Line) && LineCount > 1;
- public void ExpandToTheTop () {
- isExpanded = true;
- Parent?.ExpandToTheTop ();
- }
- public virtual void UnfoldToTheTop () {
- isFolded = false;
- Parent.UnfoldToTheTop ();
- }
- public IEnumerable<MultiNodeSyntax> VisibleFoldableNodes {
- get {
- if (IsFoldable) {
- yield return this;
- }
- if (!isFolded) {
- foreach (MultiNodeSyntax n in Children.OfType<MultiNodeSyntax>()) {
- foreach (MultiNodeSyntax folds in n.VisibleFoldableNodes)
- yield return folds;
- }
- }
- }
- }
-
- public virtual int FoldedLineCount {
- get {
- if (isFolded)
- return LineCount;
- int tmp = 0;
- if (HasChilds) {
- foreach (MultiNodeSyntax n in children.OfType<MultiNodeSyntax>().Where (c => c.IsFoldable))
- tmp += n.FoldedLineCount;
- }
- return tmp;
- }
- }
- public override SyntaxNode FindNodeIncludingSpan (TextSpan span) {
- foreach (SyntaxNode node in children) {
- if (node.Contains (span))
- return node.FindNodeIncludingSpan (span);
- }
- return this;
- }
- public override SyntaxNode FindNodeIncludingPosition (int pos) {
- foreach (SyntaxNode node in children) {
- if (node.Contains (pos))
- return node.FindNodeIncludingPosition (pos);
- }
- return this;
- }
- bool _isExpanded;
- public override bool isExpanded {
- get => _isExpanded;
- set {
- bool expand = HasChilds ? value : false;
- if (_isExpanded == expand)
- return;
- _isExpanded = value;
- if (isExpanded && Parent is SyntaxNode sn) {
- try {
- sn.isExpanded = true;
- } catch (Exception ex) {
- Debug.WriteLine($"SyntaxNode expand to the top failed:{ex.Message}");
- Debug.WriteLine(ex.StackTrace);
- }
-
- }
- NotifyValueChanged (_isExpanded);
- }
- }
- }
- public abstract class SyntaxNode : CrowEditComponent {
-
-
- #region Folding and ?expand?
- public virtual bool isExpanded {
- get => false;
- set {
- if (value && Parent is SyntaxNode sn) {
- sn.isExpanded = true;
- }
- }
- }
- #endregion
- public MultiNodeSyntax Parent { get; internal set; }
- public virtual SyntaxRootNode Root => Parent.Root;
- public virtual TokenType Type => TokenType.Unknown;
- public virtual int SpanStart => 0;
- public virtual int SpanEnd => 0;
-
-
- public virtual bool HasChilds => false;
- public virtual bool IsComplete => false;
-
-
-
- /*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;
- }
- }*/
-
-
- protected Token getTokenByIndex (int idx) => Root.GetTokenByIndex(idx);
-
-
- //public int IndexOf (SyntaxNode node) => children.IndexOf (node);
- public SyntaxNode NextSibling {
- get {
- if (Parent != null) {
- int idx = Parent.children.IndexOf (this);
- if (idx < Parent.children.Count - 1)
- return Parent.children[idx + 1];
- }
- return null;
- }
- }
- public SyntaxNode PreviousSibling {
- get {
- if (Parent != null) {
- int idx = Parent.children.IndexOf (this);
- if (idx > 0)
- return Parent.children[idx - 1];
- }
- return null;
- }
- }
- public virtual SyntaxNode NextSiblingOrParentsNextSibling
- => NextSibling ?? Parent.NextSiblingOrParentsNextSibling;
-
- /*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 TextSpan Span => new TextSpan (SpanStart, SpanEnd);
- public CharLocation StartLocation => Root.GetLocation(SpanStart);
- public CharLocation EndLocation => Root.GetLocation(SpanEnd);
- public int LineCount => EndLocation.Line - StartLocation.Line + 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 virtual SyntaxNode FindNodeIncludingPosition (int pos) => this;
- public virtual SyntaxNode FindNodeIncludingSpan (TextSpan span) => this;
-
- public bool Contains (int pos) => Span.Contains (pos);
- public bool Contains (TextSpan span) => Span.Contains (span);
- /*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}";
- public override string ToString() => $"{this.GetType().Name}";
- public string AsText() {
- return Span.Length < 0 ? "" : Root.GetText(Span).ToString();
- }
- public bool IsSimilar (SyntaxNode other) => this.GetType() == other?.GetType();
-
-
- public class CompareOnStartLine : IComparer<SyntaxNode>
- {
- public int Compare(SyntaxNode x, SyntaxNode y) => x.StartLocation.Line - y.StartLocation.Line;
- }
- }
-}
\ No newline at end of file
--- /dev/null
+// 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 Crow.Text;
+using Crow;
+using System.Diagnostics;
+
+namespace CrowEditBase
+{
+ public abstract class MultiNodeSyntax : SyntaxNode {
+ #region CTOR
+ public MultiNodeSyntax() { }
+ #endregion
+
+ internal bool isFolded;
+ bool _isExpanded;
+
+ internal List<SyntaxNode> children = new List<SyntaxNode> ();
+ public IEnumerable<SyntaxNode> Children => children;
+ public SyntaxNode AddChild (SyntaxNode child) {
+ children.Add (child);
+ child.Parent = this;
+ return child;
+ }
+ public void RemoveChild (SyntaxNode child) {
+ children.Remove (child);
+ child.Parent = null;
+ }
+ public IEnumerable<T> GetChilds<T> () => children.OfType<T>();
+
+ public bool ChildIs<T> (int idx) => children.Count() <= idx ? false : children[idx] is T;
+ public bool ChildSequenceIs(params object[] sequ) {
+ if (children.Count != sequ.Length)
+ return false;
+ for (int i = 0; i < sequ.Length; i++) {
+ if (typeof(Type).IsAssignableFrom(sequ[i].GetType())) {
+ if ((sequ[i] as Type) != children[i].GetType())
+ return false;
+ } else if (sequ[i].GetType().IsEnum) {
+ if (!(children[i] is SingleTokenSyntax tok) || (TokenType)sequ[i] != tok.Type)
+ return false;
+ } else
+ return false;
+ if (!children[i].IsComplete)
+ return false;
+
+ }
+ return true;
+ }
+
+ #region SyntaxNode implementation
+ public override bool isExpanded {
+ get => _isExpanded;
+ set {
+ bool expand = HasChilds ? value : false;
+ if (_isExpanded == expand)
+ return;
+ _isExpanded = value;
+ if (isExpanded && Parent is SyntaxNode sn) {
+ try {
+ sn.isExpanded = true;
+ } catch (Exception ex) {
+ Debug.WriteLine($"SyntaxNode expand to the top failed:{ex.Message}");
+ Debug.WriteLine(ex.StackTrace);
+ }
+
+ }
+ NotifyValueChanged (_isExpanded);
+ }
+ }
+ public override bool IsComplete {
+ get {
+ for (int i = 0; i < children.Count(); i++) {
+ if (!children[i].IsComplete)
+ return false;
+ }
+ return true;
+ }
+ }
+ public override bool HasChilds => children.Count > 0;
+ public override int SpanStart => HasChilds ? children[0].SpanStart : 0;
+ public override int SpanEnd => HasChilds ? children[children.Count - 1].SpanEnd : 0;
+ public override SyntaxNode FindNodeIncludingSpan (TextSpan span) {
+ foreach (SyntaxNode node in children) {
+ if (node.Contains (span))
+ return node.FindNodeIncludingSpan (span);
+ }
+ return this;
+ }
+ public override SyntaxNode FindNodeIncludingPosition (int pos) {
+ foreach (SyntaxNode node in children) {
+ if (node.Contains (pos))
+ return node.FindNodeIncludingPosition (pos);
+ }
+ return this;
+ }
+ #endregion
+
+ public virtual bool IsFoldable => IsComplete && !(Parent != Root && Parent.StartLocation.Line == StartLocation.Line) && LineCount > 1;
+ public virtual void UnfoldToTheTop () {
+ isFolded = false;
+ Parent.UnfoldToTheTop ();
+ }
+ public virtual int FoldedLineCount {
+ get {
+ if (isFolded)
+ return LineCount;
+ int tmp = 0;
+ if (HasChilds) {
+ foreach (MultiNodeSyntax n in children.OfType<MultiNodeSyntax>().Where (c => c.IsFoldable))
+ tmp += n.FoldedLineCount;
+ }
+ return tmp;
+ }
+ }
+
+ public void ExpandToTheTop () {
+ isExpanded = true;
+ Parent?.ExpandToTheTop ();
+ }
+ public IEnumerable<MultiNodeSyntax> VisibleFoldableNodes {
+ get {
+ if (IsFoldable) {
+ yield return this;
+ }
+ if (!isFolded) {
+ foreach (MultiNodeSyntax n in Children.OfType<MultiNodeSyntax>()) {
+ foreach (MultiNodeSyntax folds in n.VisibleFoldableNodes)
+ yield return folds;
+ }
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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)
+namespace CrowEditBase
+{
+ public class SingleTokenSyntax : SyntaxNode {
+ #region CTOR
+ public SingleTokenSyntax(Token tok) {
+ token = tok;
+ token.syntaxNode = this;
+ }
+ #endregion
+
+ protected 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
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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.Collections.Generic;
+using Crow.Text;
+
+namespace CrowEditBase
+{
+ public class UnexpectedTokenSyntax : SingleTokenSyntax {
+ public UnexpectedTokenSyntax(Token tok) : base (tok) { }
+ }
+ public class CommentTriviaSyntax : MultiNodeSyntax {
+ bool block;
+ public CommentTriviaSyntax(bool block) {
+ this.block = block;
+ }
+ public override bool IsComplete => true;
+
+ }
+
+ public abstract class SyntaxNode : CrowEditComponent {
+
+ public MultiNodeSyntax Parent { get; internal set; }
+
+ #region Folding and ?expand?
+ public virtual bool isExpanded {
+ get => false;
+ set {
+ if (value && Parent is SyntaxNode sn) {
+ sn.isExpanded = true;
+ }
+ }
+ }
+ #endregion
+
+ public virtual SyntaxRootNode Root => Parent.Root;
+ public virtual TokenType Type => TokenType.Unknown;
+ public virtual int SpanStart => 0;
+ public virtual int SpanEnd => 0;
+ public virtual bool HasChilds => false;
+ public virtual bool IsComplete => false;
+ public virtual SyntaxNode FindNodeIncludingPosition (int pos) => this;
+ public virtual SyntaxNode FindNodeIncludingSpan (TextSpan span) => this;
+ public virtual SyntaxNode NextSiblingOrParentsNextSibling
+ => NextSibling ?? Parent.NextSiblingOrParentsNextSibling;
+
+
+ public SyntaxNode NextSibling {
+ get {
+ if (Parent != null) {
+ int idx = Parent.children.IndexOf (this);
+ if (idx < Parent.children.Count - 1)
+ return Parent.children[idx + 1];
+ }
+ return null;
+ }
+ }
+ public SyntaxNode PreviousSibling {
+ get {
+ if (Parent != null) {
+ int idx = Parent.children.IndexOf (this);
+ if (idx > 0)
+ return Parent.children[idx - 1];
+ }
+ return null;
+ }
+ }
+
+ protected Token getTokenByIndex (int idx) => Root.GetTokenByIndex(idx);
+
+
+ public TextSpan Span => new TextSpan (SpanStart, SpanEnd);
+ public CharLocation StartLocation => Root.GetLocation(SpanStart);
+ public CharLocation EndLocation => Root.GetLocation(SpanEnd);
+ public int LineCount => EndLocation.Line - StartLocation.Line + 1;
+
+ public bool Contains (int pos) => Span.Contains (pos);
+ public bool Contains (TextSpan span) => Span.Contains (span);
+ public string AsText() {
+ return Span.Length < 0 ? "" : Root.GetText(Span).ToString();
+ }
+ public bool IsSimilar (SyntaxNode 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
--- /dev/null
+// 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 Crow.Text;
+
+namespace CrowEditBase
+{
+ public abstract class SyntaxRootNode : MultiNodeSyntax {
+ #region CTOR
+ public SyntaxRootNode (ReadOnlyTextBuffer buffer, Token[] tokens) {
+ this.buffer = buffer;
+ this.tokens = tokens;
+ }
+ #endregion
+
+ protected readonly ReadOnlyTextBuffer buffer;
+ protected Token[] tokens;
+ public ReadOnlySpan<Token> Tokens => tokens;
+
+ public override SyntaxRootNode Root => this;
+ public override bool IsFoldable => false;
+ public override void UnfoldToTheTop() {}
+ public override SyntaxNode NextSiblingOrParentsNextSibling => null;
+
+
+
+ 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 int FindTokenIndexIncludingPosition (int pos) {
+ if (pos == 0 || Tokens.Length == 0)
+ return default;
+ int idx = Tokens.BinarySearch(new Token (pos));
+ return idx == 0 ? 0 : idx < 0 ? ~idx - 1 : idx;
+ }
+ public ReadOnlySpan<char> GetText(TextSpan span) =>
+ buffer.Source.Span.Slice(span.Start, span.Length);
+ public CharLocation GetLocation(int pos) => buffer.Lines.GetLocation(pos);
+
+ public string GetTokenString(Token tok) =>
+ GetText(tok.Span).ToString();
+ }
+}
\ No newline at end of file
+++ /dev/null
-// 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 Crow.Text;
-
-namespace CrowEditBase
-{
- public abstract class SyntaxRootNode : MultiNodeSyntax {
- public SyntaxRootNode (ReadOnlyTextBuffer buffer, Token[] tokens) {
- this.buffer = buffer;
- this.tokens = tokens;
- }
- protected readonly ReadOnlyTextBuffer buffer;
- protected Token[] tokens;
- public override SyntaxRootNode Root => this;
-
-
- public override bool IsFoldable => false;
- public override void UnfoldToTheTop() {}
- public override SyntaxNode NextSiblingOrParentsNextSibling => null;
-
- 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 int FindTokenIndexIncludingPosition (int pos) {
- if (pos == 0 || Tokens.Length == 0)
- return default;
- int idx = Tokens.BinarySearch(new Token (pos));
- return idx == 0 ? 0 : idx < 0 ? ~idx - 1 : idx;
- }
- public ReadOnlySpan<char> GetText(TextSpan span) =>
- buffer.Source.Span.Slice(span.Start, span.Length);
- public CharLocation GetLocation(int pos) => buffer.Lines.GetLocation(pos);
-
- public string GetTokenString(Token tok) =>
- GetText(tok.Span).ToString();
- }
-}
\ No newline at end of file
namespace CrowEditBase
{
public abstract class Document : CrowEditComponent {
+ #region CTOR
public Document (string fullPath, string editorPath) {
initCommands ();
EditorPath = editorPath;
FullPath = fullPath;
}
+ #endregion
+
+ DateTime accessTime;
+ string fullPath;
+
/// <summary>
/// Editor used to open the document, can't be changed once opened
/// </summary>
public void EnterWriteLock () => documentRWLock.EnterWriteLock ();
public void ExitWriteLock () => documentRWLock.ExitWriteLock ();
- public abstract bool TryGetState<T> (object client, out T state);
- public abstract void RegisterClient (object client, bool initialState = false);
- public abstract void UnregisterClient (object client);
- DateTime accessTime;
- string fullPath;
public string FullPath {
get => fullPath;
public string Extension => System.IO.Path.GetExtension (FullPath);
public bool ExternalyModified => File.Exists (FullPath) ?
(DateTime.Compare (accessTime, System.IO.File.GetLastWriteTime (FullPath)) < 0) : false;
- public void OnQueryClose (object sender, EventArgs e){
- CloseEvent.Raise (this, null);
- }
- protected abstract void saveFileDialog_OkClicked (object sender, EventArgs e);
- public void SaveAs () {
- App.LoadIMLFragment (
- @"<FileDialog Width='60%' Height='50%' Caption='Save File' CurrentDirectory='{FileDirectory}'
- SelectedFile='{FileName}' OkClicked='saveFileDialog_OkClicked'/>"
- ).DataSource = this;
- }
- public void Save () {
- if (File.Exists (FullPath))
- writeToDisk ();
- else
- SaveAs ();
- }
+ #region commands
public Command CMDUndo, CMDRedo, CMDSave, CMDSaveAs;
-
Command CMDClose, CMDCloseOther;
public CommandGroup TabCommands => new CommandGroup (
CMDClose, CMDCloseOther
CMDClose = new ActionCommand ("Close", () => App.CloseDocument (this), "#icons.sign-out.svg");
CMDCloseOther = new ActionCommand ("Close Others", () => App.CloseOthers (this), "#icons.inbox.svg");
}
+ #endregion
+
+ public abstract bool TryGetState<T> (object client, out T state);
+ public abstract void RegisterClient (object client, bool initialState = false);
+ public abstract void UnregisterClient (object client);
+ protected abstract void saveFileDialog_OkClicked (object sender, EventArgs e);
protected abstract void undo();
protected abstract void redo();
protected abstract void writeToDisk ();
protected abstract void readFromDisk ();
protected abstract void initNewFile ();
+ public abstract bool IsDirty { get; }
+
protected virtual void reloadFromFile () {
documentRWLock.EnterWriteLock ();
try {
documentRWLock.ExitWriteLock ();
}
}
- public abstract bool IsDirty { get; }
+ public void OnQueryClose (object sender, EventArgs e){
+ CloseEvent.Raise (this, null);
+ }
+ public void SaveAs () {
+ App.LoadIMLFragment (
+ @"<FileDialog Width='60%' Height='50%' Caption='Save File' CurrentDirectory='{FileDirectory}'
+ SelectedFile='{FileName}' OkClicked='saveFileDialog_OkClicked'/>"
+ ).DataSource = this;
+ }
+ public void Save () {
+ if (File.Exists (FullPath))
+ writeToDisk ();
+ else
+ SaveAs ();
+ }
public override string ToString() => FullPath;
-// Copyright (c) 2021-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+// Copyright (c) 2021-2025 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
}
}
public class TextDocument : Document {
+ #region CTOR
public TextDocument (string fullPath, string editorPath = "default")
: base (fullPath, editorPath) {
reloadFromFile ();
}
+ #endregion
protected TextBuffer buffer;
- public ReadOnlySpan<char> source => buffer.ReadOnlySpan;
-
- public ReadOnlyTextBuffer ImmutableBufferCopy => new ReadOnlyTextBuffer(buffer.ReadOnlyCopy, buffer.GetLineListCopy());
+ protected Stack<TextChange> undoStack = new Stack<TextChange> ();
+ protected Stack<TextChange> redoStack = new Stack<TextChange> ();
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
+ Dictionary<object, List<TextChange>> registeredClients =
+ new Dictionary<object, List<TextChange>>(); // dictionnary of object per document client, when not null, client must reload content of document.
+ protected bool disableTextChangedEvent = false;
+
public event EventHandler<TextChangeEventArgs> TextChanged;
+ public ReadOnlySpan<char> source => buffer.ReadOnlySpan;
+ public ReadOnlyTextBuffer ImmutableBufferCopy => new ReadOnlyTextBuffer(buffer.ReadOnlyCopy, buffer.GetLineListCopy());
+
+ #region Document interface implementation
public override bool IsDirty => buffer.IsDirty;
- /// dictionnary of object per document client, when not null, client must reload content of document.
- Dictionary<object, List<TextChange>> registeredClients = new Dictionary<object, List<TextChange>>();
public override bool TryGetState<T>(object client, out T state) {
state = default;
if (documentRWLock.TryEnterReadLock (10)) {
registeredClients.Remove (client);
ExitWriteLock();
}
- protected void notifyClients (TextChange tc, object triggeringClient = null) {
- object[] clients = registeredClients.Keys.ToArray ();
- for (int i = 0; i < clients.Length; i++) {
- if (clients[i] != triggeringClient)
- notifyClient (clients[i], tc);
- }
- }
- protected void notifyClient (object client, TextChange tc) {
- if (registeredClients[client] == null)
- registeredClients[client] = new List<TextChange> ();
- registeredClients[client].Add (tc);
- }
-
- public virtual void SetLocation(CharLocation loc) {
- notifyClients(new TextChange(GetAbsolutePosition(loc),0));
- }
-
protected override void writeToDisk () {
using (Stream s = new FileStream(FullPath, FileMode.Create)) {
using (StreamWriter sw = new StreamWriter (s, encoding))
documentRWLock.ExitWriteLock ();
}
}
- protected Stack<TextChange> undoStack = new Stack<TextChange> ();
- protected Stack<TextChange> redoStack = new Stack<TextChange> ();
protected override void saveFileDialog_OkClicked (object sender, EventArgs e)
{
FileDialog fd = sender as FileDialog;
}
}
+ #endregion
+
protected void resetUndoRedo () {
undoStack.Clear ();
redoStack.Clear ();
CMDUndo.CanExecute = false;
CMDRedo.CanExecute = false;
}
- protected bool disableTextChangedEvent = false;
- protected virtual void apply (TextChange change) {
-
- buffer.Update(change);
-
- NotifyValueChanged ("IsDirty", IsDirty);
- CMDSave.CanExecute = IsDirty;
+ protected void notifyClients (TextChange tc, object triggeringClient = null) {
+ object[] clients = registeredClients.Keys.ToArray ();
+ for (int i = 0; i < clients.Length; i++) {
+ if (clients[i] != triggeringClient)
+ notifyClient (clients[i], tc);
+ }
+ }
+ protected void notifyClient (object client, TextChange tc) {
+ if (registeredClients[client] == null)
+ registeredClients[client] = new List<TextChange> ();
+ registeredClients[client].Add (tc);
}
protected void applyTextChange (TextChange change, object triggeringEditor = null) {
documentRWLock.EnterWriteLock ();
}
}
+ protected virtual void apply (TextChange change) {
+
+ buffer.Update(change);
+
+ NotifyValueChanged ("IsDirty", IsDirty);
+ CMDSave.CanExecute = IsDirty;
+ }
+ public virtual void SetLocation(CharLocation loc) {
+ notifyClients(new TextChange(GetAbsolutePosition(loc),0));
+ }
public virtual CharLocation GetWordStart (CharLocation loc) {
documentRWLock.EnterReadLock ();
try {
+++ /dev/null
-// 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.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Crow.Text;
-using CrowEditBase;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Text;
-
-namespace CERoslynPlugin
-{
- public class CSRootSyntax : SyntaxRootNode {
- public CSRootSyntax (ReadOnlyTextBuffer source) : base (source, null) { }
- internal void SetTokens(Token[] tokens) {
- this.tokens = tokens;
- }
- }
- public class CSToken : SingleTokenSyntax {
- SyntaxToken cstoken;
- public CSToken(SyntaxToken token, Token tok) : base (tok) {
- cstoken = token;
- }
- public override string ToString() => $"TOK: {cstoken.Kind()}";
- }
- public class CSTrivia : SingleTokenSyntax {
- SyntaxTrivia cstrivia;
- public CSTrivia(SyntaxTrivia token, Token tok) : base (tok) {
- cstrivia = token;
- }
- public override string ToString() => $"Trivia: {cstrivia.Kind()}";
- }
- public class CSSyntaxNode : MultiNodeSyntax {
- Microsoft.CodeAnalysis.SyntaxNode node;
- public CSSyntaxNode(Microsoft.CodeAnalysis.SyntaxNode node) {
- this.node = node;
- }
- public override string ToString() => $"{node.Kind()}";
-
- }
-
- public class CSSyntaxAnalyser : SyntaxAnalyser {
- /*protected override void Parse(SyntaxNode node)
- {
- throw new NotImplementedException();
- }*/
- CSDocument csdoc;
- public CSSyntaxAnalyser (CSDocument document) : base (document) {
- csdoc = document;
- }
-
- public override async Task<SyntaxRootNode> Process (CancellationToken cancel = default) {
- ReadOnlyTextBuffer buff = document.ImmutableBufferCopy;
- CsharpSyntaxWalkerBridge bridge = new CsharpSyntaxWalkerBridge(new CSRootSyntax (buff), cancel);
- CSharpSyntaxNode csroot = await csdoc.tree.GetRootAsync(cancel);
-
- if (cancel.IsCancellationRequested)
- return null;
-
- bridge.Visit(csroot);
- bridge.Root.SetTokens (bridge.Toks.ToArray());
- Root = bridge.Root;
- return Root;
- }
- }
- class CsharpSyntaxWalkerBridge : CSharpSyntaxWalker
- {
- public CSRootSyntax Root;
- public List<Token> Toks;
- MultiNodeSyntax currentNode;
- CancellationToken cancel;
- public CsharpSyntaxWalkerBridge (CSRootSyntax root, CancellationToken cancel = default) : base (SyntaxWalkerDepth.StructuredTrivia)
- {
- this.cancel = cancel;
- currentNode = Root = root;
- Toks = new List<Token>(100);
- }
- public override void Visit (Microsoft.CodeAnalysis.SyntaxNode node)
- {
- if (cancel.IsCancellationRequested)
- return;
- currentNode = currentNode.AddChild(new CSSyntaxNode(node)) as MultiNodeSyntax;
-
- base.Visit (node);
-
- currentNode = currentNode.Parent;
- }
-
- /*public override void VisitToken(SyntaxToken token)
- {
-
- base.VisitToken(token);
- }*/
-
- public override void VisitToken (SyntaxToken token)
- {
- if (cancel.IsCancellationRequested)
- return;
-
- VisitLeadingTrivia (token);
-
- Microsoft.CodeAnalysis.Text.TextSpan fs = token.Span;
- /*if (SyntaxFacts.IsLiteralExpression (token.Kind ()))
- addMultilineToken(token.ToString(), token.Span, (TokenType)token.RawKind);
- else*/
- if (fs.Length == 0)
- Debug.WriteLine($"Empty token: {token}");
- else {
- Microsoft.CodeAnalysis.Text.TextSpan span = token.Span;
- Token tok = new Token(fs.Start,fs.Length,(TokenType)token.RawKind);
- Toks.Add(tok);
- currentNode.AddChild(new CSToken(token, tok));
- }
-
- VisitTrailingTrivia (token);
- }
-
- public override void VisitTrivia (SyntaxTrivia trivia)
- {
- if (cancel.IsCancellationRequested)
- return;
-
- SyntaxKind kind = trivia.Kind ();
- Microsoft.CodeAnalysis.Text.TextSpan span = trivia.Span;
- if (kind == SyntaxKind.EndOfLineTrivia) {
- Toks.Add (new Token(span.Start, span.Length, TokenType.LineBreak));
- return;
- }
- if (trivia.HasStructure)
- this.Visit ((CSharpSyntaxNode)trivia.GetStructure());
- else if (trivia.IsKind (SyntaxKind.DisabledTextTrivia) || trivia.IsKind (SyntaxKind.MultiLineCommentTrivia))
- addMultilineToken(trivia.ToString(), trivia.Span, (TokenType)trivia.RawKind);
- else {
- Toks.Add (new Token(span.Start, span.Length, (TokenType)trivia.RawKind));
- }
- }
- int startOfTok;
- void addTok (ref SpanCharReader reader, int offset, Enum tokType) {
- if (reader.CurrentPosition == startOfTok)
- return;
- Token tok = new Token((TokenType)tokType,startOfTok + offset, reader.CurrentPosition + offset);
- Toks.Add (tok);
- currentNode.AddChild(new CSToken(default, tok));
-
- startOfTok = reader.CurrentPosition;
- }
- void addMultilineToken(ReadOnlySpan<char> txt, Microsoft.CodeAnalysis.Text.TextSpan span, TokenType mainType) {
- SpanCharReader reader = new SpanCharReader(txt);
- startOfTok = 0;
-
- while(!reader.EndOfSpan) {
- if (cancel.IsCancellationRequested)
- return;
- switch (reader.Peek) {
- case '\x85':
- case '\x2028':
- case '\xA':
- addTok (ref reader, span.Start, mainType);
- reader.Read();
- addTok (ref reader, span.Start, TokenType.LineBreak);
- break;
- case '\xD':
- addTok (ref reader, span.Start, mainType);
- reader.Read();
- if (reader.IsNextCharIn ('\xA', '\x85'))
- reader.Read();
- addTok (ref reader, span.Start, TokenType.LineBreak);
- break;
- case '\x20':
- case '\x9':
- addTok (ref reader, span.Start, mainType);
- char c = reader.Read();
- while (reader.TryPeek (c))
- reader.Read();
- addTok (ref reader, span.Start, c == '\x20' ? TokenType.WhiteSpace : TokenType.Tabulation);
- break;
- default:
- reader.Read();
- break;
- }
- }
- addTok (ref reader, span.Start, mainType);
- }
- }
-}
\ No newline at end of file
--- /dev/null
+// 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.Threading;
+using System.Threading.Tasks;
+using CrowEditBase;
+using Microsoft.CodeAnalysis.CSharp;
+
+namespace CERoslynPlugin
+{
+ public class CSSyntaxAnalyser : SyntaxAnalyser {
+ CSDocument csdoc;
+ public CSSyntaxAnalyser (CSDocument document) : base (document) {
+ csdoc = document;
+ }
+
+ public override async Task<SyntaxRootNode> Process (CancellationToken cancel = default) {
+ ReadOnlyTextBuffer buff = document.ImmutableBufferCopy;
+ CsharpSyntaxWalkerBridge bridge = new CsharpSyntaxWalkerBridge(new CSRootSyntax (buff), cancel);
+ CSharpSyntaxNode csroot = await csdoc.tree.GetRootAsync(cancel);
+
+ if (cancel.IsCancellationRequested)
+ return null;
+
+ bridge.Visit(csroot);
+ bridge.Root.SetTokens (bridge.Toks.ToArray());
+ Root = bridge.Root;
+ return Root;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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.Diagnostics;
+using System.Threading;
+using Crow.Text;
+using CrowEditBase;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+
+namespace CERoslynPlugin
+{
+ class CsharpSyntaxWalkerBridge : CSharpSyntaxWalker
+ {
+ #region CTOR
+ public CsharpSyntaxWalkerBridge (CSRootSyntax root, CancellationToken cancel = default) : base (SyntaxWalkerDepth.StructuredTrivia)
+ {
+ this.cancel = cancel;
+ currentNode = Root = root;
+ Toks = new List<Token>(100);
+ }
+ #endregion
+
+ public CSRootSyntax Root;
+ public List<Token> Toks;
+ MultiNodeSyntax currentNode;
+ int startOfTok;
+ CancellationToken cancel;
+
+ public override void Visit (Microsoft.CodeAnalysis.SyntaxNode node)
+ {
+ if (cancel.IsCancellationRequested)
+ return;
+ currentNode = currentNode.AddChild(new CSSyntaxNode(node)) as MultiNodeSyntax;
+
+ base.Visit (node);
+
+ currentNode = currentNode.Parent;
+ }
+ public override void VisitToken (SyntaxToken token)
+ {
+ if (cancel.IsCancellationRequested)
+ return;
+
+ VisitLeadingTrivia (token);
+
+ Microsoft.CodeAnalysis.Text.TextSpan fs = token.Span;
+ /*if (SyntaxFacts.IsLiteralExpression (token.Kind ()))
+ addMultilineToken(token.ToString(), token.Span, (TokenType)token.RawKind);
+ else*/
+ if (fs.Length == 0)
+ Debug.WriteLine($"Empty token: {token}");
+ else {
+ Microsoft.CodeAnalysis.Text.TextSpan span = token.Span;
+ Token tok = new Token(fs.Start,fs.Length,(TokenType)token.RawKind);
+ Toks.Add(tok);
+ currentNode.AddChild(new CSToken(token, tok));
+ }
+
+ VisitTrailingTrivia (token);
+ }
+ public override void VisitTrivia (SyntaxTrivia trivia)
+ {
+ if (cancel.IsCancellationRequested)
+ return;
+
+ SyntaxKind kind = trivia.Kind ();
+ Microsoft.CodeAnalysis.Text.TextSpan span = trivia.Span;
+ if (kind == SyntaxKind.EndOfLineTrivia) {
+ Toks.Add (new Token(span.Start, span.Length, TokenType.LineBreak));
+ return;
+ }
+ if (trivia.HasStructure)
+ this.Visit ((CSharpSyntaxNode)trivia.GetStructure());
+ else if (trivia.IsKind (SyntaxKind.DisabledTextTrivia) || trivia.IsKind (SyntaxKind.MultiLineCommentTrivia))
+ addMultilineToken(trivia.ToString(), trivia.Span, (TokenType)trivia.RawKind);
+ else {
+ Toks.Add (new Token(span.Start, span.Length, (TokenType)trivia.RawKind));
+ }
+ }
+
+ void addTok (ref SpanCharReader reader, int offset, Enum tokType) {
+ if (reader.CurrentPosition == startOfTok)
+ return;
+ Token tok = new Token((TokenType)tokType,startOfTok + offset, reader.CurrentPosition + offset);
+ Toks.Add (tok);
+ currentNode.AddChild(new CSToken(default, tok));
+
+ startOfTok = reader.CurrentPosition;
+ }
+ void addMultilineToken(ReadOnlySpan<char> txt, Microsoft.CodeAnalysis.Text.TextSpan span, TokenType mainType) {
+ SpanCharReader reader = new SpanCharReader(txt);
+ startOfTok = 0;
+
+ while(!reader.EndOfSpan) {
+ if (cancel.IsCancellationRequested)
+ return;
+ switch (reader.Peek) {
+ case '\x85':
+ case '\x2028':
+ case '\xA':
+ addTok (ref reader, span.Start, mainType);
+ reader.Read();
+ addTok (ref reader, span.Start, TokenType.LineBreak);
+ break;
+ case '\xD':
+ addTok (ref reader, span.Start, mainType);
+ reader.Read();
+ if (reader.IsNextCharIn ('\xA', '\x85'))
+ reader.Read();
+ addTok (ref reader, span.Start, TokenType.LineBreak);
+ break;
+ case '\x20':
+ case '\x9':
+ addTok (ref reader, span.Start, mainType);
+ char c = reader.Read();
+ while (reader.TryPeek (c))
+ reader.Read();
+ addTok (ref reader, span.Start, c == '\x20' ? TokenType.WhiteSpace : TokenType.Tabulation);
+ break;
+ default:
+ reader.Read();
+ break;
+ }
+ }
+ addTok (ref reader, span.Start, mainType);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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 CrowEditBase;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+
+namespace CERoslynPlugin
+{
+ public class CSRootSyntax : SyntaxRootNode {
+ public CSRootSyntax (ReadOnlyTextBuffer source) : base (source, null) { }
+ internal void SetTokens(Token[] tokens) {
+ this.tokens = tokens;
+ }
+ }
+ public class CSToken : SingleTokenSyntax {
+ SyntaxToken cstoken;
+ public CSToken(SyntaxToken token, Token tok) : base (tok) {
+ cstoken = token;
+ }
+ public override string ToString() => $"TOK: {cstoken.Kind()}";
+ }
+ public class CSTrivia : SingleTokenSyntax {
+ SyntaxTrivia cstrivia;
+ public CSTrivia(SyntaxTrivia token, Token tok) : base (tok) {
+ cstrivia = token;
+ }
+ public override string ToString() => $"Trivia: {cstrivia.Kind()}";
+ }
+ public class CSSyntaxNode : MultiNodeSyntax {
+ Microsoft.CodeAnalysis.SyntaxNode node;
+ public CSSyntaxNode(Microsoft.CodeAnalysis.SyntaxNode node) {
+ this.node = node;
+ }
+ public override string ToString() => $"{node.Kind()}";
+
+ }
+}
\ No newline at end of file
AddChild (new SingleTokenSyntax(name));
}
}
- /*public class AttributeNameSyntax : SingleTokenSyntax {
- public AttributeNameSyntax(Token name) : base(name) {}
- }*/
}
\ No newline at end of file