bool update (CodeDocument& codeDoc, int lineNum, CodeDocument::Iterator& source, CodeTokeniser* tokeniser, const int tabSpaces, const CodeDocument::Position& selStart, const CodeDocument::Position& selEnd) { Array <SyntaxToken> newTokens; newTokens.ensureStorageAllocated (8); if (tokeniser == nullptr) { const String line (codeDoc.getLine (lineNum)); addToken (newTokens, line, line.length(), -1); } else if (lineNum < codeDoc.getNumLines()) { const CodeDocument::Position pos (codeDoc, lineNum, 0); createTokens (pos.getPosition(), pos.getLineText(), source, *tokeniser, newTokens); } replaceTabsWithSpaces (newTokens, tabSpaces); int newHighlightStart = 0; int newHighlightEnd = 0; if (selStart.getLineNumber() <= lineNum && selEnd.getLineNumber() >= lineNum) { const String line (codeDoc.getLine (lineNum)); CodeDocument::Position lineStart (codeDoc, lineNum, 0), lineEnd (codeDoc, lineNum + 1, 0); newHighlightStart = indexToColumn (jmax (0, selStart.getPosition() - lineStart.getPosition()), line, tabSpaces); newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selEnd.getPosition() - lineStart.getPosition()), line, tabSpaces); } if (newHighlightStart != highlightColumnStart || newHighlightEnd != highlightColumnEnd) { highlightColumnStart = newHighlightStart; highlightColumnEnd = newHighlightEnd; } else if (tokens == newTokens) { return false; } tokens.swapWith (newTokens); return true; }
const Rectangle CodeEditorComponent::getCharacterBounds (const CodeDocument::Position& pos) const throw() { return Rectangle (roundToInt ((gutter - xOffset * charWidth) + indexToColumn (pos.getLineNumber(), pos.getIndexInLine()) * charWidth), (pos.getLineNumber() - firstLineOnScreen) * lineHeight, roundToInt (charWidth), lineHeight); }
bool CodeEditorComponent::deleteWhitespaceBackwardsToTabStop() { if (getHighlightedRegion().isEmpty()) { for (;;) { const int currentColumn = indexToColumn (caretPos.getLineNumber(), caretPos.getIndexInLine()); if (currentColumn <= 0 || (currentColumn % spacesPerTab) == 0) break; moveCaretLeft (false, true); } const String selected (getTextInRange (getHighlightedRegion())); if (selected.isNotEmpty() && selected.trim().isEmpty()) { cut(); return true; } } return false; }
void CodeEditorComponent::scrollToKeepCaretOnScreen() { if (caretPos.getLineNumber() < firstLineOnScreen) scrollBy (caretPos.getLineNumber() - firstLineOnScreen); else if (caretPos.getLineNumber() >= firstLineOnScreen + linesOnScreen) scrollBy (caretPos.getLineNumber() - (firstLineOnScreen + linesOnScreen - 1)); const int column = indexToColumn (caretPos.getLineNumber(), caretPos.getIndexInLine()); if (column >= xOffset + columnsOnScreen - 1) scrollToColumn (column + 1 - columnsOnScreen); else if (column < xOffset) scrollToColumn (column); }
void CodeEditorComponent::moveLineDelta (const int delta, const bool selecting) { CodeDocument::Position pos (caretPos); const int newLineNum = pos.getLineNumber() + delta; if (columnToTryToMaintain < 0) columnToTryToMaintain = indexToColumn (pos.getLineNumber(), pos.getIndexInLine()); pos.setLineAndIndex (newLineNum, columnToIndex (newLineNum, columnToTryToMaintain)); const int colToMaintain = columnToTryToMaintain; moveCaretTo (pos, selecting); columnToTryToMaintain = colToMaintain; }
void CodeEditorComponent::scrollToKeepCaretOnScreen() { if (getWidth() > 0 && getHeight() > 0) { const int caretLine = caretPos.getLineNumber(); scrollToKeepLinesOnScreen (Range<int> (caretLine, caretLine)); const int column = indexToColumn (caretPos.getLineNumber(), caretPos.getIndexInLine()); if (column >= xOffset + columnsOnScreen - 1) scrollToColumn (column + 1 - columnsOnScreen); else if (column < xOffset) scrollToColumn (column); } }
void CodeEditorComponent::insertTabAtCaret() { if (CharacterFunctions::isWhitespace (caretPos.getCharacter()) && caretPos.getLineNumber() == caretPos.movedBy (1).getLineNumber()) { moveCaretTo (document.findWordBreakAfter (caretPos), false); } if (useSpacesForTabs) { const int caretCol = indexToColumn (caretPos.getLineNumber(), caretPos.getIndexInLine()); const int spacesNeeded = spacesPerTab - (caretCol % spacesPerTab); insertTextAtCaret (String::repeatedString (T(" "), spacesNeeded)); } else { insertTextAtCaret (T("\t")); } }
bool CodeEditorComponent::skipBackwardsToPreviousTab() { const String currentLineText (caretPos.getLineText().removeCharacters ("\r\n")); const int currentIndex = caretPos.getIndexInLine(); if (currentLineText.isNotEmpty() && currentLineText.length() == currentIndex) { const int currentLine = caretPos.getLineNumber(); const int currentColumn = indexToColumn (currentLine, currentIndex); const int previousTabColumn = (currentColumn - 1) - ((currentColumn - 1) % spacesPerTab); const int previousTabIndex = columnToIndex (currentLine, previousTabColumn); if (currentLineText.substring (previousTabIndex, currentIndex).trim().isEmpty()) { selectionStart.moveBy (previousTabIndex - currentIndex); return true; } } return false; }
void CodeEditorComponent::indentSelectedLines (const int spacesToAdd) { newTransaction(); CodeDocument::Position oldSelectionStart (selectionStart), oldSelectionEnd (selectionEnd), oldCaret (caretPos); oldSelectionStart.setPositionMaintained (true); oldSelectionEnd.setPositionMaintained (true); oldCaret.setPositionMaintained (true); const int lineStart = selectionStart.getLineNumber(); int lineEnd = selectionEnd.getLineNumber(); if (lineEnd > lineStart && selectionEnd.getIndexInLine() == 0) --lineEnd; for (int line = lineStart; line <= lineEnd; ++line) { const String lineText (document.getLine (line)); const int nonWhitespaceStart = CodeEditorHelpers::findFirstNonWhitespaceChar (lineText); if (nonWhitespaceStart > 0 || lineText.trimStart().isNotEmpty()) { const CodeDocument::Position wsStart (document, line, 0); const CodeDocument::Position wsEnd (document, line, nonWhitespaceStart); const int numLeadingSpaces = indexToColumn (line, wsEnd.getIndexInLine()); const int newNumLeadingSpaces = jmax (0, numLeadingSpaces + spacesToAdd); if (newNumLeadingSpaces != numLeadingSpaces) { document.deleteSection (wsStart, wsEnd); document.insertText (wsStart, getTabString (newNumLeadingSpaces)); } } } selectionStart = oldSelectionStart; selectionEnd = oldSelectionEnd; caretPos = oldCaret; }
bool update (CodeDocument& document, int lineNum, CodeDocument::Iterator& source, CodeTokeniser* analyser, const int spacesPerTab, const CodeDocument::Position& selectionStart, const CodeDocument::Position& selectionEnd) { OwnedArray <SyntaxToken> newTokens; if (analyser == 0) { newTokens.add (new SyntaxToken (document.getLine (lineNum), -1)); } else if (lineNum < document.getNumLines()) { const CodeDocument::Position pos (&document, lineNum, 0); createTokens (pos.getPosition(), pos.getLineText(), source, analyser, newTokens); } replaceTabsWithSpaces (newTokens, spacesPerTab); int newHighlightStart = 0; int newHighlightEnd = 0; if (selectionStart.getLineNumber() <= lineNum && selectionEnd.getLineNumber() >= lineNum) { const String line (document.getLine (lineNum)); CodeDocument::Position lineStart (&document, lineNum, 0), lineEnd (&document, lineNum + 1, 0); newHighlightStart = indexToColumn (jmax (0, selectionStart.getPosition() - lineStart.getPosition()), line, spacesPerTab); newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selectionEnd.getPosition() - lineStart.getPosition()), line, spacesPerTab); } if (newHighlightStart != highlightColumnStart || newHighlightEnd != highlightColumnEnd) { highlightColumnStart = newHighlightStart; highlightColumnEnd = newHighlightEnd; } else { if (tokens.size() == newTokens.size()) { bool allTheSame = true; for (int i = newTokens.size(); --i >= 0;) { if (*tokens.getUnchecked(i) != *newTokens.getUnchecked(i)) { allTheSame = false; break; } } if (allTheSame) return false; } } tokens.swapWithArray (newTokens); return true; }