blob: 290fb757384f47b83813351b31e2d2d261d6a0b5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// 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)
using System;
using System.Linq;
using System.Collections.Generic;
using Crow.Text;
using Crow;
namespace Crow.Text
{
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 LineCollection GetLineListCopy() => new LineCollection(lines.ToArray());
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(Span, StringComparison.Ordinal);
public int LinesCount => lines.Count;
public int Length => length;
public ReadOnlyMemory<char> ReadOnlyCopy {
get {
return ReadOnlySpan.ToArray();
}
}
public void ResetDirtyState () {
origBuffer = Span.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);
ResetDirtyState ();
}
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 void SetLine (int index, TextLine line) => lines[index] = line;
public ReadOnlySpan<char> GetText (TextLine line) => GetText(line.Span);
public ReadOnlySpan<char> GetText (TextSpan textSpan) => buffer.Span.Slice(textSpan.Start, textSpan.Length);
public int GetAbsolutePosition (CharLocation loc) => lines.GetAbsolutePosition (loc);
public CharLocation EndLocation => new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
public virtual CharLocation GetWordStart (CharLocation loc) {
int pos = GetAbsolutePosition (loc);
//skip white spaces
ReadOnlySpan<char> txt = ReadOnlySpan;
while (pos > 0 && !char.IsLetterOrDigit (txt[pos-1]))
pos--;
while (pos > 0 && char.IsLetterOrDigit (txt[pos-1]))
pos--;
return GetLocation (pos);
}
public virtual CharLocation GetWordEnd (CharLocation loc) {
int pos = GetAbsolutePosition (loc);
//skip white spaces
ReadOnlySpan<char> txt = ReadOnlySpan;
while (pos < Length - 1 && !char.IsLetterOrDigit (txt[pos]))
pos++;
while (pos < Length - 1 && char.IsLetterOrDigit (txt[pos]))
pos++;
return GetLocation (pos);
}
public override string ToString() => ReadOnlySpan.ToString();
}
}
|