35 const int numNewLineChars,
36 const int startInFile)
37 : line (startOfLine, endOfLine),
38 lineStartInFile (startInFile),
40 lineLengthWithoutNewLines (lineLen - numNewLineChars)
47 int charNumInFile = 0;
48 bool finished =
false;
50 while (! (finished || t.isEmpty()))
53 auto startOfLineInFile = charNumInFile;
55 int numNewLineChars = 0;
59 auto c = t.getAndAdvance();
93 numNewLineChars, startOfLineInFile));
99 bool endsWithLineBreak()
const noexcept
101 return lineLengthWithoutNewLines != lineLength;
104 void updateLength()
noexcept
107 lineLengthWithoutNewLines = 0;
111 auto c = t.getAndAdvance();
118 if (c !=
'\n' && c !=
'\r')
119 lineLengthWithoutNewLines = lineLength;
124 int lineStartInFile, lineLength, lineLengthWithoutNewLines;
133 : document (p.owner),
134 line (p.getLineNumber()),
135 position (p.getPosition())
137 reinitialiseCharPtr();
139 for (
int i = 0; i < p.getIndexInLine(); ++i)
141 charPointer.getAndAdvance();
143 if (charPointer.isEmpty())
145 position -= (p.getIndexInLine() - i);
156CodeDocument::Iterator::~Iterator() noexcept {}
159bool CodeDocument::Iterator::reinitialiseCharPtr()
const
164 if (charPointer.getAddress() ==
nullptr)
166 if (
auto* l = document->lines[line])
167 charPointer = l->line.getCharPointer();
179 if (! reinitialiseCharPtr())
182 if (
auto result = charPointer.getAndAdvance())
184 if (charPointer.isEmpty())
187 charPointer =
nullptr;
195 charPointer =
nullptr;
206 if (! reinitialiseCharPtr())
209 position += (
int) charPointer.length();
211 charPointer =
nullptr;
216 if (! reinitialiseCharPtr())
219 if (
auto* l = document->lines [line])
221 auto startPtr = l->line.getCharPointer();
222 position -= (
int) startPtr.lengthUpTo (charPointer);
223 charPointer = startPtr;
229 if (! reinitialiseCharPtr())
232 if (
auto c = *charPointer)
235 if (
auto* l = document->lines [line + 1])
243 if (! reinitialiseCharPtr())
248 if (
auto* l = document->lines[line])
250 if (charPointer != l->line.getCharPointer())
263 if (
auto* prev = document->lines[line])
264 charPointer = prev->line.getCharPointer().findTerminatingNull();
272 if (! reinitialiseCharPtr())
275 if (
auto* l = document->lines[line])
277 if (charPointer != l->line.getCharPointer())
278 return *(charPointer - 1);
280 if (
auto* prev = document->lines[line - 1])
281 return *(prev->line.getCharPointer().findTerminatingNull() - 1);
295 return charPointer.getAddress() ==
nullptr && line >= document->lines.size();
300 return position == 0;
305 if (
auto* l = document->lines[line])
307 reinitialiseCharPtr();
309 auto linePtr = l->line.getCharPointer();
311 while (linePtr != charPointer && ! linePtr.isEmpty())
322 if (
auto* last = document->lines.getLast())
324 auto lineIndex = document->lines.size() - 1;
338 const int lineNum,
const int index) noexcept
340 line (lineNum), indexInLine (index)
342 setLineAndIndex (lineNum, index);
352 : owner (other.owner), characterPos (other.characterPos), line (other.line),
353 indexInLine (other.indexInLine)
360 setPositionMaintained (
false);
367 const bool wasPositionMaintained = positionMaintained;
368 if (owner != other.owner)
369 setPositionMaintained (
false);
373 indexInLine = other.indexInLine;
374 characterPos = other.characterPos;
375 setPositionMaintained (wasPositionMaintained);
383bool CodeDocument::Position::operator== (
const Position& other)
const noexcept
385 jassert ((characterPos == other.characterPos)
386 == (line == other.line && indexInLine == other.indexInLine));
388 return characterPos == other.characterPos
389 && line == other.line
390 && indexInLine == other.indexInLine
391 && owner == other.owner;
394bool CodeDocument::Position::operator!= (
const Position& other)
const noexcept
396 return ! operator== (other);
403 if (owner->lines.size() == 0)
411 if (newLineNum >= owner->lines.size())
413 line = owner->lines.size() - 1;
415 auto& l = *owner->lines.getUnchecked (line);
416 indexInLine = l.lineLengthWithoutNewLines;
417 characterPos = l.lineStartInFile + indexInLine;
421 line =
jmax (0, newLineNum);
423 auto& l = *owner->lines.getUnchecked (line);
425 if (l.lineLengthWithoutNewLines > 0)
426 indexInLine =
jlimit (0, l.lineLengthWithoutNewLines, newIndexInLine);
430 characterPos = l.lineStartInFile + indexInLine;
446 auto lineEnd = owner->lines.size();
450 if (lineEnd - lineStart < 4)
452 for (
int i = lineStart; i < lineEnd; ++i)
454 auto& l = *owner->lines.getUnchecked (i);
455 auto index = newPosition - l.lineStartInFile;
457 if (index >= 0 && (index < l.lineLength || i == lineEnd - 1))
460 indexInLine =
jmin (l.lineLengthWithoutNewLines, index);
461 characterPos = l.lineStartInFile + indexInLine;
469 auto midIndex = (lineStart + lineEnd + 1) / 2;
471 if (newPosition >= owner->lines.getUnchecked (midIndex)->lineStartInFile)
472 lineStart = midIndex;
484 if (characterDelta == 1)
486 setPosition (getPosition());
489 if (line < owner->lines.size())
491 auto& l = *owner->lines.getUnchecked (line);
493 if (indexInLine + characterDelta < l.lineLength
494 && indexInLine + characterDelta >= l.lineLengthWithoutNewLines + 1)
499 setPosition (characterPos + characterDelta);
505 p.
moveBy (characterDelta);
518 if (
auto* l = owner->lines [line])
519 return l->line [getIndexInLine()];
526 if (
auto* l = owner->lines [line])
534 if (isMaintained != positionMaintained)
536 positionMaintained = isMaintained;
538 if (owner !=
nullptr)
542 jassert (! owner->positionsToMaintain.contains (
this));
543 owner->positionsToMaintain.add (
this);
548 jassert (owner->positionsToMaintain.contains (
this));
549 owner->positionsToMaintain.removeFirstMatchingValue (
this);
576 auto endLine =
end.getLineNumber();
578 if (startLine == endLine)
580 if (
auto* line = lines [startLine])
589 auto maxLine =
jmin (lines.size() - 1, endLine);
591 for (
int i =
jmax (0, startLine); i <= maxLine; ++i)
593 auto& line = *lines.getUnchecked (i);
594 auto len = line.lineLength;
599 mo << line.line.substring (index, len);
601 else if (i == endLine)
603 len =
end.getIndexInLine();
604 mo << line.line.substring (0, len);
617 if (
auto* lastLine = lines.getLast())
618 return lastLine->lineStartInFile + lastLine->lineLength;
625 if (
auto* line = lines[lineIndex])
633 if (maximumLineLength < 0)
635 maximumLineLength = 0;
637 for (
auto* l : lines)
638 maximumLineLength =
jmax (maximumLineLength, l->lineLength);
641 return maximumLineLength;
651 remove (start,
end,
true);
661 insert (text, insertIndex,
true);
673 .joinIntoString (newLineChars));
680 remove (c.start, c.start + c.length,
true);
682 insert (c.insertedText, c.start,
true);
689 insert (newContent, 0,
true);
703 for (
auto* l : lines)
706 const char* utf8 = temp.toUTF8();
717 jassert (newChars ==
"\r\n" || newChars ==
"\n" || newChars ==
"\r");
718 newLineChars = newChars;
744 indexOfSavedState = currentActionIndex;
749 return currentActionIndex != indexOfSavedState;
753static int getCharacterType (
juce_wchar character)
noexcept
762 const int maxDistance = 256;
765 while (i < maxDistance
767 && (i == 0 || (p.getCharacter() !=
'\n'
768 && p.getCharacter() !=
'\r')))
776 auto type = getCharacterType (p.getCharacter());
778 while (i < maxDistance && type == getCharacterType (p.getCharacter()))
784 while (i < maxDistance
786 && (i == 0 || (p.getCharacter() !=
'\n'
787 && p.getCharacter() !=
'\r')))
800 const int maxDistance = 256;
802 bool stoppedAtLineStart =
false;
804 while (i < maxDistance)
808 if (c ==
'\r' || c ==
'\n')
810 stoppedAtLineStart =
true;
823 if (i < maxDistance && ! stoppedAtLineStart)
825 auto type = getCharacterType (p.movedBy (-1).getCharacter());
827 while (i < maxDistance && type == getCharacterType (p.movedBy (-1).getCharacter()))
842 while (isTokenCharacter (
end.getCharacter()))
846 while (start.getIndexInLine() > 0
847 && isTokenCharacter (start.movedBy (-1).getCharacter()))
853 s.setLineAndIndex (pos.getLineNumber(), 0);
854 e.setLineAndIndex (pos.getLineNumber() + 1, 0);
857void CodeDocument::checkLastLineStatus()
859 while (lines.size() > 0
860 && lines.getLast()->lineLength == 0
861 && (lines.size() == 1 || ! lines.getUnchecked (lines.size() - 2)->endsWithLineBreak()))
867 const CodeDocumentLine*
const lastLine = lines.getLast();
869 if (lastLine !=
nullptr && lastLine->endsWithLineBreak())
872 lines.add (
new CodeDocumentLine (StringRef(), StringRef(), 0, 0,
873 lastLine->lineStartInFile + lastLine->lineLength));
885 : owner (doc), text (t), insertPos (pos)
891 owner.currentActionIndex++;
892 owner.insert (text, insertPos,
false);
898 owner.currentActionIndex--;
899 owner.remove (insertPos, insertPos + text.
length(),
false);
912void CodeDocument::insert (
const String& text,
const int insertPos,
const bool undoable)
918 undoManager.
perform (
new InsertAction (*
this, text, insertPos));
922 Position pos (*
this, insertPos);
923 auto firstAffectedLine = pos.getLineNumber();
925 auto* firstLine = lines[firstAffectedLine];
926 auto textInsideOriginalLine = text;
928 if (firstLine !=
nullptr)
930 auto index = pos.getIndexInLine();
931 textInsideOriginalLine = firstLine->line.
substring (0, index)
932 + textInsideOriginalLine
936 maximumLineLength = -1;
937 Array<CodeDocumentLine*> newLines;
938 CodeDocumentLine::createLines (newLines, textInsideOriginalLine);
941 auto* newFirstLine = newLines.getUnchecked (0);
942 newFirstLine->lineStartInFile = firstLine !=
nullptr ? firstLine->lineStartInFile : 0;
943 lines.set (firstAffectedLine, newFirstLine);
945 if (newLines.size() > 1)
946 lines.insertArray (firstAffectedLine + 1, newLines.getRawDataPointer() + 1, newLines.size() - 1);
948 int lineStart = newFirstLine->lineStartInFile;
950 for (
int i = firstAffectedLine; i < lines.size(); ++i)
952 auto& l = *lines.getUnchecked (i);
953 l.lineStartInFile = lineStart;
954 lineStart += l.lineLength;
957 checkLastLineStatus();
958 auto newTextLength = text.
length();
960 for (
auto* p : positionsToMaintain)
961 if (p->getPosition() >= insertPos)
962 p->setPosition (p->getPosition() + newTextLength);
964 listeners.call ([&] (Listener& l) { l.codeDocumentTextInserted (text, insertPos); });
973 : owner (doc), startPos (start), endPos (
end),
981 owner.currentActionIndex++;
982 owner.remove (startPos, endPos,
false);
988 owner.currentActionIndex--;
989 owner.insert (removedText, startPos,
false);
996 const int startPos, endPos;
1002void CodeDocument::remove (
const int startPos,
const int endPos,
const bool undoable)
1004 if (endPos <= startPos)
1009 undoManager.
perform (
new DeleteAction (*
this, startPos, endPos));
1013 Position startPosition (*
this, startPos);
1014 Position endPosition (*
this, endPos);
1016 maximumLineLength = -1;
1017 auto firstAffectedLine = startPosition.getLineNumber();
1018 auto endLine = endPosition.getLineNumber();
1019 auto& firstLine = *lines.getUnchecked (firstAffectedLine);
1021 if (firstAffectedLine == endLine)
1023 firstLine.line = firstLine.line.substring (0, startPosition.getIndexInLine())
1024 + firstLine.line.substring (endPosition.getIndexInLine());
1025 firstLine.updateLength();
1029 auto& lastLine = *lines.getUnchecked (endLine);
1031 firstLine.line = firstLine.line.substring (0, startPosition.getIndexInLine())
1032 + lastLine.line.substring (endPosition.getIndexInLine());
1033 firstLine.updateLength();
1035 int numLinesToRemove = endLine - firstAffectedLine;
1036 lines.removeRange (firstAffectedLine + 1, numLinesToRemove);
1039 for (
int i = firstAffectedLine + 1; i < lines.size(); ++i)
1041 auto& l = *lines.getUnchecked (i);
1042 auto& previousLine = *lines.getUnchecked (i - 1);
1043 l.lineStartInFile = previousLine.lineStartInFile + previousLine.lineLength;
1046 checkLastLineStatus();
1049 for (
auto* p : positionsToMaintain)
1051 if (p->getPosition() > startPosition.getPosition())
1052 p->setPosition (
jmax (startPos, p->getPosition() + startPos - endPos));
1054 if (p->getPosition() > totalChars)
1055 p->setPosition (totalChars);
1058 listeners.call ([=] (Listener& l) { l.codeDocumentTextDeleted (startPos, endPos); });
1066struct CodeDocumentTest final :
public UnitTest
1069 : UnitTest (
"CodeDocument", UnitTestCategories::text)
1072 void runTest()
override
1074 const juce::String jabberwocky (
"'Twas brillig, and the slithy toves\n"
1075 "Did gyre and gimble in the wabe;\n"
1076 "All mimsy were the borogoves,\n"
1077 "And the mome raths outgrabe.\n\n"
1079 "'Beware the Jabberwock, my son!\n"
1080 "The jaws that bite, the claws that catch!\n"
1081 "Beware the Jubjub bird, and shun\n"
1082 "The frumious Bandersnatch!'");
1085 beginTest (
"Basic checks");
1087 d.replaceAllContent (jabberwocky);
1089 expectEquals (d.getNumLines(), 9);
1090 expect (d.getLine (0).startsWith (
"'Twas brillig"));
1091 expect (d.getLine (2).startsWith (
"All mimsy"));
1092 expectEquals (d.getLine (4), String (
"\n"));
1096 beginTest (
"Insert/replace/delete");
1099 d.replaceAllContent (jabberwocky);
1101 d.insertText (CodeDocument::Position (d, 0, 6),
"very ");
1102 expect (d.getLine (0).startsWith (
"'Twas very brillig"),
1103 "Insert text within a line");
1105 d.replaceSection (74, 83,
"Quite hungry");
1106 expectEquals (d.getLine (2), String (
"Quite hungry were the borogoves,\n"),
1107 "Replace section at start of line");
1109 d.replaceSection (11, 18,
"cold");
1110 expectEquals (d.getLine (0), String (
"'Twas very cold, and the slithy toves\n"),
1111 "Replace section within a line");
1113 d.deleteSection (CodeDocument::Position (d, 2, 0), CodeDocument::Position (d, 2, 6));
1114 expectEquals (d.getLine (2), String (
"hungry were the borogoves,\n"),
1115 "Delete section within a line");
1117 d.deleteSection (CodeDocument::Position (d, 2, 6), CodeDocument::Position (d, 5, 11));
1118 expectEquals (d.getLine (2), String (
"hungry Jabberwock, my son!\n"),
1119 "Delete section across multiple line");
1123 beginTest (
"Line splitting and joining");
1126 d.replaceAllContent (jabberwocky);
1127 expectEquals (d.getNumLines(), 9);
1129 const String splitComment (
"Adding a newline should split a line into two.");
1130 d.insertText (49,
"\n");
1132 expectEquals (d.getNumLines(), 10, splitComment);
1133 expectEquals (d.getLine (1), String (
"Did gyre and \n"), splitComment);
1134 expectEquals (d.getLine (2), String (
"gimble in the wabe;\n"), splitComment);
1136 const String joinComment (
"Removing a newline should join two lines.");
1137 d.deleteSection (CodeDocument::Position (d, 0, 35),
1138 CodeDocument::Position (d, 1, 0));
1140 expectEquals (d.getNumLines(), 9, joinComment);
1141 expectEquals (d.getLine (0), String (
"'Twas brillig, and the slithy tovesDid gyre and \n"), joinComment);
1142 expectEquals (d.getLine (1), String (
"gimble in the wabe;\n"), joinComment);
1146 beginTest (
"Undo/redo");
1149 d.replaceAllContent (jabberwocky);
1151 d.insertText (30,
"INSERT1");
1153 d.insertText (70,
"INSERT2");
1156 expect (d.getAllContent().contains (
"INSERT1"),
"1st edit should remain.");
1157 expect (! d.getAllContent().contains (
"INSERT2"),
"2nd edit should be undone.");
1160 expect (d.getAllContent().contains (
"INSERT2"),
"2nd edit should be redone.");
1163 d.deleteSection (25, 90);
1164 expect (! d.getAllContent().contains (
"INSERT1"),
"1st edit should be deleted.");
1165 expect (! d.getAllContent().contains (
"INSERT2"),
"2nd edit should be deleted.");
1167 expect (d.getAllContent().contains (
"INSERT1"),
"1st edit should be restored.");
1168 expect (d.getAllContent().contains (
"INSERT2"),
"1st edit should be restored.");
1172 expectEquals (d.getAllContent(), jabberwocky,
"Original document should be restored.");
1176 beginTest (
"Positions");
1179 d.replaceAllContent (jabberwocky);
1182 const String comment (
"Keeps negative positions inside document.");
1183 CodeDocument::Position p1 (d, 0, -3);
1184 CodeDocument::Position p2 (d, -8);
1185 expectEquals (p1.getLineNumber(), 0, comment);
1186 expectEquals (p1.getIndexInLine(), 0, comment);
1187 expectEquals (p1.getCharacter(),
juce_wchar (
'\''), comment);
1188 expectEquals (p2.getLineNumber(), 0, comment);
1189 expectEquals (p2.getIndexInLine(), 0, comment);
1190 expectEquals (p2.getCharacter(),
juce_wchar (
'\''), comment);
1194 const String comment (
"Moving by character handles newlines correctly.");
1195 CodeDocument::Position p1 (d, 0, 35);
1197 expectEquals (p1.getLineNumber(), 1, comment);
1198 expectEquals (p1.getIndexInLine(), 0, comment);
1200 expectEquals (p1.getLineNumber(), 3, comment);
1204 const String comment1 (
"setPositionMaintained tracks position.");
1205 const String comment2 (
"setPositionMaintained tracks position following undos.");
1207 CodeDocument::Position p1 (d, 3, 0);
1208 p1.setPositionMaintained (
true);
1209 expectEquals (p1.getCharacter(),
juce_wchar (
'A'), comment1);
1212 d.insertText (p1,
"INSERT1");
1214 expectEquals (p1.getCharacter(),
juce_wchar (
'A'), comment1);
1215 expectEquals (p1.getLineNumber(), 3, comment1);
1216 expectEquals (p1.getIndexInLine(), 7, comment1);
1218 expectEquals (p1.getIndexInLine(), 0, comment2);
1221 d.insertText (15,
"\n");
1223 expectEquals (p1.getLineNumber(), 4, comment1);
1225 expectEquals (p1.getLineNumber(), 3, comment2);
1230 beginTest (
"Iterators");
1233 d.replaceAllContent (jabberwocky);
1236 const String comment1 (
"Basic iteration.");
1237 const String comment2 (
"Reverse iteration.");
1238 const String comment3 (
"Reverse iteration stops at doc start.");
1239 const String comment4 (
"Check iteration across line boundaries.");
1241 CodeDocument::Iterator it (d);
1242 expectEquals (it.peekNextChar(),
juce_wchar (
'\''), comment1);
1243 expectEquals (it.nextChar(),
juce_wchar (
'\''), comment1);
1244 expectEquals (it.nextChar(),
juce_wchar (
'T'), comment1);
1245 expectEquals (it.nextChar(),
juce_wchar (
'w'), comment1);
1246 expectEquals (it.peekNextChar(),
juce_wchar (
'a'), comment2);
1247 expectEquals (it.previousChar(),
juce_wchar (
'w'), comment2);
1248 expectEquals (it.previousChar(),
juce_wchar (
'T'), comment2);
1249 expectEquals (it.previousChar(),
juce_wchar (
'\''), comment2);
1250 expectEquals (it.previousChar(),
juce_wchar (0), comment3);
1251 expect (it.isSOF(), comment3);
1253 while (it.peekNextChar() !=
juce_wchar (
'D'))
1256 expectEquals (it.nextChar(),
juce_wchar (
'D'), comment3);
1257 expectEquals (it.peekNextChar(),
juce_wchar (
'i'), comment3);
1258 expectEquals (it.previousChar(),
juce_wchar (
'D'), comment3);
1259 expectEquals (it.previousChar(),
juce_wchar (
'\n'), comment3);
1260 expectEquals (it.previousChar(),
juce_wchar (
's'), comment3);
1264 const String comment1 (
"Iterator created from CodeDocument::Position objects.");
1265 const String comment2 (
"CodeDocument::Position created from Iterator objects.");
1266 const String comment3 (
"CodeDocument::Position created from EOF Iterator objects.");
1268 CodeDocument::Position p (d, 6, 0);
1269 CodeDocument::Iterator it (p);
1271 expectEquals (it.nextChar(),
juce_wchar (
'T'), comment1);
1272 expectEquals (it.nextChar(),
juce_wchar (
'h'), comment1);
1273 expectEquals (it.previousChar(),
juce_wchar (
'h'), comment1);
1274 expectEquals (it.previousChar(),
juce_wchar (
'T'), comment1);
1275 expectEquals (it.previousChar(),
juce_wchar (
'\n'), comment1);
1276 expectEquals (it.previousChar(),
juce_wchar (
'!'), comment1);
1278 const auto p2 = it.toPosition();
1279 expectEquals (p2.getLineNumber(), 5, comment2);
1280 expectEquals (p2.getIndexInLine(), 30, comment2);
1282 while (! it.isEOF())
1285 const auto p3 = it.toPosition();
1286 expectEquals (p3.getLineNumber(), d.getNumLines() - 1, comment3);
1287 expectEquals (p3.getIndexInLine(), d.getLine (d.getNumLines() - 1).length(), comment3);
1293static CodeDocumentTest codeDocumentTests;
Holds a resizable array of primitive or copy-by-value objects.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
static bool isWhitespace(char character) noexcept
Checks whether a character is whitespace.
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
void skip() noexcept
Advances the position by one character.
juce_wchar peekNextChar() const noexcept
Reads the next character without moving the current position.
bool isEOF() const noexcept
Returns true if the iterator has reached the end of the document.
CodeDocument::Position toPosition() const
Convert this iterator to a CodeDocument::Position.
Iterator() noexcept
Creates an uninitialised iterator.
bool isSOF() const noexcept
Returns true if the iterator is at the start of the document.
juce_wchar nextChar() noexcept
Reads the next character and returns it.
void skipToEndOfLine() noexcept
Skips forward until the next character will be the first character on the next line.
void skipToStartOfLine() noexcept
Skips backward until the next character will be the first character on this line.
juce_wchar peekPreviousChar() const noexcept
Reads the next character without moving the current position.
juce_wchar previousChar() noexcept
Reads the previous character and returns it.
void skipWhitespace() noexcept
Skips over any whitespace characters until the next character is non-whitespace.
An object that receives callbacks from the CodeDocument when its text changes.
A position in a code document.
juce_wchar getCharacter() const
Returns the character in the document at this position.
int getIndexInLine() const noexcept
Returns the number of characters from the start of the line.
int getPosition() const noexcept
Returns the position as the number of characters from the start of the document.
int getLineNumber() const noexcept
Returns the line number of this position.
void setLineAndIndex(int newLineNumber, int newIndexInLine)
Moves the position to a new line and index within the line.
void moveBy(int characterDelta)
Moves the position forwards or backwards by the specified number of characters.
void setPositionMaintained(bool isMaintained)
Allows the position to be automatically updated when the document changes.
Position movedByLines(int deltaLines) const
Returns a position which is the same as this one, moved up or down by the specified number of lines.
Position movedBy(int characterDelta) const
Returns a position which is the same as this one, moved by the specified number of characters.
Position() noexcept
Creates an uninitialised position.
void setPosition(int charactersFromStartOfDocument)
Points this object at a new position within the document.
String getLineText() const
Returns the line from the document that this position is within.
A class for storing and manipulating a source code file.
void undo()
Undo the last operation.
Position findWordBreakBefore(const Position &position) const noexcept
Searches for a word-break.
void addListener(Listener *listener)
Registers a listener object to receive callbacks when the document changes.
String getAllContent() const
Returns the full text of the document.
int getNumCharacters() const noexcept
Returns the number of characters in the document.
void replaceAllContent(const String &newContent)
Clears the document and replaces it with some new text.
String getLine(int lineIndex) const noexcept
Returns a line from the document.
void clearUndoHistory()
Clears the undo history.
void newTransaction()
Begins a new undo transaction.
void setNewLineCharacters(const String &newLineCharacters) noexcept
Sets the new-line characters that the document should use.
void replaceSection(int startIndex, int endIndex, const String &newText)
Replaces a section of the text with a new string.
void applyChanges(const String &newContent)
Analyses the changes between the current content and some new text, and applies those changes.
Position findWordBreakAfter(const Position &position) const noexcept
Searches for a word-break.
void findLineContaining(const Position &pos, Position &start, Position &end) const noexcept
Finds the line that contains the given position.
void removeListener(Listener *listener)
Deregisters a listener.
void insertText(const Position &position, const String &text)
Inserts some text into the document at a given position.
CodeDocument()
Creates a new, empty document.
void deleteSection(const Position &startPosition, const Position &endPosition)
Deletes a section of the text.
~CodeDocument()
Destructor.
int getMaximumLineLength() noexcept
Returns the number of characters in the longest line of the document.
bool loadFromStream(InputStream &stream)
Replaces the editor's contents with the contents of a stream.
bool writeToStream(OutputStream &stream)
Writes the editor's current contents to a stream.
void redo()
Redo the last operation.
bool hasChangedSinceSavePoint() const noexcept
Returns true if the state of the document differs from the state it was in when setSavePoint() was la...
void findTokenContaining(const Position &pos, Position &start, Position &end) const noexcept
Finds the token that contains the given position.
void setSavePoint() noexcept
Makes a note that the document's current state matches the one that is saved.
String getTextBetween(const Position &start, const Position &end) const
Returns a section of the document's text.
Writes data to an internal memory buffer, which grows as required.
String toUTF8() const
Returns a String created from the (UTF8) data that has been written to the stream.
void preallocate(size_t bytesToPreallocate)
Increases the internal storage capacity to be able to contain at least the specified amount of data w...
The base class for streams that write data to some kind of destination.
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
static StringArray fromLines(StringRef stringToBreakUp)
Returns an array containing the lines in a given string.
A simple class for holding temporary references to a string literal or String.
int length() const noexcept
Returns the number of characters in the string.
String::CharPointerType text
The text that is referenced.
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
int length() const noexcept
Returns the number of characters in the string.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
Calculates and applies a sequence of changes to convert one text string into another.
Array< Change > changes
The list of changes required to perform the transformation.
void beginNewTransaction()
Starts a new group of actions that together will be treated as a single transaction.
bool redo()
Tries to redo the last transaction that was undone.
bool undo()
Tries to roll-back the last transaction.
void clearUndoHistory()
Deletes all stored actions in the list.
bool perform(UndoableAction *action)
Performs an action and adds it to the undo history list.
Used by the UndoManager class to store an action which can be done and undone.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Returns a default-constructed sentinel value.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
bool perform() override
Overridden by a subclass to perform the action.
bool undo() override
Overridden by a subclass to undo the action.
int getSizeInUnits() override
Returns a value to indicate how much memory this object takes up.
bool undo() override
Overridden by a subclass to undo the action.
int getSizeInUnits() override
Returns a value to indicate how much memory this object takes up.
bool perform() override
Overridden by a subclass to perform the action.