35 codeEditorComponentToWrap.
isReadOnly() ? AccessibilityRole::staticText
36 : AccessibilityRole::editableText,
47 : codeEditorComponent (codeEditorComponentToWrap)
51 bool isDisplayingProtectedText()
const override
56 bool isReadOnly()
const override
58 return codeEditorComponent.isReadOnly();
61 int getTotalNumCharacters()
const override
63 return codeEditorComponent.document.getAllContent().length();
68 return { codeEditorComponent.selectionStart.getPosition(),
69 codeEditorComponent.selectionEnd.getPosition() };
74 codeEditorComponent.setHighlightedRegion (r);
79 auto& doc = codeEditorComponent.document;
85 void setText (
const String& newText)
override
87 codeEditorComponent.document.replaceAllContent (newText);
90 int getTextInsertionOffset()
const override
92 return codeEditorComponent.caretPos.getPosition();
97 const auto localRects = codeEditorComponent.getTextBounds (textRange);
101 for (
auto r : localRects)
102 globalRects.
add (codeEditorComponent.localAreaToGlobal (r));
107 int getOffsetAtPoint (
Point<int> point)
const override
109 return codeEditorComponent.getPositionAt (point.
x, point.
y).getPosition();
135 if (tokeniser ==
nullptr)
137 auto line = codeDoc.
getLine (lineNum);
138 addToken (newTokens, line, line.length(), -1);
144 source, *tokeniser, newTokens);
147 replaceTabsWithSpaces (newTokens, tabSpaces);
149 int newHighlightStart = 0;
150 int newHighlightEnd = 0;
154 auto line = codeDoc.
getLine (lineNum);
157 newHighlightStart = indexToColumn (
jmax (0, selStart.
getPosition() - lineStart.getPosition()),
159 newHighlightEnd = indexToColumn (
jmin (lineEnd.
getPosition() - lineStart.getPosition(), selEnd.
getPosition() - lineStart.getPosition()),
163 if (newHighlightStart != highlightColumnStart || newHighlightEnd != highlightColumnEnd)
165 highlightColumnStart = newHighlightStart;
166 highlightColumnEnd = newHighlightEnd;
168 else if (tokens == newTokens)
179 return getHighlightArea (x, y, lineH, characterWidth, { highlightColumnStart, highlightColumnEnd });
185 float characterWidth,
188 if (highlightColumns.
isEmpty())
192 (
float) (highlightColumns.
getEnd() - highlightColumns.
getStart()) * characterWidth + 1.5f, (
float) lineH + 1.0f);
197 const float rightClip,
const float x,
const int y,
198 const int lineH,
const float characterWidth)
const
205 for (
auto& token : tokens)
207 const float tokenX = x + (
float) column * characterWidth;
208 if (tokenX > rightClip)
212 column += token.length;
215 as.
draw (g, { x, (
float) y, (
float) column * characterWidth + 10.0f, (
float) lineH });
221 SyntaxToken (
const String& t,
const int len,
const int type) noexcept
222 : text (t), length (len), tokenType (type)
225 bool operator== (
const SyntaxToken& other)
const noexcept
227 return tokenType == other.tokenType
228 && length == other.length
229 && text == other.text;
238 int highlightColumnStart = 0, highlightColumnEnd = 0;
240 static void createTokens (
int startPosition,
const String& lineText,
246 const int lineLength = lineText.
length();
254 if (tokenEnd <= tokenStart)
257 tokenEnd -= startPosition;
261 tokenStart -= startPosition;
262 const int start =
jmax (0, tokenStart);
263 addToken (newTokens, lineText.
substring (start, tokenEnd),
264 tokenEnd - start, tokenType);
266 if (tokenEnd >= lineLength)
270 lastIterator = source;
273 source = lastIterator;
276 static void replaceTabsWithSpaces (
Array<SyntaxToken>& tokens,
const int spacesPerTab)
280 for (
auto& t : tokens)
284 const int tabPos = t.text.indexOfChar (
'\t');
288 const int spacesNeeded = spacesPerTab - ((tabPos + x) % spacesPerTab);
290 t.length = t.text.length();
297 int indexToColumn (
int index,
const String& line,
int tabSpaces)
const noexcept
304 for (
int i = 0; i < index; ++i)
306 if (t.getAndAdvance() !=
'\t')
309 col += tabSpaces - (col % tabSpaces);
320 addToken (dest, text.
substring (0, length / 2), length / 2, type);
321 addToken (dest, text.
substring (length / 2), length - length / 2, type);
325 dest.
add (SyntaxToken (text, length, type));
330namespace CodeEditorHelpers
332 static int findFirstNonWhitespaceChar (
StringRef line)
noexcept
337 while (! t.isEmpty())
339 if (! t.isWhitespace())
362 void timerCallback()
override { owner.newTransaction(); }
363 void handleAsyncUpdate()
override { owner.rebuildLineTokens(); }
365 void scrollBarMoved (
ScrollBar* scrollBarThatHasMoved,
double newRangeStart)
override
368 owner.scrollToLineInternal ((
int) newRangeStart);
370 owner.scrollToColumnInternal (newRangeStart);
373 void codeDocumentTextInserted (
const String& newText,
int pos)
override
375 owner.codeDocumentChanged (pos, pos + newText.
length());
378 void codeDocumentTextDeleted (
int start,
int end)
override
380 owner.codeDocumentChanged (start,
end);
401 const int lineH = editor.lineHeight;
402 const float lineHeightFloat = (
float) lineH;
403 const int firstLineToDraw =
jmax (0, clip.getY() / lineH);
404 const int lastLineToDraw =
jmin (editor.lines.size(), clip.getBottom() / lineH + 1,
405 lastNumLines - editor.firstLineOnScreen);
407 auto lineNumberFont = editor.getFont().withHeight (
jmin (13.0f, lineHeightFloat * 0.8f));
411 for (
int i = firstLineToDraw; i < lastLineToDraw; ++i)
413 0, (
float) (lineH * i), w, lineHeightFloat,
420 void documentChanged (
CodeDocument& doc,
int newFirstLine)
424 if (newNumLines != lastNumLines || firstLine != newFirstLine)
426 firstLine = newFirstLine;
427 lastNumLines = newNumLines;
433 int firstLine = 0, lastNumLines = 0;
440 caretPos (doc, 0, 0),
441 selectionStart (doc, 0, 0),
442 selectionEnd (doc, 0, 0),
443 codeTokeniser (tokeniser)
465 if (codeTokeniser !=
nullptr)
480 peer->refreshTextInputTarget();
485int CodeEditorComponent::getGutterSize() const noexcept
487 return showLineNumbers ? 35 : 5;
492 clearCachedIterators (0);
514 if (showLineNumbers != shouldBeShown)
516 showLineNumbers = shouldBeShown;
536 removeChildComponent (caret.get());
538 addAndMakeVisible (caret.get());
540 invalidateAccessibilityHandler();
547 auto visibleWidth =
getWidth() - scrollbarThickness - getGutterSize();
548 linesOnScreen =
jmax (1, (
getHeight() - scrollbarThickness) / lineHeight);
549 columnsOnScreen =
jmax (1, (
int) ((
float) visibleWidth / charWidth));
552 updateCaretPosition();
554 if (gutter !=
nullptr)
555 gutter->setBounds (0, 0, getGutterSize() - 2,
getHeight());
558 scrollbarThickness,
getHeight() - scrollbarThickness);
561 visibleWidth, scrollbarThickness);
569 const auto gutterSize = getGutterSize();
578 const auto firstLineToDraw =
jmax (0, clip.getY() / lineHeight);
579 const auto lastLineToDraw =
jmin (lines.size(), clip.getBottom() / lineHeight + 1);
580 const auto x = (
float) (gutterSize - xOffset * charWidth);
581 const auto rightClip = (
float) clip.getRight();
586 for (
int i = firstLineToDraw; i < lastLineToDraw; ++i)
587 if (
const auto area = lines.getUnchecked (i)->getHighlightArea (x, lineHeight * i, lineHeight, charWidth))
588 highlightArea.
add (*area);
594 for (
int i = firstLineToDraw; i < lastLineToDraw; ++i)
595 lines.getUnchecked (i)->draw (*
this, g, font, rightClip, x, lineHeight * i, lineHeight, charWidth);
600 if (scrollbarThickness != thickness)
602 scrollbarThickness = thickness;
607void CodeEditorComponent::rebuildLineTokensAsync()
609 pimpl->triggerAsyncUpdate();
612void CodeEditorComponent::rebuildLineTokens()
614 pimpl->cancelPendingUpdate();
616 auto numNeeded = linesOnScreen + 1;
617 auto minLineToRepaint = numNeeded;
618 int maxLineToRepaint = 0;
620 if (numNeeded != lines.size())
624 for (
int i = numNeeded; --i >= 0;)
625 lines.add (
new CodeEditorLine());
627 minLineToRepaint = 0;
628 maxLineToRepaint = numNeeded;
631 jassert (numNeeded == lines.size());
633 CodeDocument::Iterator source (document);
634 getIteratorForPosition (CodeDocument::Position (document, firstLineOnScreen, 0).
getPosition(), source);
636 for (
int i = 0; i < numNeeded; ++i)
638 if (lines.getUnchecked (i)->update (document, firstLineOnScreen + i, source, codeTokeniser,
639 spacesPerTab, selectionStart, selectionEnd))
641 minLineToRepaint =
jmin (minLineToRepaint, i);
642 maxLineToRepaint =
jmax (maxLineToRepaint, i);
646 if (minLineToRepaint <= maxLineToRepaint)
647 repaint (0, lineHeight * minLineToRepaint - 1,
648 verticalScrollBar.
getX(), lineHeight * (1 + maxLineToRepaint - minLineToRepaint) + 2);
650 if (gutter !=
nullptr)
651 gutter->documentChanged (document, firstLineOnScreen);
654void CodeEditorComponent::codeDocumentChanged (
const int startIndex,
const int endIndex)
656 const CodeDocument::Position affectedTextStart (document, startIndex);
657 const CodeDocument::Position affectedTextEnd (document, endIndex);
661 updateCaretPosition();
662 columnToTryToMaintain = -1;
664 if (affectedTextEnd.getPosition() >= selectionStart.
getPosition()
665 && affectedTextStart.getPosition() <= selectionEnd.
getPosition())
668 if (shouldFollowDocumentChanges)
669 if (caretPos.
getPosition() > affectedTextEnd.getPosition()
670 || caretPos.
getPosition() < affectedTextStart.getPosition())
682 rebuildLineTokensAsync();
686void CodeEditorComponent::updateCaretPosition()
688 if (caret !=
nullptr)
700 columnToTryToMaintain = -1;
701 bool selectionWasActive = isHighlightActive();
705 if (dragType == notDragging)
708 auto isStart = std::abs (oldCaretPos - selectionStart.
getPosition())
709 < std::abs (oldCaretPos - selectionEnd.
getPosition());
711 dragType = isStart ? draggingSelectionStart : draggingSelectionEnd;
714 if (dragType == draggingSelectionStart)
718 setSelection (selectionEnd, caretPos);
719 dragType = draggingSelectionEnd;
723 setSelection (caretPos, selectionEnd);
730 setSelection (caretPos, selectionStart);
731 dragType = draggingSelectionStart;
735 setSelection (selectionStart, caretPos);
739 rebuildLineTokensAsync();
746 updateCaretPosition();
747 scrollToKeepCaretOnScreen();
754 if (appCommandManager !=
nullptr && selectionWasActive != isHighlightActive())
758void CodeEditorComponent::deselectAll()
760 if (isHighlightActive())
761 rebuildLineTokensAsync();
763 setSelection (caretPos, caretPos);
764 dragType = notDragging;
767void CodeEditorComponent::updateScrollBars()
776void CodeEditorComponent::scrollToLineInternal (
int newFirstLineOnScreen)
779 newFirstLineOnScreen);
781 if (newFirstLineOnScreen != firstLineOnScreen)
783 firstLineOnScreen = newFirstLineOnScreen;
784 updateCaretPosition();
786 updateCachedIterators (firstLineOnScreen);
787 rebuildLineTokensAsync();
788 pimpl->handleUpdateNowIfNeeded();
794void CodeEditorComponent::scrollToColumnInternal (
double column)
801 updateCaretPosition();
806void CodeEditorComponent::scrollToLine (
int newFirstLineOnScreen)
808 scrollToLineInternal (newFirstLineOnScreen);
812void CodeEditorComponent::scrollToColumn (
int newFirstColumnOnScreen)
814 scrollToColumnInternal (newFirstColumnOnScreen);
818void CodeEditorComponent::scrollBy (
int deltaLines)
820 scrollToLine (firstLineOnScreen + deltaLines);
823void CodeEditorComponent::scrollToKeepLinesOnScreen (Range<int> rangeToShow)
825 if (rangeToShow.getStart() < firstLineOnScreen)
826 scrollBy (rangeToShow.getStart() - firstLineOnScreen);
827 else if (rangeToShow.getEnd() >= firstLineOnScreen + linesOnScreen)
828 scrollBy (rangeToShow.getEnd() - (firstLineOnScreen + linesOnScreen - 1));
831void CodeEditorComponent::scrollToKeepCaretOnScreen()
836 scrollToKeepLinesOnScreen ({ caretLine, caretLine });
840 if (column >= xOffset + columnsOnScreen - 1)
841 scrollToColumn (column + 1 - columnsOnScreen);
842 else if (column < xOffset)
843 scrollToColumn (column);
857 const int line = y / lineHeight + firstLineOnScreen;
858 const int column =
roundToInt ((x - (getGutterSize() - xOffset * charWidth)) / charWidth);
859 const int index = columnToIndex (line, column);
898 insertText (newText);
901void CodeEditorComponent::insertText (
const String& newText)
910 scrollToKeepCaretOnScreen();
918void CodeEditorComponent::insertTabAtCaret()
928 if (useSpacesForTabs)
931 auto spacesNeeded = spacesPerTab - (caretCol % spacesPerTab);
941bool CodeEditorComponent::deleteWhitespaceBackwardsToTabStop()
949 if (currentColumn <= 0 || (currentColumn % spacesPerTab) == 0)
952 moveCaretLeft (
false,
true);
957 if (selected.isNotEmpty() && selected.trim().isEmpty())
967void CodeEditorComponent::indentSelection() { indentSelectedLines ( spacesPerTab); }
968void CodeEditorComponent::unindentSelection() { indentSelectedLines (-spacesPerTab); }
970void CodeEditorComponent::indentSelectedLines (
const int spacesToAdd)
976 CodeDocument::Position oldSelectionStart (selectionStart), oldSelectionEnd (selectionEnd), oldCaret (caretPos);
977 oldSelectionStart.setPositionMaintained (
true);
978 oldSelectionEnd.setPositionMaintained (
true);
979 oldCaret.setPositionMaintained (
true);
987 for (
int line = lineStart; line <= lineEnd; ++line)
989 auto lineText = document.
getLine (line);
990 auto nonWhitespaceStart = CodeEditorHelpers::findFirstNonWhitespaceChar (lineText);
992 if (nonWhitespaceStart > 0 || lineText.trimStart().isNotEmpty())
994 const CodeDocument::Position wsStart (document, line, 0);
995 const CodeDocument::Position wsEnd (document, line, nonWhitespaceStart);
997 const int numLeadingSpaces = indexToColumn (line, wsEnd.getIndexInLine());
998 const int newNumLeadingSpaces =
jmax (0, numLeadingSpaces + spacesToAdd);
1000 if (newNumLeadingSpaces != numLeadingSpaces)
1008 setSelection (oldSelectionStart, oldSelectionEnd);
1010 if (caretPos != oldCaret)
1012 caretPos = oldCaret;
1020void CodeEditorComponent::cut()
1025bool CodeEditorComponent::copyToClipboard()
1028 auto selection = document.
getTextBetween (selectionStart, selectionEnd);
1030 if (selection.isNotEmpty())
1036bool CodeEditorComponent::cutToClipboard()
1044bool CodeEditorComponent::pasteFromClipboard()
1049 if (clip.isNotEmpty())
1056bool CodeEditorComponent::moveCaretLeft (
const bool moveInWholeWordSteps,
const bool selecting)
1060 if (selecting && dragType == notDragging)
1062 selectRegion (CodeDocument::Position (selectionEnd), CodeDocument::Position (selectionStart));
1063 dragType = draggingSelectionStart;
1066 if (isHighlightActive() && ! (selecting || moveInWholeWordSteps))
1072 if (moveInWholeWordSteps)
1080bool CodeEditorComponent::moveCaretRight (
const bool moveInWholeWordSteps,
const bool selecting)
1084 if (selecting && dragType == notDragging)
1086 selectRegion (CodeDocument::Position (selectionStart), CodeDocument::Position (selectionEnd));
1087 dragType = draggingSelectionEnd;
1090 if (isHighlightActive() && ! (selecting || moveInWholeWordSteps))
1096 if (moveInWholeWordSteps)
1104void CodeEditorComponent::moveLineDelta (
const int delta,
const bool selecting)
1106 CodeDocument::Position pos (caretPos);
1107 auto newLineNum = pos.getLineNumber() + delta;
1109 if (columnToTryToMaintain < 0)
1110 columnToTryToMaintain = indexToColumn (pos.getLineNumber(), pos.getIndexInLine());
1112 pos.setLineAndIndex (newLineNum, columnToIndex (newLineNum, columnToTryToMaintain));
1114 auto colToMaintain = columnToTryToMaintain;
1116 columnToTryToMaintain = colToMaintain;
1119bool CodeEditorComponent::moveCaretDown (
const bool selecting)
1126 moveLineDelta (1, selecting);
1131bool CodeEditorComponent::moveCaretUp (
const bool selecting)
1136 moveCaretTo (CodeDocument::Position (document, 0, 0), selecting);
1138 moveLineDelta (-1, selecting);
1143bool CodeEditorComponent::pageDown (
const bool selecting)
1146 scrollBy (
jlimit (0, linesOnScreen, 1 + document.
getNumLines() - firstLineOnScreen - linesOnScreen));
1147 moveLineDelta (linesOnScreen, selecting);
1151bool CodeEditorComponent::pageUp (
const bool selecting)
1154 scrollBy (-linesOnScreen);
1155 moveLineDelta (-linesOnScreen, selecting);
1159bool CodeEditorComponent::scrollUp()
1165 moveLineDelta (1,
false);
1170bool CodeEditorComponent::scrollDown()
1175 if (caretPos.
getLineNumber() >= firstLineOnScreen + linesOnScreen)
1176 moveLineDelta (-1,
false);
1181bool CodeEditorComponent::moveCaretToTop (
const bool selecting)
1184 moveCaretTo (CodeDocument::Position (document, 0, 0), selecting);
1188bool CodeEditorComponent::moveCaretToStartOfLine (
const bool selecting)
1192 int index = CodeEditorHelpers::findFirstNonWhitespaceChar (caretPos.
getLineText());
1201bool CodeEditorComponent::moveCaretToEnd (
const bool selecting)
1209bool CodeEditorComponent::moveCaretToEndOfLine (
const bool selecting)
1217bool CodeEditorComponent::deleteBackwards (
const bool moveInWholeWordSteps)
1219 if (moveInWholeWordSteps)
1224 else if (selectionStart == selectionEnd && ! skipBackwardsToPreviousTab())
1226 selectionStart.
moveBy (-1);
1233bool CodeEditorComponent::skipBackwardsToPreviousTab()
1238 if (currentLineText.isNotEmpty() && currentLineText.length() == currentIndex)
1241 const int currentColumn = indexToColumn (currentLine, currentIndex);
1242 const int previousTabColumn = (currentColumn - 1) - ((currentColumn - 1) % spacesPerTab);
1243 const int previousTabIndex = columnToIndex (currentLine, previousTabColumn);
1245 if (currentLineText.substring (previousTabIndex, currentIndex).trim().isEmpty())
1247 selectionStart.
moveBy (previousTabIndex - currentIndex);
1255bool CodeEditorComponent::deleteForwards (
const bool moveInWholeWordSteps)
1257 if (moveInWholeWordSteps)
1264 if (selectionStart == selectionEnd)
1274bool CodeEditorComponent::selectAll()
1279 CodeDocument::Position (document, 0, 0));
1283void CodeEditorComponent::selectRegion (
const CodeDocument::Position& start,
1284 const CodeDocument::Position&
end)
1291bool CodeEditorComponent::undo()
1296 ScopedValueSetter<bool> svs (shouldFollowDocumentChanges,
true,
false);
1298 scrollToKeepCaretOnScreen();
1302bool CodeEditorComponent::redo()
1307 ScopedValueSetter<bool> svs (shouldFollowDocumentChanges,
true,
false);
1309 scrollToKeepCaretOnScreen();
1313void CodeEditorComponent::newTransaction()
1316 pimpl->startTimer (600);
1321 appCommandManager = newManager;
1331bool CodeEditorComponent::isHighlightActive() const noexcept
1333 return selectionStart != selectionEnd;
1370 pimpl->handleUpdateNowIfNeeded();
1418 const bool anythingSelected = isHighlightActive();
1423 result.
setInfo (
TRANS (
"Cut"),
TRANS (
"Copies the currently selected text to the clipboard and deletes it."),
"Editing", 0);
1424 result.
setActive (anythingSelected && ! readOnly);
1429 result.
setInfo (
TRANS (
"Copy"),
TRANS (
"Copies the currently selected text to the clipboard."),
"Editing", 0);
1435 result.
setInfo (
TRANS (
"Paste"),
TRANS (
"Inserts text from the clipboard."),
"Editing", 0);
1441 result.
setInfo (
TRANS (
"Delete"),
TRANS (
"Deletes any selected text."),
"Editing", 0);
1442 result.
setActive (anythingSelected && ! readOnly);
1446 result.
setInfo (
TRANS (
"Select All"),
TRANS (
"Selects all the text in the editor."),
"Editing", 0);
1478bool CodeEditorComponent::performCommand (
const CommandID commandID)
1489 default:
return false;
1495void CodeEditorComponent::setSelection (CodeDocument::Position newSelectionStart,
1496 CodeDocument::Position newSelectionEnd)
1498 if (selectionStart != newSelectionStart
1499 || selectionEnd != newSelectionEnd)
1501 selectionStart = newSelectionStart;
1502 selectionEnd = newSelectionEnd;
1525 performCommand (menuItemID);
1530 if (editor !=
nullptr && menuResult != 0)
1538 dragType = notDragging;
1550 selectRegion (start,
end);
1577 dragType = notDragging;
1591 selectRegion (tokenStart, tokenEnd);
1592 dragType = notDragging;
1625 useSpacesForTabs = insertSpaces;
1627 if (spacesPerTab != numSpaces)
1629 spacesPerTab = numSpaces;
1630 rebuildLineTokensAsync();
1637 useSpacesForTabs ? numSpaces
1638 : (numSpaces / spacesPerTab));
1641int CodeEditorComponent::indexToColumn (
int lineNum,
int index)
const noexcept
1643 auto line = document.getLine (lineNum);
1644 auto t = line.getCharPointer();
1647 for (
int i = 0; i < index; ++i)
1655 if (t.getAndAdvance() !=
'\t')
1658 col += getTabSize() - (col % getTabSize());
1664int CodeEditorComponent::columnToIndex (
int lineNum,
int column)
const noexcept
1666 auto line = document.getLine (lineNum);
1667 auto t = line.getCharPointer();
1670 while (! t.isEmpty())
1672 if (t.getAndAdvance() !=
'\t')
1675 col += getTabSize() - (col % getTabSize());
1695void CodeEditorComponent::ColourScheme::set (
const String& name,
Colour colour)
1697 for (
auto& tt : types)
1699 if (tt.name == name)
1714 colourScheme = scheme;
1721 ? colourScheme.types.getReference (tokenType).colour
1725void CodeEditorComponent::clearCachedIterators (
const int firstLineToBeInvalid)
1728 for (i = cachedIterators.size(); --i >= 0;)
1729 if (cachedIterators.getUnchecked (i).getLine() < firstLineToBeInvalid)
1732 cachedIterators.removeRange (
jmax (0, i - 1), cachedIterators.size());
1735void CodeEditorComponent::updateCachedIterators (
int maxLineNum)
1737 const int maxNumCachedPositions = 5000;
1738 const int linesBetweenCachedSources =
jmax (10, document.
getNumLines() / maxNumCachedPositions);
1740 if (cachedIterators.size() == 0)
1741 cachedIterators.add (CodeDocument::Iterator (document));
1743 if (codeTokeniser !=
nullptr)
1747 const auto last = cachedIterators.getLast();
1749 if (last.getLine() >= maxLineNum)
1752 cachedIterators.add (CodeDocument::Iterator (last));
1753 auto& t = cachedIterators.getReference (cachedIterators.size() - 1);
1754 const int targetLine =
jmin (maxLineNum, last.getLine() + linesBetweenCachedSources);
1760 if (t.getLine() >= targetLine)
1770void CodeEditorComponent::getIteratorForPosition (
int position, CodeDocument::Iterator& source)
1772 if (codeTokeniser !=
nullptr)
1774 for (
int i = cachedIterators.size(); --i >= 0;)
1776 auto& t = cachedIterators.getReference (i);
1778 if (t.getPosition() <= position)
1785 while (source.getPosition() < position)
1787 const CodeDocument::Iterator original (source);
1790 if (source.getPosition() > position || source.isEOF())
1802 lastSelectionEnd (lastCaretPos)
1806 if (lastCaretPos == selection.getStart())
1807 lastSelectionEnd = selection.getEnd();
1809 lastSelectionEnd = selection.getStart();
1813 : lastTopLine (other.lastTopLine),
1814 lastCaretPos (other.lastCaretPos),
1815 lastSelectionEnd (other.lastSelectionEnd)
1825 editor.scrollToLine (lastTopLine);
1832 lastTopLine = tokens[0].getIntValue();
1833 lastCaretPos = tokens[1].getIntValue();
1834 lastSelectionEnd = tokens[2].getIntValue();
1839 return String (lastTopLine) +
":" +
String (lastCaretPos) +
":" +
String (lastSelectionEnd);
Base class for accessible Components.
An abstract interface which represents a UI element that supports a text interface.
One of these objects holds a list of all the commands your app can perform, and despatches these comm...
void commandStatusChanged()
This should be called to tell the manager that one of its registered commands may have changed its ac...
A command target publishes a list of command IDs that it can perform.
ApplicationCommandTarget * findFirstTargetParentComponent()
If this object is a Component, this method will search upwards in its current UI hierarchy for the ne...
Holds a resizable array of primitive or copy-by-value objects.
void swapWith(OtherArrayType &otherArray) noexcept
This swaps the contents of this array with those of another array.
void ensureStorageAllocated(int minNumElements)
Increases the array's internal storage to hold a minimum number of elements.
void addArray(const Type *elementsToAdd, int numElementsToAdd)
Adds elements from an array to the end of this array.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Has a callback method that is triggered asynchronously.
A text string with a set of colour/font settings that are associated with sub-ranges of the text.
void draw(Graphics &g, const Rectangle< float > &area) const
Draws this string within the given area.
void append(const String &textToAppend)
Appends some text (with a default font and colour).
void setJustification(Justification newJustification) noexcept
Sets the justification that should be used for laying-out the text.
static bool isWhitespace(char character) noexcept
Checks whether a character is whitespace.
Iterates the text in a CodeDocument.
int getPosition() const noexcept
Returns the position as the number of characters from the start of the document.
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 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 movedBy(int characterDelta) const
Returns a position which is the same as this one, moved by the specified number of characters.
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.
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.
int getNumLines() const noexcept
Returns the number of lines in the document.
UndoManager & getUndoManager() noexcept
Returns the document's UndoManager.
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.
void deleteSection(const Position &startPosition, const Position &endPosition)
Deletes a section of the text.
int getMaximumLineLength() noexcept
Returns the number of characters in the longest line of the document.
String getNewLineCharacters() const noexcept
Returns the preferred new-line characters for the document.
void redo()
Redo the last operation.
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.
void paint(Graphics &g) override
Components can override this method to draw their content.
A text editor component designed specifically for source code.
int getFirstLineOnScreen() const noexcept
Returns the index of the first line that's visible at the top of the editor.
void getCommandInfo(CommandID, ApplicationCommandInfo &) override
This must provide details about one of the commands that this target can perform.
void lookAndFeelChanged() override
Called to let the component react to a change in the look-and-feel setting.
void mouseUp(const MouseEvent &) override
Called when a mouse button is released.
void mouseDrag(const MouseEvent &) override
Called when the mouse is moved while a button is held down.
~CodeEditorComponent() override
Destructor.
String getTabString(int numSpaces) const
Returns a string containing spaces or tab characters to generate the given number of spaces.
CodeEditorComponent(CodeDocument &document, CodeTokeniser *codeTokeniser)
Creates an editor for a document.
void setTemporaryUnderlining(const Array< Range< int > > &) override
Sets a number of temporarily underlined sections.
int getLineHeight() const noexcept
Returns the height of a line of text, in pixels.
virtual void handleTabKey()
Called when the tab key is pressed - this can be overridden for custom behaviour.
void retokenise(int startIndex, int endIndex)
Rebuilds the syntax highlighting for a section of text.
virtual void handleReturnKey()
Called when the return key is pressed - this can be overridden for custom behaviour.
void setHighlightedRegion(const Range< int > &newRange) override
Sets the currently-selected text region.
Colour getColourForTokenType(int tokenType) const
Returns one the syntax highlighting colour for the given token.
void setReadOnly(bool shouldBeReadOnly) noexcept
Makes the editor read-only.
void loadContent(const String &newContent)
Loads the given content into the document.
void setScrollbarThickness(int thickness)
Changes the size of the scrollbars.
void focusLost(FocusChangeType) override
Called to indicate that this component has just lost the keyboard focus.
void paint(Graphics &) override
Components can override this method to draw their content.
virtual void performPopupMenuAction(int menuItemID)
This is called to perform one of the items that was shown on the popup menu.
CodeDocument::Position getCaretPos() const
Returns the current caret position.
virtual void caretPositionMoved()
Called when the caret position moves.
void setTabSize(int numSpacesPerTab, bool insertSpacesInsteadOfTabCharacters)
Changes the current tab settings.
void setLineNumbersShown(bool shouldBeShown)
Enables or disables the line-number display in the gutter.
Range< int > getHighlightedRegion() const override
Returns the extents of the selected text region, or an empty range if nothing is selected,...
void resized() override
Called when this component's size has been changed.
bool perform(const InvocationInfo &) override
This must actually perform the specified command.
void focusGained(FocusChangeType) override
Called to indicate that this component has just acquired the keyboard focus.
void insertTextAtCaret(const String &textToInsert) override
Inserts some text, overwriting the selected text region, if there is one.
CodeDocument & getDocument() const noexcept
Returns the code document that this component is editing.
void mouseDown(const MouseEvent &) override
Called when a mouse button is pressed.
void setCommandManager(ApplicationCommandManager *newManager) noexcept
Specifies a command-manager which the editor will notify whenever the state of any of its commands ch...
virtual void handleEscapeKey()
Called when the escape key is pressed - this can be overridden for custom behaviour.
void mouseDoubleClick(const MouseEvent &) override
Called when a mouse button has been double-clicked on a component.
void setColourScheme(const ColourScheme &scheme)
Changes the syntax highlighting scheme.
Rectangle< int > getCharacterBounds(const CodeDocument::Position &pos) const
Returns the on-screen position of a character in the document.
String getTextInRange(const Range< int > &range) const override
Returns a specified sub-section of the text.
ApplicationCommandTarget * getNextCommandTarget() override
This must return the next target to try after this one.
bool isTextInputActive() const override
Returns true if this input target is currently accepting input.
void getAllCommands(Array< CommandID > &) override
This must return a complete list of commands that this target can handle.
void setFont(const Font &newFont)
Changes the font.
CodeDocument::Position getPositionAt(int x, int y) const
Finds the character at a given on-screen position.
RectangleList< int > getTextBounds(Range< int > textRange) const override
Returns the bounding box for a range of text in the editor.
std::unique_ptr< AccessibilityHandler > createAccessibilityHandler() override
Override this method to return a custom AccessibilityHandler for this component.
void mouseWheelMove(const MouseEvent &, const MouseWheelDetails &) override
Called when the mouse-wheel is moved.
bool keyPressed(const KeyPress &) override
Called when a key is pressed.
bool isReadOnly() const noexcept
Returns true if the editor is set to be read-only.
virtual void editorViewportPositionChanged()
Called when the view position is scrolled horizontally or vertically.
virtual void addPopupMenuItems(PopupMenu &menuToAddTo, const MouseEvent *mouseClickEvent)
This adds the items to the popup menu.
@ lineNumberTextId
The colour to use for drawing the line numbers.
@ backgroundColourId
A colour to use to fill the editor's background.
@ highlightColourId
The colour to use for the highlighted background under selected text.
@ lineNumberBackgroundId
The colour to use for filling the background of the line-number gutter.
@ defaultTextColourId
The colour to use for text when no syntax colouring is enabled.
void moveCaretTo(const CodeDocument::Position &newPos, bool selecting)
Moves the caret.
int getCharIndexForPoint(Point< int > point) const override
A base class for tokenising code so that the syntax can be displayed in a code editor.
virtual CodeEditorComponent::ColourScheme getDefaultColourScheme()=0
Returns a suggested syntax highlighting colour scheme.
virtual int readNextToken(CodeDocument::Iterator &source)=0
Reads the next token from the source and returns its token type.
Represents a colour, also including a transparency value.
The base class for all JUCE user-interface objects.
bool isVisible() const noexcept
Tests whether the component is visible or not.
Component * getParentComponent() const noexcept
Returns the component which this component is inside.
Point< int > getPosition() const noexcept
Returns the component's top-left position as a Point.
int getHeight() const noexcept
Returns the component's height in pixels.
int getX() const noexcept
Returns the x coordinate of the component's left edge.
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
FocusChangeType
Enumeration used by the focusGained() and focusLost() methods.
AccessibilityHandler * getAccessibilityHandler()
Returns the accessibility handler for this component, or nullptr if this component is not accessible.
void setOpaque(bool shouldBeOpaque)
Indicates whether any parts of the component might be transparent.
void setMouseCursor(const MouseCursor &cursorType)
Changes the mouse cursor shape to use when the mouse is over this component.
void repaint()
Marks the whole component as needing to be redrawn.
int getY() const noexcept
Returns the y coordinate of the top of this component.
void setBounds(int x, int y, int width, int height)
Changes the component's position and size.
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Sets a flag to indicate whether this component wants keyboard focus or not.
Colour findColour(int colourID, bool inheritFromParent=false) const
Looks for a colour that has been registered with the given colour ID number.
int getWidth() const noexcept
Returns the component's width in pixels.
void mouseWheelMove(const MouseEvent &event, const MouseWheelDetails &wheel) override
Called when the mouse-wheel is moved.
static void JUCE_CALLTYPE beginDragAutoRepeat(int millisecondsBetweenCallbacks)
Ensures that a non-stop stream of mouse-drag events will be sent during the current mouse-drag operat...
ComponentPeer * getPeer() const
Returns the heavyweight window that contains this component.
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
Represents a particular font, including its size, style, etc.
float getHeight() const noexcept
Returns the total height of this font, in pixels.
static const String & getDefaultMonospacedFontName()
Returns a typeface font family that represents the default monospaced font.
float getStringWidthFloat(const String &text) const
Returns the total width of a string as it would be drawn using this font.
void setTypefaceName(const String &faceName)
Changes the font family of the typeface.
A set of glyphs, each with a position.
void addFittedText(const Font &font, const String &text, float x, float y, float width, float height, Justification layout, int maximumLinesToUse, float minimumHorizontalScale=0.0f)
Tries to fit some text within a given space.
void draw(const Graphics &) const
Draws this glyph arrangement to a graphics context.
A graphics context, used for drawing a component or image.
void setFont(const Font &newFont)
Changes the font to use for subsequent text-drawing functions.
void fillRectList(const RectangleList< float > &rectangles) const
Fills a set of rectangles using the current colour or brush.
bool reduceClipRegion(int x, int y, int width, int height)
Intersects the current clipping region with another region.
Rectangle< int > getClipBounds() const
Returns the position of the bounding box for the current clipping region.
void setColour(Colour newColour)
Changes the current drawing colour.
void fillAll() const
Fills the context's entire clip region with the current colour or brush.
@ centredRight
Indicates that the item should be centred vertically but placed on the right hand side.
@ centredLeft
Indicates that the item should be centred vertically but placed on the left hand side.
Represents a key press, including any modifier keys that are needed.
static const int tabKey
key-code for the tab key
juce_wchar getTextCharacter() const noexcept
Returns the character that is associated with this keypress.
static const int escapeKey
key-code for the escape key
static const int returnKey
key-code for the return key
static ModalComponentManager::Callback * forComponent(void(*functionToCall)(int, ComponentType *), ComponentType *component)
This is a utility function to create a ModalComponentManager::Callback that will call a static functi...
bool isPopupMenu() const noexcept
Checks whether the user is trying to launch a pop-up menu.
bool isShiftDown() const noexcept
Checks whether the shift key's flag is set.
@ commandModifier
Command key flag - on windows this is the same as the CTRL key flag.
@ shiftModifier
Shift key flag.
@ NormalCursor
The standard arrow cursor.
@ IBeamCursor
A vertical I-beam for positioning within text.
Contains position and status information about a mouse event.
const ModifierKeys mods
The key modifiers associated with the event.
const int x
The x-position of the mouse when the event occurred.
const int y
The y-position of the mouse when the event occurred.
int getNumberOfClicks() const noexcept
For a click event, the number of times the mouse was clicked in succession.
A pair of (x, y) coordinates.
ValueType y
The point's Y coordinate.
ValueType x
The point's X coordinate.
A general-purpose range object, that simply represents any linear range with a start and end point.
constexpr ValueType getStart() const noexcept
Returns the start of the range.
constexpr bool isEmpty() const noexcept
Returns true if the range has a length of zero.
constexpr ValueType getEnd() const noexcept
Returns the end of the range.
Maintains a set of rectangles as a complex region.
void add(RectangleType rect)
Merges a new rectangle into the list.
Manages a rectangle and allows geometric operations to be performed on it.
Point< ValueType > getTopLeft() const noexcept
Returns the rectangle's top-left position as a Point.
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Returns an array containing the tokens in a given string.
A simple class for holding temporary references to a string literal or String.
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Creates a string which is a version of a string repeated and joined together.
int length() const noexcept
Returns the number of characters in the string.
String removeCharacters(StringRef charactersToRemove) const
Returns a version of this string with a set of characters removed.
static String charToString(juce_wchar character)
Creates a string from a single character.
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.
static String getTextFromClipboard()
Gets the current clipboard's contents.
static void copyTextToClipboard(const String &text)
Copies a string of text onto the clipboard.
Makes repeated callbacks to a virtual method at a specified time interval.
bool canUndo() const
Returns true if there's at least one action in the list to undo.
bool canRedo() const
Returns true if there's at least one action in the list to redo.
#define TRANS(stringLiteral)
Uses the LocalisedStrings class to translate the given string literal.
@ paste
The command ID that should be used to send a "Paste from clipboard" command.
@ del
The command ID that should be used to send a "Delete" command.
@ redo
The command ID that should be used to send a "redo" command.
@ undo
The command ID that should be used to send a "undo" command.
@ cut
The command ID that should be used to send a "Cut" command.
@ copy
The command ID that should be used to send a "Copy to clipboard" command.
@ selectAll
The command ID that should be used to send a "Select all" command.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
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.
@ textChanged
Indicates that the visible text of a text element has changed.
@ textSelectionChanged
Indicates that the selection of a text element has changed.
float deltaY
The amount that the wheel has been moved in the Y axis.
float deltaX
The amount that the wheel has been moved in the X axis.
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
int CommandID
A type used to hold the unique ID for an application command.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
Contains status information about a mouse wheel event.
Holds information describing an application command.
Array< KeyPress > defaultKeypresses
A list of zero or more keypresses that should be used as the default keys for this command.
void setActive(bool isActive) noexcept
An easy way to set or remove the isDisabled bit in the structure's flags field.
void setInfo(const String &shortName, const String &description, const String &categoryName, int flags) noexcept
Sets a number of the structures values at once.
Contains contextual details about the invocation of a command.
CommandID commandID
The UID of the command that should be performed.
Defines a syntax highlighting colour scheme.
Can be used to save and restore the editor's caret position, selection state, etc.
State(const CodeEditorComponent &)
Creates an object containing the state of the given editor.
void restoreState(CodeEditorComponent &) const
Updates the given editor with this saved state.
String toString() const
Returns a stringified version of this state that can be used to recreate it later.
This class is used to invoke a range of text-editor navigation methods on an object,...