public enum Flags
{
None = 0x00,
- /// A text inserted before a character that has this property
- /// inherits this property. If the text already has properties
- /// of the same key, they are deleted.
- FrontSticky = 0x01,
- /// A text inserted after a character that has this property
- /// inherits this property. If the text already has properties
- /// of the same key, they are deleted.
- RearSticky = 0x02,
+
+ /// On inserting a text in between two characters, if the
+ /// preceding and following characters have Sticky properties of
+ /// the same key with same values, the inserted text inherits
+ /// those properties. In that case, properties of the inserted
+ /// text are overriden.
+ Sticky = 0x01, // 00000001
+
+ /// On inserting a text before a character, if the character has
+ /// FrontSticky properties, the inserted text inherits those
+ /// properties.
+ FrontSticky = 0x03, // 00000011
+
+ /// On inserting a text after a character, if the character has
+ /// RearSticky properties, the inserted text inherits those
+ /// properties.
+ RearSticky = 0x05, // 00000101
+
+ /// Like RearSticky, but if the inserted text inherits no
+ /// properties from the preceding character, it inherits
+ /// BothSticky properties from the following character if any.
+ BothSticky = 0x07, // 00000111
+
/// This property is deleted from a span of text if the span is
- /// modified (i.e. a character is changed, a text is inserted,
- /// some part is deleted). This propery is also deleted if a
- /// property of the same key is added, which means that this
- /// property is not stackable.
- Sensitive = 0x04,
+ /// modified (i.e. one of a character is changed, a text is
+ /// inserted, some part is deleted). Here, "span" means a
+ /// sequence of characters that has this property with the same
+ /// value. This property is also deleted if a property of the
+ /// same key is added, which means that this property is not
+ /// stackable. In addition this property is never merged with
+ /// the same value of preceding or following property. At last,
+ /// this property can't be sticky in any way.
+ Sensitive = 0x10, // 00010000
+
/// Like Sensitive but also this property is deleted from a span
- /// of text if a text just before the span is modified,
+ /// of text if a characeter just before the span is modified,
/// inserted, or deleted.
- FrontSensitive = 0x08,
+ FrontSensitive = 0x30, // 00110000
+
/// Like Sensitive but also this property is deleted from a span
- /// of text if a text just after the span is modified, inserted,
- /// or deleted.
- RearSensitive = 0x10
+ /// of text if a character just after the span is modified,
+ /// inserted, or deleted.
+ RearSensitive = 0x50, // 01010000
+
+ /// Same as (FrontSensitive | RearSensitive).
+ BothSensitive = 0x70, // 01110000
};
internal MSymbol key;
public static bool HasFlags (MSymbol key, Flags flags)
{
- return ((key.flags & flags) != Flags.None);
+ return ((key.flags & flags) == flags);
}
public override string ToString ()
int len = str.Length, n = 0;
for (int i = 0; i < len; i++, n++)
- if (surrogate_high_p (str[i]))
+ if (Char.IsHighSurrogate (str[i]))
i++;
return n;
}
int len = str.Length, n = 0;
for (int i = 0; i < len; i++, n++)
- if (surrogate_high_p (str[i]))
+ if (Char.IsHighSurrogate (str[i]))
i++;
return n;
}
intervals = new MPlist ();
}
+ public MText (byte[] str, int offset, int length)
+ {
+ sb = new StringBuilder (utf8.GetString (str, offset, length));
+ nchars = count_chars (sb);
+ intervals = new MPlist ();
+ }
+
public MText (String str)
{
sb = new StringBuilder (str);
intervals = new MPlist ();
}
+ public MText (int c, int len) : this ()
+ {
+ while (len-- > 0)
+ this.Cat (c);
+ }
+
+ public MText (int c) : this (c, 1) { }
+
public static MText operator+ (object obj, MText mt)
{
if (obj is string)
public override string ToString () { return sb.ToString (); }
- private static bool surrogate_high_p (char c)
+ public static implicit operator MText (string str)
{
- return (c >= 0xD800 && c < 0xDC00);
+ return new MText (str);
}
- private static bool surrogate_low_p (char c)
+ public static explicit operator string (MText mt)
{
- return (c >= 0xDC00 && c < 0xE000);
+ return mt.ToString ();
}
private static int inc_idx (StringBuilder sb, int i)
{
- return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
+ return (i + (Char.IsHighSurrogate (sb[i]) ? 2 : 1));
}
private static int dec_idx (StringBuilder sb, int i)
{
- return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
+ return (i - (Char.IsLowSurrogate (sb[i - 1]) ? 2 : 1));
}
private static int pos_to_idx (MText mt, int pos)
if (pos < mt.cache_pos)
{
if (mt.cache_pos == mt.cache_idx)
- return mt.cache_idx;
+ return pos;
if (pos < mt.cache_pos - pos)
{
p = i = 0;
i = pos_to_idx (this, i);
if (value < 0x10000)
{
- if (surrogate_high_p (sb[i]))
+ if (Char.IsHighSurrogate (sb[i]))
sb.Remove (i, 1);
sb[i] = (char) value;
}
char high = (char) (0xD800 + ((value - 0x10000) >> 10));
char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
- if (! surrogate_high_p (sb[i]))
+ if (! Char.IsHighSurrogate (sb[i]))
sb.Insert (i, 0);
sb[i] = high;
sb[i + 1] = low;
}
+ PopProp (i, i + 1);
}
get {
i = pos_to_idx (this, i);
- return (surrogate_high_p (sb[i])
+ return (Char.IsHighSurrogate (sb[i])
? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
: sb[i]);
}
}
+ public MText this[int from, int to]
+ {
+ set {
+ if (from < to)
+ Del (from, to);
+ if (value != null)
+ Ins (from, value);
+ }
+ get { return Dup (from, to); }
+ }
+
public MText Dup ()
{
MText mt = new MText (sb.ToString ());
return this;
}
+ public MText Cat (MText mt)
+ {
+ insert (nchars, mt, 0, mt.Length);
+ return this;
+ }
+
+ public MText Cat (MText mt, int from, int to)
+ {
+ insert (nchars, mt, from, to);
+ return this;
+ }
+
+ public MText Del ()
+ {
+ return Del (0, Length);
+ }
+
public MText Del (int from, int to)
{
if (check_range (from, to, true))
return this;
-
sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
nchars -= to - from;
-
if (nchars > 0)
foreach (MPlist plist in intervals)
{
intervals.Push (prop.key, root);
}
else
- root = (MInterval) p.Val;
-
- if (root.isSensitive)
- root.PopSensitive (from, to);
+ {
+ root = (MInterval) p.Val;
+ if (root.isSensitive)
+ {
+ root.PopSensitive (from, to);
+ root.MergeAfterChange (from, to);
+ root = (MInterval) p.Val;
+ if (M17n.debug)
+ DumpPropNested ();
+ }
+ }
root.Push (from, to, prop);
root.MergeAfterChange (from, to);
root.Balance ();
}
}
+ public void PopProp (int from, int to)
+ {
+ if (from < 0)
+ {
+ default_property = null;
+ }
+ else
+ {
+ if (check_range (from, to, true))
+ return;
+ for (MPlist p = intervals; ! p.IsEmpty; p = p.next)
+ {
+ MInterval root = (MInterval) p.Val;
+ root.PopAll (from, to);
+ root = (MInterval) p.Val;
+ if (M17n.debug)
+ DumpPropNested ();
+ root.MergeAfterChange (from, to);
+ root.Balance ();
+ }
+ }
+ }
+
public void PopProp (int from, int to, MSymbol key)
{
if (from < 0)
}
}
+ public object FindProp (MSymbol key, int pos, out int from, out int to)
+ {
+ from = 0;
+ to = Length;
+ check_pos (pos, false);
+
+ MInterval i = (MInterval) intervals.Get (key);
+ if (i != null
+ && (i = i.Find (pos, out from, out to)) != null)
+ return GetProp (from, key);
+ return null;
+ }
+
public void DumpProp ()
{
Console.Write ("(");
MProperty.Flags.RearSensitive) ; }
}
- public bool isAnySensitive
- {
- get { return MProperty.HasFlags (Key,
- (MProperty.Flags.Sensitive
- | MProperty.Flags.RearSensitive
- | MProperty.Flags.FrontSensitive)) ; }
- }
-
private void update_from_to ()
{
if (Parent == null)
{
MPlist p1, p2;
+ if (Stack.IsEmpty && i.Stack.IsEmpty)
+ return true;
+ if (isSensitive)
+ return false;
for (p1 = Stack, p2 = i.Stack; ! p1.IsEmpty && ! p2.IsEmpty;
p1 = p1.Next, p2 = p2.Next)
if (p1.Val != p2.Val)
return Parent;
}
+ public MInterval Find (int pos, out int from, out int to)
+ {
+ MInterval i = find_head (pos);
+
+ from = to = pos;
+ if (i.Stack.IsEmpty)
+ i = i.Next;
+ if (i != null)
+ {
+ from = i.From;
+ to = i.To;
+ }
+ return i;
+ }
+
public MInterval Balance ()
{
MInterval i = this;
MInterval head = find_head (start);
MInterval tail = find_tail (end);
+ M17n.DebugPrint ("Copying: {0}", copy);
+
if (! head.Stack.IsEmpty
- && (isAnySensitive && head.From < start
- || isFrontSensitive && ! first))
+ && (isSensitive && head.From < start
+ || (isFrontSensitive && ! first)))
{
+ M17n.DebugPrint (" clear head");
head = copy.find_head (0);
head.Stack.Clear ();
}
if (! tail.Stack.IsEmpty
- && (isAnySensitive && end < head.To
- || isRearSensitive && ! last))
+ && (isSensitive && end < tail.To
+ || (isRearSensitive && ! last)))
{
+ M17n.DebugPrint (" clear tail");
tail = copy.find_tail (copy.Length);
tail.Stack.Clear ();
}
- M17n.DebugPrint ("Copied: {0}\n", copy);
+ M17n.DebugPrint ("\n");
return copy;
}
len = 0;
if (Stack.IsEmpty
- && (isFrontSensitive
- || ((isSensitive || isRearSensitive) && i.From < start)))
+ && (isFrontSensitive || (isSensitive && i.From < start)))
{
- M17n.DebugPrint (" grafting {0}", i);
+ M17n.DebugPrint (" forward grafting {0}", i);
if (i.To < end)
len = i.To - start;
else
}
while (i != null && i.From < end && mergeable (i))
{
- M17n.DebugPrint (" grafting {0}", i);
+ M17n.DebugPrint (" forward grafting {0}", i);
len += i.To - i.From;
if (i.From < start)
len -= start - i.From;
len = 0;
if (Stack.IsEmpty
- && (isRearSensitive
- || ((isSensitive || isFrontSensitive) && end < i.To)))
+ && (isRearSensitive || (isSensitive && end < i.To)))
{
- M17n.DebugPrint (" grafting {0}", i);
+ M17n.DebugPrint (" backward grafting {0}", i);
if (i.From <= start)
len = end - start;
else
}
while (i != null && i.To <= start && mergeable (i))
{
- M17n.DebugPrint (" grafting {0}", i);
+ M17n.DebugPrint (" backward grafting {0}", i);
len += i.To - i.From;
if (end < i.To)
len -= i.To - end;
if (prev != null && isRearSticky && ! prev.Stack.IsEmpty)
{
prev.enlarge (end - start);
+ M17n.DebugPrint (" done\n");
return;
}
if (isFrontSticky && ! Stack.IsEmpty)
{
enlarge (end - start);
+ M17n.DebugPrint (" done\n");
return;
}
bool front_grafted = false, rear_grafted = false;
{
start += grafted;
if (start == end)
- return;
+ {
+ M17n.DebugPrint (" done\n");
+ return;
+ }
front_grafted = true;
}
if ((grafted = graft_backward (interval, start, end)) > 0)
{
end -= grafted;
if (start == end)
- return;
+ {
+ M17n.DebugPrint (" done\n");
+ return;
+ }
rear_grafted = true;
}
{
if (! Stack.IsEmpty)
{
- if (isSensitive || isFrontSensitive || isRearSensitive)
+ if (isSensitive)
Stack.Clear ();
else if (isFrontSticky || isRearSticky)
{
{
start += grafted;
if (start == end)
- return;
+ {
+ M17n.DebugPrint (" done\n");
+ return;
+ }
front_grafted = true;
pos += grafted;
}
{
end -= grafted;
if (start == end)
- return;
+ {
+ M17n.DebugPrint (" done\n");
+ return;
+ }
rear_grafted = true;
}
if (interval != null)
if (isRearSticky && ! Stack.IsEmpty)
{
enlarge (end - start);
+ M17n.DebugPrint (" done by enlarging this\n");
return;
}
if (next != null && isFrontSticky && ! next.Stack.IsEmpty)
{
+ M17n.DebugPrint (" next is {0}\n", next);
next.enlarge (end - start);
+ M17n.DebugPrint (" done by enlarging next\n");
return;
}
bool front_grafted = false, rear_grafted = false;
{
end -= grafted;
if (start == end)
- return;
+ {
+ M17n.DebugPrint (" done\n");
+ return;
+ }
rear_grafted = true;
}
if ((grafted = graft_forward (interval, start, end)) > 0)
{
start += grafted;
if (start == end)
- return;
+ {
+ M17n.DebugPrint (" done\n");
+ return;
+ }
front_grafted = true;
}
if (interval != null)
interval = interval.Copy (mtext, start, end,
front_grafted,
(rear_grafted
- || (next == null && end < interval.mtext.Length)));
+ || (next == null && end == interval.mtext.Length)));
else
interval = new MInterval (Key, mtext, end - start, null);
Left.Delete (start, end);
return;
}
- if (isSensitive || isFrontSensitive)
+ if (isSensitive)
Stack.Clear ();
Left.Delete (start, From);
To -= From - start;
Right.Delete (start, end);
return;
}
- if (isSensitive || isRearSensitive)
+ if (isSensitive)
Stack.Clear ();
Right.Delete (To, end);
end = To;
{
int len = end - start;
- if (isAnySensitive)
+ if (isSensitive)
Stack.Clear ();
for (MInterval i = this; i != null; i = i.Parent)
i.Length -= len;
end = To;
}
- if (! Stack.IsEmpty && isAnySensitive)
+ if (! Stack.IsEmpty && isSensitive)
Stack.Clear ();
if (start > From)
divide_left (start);
if (! Stack.IsEmpty)
{
- if (isAnySensitive)
+ if (isSensitive)
Stack.Clear ();
else
{
update_from_to ();
MInterval head = find_head (start);
MInterval tail = find_tail (end);
- while (! head.Stack.IsEmpty && head.From > 0)
- {
- MInterval prev = head.Prev;
+ Pop (head.From, tail.To);
+ }
- if (prev.Stack.IsEmpty || head.Stack.Val != prev.Stack.Val)
- break;
- head = head.Prev;
+ public void PopAll (int start, int end)
+ {
+ update_from_to ();
+ M17n.DebugPrint ("popall({0} {1}) at {2}\n", start, end, this);
+ if (start < From)
+ {
+ if (end <= From)
+ {
+ Left.PopAll (start, end);
+ return;
+ }
+ Left.PopAll (start, From);
+ start = From;
}
- while (! tail.Stack.IsEmpty && tail.To < mtext.Length)
+ if (end > To)
{
- MInterval next = tail.Next;
+ if (start >= To)
+ {
+ Right.PopAll (start, end);
+ return;
+ }
+ Right.PopAll (To, end);
+ end = To;
+ }
- if (next.Stack.IsEmpty || tail.Stack.Val != next.Stack.Val)
- break;
- tail = tail.Next;
+ if (! Stack.IsEmpty)
+ {
+ if (isSensitive)
+ Stack.Clear ();
+ else
+ {
+ if (start > From)
+ divide_left (start);
+ if (end < To)
+ divide_right (end);
+ Stack.Clear ();
+ }
}
- Pop (head.From, tail.To);
}
public override string ToString ()
public void DumpNested (bool force)
{
- DumpNested (Key.ToString () + ":", force);
+ DumpNested (" " + Key.ToString () + ":", force);
}
public void DumpNested (string indent, bool force)