diff options
Diffstat (limited to 'src/CellBuffer.cxx')
| -rw-r--r-- | src/CellBuffer.cxx | 103 |
1 files changed, 79 insertions, 24 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx index 3e9deb934..3d4050633 100644 --- a/src/CellBuffer.cxx +++ b/src/CellBuffer.cxx @@ -439,35 +439,90 @@ const char *CellBuffer::InsertString(Sci::Position position, const char *s, Sci: return data; } -bool CellBuffer::SetStyleAt(Sci::Position position, char styleValue) noexcept { - if (!hasStyles) { - return false; - } - const char curVal = style.ValueAt(position); - if (curVal != styleValue) { - style.SetValueAt(position, styleValue); - return true; - } else { - return false; +namespace { + +ChangedRange CopyBytes(char *p, const char *styles, Sci::Position length, Sci::Position offset) noexcept { + for (Sci::Position start = 0; start < length; start++) { + if (p[start] != styles[start]) { + for (Sci::Position end = length - 1; end >= 0; end--) { + if (p[end] != styles[end]) { + memcpy(p+start, styles+start, end-start+1); + return { start + offset, end + offset }; + } + } + } } + return {}; } -bool CellBuffer::SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept { - if (!hasStyles) { - return false; - } - bool changed = false; - PLATFORM_ASSERT(lengthStyle == 0 || - (lengthStyle > 0 && lengthStyle + position <= style.Length())); - while (lengthStyle--) { - const char curVal = style.ValueAt(position); - if (curVal != styleValue) { - style.SetValueAt(position, styleValue); - changed = true; +ChangedRange SetBytes(char *p, char style, Sci::Position length, Sci::Position offset) noexcept { + for (Sci::Position start = 0; start < length; start++) { + if (p[start] != style) { + for (Sci::Position end = length - 1; end >= 0; end--) { + if (p[end] != style) { + memset(p+start, style, end-start+1); + return { start + offset, end + offset }; + } + } } - position++; } - return changed; + return {}; +} + +struct Lengths { + Sci::Position length1; + Sci::Position length2; +}; + +Lengths SplitUpdate(const SplitVector<char> &style, Sci::Position position, Sci::Position length) noexcept { + length = std::min(length, style.Length() - position); + + // Divide length into two parts if it overlaps the gap + const Sci::Position part1Length = style.GapPosition(); + + // If all after gap then place in length1 to avoid second call + if (position >= part1Length) { + return { length, 0 }; + } + // If all before gap then place in length1 + const Sci::Position beforeGap = part1Length - position; + if (length <= beforeGap) { + return { length, 0 }; + } + // Some before gap and some after gap so put portion in length1 and rest in length2 + return { beforeGap, length - beforeGap }; +} + +} + +ChangedRange CellBuffer::SetStyles(Sci::Position position, const char *styles, Sci::Position length) noexcept { + if (!hasStyles || (position < 0) || (length <= 0)) { + return {}; + } + + const Lengths lengths = SplitUpdate(style, position, length); + ChangedRange cr = CopyBytes(&style[position], styles, lengths.length1, position); + if (lengths.length2) { + const ChangedRange cr2 = CopyBytes(&style[position + lengths.length1], styles + lengths.length1, + lengths.length2, position + lengths.length1); + cr.Merge(cr2); + } + return cr; +} + +ChangedRange CellBuffer::SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept { + if (!hasStyles || (position < 0) || (lengthStyle <= 0)) { + return {}; + } + + const Lengths lengths = SplitUpdate(style, position, lengthStyle); + ChangedRange cr = SetBytes(&style[position], styleValue, lengths.length1, position); + if (lengths.length2) { + const ChangedRange cr2 = SetBytes(&style[position + lengths.length1], styleValue, + lengths.length2, position + lengths.length1); + cr.Merge(cr2); + } + return cr; } // The char* returned is to an allocation owned by the undo history |
