public Token[] Tokens => tokens;
public IEnumerable<SyntaxNode> SyntaxRootChildNodes => root?.children;
- public LineCollection Lines => lines;
public Token FindTokenIncludingPosition (int pos) {
if (pos == 0 || tokens == null || tokens.Length == 0)
return default;
/// <summary>
/// if outermost is true, return oldest ancestor exept root node, useful for folding.
/// </summary>
- public SyntaxNode FindNodeIncludingPosition (int pos, bool outerMost = false) {
+ /*public SyntaxNode FindNodeIncludingPosition (int pos, bool outerMost = false) {
if (root == null)
return null;
if (!root.Contains (pos))
if (!root.Contains (span))
return null;
return root.FindNodeIncludingSpan (span);
- }
+ }*/
+
protected override void reloadFromFile () {
base.reloadFromFile ();
parse ();
}
protected override void apply(TextChange change)
{
- SyntaxNode editedNode = FindNodeIncludingSpan (new TextSpan (change.Start, change.End));
+ SyntaxNode editedNode = root?.FindNodeIncludingSpan (new TextSpan (change.Start, change.End));
base.apply(change);
}
internal void updateCurrentTokAndNode (CharLocation loc) {
- int pos = lines.GetAbsolutePosition(loc);
+ int pos = buffer.GetAbsolutePosition(loc);
if (tokens.Length > 0) {
currentTokenIndex = FindTokenIndexIncludingPosition (pos);
- CurrentNode = FindNodeIncludingSpan (currentToken.Span);
+ CurrentNode = root?.FindNodeIncludingSpan (currentToken.Span);
NotifyValueChanged ("CurrentTokenString", (object)CurrentTokenString);
//NotifyValueChanged ("CurrentTokenType", (uint)(currentToken.Type)>>8);
NotifyValueChanged ("CurrentTokenType", (object)GetTokenTypeString(currentToken.Type));
-// 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;
namespace CrowEditBase
{
- public abstract class SyntaxRootNode : SyntaxNode {
- protected readonly SourceDocument source;
- public SyntaxRootNode (SourceDocument source) {
- this.source = source;
- }
- public override int TokenIndexBase => 0;
- public override int? TokenCount { get => Math.Max (0, source.Tokens.Length - 1); internal set {} }
- public override SyntaxRootNode Root => this;
- public override bool IsFoldable => false;
- public override SyntaxNode NextSiblingOrParentsNextSibling => null;
- public override void UnfoldToTheTop() {}
- public string GetTokenStringByIndex (int idx) =>
- idx >= 0 && idx < source.Tokens.Length ? Root.GetText(source.Tokens[idx].Span).ToString() : null;
- public Token GetTokenByIndex (int idx) =>
- idx >= 0 && idx < source.Tokens.Length ? source.Tokens[idx] : default;
- public ReadOnlySpan<char> GetText(TextSpan span) =>
- source.GetText(span);
- public string GetTokenString(Token tok) =>
- source.GetText(tok.Span).ToString();
- }
public class SyntaxNode : CrowEditComponent {
internal SyntaxNode () {}
public SyntaxNode (int startLine, int tokenBase, int? lastTokenIdx = null) {
if (lastTokenIdx.HasValue)
TokenCount = lastTokenIdx - tokenBase;
}
+
bool _isExpanded;
+
public bool isExpanded {
get => _isExpanded;
set {
--- /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 : SyntaxNode {
+ protected readonly SourceDocument source;
+ public SyntaxRootNode (SourceDocument source) {
+ this.source = source;
+ }
+ public override int TokenIndexBase => 0;
+ public override int? TokenCount { get => Math.Max (0, source.Tokens.Length - 1); internal set {} }
+ public override SyntaxRootNode Root => this;
+ public override bool IsFoldable => false;
+ public override SyntaxNode NextSiblingOrParentsNextSibling => null;
+ public override void UnfoldToTheTop() {}
+ public string GetTokenStringByIndex (int idx) =>
+ idx >= 0 && idx < source.Tokens.Length ? Root.GetText(source.Tokens[idx].Span).ToString() : null;
+ public Token GetTokenByIndex (int idx) =>
+ idx >= 0 && idx < source.Tokens.Length ? source.Tokens[idx] : default;
+ public ReadOnlySpan<char> GetText(TextSpan span) =>
+ source.GetText(span);
+ public string GetTokenString(Token tok) =>
+ source.GetText(tok.Span).ToString();
+ }
+}
\ No newline at end of file
}
//}
- if (document.Lenght > 0) {
+ if (document.Length > 0) {
Foreground?.SetAsSource (IFace, gr);
TextExtents extents;
break;
case Key.Delete:
if (selection.IsEmpty) {
- if (selection.Start == document.Lenght)
+ if (selection.Start == document.Length)
return;
if (CurrentLoc.Value.Column >= document.GetLine (CurrentLoc.Value.Line).Length)
update (new TextChange (selection.Start, document.GetLine (CurrentLoc.Value.Line).LineBreakLength, ""));
--- /dev/null
+// Copyright (c) 2021-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using Crow.Text;
+
+namespace CrowEditBase
+{
+ public class TextBuffer {
+ static int bufferExpension = 100;
+ int length;
+ Memory<char> buffer;
+ ReadOnlyMemory<char> origBuffer;
+ LineCollection lines;
+ public bool mixedLineBreak = false;
+ public string lineBreak = null;
+
+ public Span<char> Span => buffer.Span.Slice(0, length);
+ public ReadOnlySpan<char> ReadOnlySpan => buffer.Span.Slice(0, length);
+ public bool IsEmpty => length == 0;
+ public bool IsDirty => origBuffer.Span.Equals(buffer.Span, StringComparison.Ordinal);
+ public int LinesCount => lines.Count;
+ public int Length => length;
+ public ReadOnlyMemory<char> ReadOnlyCopy {
+ get {
+ return ReadOnlySpan.ToArray();
+ }
+ }
+ public void ResetDirtyState () {
+ origBuffer = buffer.ToArray();
+ }
+ public TextBuffer(ReadOnlySpan<char> origText) {
+ length = origText.Length;
+ buffer = new char[length + bufferExpension];
+ origText.CopyTo(buffer.Span);
+ lines = new LineCollection (10);
+ if (IsEmpty)
+ lines.Add (new TextLine (0, 0, 0));
+ else
+ lines.Update (Span);
+ }
+ public void Update (TextChange change) {
+ ReadOnlySpan<char> orig = buffer.Span;
+ char[] newBuff = null;
+ Span<char> tmp;
+ if (buffer.Length < length + change.CharDiff) {
+ newBuff = new char[length + change.CharDiff + bufferExpension];
+ tmp = newBuff;
+ orig.Slice(0, change.Start).CopyTo(tmp);
+ if (change.CharDiff == 0)
+ orig.Slice(change.End, length - change.End).CopyTo(tmp.Slice(change.End));
+ } else
+ tmp = buffer.Span;
+
+ if (change.CharDiff != 0)
+ orig.Slice(change.End, length - 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;
+ length += change.CharDiff;
+
+ lines.Update (change);
+ }
+ public string GetLineBreak () {
+ if (string.IsNullOrEmpty (lineBreak)) {
+ mixedLineBreak = false;
+
+ if (lines.Count == 0 || lines[0].LineBreakLength == 0)
+ lineBreak = Environment.NewLine;
+ else {
+ lineBreak = ReadOnlySpan.GetLineBreak (lines[0]).ToString ();
+ for (int i = 1; i < lines.Count; i++) {
+ if (!ReadOnlySpan.GetLineBreak (lines[i]).SequenceEqual (lineBreak)) {
+ mixedLineBreak = true;
+ break;
+ }
+ }
+ }
+ }
+ return lineBreak;
+ }
+ public CharLocation GetLocation (int absolutePosition) => lines.GetLocation (absolutePosition);
+ public TextLine GetLine (int index) => lines[index];
+ public int GetAbsolutePosition (CharLocation loc) => lines.GetAbsolutePosition (loc);
+ public CharLocation EndLocation => new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
+ public override string ToString() => ReadOnlySpan.ToString();
+ }
+}
\ No newline at end of file
using static CrowEditBase.CrowEditBase;
using System.Collections.Immutable;
using System.Reflection.Metadata;
+using System.Diagnostics;
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) {
}
protected TextBuffer buffer;
- public ReadOnlySpan<char> source => buffer.Span;
-
+ public ReadOnlySpan<char> source => buffer.ReadOnlySpan;
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
- protected bool mixedLineBreak = false;
- protected string lineBreak = null;
-
-
-
-
-// NotifyValueChanged ("IsDirty", IsDirty);
-// CMDSave.CanExecute = IsDirty;
-
- protected LineCollection lines;
public override bool IsDirty => buffer.IsDirty;
/// dictionnary of object per document client, when not null, client must reload content of document.
}
-
protected override void writeToDisk () {
using (Stream s = new FileStream(FullPath, FileMode.Create)) {
using (StreamWriter sw = new StreamWriter (s, encoding))
encoding = sr.CurrentEncoding;
}
}
+ ReadOnlyMemory<char> testbuff = buffer.ReadOnlyCopy;
+
+ buffer.Update(new TextChange(0,0,"test"));
+
+ Debug.WriteLine($"buffer: {buffer.ToString()}");
+ Debug.WriteLine($"testbuff: {testbuff.ToString()}");
}
protected override void initNewFile()
{
protected virtual void apply (TextChange change) {
buffer.Update(change);
- lines.Update (change);
NotifyValueChanged ("IsDirty", IsDirty);
CMDSave.CanExecute = IsDirty;
protected void onTextChanged (object sender, TextChangeEventArgs e) {
applyTextChange (e.Change, sender);
}
- protected void getLines () {
- documentRWLock.EnterWriteLock ();
- if (lines == null)
- lines = new LineCollection (10);
- else
- lines.Clear ();
- if (buffer.IsEmpty)
- lines.Add (new TextLine (0, 0, 0));
- else
- lines.Update (source);
- documentRWLock.ExitWriteLock ();
- }
public string GetLineBreak () {
documentRWLock.EnterReadLock ();
try {
- if (string.IsNullOrEmpty (lineBreak)) {
- mixedLineBreak = false;
-
- if (lines.Count == 0 || lines[0].LineBreakLength == 0)
- lineBreak = Environment.NewLine;
- else {
- lineBreak = source.GetLineBreak (lines[0]).ToString ();
-
- for (int i = 1; i < lines.Count; i++) {
- ReadOnlySpan<char> lb = source.GetLineBreak (lines[i]);
- if (!lb.SequenceEqual (lineBreak)) {
- mixedLineBreak = true;
- break;
- }
- }
- }
- }
- return lineBreak;
+ return buffer.GetLineBreak();
} finally {
documentRWLock.ExitReadLock();
}
public CharLocation GetLocation (int absolutePosition) {
documentRWLock.EnterReadLock ();
try {
- return lines.GetLocation (absolutePosition);
+ return buffer.GetLocation (absolutePosition);
} finally {
documentRWLock.ExitReadLock();
}
public int GetAbsolutePosition (CharLocation loc) {
documentRWLock.EnterReadLock ();
try {
- return lines.GetAbsolutePosition (loc);
+ return buffer.GetAbsolutePosition (loc);
} finally {
documentRWLock.ExitReadLock();
}
get {
documentRWLock.EnterReadLock ();
try {
- return new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
+ return buffer.EndLocation;
} finally {
documentRWLock.ExitReadLock();
}
}
public int LinesCount {
get {
- if (lines == null)
- getLines();
documentRWLock.EnterReadLock ();
try {
- return lines.Count;
+ return buffer.LinesCount;
} finally {
documentRWLock.ExitReadLock();
}
}
}
- public int Lenght {
+ public int Length {
get {
documentRWLock.EnterReadLock ();
try {
- return source.Length;
+ return buffer.Length;
} finally {
documentRWLock.ExitReadLock();
}
public TextLine GetLine (int index) {
documentRWLock.EnterReadLock ();
try {
- return lines[index];
+ return buffer.GetLine(index);
} finally {
documentRWLock.ExitReadLock();
}
public virtual CharLocation GetWordStart (CharLocation loc) {
documentRWLock.EnterReadLock ();
try {
- int pos = lines.GetAbsolutePosition (loc);
+ int pos = buffer.GetAbsolutePosition (loc);
//skip white spaces
while (pos > 0 && !char.IsLetterOrDigit (source[pos-1]))
pos--;
while (pos > 0 && char.IsLetterOrDigit (source[pos-1]))
pos--;
- return lines.GetLocation (pos);
+ return buffer.GetLocation (pos);
} finally {
documentRWLock.ExitReadLock();
}
public virtual CharLocation GetWordEnd (CharLocation loc) {
documentRWLock.EnterReadLock ();
try {
- int pos = lines.GetAbsolutePosition (loc);
+ int pos = buffer.GetAbsolutePosition (loc);
//skip white spaces
- while (pos < Lenght - 1 && !char.IsLetterOrDigit (source[pos]))
+ while (pos < Length - 1 && !char.IsLetterOrDigit (source[pos]))
pos++;
- while (pos < Lenght - 1 && char.IsLetterOrDigit (source[pos]))
+ while (pos < Length - 1 && char.IsLetterOrDigit (source[pos]))
pos++;
- return lines.GetLocation (pos);
+ return buffer.GetLocation (pos);
} finally {
documentRWLock.ExitReadLock();
}