CrowDesignAssembly/
netcoredbg/
+testfiles/
#Autosave files
*~
SyntaxNode changedNode = RootNode.FindNodeIncludingSpan (TextSpan.FromStartAndLength (change.Start, change.ChangedText.Length));
- tokens = tokenizer.Tokenize (Source);
-
+ tokens = tokenizer.Tokenize (buffer.Span);
syntaxAnalyser.Process ();
protected bool previousTokHasFlag(TokenType flag) => previousToken.HasValue && previousToken.Value.Type.HasFlag(flag);
void parse () {
Tokenizer tokenizer = CreateTokenizer ();
- tokens = tokenizer?.Tokenize (Source);
+ tokens = tokenizer?.Tokenize (source);
SyntaxAnalyser syntaxAnalyser = CreateSyntaxAnalyser ();
Stopwatch sw = Stopwatch.StartNew ();
syntaxAnalyser?.Process ();
public override SyntaxNode NextSiblingOrParentsNextSibling => null;
public override void UnfoldToTheTop() {}
public string GetTokenStringByIndex (int idx) =>
- idx >= 0 && idx < source.Tokens.Length ? source.Tokens[idx].AsString (source.Source) : null;
+ idx >= 0 && idx < source.Tokens.Length ? Root.GetText(source.Tokens[idx].Span).ToString() : null;
public Token GetTokenByIndex (int idx) =>
idx >= 0 && idx < source.Tokens.Length ? source.Tokens[idx] : default;
public ReadOnlySpan<char> GetText(TextSpan span) =>
source.GetText(span);
+ public string GetTokenString(Token tok) =>
+ source.GetText(tok.Span).ToString();
}
public class SyntaxNode : CrowEditComponent {
internal SyntaxNode () {}
protected int startOfTok;
public Tokenizer () {}
- public abstract Token[] Tokenize (string source);
+ public abstract Token[] Tokenize (ReadOnlySpan<char> source);
/// <summary>
/// First method to call in tokenizers to init parsing variables
/// </summary>
/// <returns></returns>
- protected virtual SpanCharReader initParsing (string source) {
+ protected virtual SpanCharReader initParsing (ReadOnlySpan<char> source) {
startOfTok = 0;
Toks = new List<Token>(100);
return new SpanCharReader(source);
using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
gr.SetFontSize (Font.Size);
- updateLocation (gr, ClientRectangle.Width, ref hoverLoc);
+ updateLocation (gr, ref hoverLoc);
}
#if DEBUG_NODES
if (Document is SourceDocument doc) {
Foreground.SetAsSource (IFace, gr);
gr.Translate (-ScrollX, -ScrollY);
- ReadOnlySpan<char> sourceBytes = doc.Source.AsSpan();
+ ReadOnlySpan<char> sourceBytes = doc.source;
Span<byte> bytes = stackalloc byte[128];
TextExtents extents;
int tokPtr = 0;
using Crow;
using Crow.Text;
using static CrowEditBase.CrowEditBase;
+using System.Collections.Immutable;
+using System.Reflection.Metadata;
namespace CrowEditBase
{
+ public class TextBuffer {
+ static int bufferExpension = 100;
+ int lenght;
+ Memory<char> buffer;
+ ReadOnlyMemory<char> origBuffer;
+ public Span<char> Span => buffer.Span.Slice(0, lenght);
+ public bool IsEmpty => lenght == 0;
+ public bool IsDirty => origBuffer.Span.Equals(buffer.Span, StringComparison.Ordinal);
+ public void ResetDirtyState () {
+ origBuffer = buffer.ToArray();
+ }
+ public TextBuffer(ReadOnlySpan<char> origText) {
+ lenght = origText.Length;
+ buffer = new char[lenght + bufferExpension];
+ origText.CopyTo(buffer.Span);
+ }
+ public void Update (TextChange change) {
+ ReadOnlySpan<char> orig = buffer.Span;
+ char[] newBuff = null;
+ Span<char> tmp;
+ if (buffer.Length < lenght + change.CharDiff) {
+ newBuff = new char[lenght + change.CharDiff + bufferExpension];
+ tmp = newBuff;
+ orig.Slice(0, change.Start).CopyTo(tmp);
+ if (change.CharDiff == 0)
+ orig.Slice(change.End, lenght - change.End).CopyTo(tmp.Slice(change.End));
+ } else
+ tmp = buffer.Span;
+
+ if (change.CharDiff != 0)
+ orig.Slice(change.End, lenght - change.End).CopyTo(tmp.Slice(change.End2));
+ if (!string.IsNullOrEmpty (change.ChangedText))
+ change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
+
+ if (newBuff != null)
+ buffer = newBuff;
+ lenght += change.CharDiff;
+ }
+ }
public class TextDocument : Document {
public TextDocument (string fullPath, string editorPath = "default")
: base (fullPath, editorPath) {
reloadFromFile ();
}
- string source, origSource;
+ protected TextBuffer buffer;
+ public ReadOnlySpan<char> source => buffer.Span;
+
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
protected bool mixedLineBreak = false;
protected string lineBreak = null;
- public string Source {
- get => source;
- set {
- if (source == value)
- return;
- source = value;
- getLines();
+
+
+// NotifyValueChanged ("IsDirty", IsDirty);
+// CMDSave.CanExecute = IsDirty;
- NotifyValueChanged (source);
- NotifyValueChanged ("IsDirty", IsDirty);
- CMDSave.CanExecute = IsDirty;
- }
- }
protected LineCollection lines;
- public override bool IsDirty => origSource != source;
+ 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) {
protected override void writeToDisk () {
using (Stream s = new FileStream(FullPath, FileMode.Create)) {
using (StreamWriter sw = new StreamWriter (s, encoding))
- sw.Write (source);
+ sw.Write (buffer.Span);
}
- origSource = source;
+ buffer.ResetDirtyState();
NotifyValueChanged ("IsDirty", IsDirty);
CMDSave.CanExecute = IsDirty;
}
{
using (Stream s = new FileStream (FullPath, FileMode.Open)) {
using (StreamReader sr = new StreamReader (s)) {
- Source = origSource = sr.ReadToEnd ();
+ buffer = new TextBuffer(sr.ReadToEnd ());
encoding = sr.CurrentEncoding;
}
}
}
protected override void initNewFile()
{
- Source = origSource = "";
+ buffer = new TextBuffer("");
}
protected override void reloadFromFile () {
editorRWLock.EnterWriteLock ();
protected bool disableTextChangedEvent = false;
protected virtual void apply (TextChange change) {
- Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)];
- ReadOnlySpan<char> src = source.AsSpan ();
- src.Slice (0, change.Start).CopyTo (tmp);
- if (!string.IsNullOrEmpty (change.ChangedText))
- change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
- src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
- source = tmp.ToString ();
-
+ buffer.Update(change);
lines.Update (change);
NotifyValueChanged ("IsDirty", IsDirty);
else
lines.Clear ();
- if (string.IsNullOrEmpty (source))
+ if (buffer.IsEmpty)
lines.Add (new TextLine (0, 0, 0));
else
lines.Update (source);
}
public int LinesCount {
get {
+ if (lines == null)
+ getLines();
editorRWLock.EnterReadLock ();
try {
return lines.Count;
public ReadOnlySpan<char> GetText (TextSpan span) {
editorRWLock.EnterReadLock ();
try {
- return source.AsSpan (span.Start, span.Length);
+ return source.Slice (span.Start, span.Length);
} finally {
editorRWLock.ExitReadLock();
}
<?xml version="1.0"?>
<ListItem IsVisible="{IsSelected}" IsSelected="{²IsSelected}" Selected="{/tb.HasFocus='true'}">
<VerticalStack Spacing="0">
- <HorizontalStack Spacing="0" Background="White">
- <SourceEditor Name="tb" Font="mono, 14" Margin='0' CurrentNode="{CurrentNode}"
- Document="{}" TextChanged="onTextChanged" />
- <ScrollBar Value="{²../tb.ScrollY}"
- LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
- CursorRatio="{../tb.ChildHeightRatio}" Maximum="{../tb.MaxScrollY}" />
- </HorizontalStack>
- <ScrollBar Style="HScrollBar" Value="{²../tb.ScrollX}"
- LargeIncrement="{../tb.PageWidth}" SmallIncrement="1"
- CursorRatio="{../tb.ChildWidthRatio}" Maximum="{../tb.MaxScrollX}" />
+ <HorizontalStack Spacing="0" Background="White">
+ <SourceEditor Name="tb" Font="mono, 14" Margin='0' CurrentNode="{CurrentNode}"
+ Document="{}" TextChanged="onTextChanged" />
+ <ScrollBar Value="{²../tb.ScrollY}"
+ LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
+ CursorRatio="{../tb.ChildHeightRatio}" Maximum="{../tb.MaxScrollY}" />
+ </HorizontalStack>
+ <ScrollBar Style="HScrollBar" Value="{²../tb.ScrollX}"
+ LargeIncrement="{../tb.PageWidth}" SmallIncrement="1"
+ CursorRatio="{../tb.ChildWidthRatio}" Maximum="{../tb.MaxScrollX}" />
+ <HorizontalStack Height="Fit" Spacing='3'>
+ <Widget Width="Stretched"/>
+ <Label Text="TokType" Foreground="Grey"/>
+ <Label Text="{CurrentTokenType}" Margin="3"/>
+ <Label Text="Tok" Foreground="Grey"/>
+ <Label Text="{CurrentTokenString}" Margin="3"/>
+ <Label Text="Node" Foreground="Grey"/>
+ <Label Text="{CurrentNode}" Margin="3"/>
+ <Label Text="MouseY:" Foreground="Grey"/>
+ <Label Text="{../../tb.MouseY}" Margin="3"/>
+ <Label Text="VisibleLines:" Foreground="Grey"/>
+ <Label Text="{../../tb.VisibleLines}" Margin="3"/>
+ <Label Text="ScrollX:" Foreground="Grey"/>
+ <Label Text="{../../tb.ScrollX}" Margin="3"/>
+ <Label Text="ScrollY:" Foreground="Grey"/>
+ <Label Text="{../../tb.ScrollY}" Margin="3"/>
+ <Label Text="ScrollLine:" Foreground="Grey"/>
+ <Label Text="{../../tb.ScrollLine}" Margin="3"/>
+ <Label Text="HoverLine:" Foreground="Grey"/>
+ <Label Text="{../../tb.HoverLine}" Margin="3"/>
+ <Label Text="Line:" Foreground="Grey"/>
+ <Label Text="{../../tb.CurrentLine}" Margin="3"/>
+ <Label Text="Col:" Foreground="Grey"/>
+ <Label Text="{../../tb.TabulatedColumn}" Margin="3"/>
+ </HorizontalStack>
<Splitter/>
- <ListBox Data='{Exceptions}' Height='10%' Width='Stretched'/>
- <HorizontalStack Height="Fit" Spacing='3'>
- <Widget Width="Stretched"/>
- <Label Text="TokType" Foreground="Grey"/>
- <Label Text="{CurrentTokenType}" Margin="3"/>
- <Label Text="Tok" Foreground="Grey"/>
- <Label Text="{CurrentTokenString}" Margin="3"/>
- <Label Text="Node" Foreground="Grey"/>
- <Label Text="{CurrentNode}" Margin="3"/>
- <Label Text="MouseY:" Foreground="Grey"/>
- <Label Text="{../../tb.MouseY}" Margin="3"/>
- <Label Text="VisibleLines:" Foreground="Grey"/>
- <Label Text="{../../tb.VisibleLines}" Margin="3"/>
- <Label Text="ScrollX:" Foreground="Grey"/>
- <Label Text="{../../tb.ScrollX}" Margin="3"/>
- <Label Text="ScrollY:" Foreground="Grey"/>
- <Label Text="{../../tb.ScrollY}" Margin="3"/>
- <Label Text="ScrollLine:" Foreground="Grey"/>
- <Label Text="{../../tb.ScrollLine}" Margin="3"/>
- <Label Text="HoverLine:" Foreground="Grey"/>
- <Label Text="{../../tb.HoverLine}" Margin="3"/>
- <Label Text="Line:" Foreground="Grey"/>
- <Label Text="{../../tb.CurrentLine}" Margin="3"/>
- <Label Text="Col:" Foreground="Grey"/>
- <Label Text="{../../tb.TabulatedColumn}" Margin="3"/>
- </HorizontalStack>
+ <ListBox Data='{Exceptions}' Height='100' Width='Stretched'/>
</VerticalStack>
</ListItem>
if (tok.GetTokenType() == XmlTokenType.ElementOpen)
return new List<string> (allWidgetNames);
if (tok.GetTokenType() == XmlTokenType.ElementName)
- return allWidgetNames.Where (s => s.StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ return allWidgetNames.Where (s => s.StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
if ((tok.Type.HasFlag(TokenType.WhiteSpace) || previousTokHasFlag(TokenType.WhiteSpace)) &&
tryCast(CurrentNode, out ElementTagSyntax ets)) {
if (ets.name.HasValue)
if (!string.IsNullOrEmpty (eltTag.Name)) {
if (tok.GetTokenType() == XmlTokenType.AttributeName) {
return getAllCrowTypeMembers (eltTag.Name)
- .Where (s => s.Name.StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ .Where (s => s.Name.StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
} else if (!string.IsNullOrEmpty (attribNode.Name)) {
if (tok.GetTokenType() == XmlTokenType.AttributeValue) {
MemberInfo mi = getCrowTypeMember (
if (mi is PropertyInfo pi) {
if (pi.Name == "Style")
return App.Styling.Keys
- .Where (s => s.StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ .Where (s => s.StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
if (pi.PropertyType.IsEnum)
return Enum.GetNames (pi.PropertyType)
- .Where (s => s.StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ .Where (s => s.StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
if (pi.PropertyType == typeof(bool))
return (new string[] {"true", "false"}).
- Where (s => s.StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ Where (s => s.StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
if (pi.PropertyType == typeof (Measure))
return (new string[] {"Stretched", "Fit"}).
- Where (s => s.StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ Where (s => s.StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
if (pi.PropertyType == typeof (Fill))
return EnumsNET.Enums.GetValues<Colors> ()
- .Where (s => s.ToString().StartsWith (tok.AsString (Source), StringComparison.OrdinalIgnoreCase)).ToList ();
+ .Where (s => s.ToString().StartsWith (RootNode.Root.GetTokenString(tok), StringComparison.OrdinalIgnoreCase)).ToList ();
}
} else if (tok.GetTokenType() == XmlTokenType.AttributeValueOpen) {
MemberInfo mi = getCrowTypeMember (
return false;
}
- public override Token[] Tokenize (string source) {
+ public override Token[] Tokenize (ReadOnlySpan<char> source) {
SpanCharReader reader = initParsing (source);
curState = States.classNames;
public static bool IsValidHexDigit (char c) =>
char.IsDigit (c) || (c > 64 && c < 71) || (c > 96 && c < 103);
- public override Token[] Tokenize (string source) {
+ public override Token[] Tokenize (ReadOnlySpan<char> source) {
SpanCharReader reader = new SpanCharReader(source);
startOfTok = 0;
CSharpSyntaxTree tree;
public CSDocument (string fullPath, string editorPath) : base (fullPath, editorPath) {
- tree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText (Source, CSharpParseOptions.Default);
+ tree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText (source.ToString(), CSharpParseOptions.Default);
var root = tree.GetRoot();
/*foreach (SyntaxKind v in Enum.GetValues<SyntaxKind>().OrderBy(k=>(uint)k)) {
Console.WriteLine($"{v,50} {(((uint)v) ).ToString("B16") } {(((uint)v) ).ToString("X4") }");
}
}
- public override Token[] Tokenize(string source)
+ public override Token[] Tokenize(ReadOnlySpan<char> source)
{
- var tree = CSharpSyntaxTree.ParseText(source);
+ var tree = CSharpSyntaxTree.ParseText(source.ToString());
CsharpSyntaxWalkerBridge bridge = new CsharpSyntaxWalkerBridge();
bridge.Visit(tree.GetRoot());
//SpanCharReader reader = new SpanCharReader(source);
CurrentNode is ElementEndTagSyntax eltEndTag && !eltEndTag.IsComplete) {
ElementSyntax es = eltEndTag.Parent as ElementSyntax;
if (es?.StartTag.name != null)
- return new List<string> (new string[] {tokens[es.StartTag.name.Value].AsString(Source)});
+ return new List<string> (new string[] {es.StartTag.Name});
}
return null;
}
} else {
int offset = 1;
if (!attrib.valueClose.HasValue) {
- selectedSugg += tokens[attrib.valueClose.Value].AsString(Source);
+ selectedSugg += RootNode.Root.GetTokenStringByIndex(attrib.valueClose.Value);
offset = 0;
}
if (tokType == XmlTokenType.AttributeValueOpen)
reader.Read ();
}
}
- public override Token[] Tokenize (string source) {
+ public override Token[] Tokenize (ReadOnlySpan<char> source) {
SpanCharReader reader = initParsing (source);
int curObjectLevel = 0;