Browse Source

Minor optimisations. New method OwnedArray::insertArray(). Changed some CodeDocument inner class constructors to use references rather than pointers.

tags/2021-05-28
jules 13 years ago
parent
commit
d4ae8f3d55
8 changed files with 230 additions and 229 deletions
  1. +1
    -0
      .gitignore
  2. +1
    -1
      extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp
  3. +2
    -2
      modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp
  4. +3
    -3
      modules/juce_core/containers/juce_Array.h
  5. +40
    -0
      modules/juce_core/containers/juce_OwnedArray.h
  6. +123
    -146
      modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp
  7. +15
    -16
      modules/juce_gui_extra/code_editor/juce_CodeDocument.h
  8. +45
    -61
      modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp

+ 1
- 0
.gitignore View File

@@ -15,6 +15,7 @@
*.manifest.res *.manifest.res
*.o *.o
*.d *.d
*.sdf
xcuserdata xcuserdata
contents.xcworkspacedata contents.xcworkspacedata
.DS_Store .DS_Store


+ 1
- 1
extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp View File

@@ -142,7 +142,7 @@ void SourceCodeEditor::highlightLine (int lineNum, int characterIndex)
editor->getDocument().getNumLines() - editor->getNumLinesOnScreen()))); editor->getDocument().getNumLines() - editor->getNumLinesOnScreen())));
} }
editor->moveCaretTo (CodeDocument::Position (&editor->getDocument(), lineNum - 1, characterIndex), false);
editor->moveCaretTo (CodeDocument::Position (editor->getDocument(), lineNum - 1, characterIndex), false);
} }
void SourceCodeEditor::resized() void SourceCodeEditor::resized()


+ 2
- 2
modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp View File

@@ -135,10 +135,10 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
for (int m = info.numSamples; --m >= 0;) for (int m = info.numSamples; --m >= 0;)
{ {
const float alpha = (float) subSampleOffset; const float alpha = (float) subSampleOffset;
const float invAlpha = 1.0f - alpha;
for (int channel = 0; channel < channelsToProcess; ++channel) for (int channel = 0; channel < channelsToProcess; ++channel)
*destBuffers[channel]++ = srcBuffers[channel][bufferPos] * invAlpha + srcBuffers[channel][nextPos] * alpha;
*destBuffers[channel]++ = srcBuffers[channel][bufferPos]
+ alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]);
subSampleOffset += localRatio; subSampleOffset += localRatio;


+ 3
- 3
modules/juce_core/containers/juce_Array.h View File

@@ -460,17 +460,17 @@ public:
{ {
const ScopedLockType lock (getLock()); const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + numberOfElements); data.ensureAllocatedSize (numUsed + numberOfElements);
ElementType* insertPos;
ElementType* insertPos = data.elements;
if (isPositiveAndBelow (indexToInsertAt, numUsed)) if (isPositiveAndBelow (indexToInsertAt, numUsed))
{ {
insertPos = data.elements + indexToInsertAt;
insertPos += indexToInsertAt;
const int numberToMove = numUsed - indexToInsertAt; const int numberToMove = numUsed - indexToInsertAt;
memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ElementType)); memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ElementType));
} }
else else
{ {
insertPos = data.elements + numUsed;
insertPos += numUsed;
} }
numUsed += numberOfElements; numUsed += numberOfElements;


+ 40
- 0
modules/juce_core/containers/juce_OwnedArray.h View File

@@ -292,6 +292,46 @@ public:
} }
} }
/** Inserts an array of values into this array at a given position.
If the index is less than 0 or greater than the size of the array, the
new elements will be added to the end of the array.
Otherwise, they will be inserted into the array, moving all the later elements
along to make room.
@param indexToInsertAt the index at which the first new element should be inserted
@param newObjects the new values to add to the array
@param numberOfElements how many items are in the array
@see insert, add, addSorted, set
*/
void insertArray (int indexToInsertAt,
ObjectClass* const* newObjects,
int numberOfElements)
{
if (numberOfElements > 0)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + numberOfElements);
ObjectClass** insertPos = data.elements;
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
insertPos += indexToInsertAt;
const int numberToMove = numUsed - indexToInsertAt;
memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
}
else
{
insertPos += numUsed;
}
numUsed += numberOfElements;
while (--numberOfElements >= 0)
*insertPos++ = *newObjects++;
}
}
/** Appends a new object at the end of the array as long as the array doesn't /** Appends a new object at the end of the array as long as the array doesn't
already contain it. already contain it.


+ 123
- 146
modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp View File

@@ -123,15 +123,15 @@ public:
}; };
//============================================================================== //==============================================================================
CodeDocument::Iterator::Iterator (CodeDocument* const document_)
: document (document_),
CodeDocument::Iterator::Iterator (const CodeDocument& document_) noexcept
: document (&document_),
charPointer (nullptr), charPointer (nullptr),
line (0), line (0),
position (0) position (0)
{ {
} }
CodeDocument::Iterator::Iterator (const CodeDocument::Iterator& other)
CodeDocument::Iterator::Iterator (const CodeDocument::Iterator& other) noexcept
: document (other.document), : document (other.document),
charPointer (other.charPointer), charPointer (other.charPointer),
line (other.line), line (other.line),
@@ -153,13 +153,13 @@ CodeDocument::Iterator::~Iterator() noexcept
{ {
} }
juce_wchar CodeDocument::Iterator::nextChar()
juce_wchar CodeDocument::Iterator::nextChar() noexcept
{ {
for (;;) for (;;)
{ {
if (charPointer.getAddress() == nullptr) if (charPointer.getAddress() == nullptr)
{ {
CodeDocumentLine* const l = document->lines[line];
const CodeDocumentLine* const l = document->lines[line];
if (l == nullptr) if (l == nullptr)
return 0; return 0;
@@ -182,16 +182,16 @@ juce_wchar CodeDocument::Iterator::nextChar()
} }
} }
void CodeDocument::Iterator::skip()
void CodeDocument::Iterator::skip() noexcept
{ {
nextChar(); nextChar();
} }
void CodeDocument::Iterator::skipToEndOfLine()
void CodeDocument::Iterator::skipToEndOfLine() noexcept
{ {
if (charPointer.getAddress() == nullptr) if (charPointer.getAddress() == nullptr)
{ {
CodeDocumentLine* const l = document->lines[line];
const CodeDocumentLine* const l = document->lines[line];
if (l == nullptr) if (l == nullptr)
return; return;
@@ -204,11 +204,11 @@ void CodeDocument::Iterator::skipToEndOfLine()
charPointer = nullptr; charPointer = nullptr;
} }
juce_wchar CodeDocument::Iterator::peekNextChar() const
juce_wchar CodeDocument::Iterator::peekNextChar() const noexcept
{ {
if (charPointer.getAddress() == nullptr) if (charPointer.getAddress() == nullptr)
{ {
CodeDocumentLine* const l = document->lines[line];
const CodeDocumentLine* const l = document->lines[line];
if (l == nullptr) if (l == nullptr)
return 0; return 0;
@@ -221,11 +221,11 @@ juce_wchar CodeDocument::Iterator::peekNextChar() const
if (c != 0) if (c != 0)
return c; return c;
CodeDocumentLine* const l = document->lines [line + 1];
const CodeDocumentLine* const l = document->lines [line + 1];
return l == nullptr ? 0 : l->line[0]; return l == nullptr ? 0 : l->line[0];
} }
void CodeDocument::Iterator::skipWhitespace()
void CodeDocument::Iterator::skipWhitespace() noexcept
{ {
while (CharacterFunctions::isWhitespace (peekNextChar())) while (CharacterFunctions::isWhitespace (peekNextChar()))
skip(); skip();
@@ -238,23 +238,22 @@ bool CodeDocument::Iterator::isEOF() const noexcept
//============================================================================== //==============================================================================
CodeDocument::Position::Position() noexcept CodeDocument::Position::Position() noexcept
: owner (0), characterPos (0), line (0),
: owner (nullptr), characterPos (0), line (0),
indexInLine (0), positionMaintained (false) indexInLine (0), positionMaintained (false)
{ {
} }
CodeDocument::Position::Position (const CodeDocument* const ownerDocument,
CodeDocument::Position::Position (const CodeDocument& ownerDocument,
const int line_, const int indexInLine_) noexcept const int line_, const int indexInLine_) noexcept
: owner (const_cast <CodeDocument*> (ownerDocument)),
: owner (const_cast <CodeDocument*> (&ownerDocument)),
characterPos (0), line (line_), characterPos (0), line (line_),
indexInLine (indexInLine_), positionMaintained (false) indexInLine (indexInLine_), positionMaintained (false)
{ {
setLineAndIndex (line_, indexInLine_); setLineAndIndex (line_, indexInLine_);
} }
CodeDocument::Position::Position (const CodeDocument* const ownerDocument,
const int characterPos_) noexcept
: owner (const_cast <CodeDocument*> (ownerDocument)),
CodeDocument::Position::Position (const CodeDocument& ownerDocument, const int characterPos_) noexcept
: owner (const_cast <CodeDocument*> (&ownerDocument)),
positionMaintained (false) positionMaintained (false)
{ {
setPosition (characterPos_); setPosition (characterPos_);
@@ -324,25 +323,22 @@ void CodeDocument::Position::setLineAndIndex (const int newLineNum, const int ne
{ {
line = owner->lines.size() - 1; line = owner->lines.size() - 1;
CodeDocumentLine* const l = owner->lines.getUnchecked (line);
jassert (l != nullptr);
indexInLine = l->lineLengthWithoutNewLines;
characterPos = l->lineStartInFile + indexInLine;
const CodeDocumentLine& l = *owner->lines.getUnchecked (line);
indexInLine = l.lineLengthWithoutNewLines;
characterPos = l.lineStartInFile + indexInLine;
} }
else else
{ {
line = jmax (0, newLineNum); line = jmax (0, newLineNum);
CodeDocumentLine* const l = owner->lines.getUnchecked (line);
jassert (l != nullptr);
const CodeDocumentLine& l = *owner->lines.getUnchecked (line);
if (l->lineLengthWithoutNewLines > 0)
indexInLine = jlimit (0, l->lineLengthWithoutNewLines, newIndexInLine);
if (l.lineLengthWithoutNewLines > 0)
indexInLine = jlimit (0, l.lineLengthWithoutNewLines, newIndexInLine);
else else
indexInLine = 0; indexInLine = 0;
characterPos = l->lineStartInFile + indexInLine;
characterPos = l.lineStartInFile + indexInLine;
} }
} }
} }
@@ -366,15 +362,14 @@ void CodeDocument::Position::setPosition (const int newPosition)
{ {
for (int i = lineStart; i < lineEnd; ++i) for (int i = lineStart; i < lineEnd; ++i)
{ {
CodeDocumentLine* const l = owner->lines.getUnchecked (i);
int index = newPosition - l->lineStartInFile;
const CodeDocumentLine& l = *owner->lines.getUnchecked (i);
const int index = newPosition - l.lineStartInFile;
if (index >= 0 && (index < l->lineLength || i == lineEnd - 1))
if (index >= 0 && (index < l.lineLength || i == lineEnd - 1))
{ {
line = i; line = i;
indexInLine = jmin (l->lineLengthWithoutNewLines, index);
characterPos = l->lineStartInFile + indexInLine;
indexInLine = jmin (l.lineLengthWithoutNewLines, index);
characterPos = l.lineStartInFile + indexInLine;
} }
} }
@@ -383,9 +378,8 @@ void CodeDocument::Position::setPosition (const int newPosition)
else else
{ {
const int midIndex = (lineStart + lineEnd + 1) / 2; const int midIndex = (lineStart + lineEnd + 1) / 2;
CodeDocumentLine* const mid = owner->lines.getUnchecked (midIndex);
if (newPosition >= mid->lineStartInFile)
if (newPosition >= owner->lines.getUnchecked (midIndex)->lineStartInFile)
lineStart = midIndex; lineStart = midIndex;
else else
lineEnd = midIndex; lineEnd = midIndex;
@@ -405,9 +399,10 @@ void CodeDocument::Position::moveBy (int characterDelta)
// If moving right, make sure we don't get stuck between the \r and \n characters.. // If moving right, make sure we don't get stuck between the \r and \n characters..
if (line < owner->lines.size()) if (line < owner->lines.size())
{ {
CodeDocumentLine* const l = owner->lines.getUnchecked (line);
if (indexInLine + characterDelta < l->lineLength
&& indexInLine + characterDelta >= l->lineLengthWithoutNewLines + 1)
const CodeDocumentLine& l = *owner->lines.getUnchecked (line);
if (indexInLine + characterDelta < l.lineLength
&& indexInLine + characterDelta >= l.lineLengthWithoutNewLines + 1)
++characterDelta; ++characterDelta;
} }
} }
@@ -415,21 +410,21 @@ void CodeDocument::Position::moveBy (int characterDelta)
setPosition (characterPos + characterDelta); setPosition (characterPos + characterDelta);
} }
const CodeDocument::Position CodeDocument::Position::movedBy (const int characterDelta) const
CodeDocument::Position CodeDocument::Position::movedBy (const int characterDelta) const
{ {
CodeDocument::Position p (*this); CodeDocument::Position p (*this);
p.moveBy (characterDelta); p.moveBy (characterDelta);
return p; return p;
} }
const CodeDocument::Position CodeDocument::Position::movedByLines (const int deltaLines) const
CodeDocument::Position CodeDocument::Position::movedByLines (const int deltaLines) const
{ {
CodeDocument::Position p (*this); CodeDocument::Position p (*this);
p.setLineAndIndex (getLineNumber() + deltaLines, getIndexInLine()); p.setLineAndIndex (getLineNumber() + deltaLines, getIndexInLine());
return p; return p;
} }
const juce_wchar CodeDocument::Position::getCharacter() const
juce_wchar CodeDocument::Position::getCharacter() const
{ {
const CodeDocumentLine* const l = owner->lines [line]; const CodeDocumentLine* const l = owner->lines [line];
return l == nullptr ? 0 : l->line [getIndexInLine()]; return l == nullptr ? 0 : l->line [getIndexInLine()];
@@ -480,8 +475,8 @@ CodeDocument::~CodeDocument()
String CodeDocument::getAllContent() const String CodeDocument::getAllContent() const
{ {
return getTextBetween (Position (this, 0),
Position (this, lines.size(), 0));
return getTextBetween (Position (*this, 0),
Position (*this, lines.size(), 0));
} }
String CodeDocument::getTextBetween (const Position& start, const Position& end) const String CodeDocument::getTextBetween (const Position& start, const Position& end) const
@@ -505,22 +500,22 @@ String CodeDocument::getTextBetween (const Position& start, const Position& end)
for (int i = jmax (0, startLine); i <= maxLine; ++i) for (int i = jmax (0, startLine); i <= maxLine; ++i)
{ {
const CodeDocumentLine* line = lines.getUnchecked(i);
int len = line->lineLength;
const CodeDocumentLine& line = *lines.getUnchecked(i);
int len = line.lineLength;
if (i == startLine) if (i == startLine)
{ {
const int index = start.getIndexInLine(); const int index = start.getIndexInLine();
mo << line->line.substring (index, len);
mo << line.line.substring (index, len);
} }
else if (i == endLine) else if (i == endLine)
{ {
len = end.getIndexInLine(); len = end.getIndexInLine();
mo << line->line.substring (0, len);
mo << line.line.substring (0, len);
} }
else else
{ {
mo << line->line;
mo << line.line;
} }
} }
@@ -736,20 +731,13 @@ void CodeDocument::checkLastLineStatus()
} }
//============================================================================== //==============================================================================
void CodeDocument::addListener (CodeDocument::Listener* const listener) noexcept
{
listeners.add (listener);
}
void CodeDocument::removeListener (CodeDocument::Listener* const listener) noexcept
{
listeners.remove (listener);
}
void CodeDocument::addListener (CodeDocument::Listener* const l) noexcept { listeners.add (l); }
void CodeDocument::removeListener (CodeDocument::Listener* const l) noexcept { listeners.remove (l); }
void CodeDocument::sendListenerChangeMessage (const int startLine, const int endLine) void CodeDocument::sendListenerChangeMessage (const int startLine, const int endLine)
{ {
Position startPos (this, startLine, 0);
Position endPos (this, endLine, 0);
Position startPos (*this, startLine, 0);
Position endPos (*this, endLine, 0);
listeners.call (&CodeDocument::Listener::codeDocumentChanged, startPos, endPos); listeners.call (&CodeDocument::Listener::codeDocumentChanged, startPos, endPos);
} }
@@ -758,10 +746,8 @@ void CodeDocument::sendListenerChangeMessage (const int startLine, const int end
class CodeDocumentInsertAction : public UndoableAction class CodeDocumentInsertAction : public UndoableAction
{ {
public: public:
CodeDocumentInsertAction (CodeDocument& owner_, const String& text_, const int insertPos_) noexcept
: owner (owner_),
text (text_),
insertPos (insertPos_)
CodeDocumentInsertAction (CodeDocument& doc, const String& t, const int pos) noexcept
: owner (doc), text (t), insertPos (pos)
{ {
} }
@@ -784,77 +770,72 @@ public:
private: private:
CodeDocument& owner; CodeDocument& owner;
const String text; const String text;
int insertPos;
const int insertPos;
JUCE_DECLARE_NON_COPYABLE (CodeDocumentInsertAction); JUCE_DECLARE_NON_COPYABLE (CodeDocumentInsertAction);
}; };
void CodeDocument::insert (const String& text, const int insertPos, const bool undoable) void CodeDocument::insert (const String& text, const int insertPos, const bool undoable)
{ {
if (text.isEmpty())
return;
if (undoable)
if (text.isNotEmpty())
{ {
undoManager.perform (new CodeDocumentInsertAction (*this, text, insertPos));
}
else
{
Position pos (this, insertPos);
const int firstAffectedLine = pos.getLineNumber();
int lastAffectedLine = firstAffectedLine + 1;
CodeDocumentLine* const firstLine = lines [firstAffectedLine];
String textInsideOriginalLine (text);
if (firstLine != nullptr)
if (undoable)
{ {
const int index = pos.getIndexInLine();
textInsideOriginalLine = firstLine->line.substring (0, index)
+ textInsideOriginalLine
+ firstLine->line.substring (index);
undoManager.perform (new CodeDocumentInsertAction (*this, text, insertPos));
} }
else
{
Position pos (*this, insertPos);
const int firstAffectedLine = pos.getLineNumber();
int lastAffectedLine = firstAffectedLine + 1;
maximumLineLength = -1;
Array <CodeDocumentLine*> newLines;
CodeDocumentLine::createLines (newLines, textInsideOriginalLine);
jassert (newLines.size() > 0);
CodeDocumentLine* const firstLine = lines [firstAffectedLine];
String textInsideOriginalLine (text);
CodeDocumentLine* const newFirstLine = newLines.getUnchecked (0);
newFirstLine->lineStartInFile = firstLine != nullptr ? firstLine->lineStartInFile : 0;
lines.set (firstAffectedLine, newFirstLine);
if (firstLine != nullptr)
{
const int index = pos.getIndexInLine();
textInsideOriginalLine = firstLine->line.substring (0, index)
+ textInsideOriginalLine
+ firstLine->line.substring (index);
}
if (newLines.size() > 1)
{
for (int i = 1; i < newLines.size(); ++i)
maximumLineLength = -1;
Array <CodeDocumentLine*> newLines;
CodeDocumentLine::createLines (newLines, textInsideOriginalLine);
jassert (newLines.size() > 0);
CodeDocumentLine* const newFirstLine = newLines.getUnchecked (0);
newFirstLine->lineStartInFile = firstLine != nullptr ? firstLine->lineStartInFile : 0;
lines.set (firstAffectedLine, newFirstLine);
if (newLines.size() > 1)
{ {
CodeDocumentLine* const l = newLines.getUnchecked (i);
lines.insert (firstAffectedLine + i, l);
lines.insertArray (firstAffectedLine + 1, newLines.getRawDataPointer() + 1, newLines.size() - 1);
lastAffectedLine = lines.size();
} }
lastAffectedLine = lines.size();
}
int lineStart = newFirstLine->lineStartInFile;
for (int i = firstAffectedLine; i < lines.size(); ++i)
{
CodeDocumentLine& l = *lines.getUnchecked (i);
l.lineStartInFile = lineStart;
lineStart += l.lineLength;
}
int i, lineStart = newFirstLine->lineStartInFile;
for (i = firstAffectedLine; i < lines.size(); ++i)
{
CodeDocumentLine* const l = lines.getUnchecked (i);
l->lineStartInFile = lineStart;
lineStart += l->lineLength;
}
checkLastLineStatus();
checkLastLineStatus();
const int newTextLength = text.length();
for (int i = 0; i < positionsToMaintain.size(); ++i)
{
CodeDocument::Position& p = *positionsToMaintain.getUnchecked(i);
const int newTextLength = text.length();
for (i = 0; i < positionsToMaintain.size(); ++i)
{
CodeDocument::Position* const p = positionsToMaintain.getUnchecked(i);
if (p.getPosition() >= insertPos)
p.setPosition (p.getPosition() + newTextLength);
}
if (p->getPosition() >= insertPos)
p->setPosition (p->getPosition() + newTextLength);
sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);
} }
sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);
} }
} }
@@ -862,13 +843,11 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
class CodeDocumentDeleteAction : public UndoableAction class CodeDocumentDeleteAction : public UndoableAction
{ {
public: public:
CodeDocumentDeleteAction (CodeDocument& owner_, const int startPos_, const int endPos_) noexcept
: owner (owner_),
startPos (startPos_),
endPos (endPos_)
CodeDocumentDeleteAction (CodeDocument& doc, const int start, const int end) noexcept
: owner (doc), startPos (start), endPos (end),
removedText (doc.getTextBetween (CodeDocument::Position (doc, start),
CodeDocument::Position (doc, end)))
{ {
removedText = owner.getTextBetween (CodeDocument::Position (&owner, startPos),
CodeDocument::Position (&owner, endPos));
} }
bool perform() bool perform()
@@ -885,12 +864,12 @@ public:
return true; return true;
} }
int getSizeInUnits() { return removedText.length() + 32; }
int getSizeInUnits() { return (endPos - startPos) + 32; }
private: private:
CodeDocument& owner; CodeDocument& owner;
int startPos, endPos;
String removedText;
const int startPos, endPos;
const String removedText;
JUCE_DECLARE_NON_COPYABLE (CodeDocumentDeleteAction); JUCE_DECLARE_NON_COPYABLE (CodeDocumentDeleteAction);
}; };
@@ -906,57 +885,55 @@ void CodeDocument::remove (const int startPos, const int endPos, const bool undo
} }
else else
{ {
Position startPosition (this, startPos);
Position endPosition (this, endPos);
Position startPosition (*this, startPos);
Position endPosition (*this, endPos);
maximumLineLength = -1; maximumLineLength = -1;
const int firstAffectedLine = startPosition.getLineNumber(); const int firstAffectedLine = startPosition.getLineNumber();
const int endLine = endPosition.getLineNumber(); const int endLine = endPosition.getLineNumber();
int lastAffectedLine = firstAffectedLine + 1; int lastAffectedLine = firstAffectedLine + 1;
CodeDocumentLine* const firstLine = lines.getUnchecked (firstAffectedLine);
CodeDocumentLine& firstLine = *lines.getUnchecked (firstAffectedLine);
if (firstAffectedLine == endLine) if (firstAffectedLine == endLine)
{ {
firstLine->line = firstLine->line.substring (0, startPosition.getIndexInLine())
+ firstLine->line.substring (endPosition.getIndexInLine());
firstLine->updateLength();
firstLine.line = firstLine.line.substring (0, startPosition.getIndexInLine())
+ firstLine.line.substring (endPosition.getIndexInLine());
firstLine.updateLength();
} }
else else
{ {
lastAffectedLine = lines.size(); lastAffectedLine = lines.size();
CodeDocumentLine* const lastLine = lines.getUnchecked (endLine);
jassert (lastLine != nullptr);
CodeDocumentLine& lastLine = *lines.getUnchecked (endLine);
firstLine->line = firstLine->line.substring (0, startPosition.getIndexInLine())
+ lastLine->line.substring (endPosition.getIndexInLine());
firstLine->updateLength();
firstLine.line = firstLine.line.substring (0, startPosition.getIndexInLine())
+ lastLine.line.substring (endPosition.getIndexInLine());
firstLine.updateLength();
int numLinesToRemove = endLine - firstAffectedLine; int numLinesToRemove = endLine - firstAffectedLine;
lines.removeRange (firstAffectedLine + 1, numLinesToRemove); lines.removeRange (firstAffectedLine + 1, numLinesToRemove);
} }
int i;
for (i = firstAffectedLine + 1; i < lines.size(); ++i)
for (int i = firstAffectedLine + 1; i < lines.size(); ++i)
{ {
CodeDocumentLine* const l = lines.getUnchecked (i);
const CodeDocumentLine* const previousLine = lines.getUnchecked (i - 1);
l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
CodeDocumentLine& l = *lines.getUnchecked (i);
const CodeDocumentLine& previousLine = *lines.getUnchecked (i - 1);
l.lineStartInFile = previousLine.lineStartInFile + previousLine.lineLength;
} }
checkLastLineStatus(); checkLastLineStatus();
const int totalChars = getNumCharacters(); const int totalChars = getNumCharacters();
for (i = 0; i < positionsToMaintain.size(); ++i)
for (int i = 0; i < positionsToMaintain.size(); ++i)
{ {
CodeDocument::Position* p = positionsToMaintain.getUnchecked(i);
CodeDocument::Position& p = *positionsToMaintain.getUnchecked(i);
if (p->getPosition() > startPosition.getPosition())
p->setPosition (jmax (startPos, p->getPosition() + startPos - endPos));
if (p.getPosition() > startPosition.getPosition())
p.setPosition (jmax (startPos, p.getPosition() + startPos - endPos));
if (p->getPosition() > totalChars)
p->setPosition (totalChars);
if (p.getPosition() > totalChars)
p.setPosition (totalChars);
} }
sendListenerChangeMessage (firstAffectedLine, lastAffectedLine); sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);


+ 15
- 16
modules/juce_gui_extra/code_editor/juce_CodeDocument.h View File

@@ -77,7 +77,7 @@ public:
Lines are numbered from zero, and if the line or index are beyond the bounds of the document, Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
they will be adjusted to keep them within its limits. they will be adjusted to keep them within its limits.
*/ */
Position (const CodeDocument* ownerDocument,
Position (const CodeDocument& ownerDocument,
int line, int indexInLine) noexcept; int line, int indexInLine) noexcept;
/** Creates a position based on a character index in a document. /** Creates a position based on a character index in a document.
@@ -87,7 +87,7 @@ public:
If the position is beyond the range of the document, it'll be adjusted to keep it If the position is beyond the range of the document, it'll be adjusted to keep it
inside. inside.
*/ */
Position (const CodeDocument* ownerDocument,
Position (const CodeDocument& ownerDocument,
int charactersFromStartOfDocument) noexcept; int charactersFromStartOfDocument) noexcept;
/** Creates a copy of another position. /** Creates a copy of another position.
@@ -101,6 +101,7 @@ public:
~Position(); ~Position();
Position& operator= (const Position& other); Position& operator= (const Position& other);
bool operator== (const Position& other) const noexcept; bool operator== (const Position& other) const noexcept;
bool operator!= (const Position& other) const noexcept; bool operator!= (const Position& other) const noexcept;
@@ -159,18 +160,18 @@ public:
characters. characters.
@see moveBy @see moveBy
*/ */
const Position movedBy (int characterDelta) const;
Position movedBy (int characterDelta) const;
/** Returns a position which is the same as this one, moved up or down by the specified /** Returns a position which is the same as this one, moved up or down by the specified
number of lines. number of lines.
@see movedBy @see movedBy
*/ */
const Position movedByLines (int deltaLines) const;
Position movedByLines (int deltaLines) const;
/** Returns the character in the document at this position. /** Returns the character in the document at this position.
@see getLineText @see getLineText
*/ */
const juce_wchar getCharacter() const;
juce_wchar getCharacter() const;
/** Returns the line from the document that this position is within. /** Returns the line from the document that this position is within.
@see getCharacter, getLineNumber @see getCharacter, getLineNumber
@@ -334,32 +335,30 @@ public:
class JUCE_API Iterator class JUCE_API Iterator
{ {
public: public:
Iterator (CodeDocument* document);
Iterator (const Iterator& other);
Iterator (const CodeDocument& document) noexcept;
Iterator (const Iterator& other) noexcept;
Iterator& operator= (const Iterator& other) noexcept; Iterator& operator= (const Iterator& other) noexcept;
~Iterator() noexcept; ~Iterator() noexcept;
/** Reads the next character and returns it. /** Reads the next character and returns it.
@see peekNextChar @see peekNextChar
*/ */
juce_wchar nextChar();
juce_wchar nextChar() noexcept;
/** Reads the next character without advancing the current position. */ /** Reads the next character without advancing the current position. */
juce_wchar peekNextChar() const;
juce_wchar peekNextChar() const noexcept;
/** Advances the position by one character. */ /** Advances the position by one character. */
void skip();
void skip() noexcept;
/** Returns the position of the next character as its position within the
whole document.
*/
/** Returns the position as the number of characters from the start of the document. */
int getPosition() const noexcept { return position; } int getPosition() const noexcept { return position; }
/** Skips over any whitespace characters until the next character is non-whitespace. */ /** Skips over any whitespace characters until the next character is non-whitespace. */
void skipWhitespace();
void skipWhitespace() noexcept;
/** Skips forward until the next character will be the first character on the next line */ /** Skips forward until the next character will be the first character on the next line */
void skipToEndOfLine();
void skipToEndOfLine() noexcept;
/** Returns the line number of the next character. */ /** Returns the line number of the next character. */
int getLine() const noexcept { return line; } int getLine() const noexcept { return line; }
@@ -368,7 +367,7 @@ public:
bool isEOF() const noexcept; bool isEOF() const noexcept;
private: private:
CodeDocument* document;
const CodeDocument* document;
mutable String::CharPointerType charPointer; mutable String::CharPointerType charPointer;
int line, position; int line, position;
}; };


+ 45
- 61
modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp View File

@@ -45,7 +45,7 @@ public:
} }
else if (lineNum < document.getNumLines()) else if (lineNum < document.getNumLines())
{ {
const CodeDocument::Position pos (&document, lineNum, 0);
const CodeDocument::Position pos (document, lineNum, 0);
createTokens (pos.getPosition(), pos.getLineText(), createTokens (pos.getPosition(), pos.getLineText(),
source, *tokeniser, newTokens); source, *tokeniser, newTokens);
} }
@@ -59,7 +59,7 @@ public:
{ {
const String line (document.getLine (lineNum)); const String line (document.getLine (lineNum));
CodeDocument::Position lineStart (&document, lineNum, 0), lineEnd (&document, lineNum + 1, 0);
CodeDocument::Position lineStart (document, lineNum, 0), lineEnd (document, lineNum + 1, 0);
newHighlightStart = indexToColumn (jmax (0, selectionStart.getPosition() - lineStart.getPosition()), newHighlightStart = indexToColumn (jmax (0, selectionStart.getPosition() - lineStart.getPosition()),
line, spacesPerTab); line, spacesPerTab);
newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selectionEnd.getPosition() - lineStart.getPosition()), newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selectionEnd.getPosition() - lineStart.getPosition()),
@@ -71,24 +71,9 @@ public:
highlightColumnStart = newHighlightStart; highlightColumnStart = newHighlightStart;
highlightColumnEnd = newHighlightEnd; highlightColumnEnd = newHighlightEnd;
} }
else
else if (tokens == newTokens)
{ {
if (tokens.size() == newTokens.size())
{
bool allTheSame = true;
for (int i = newTokens.size(); --i >= 0;)
{
if (tokens.getReference(i) != newTokens.getReference(i))
{
allTheSame = false;
break;
}
}
if (allTheSame)
return false;
}
return false;
} }
tokens.swapWithArray (newTokens); tokens.swapWithArray (newTokens);
@@ -144,14 +129,14 @@ public:
private: private:
struct SyntaxToken struct SyntaxToken
{ {
SyntaxToken (const String& text_, const int type) noexcept
: text (text_), tokenType (type), width (-1.0f)
SyntaxToken (const String& t, const int type) noexcept
: text (t), tokenType (type), width (-1.0f)
{ {
} }
bool operator!= (const SyntaxToken& other) const noexcept
bool operator== (const SyntaxToken& other) const noexcept
{ {
return text != other.text || tokenType != other.tokenType;
return tokenType == other.tokenType && text == other.text;
} }
String text; String text;
@@ -321,13 +306,13 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& document_,
horizontalScrollBar (false), horizontalScrollBar (false),
codeTokeniser (codeTokeniser_) codeTokeniser (codeTokeniser_)
{ {
caretPos = CodeDocument::Position (&document_, 0, 0);
caretPos = CodeDocument::Position (document_, 0, 0);
caretPos.setPositionMaintained (true); caretPos.setPositionMaintained (true);
selectionStart = CodeDocument::Position (&document_, 0, 0);
selectionStart = CodeDocument::Position (document_, 0, 0);
selectionStart.setPositionMaintained (true); selectionStart.setPositionMaintained (true);
selectionEnd = CodeDocument::Position (&document_, 0, 0);
selectionEnd = CodeDocument::Position (document_, 0, 0);
selectionEnd.setPositionMaintained (true); selectionEnd.setPositionMaintained (true);
setOpaque (true); setOpaque (true);
@@ -509,8 +494,8 @@ void CodeEditorComponent::rebuildLineTokens()
jassert (numNeeded == lines.size()); jassert (numNeeded == lines.size());
CodeDocument::Iterator source (&document);
getIteratorForPosition (CodeDocument::Position (&document, firstLineOnScreen, 0).getPosition(), source);
CodeDocument::Iterator source (document);
getIteratorForPosition (CodeDocument::Position (document, firstLineOnScreen, 0).getPosition(), source);
for (int i = 0; i < numNeeded; ++i) for (int i = 0; i < numNeeded; ++i)
{ {
@@ -686,7 +671,7 @@ CodeDocument::Position CodeEditorComponent::getPositionAt (int x, int y)
const int column = roundToInt ((x - (getGutterSize() - xOffset * charWidth)) / charWidth); const int column = roundToInt ((x - (getGutterSize() - xOffset * charWidth)) / charWidth);
const int index = columnToIndex (line, column); const int index = columnToIndex (line, column);
return CodeDocument::Position (&document, line, index);
return CodeDocument::Position (document, line, index);
} }
//============================================================================== //==============================================================================
@@ -727,25 +712,25 @@ void CodeEditorComponent::insertTabAtCaret()
bool CodeEditorComponent::deleteWhitespaceBackwardsToTabStop() bool CodeEditorComponent::deleteWhitespaceBackwardsToTabStop()
{ {
if (! getHighlightedRegion().isEmpty())
return false;
for (;;)
if (getHighlightedRegion().isEmpty())
{ {
const int currentColumn = indexToColumn (caretPos.getLineNumber(), caretPos.getIndexInLine());
for (;;)
{
const int currentColumn = indexToColumn (caretPos.getLineNumber(), caretPos.getIndexInLine());
if (currentColumn <= 0 || (currentColumn % spacesPerTab) == 0)
break;
if (currentColumn <= 0 || (currentColumn % spacesPerTab) == 0)
break;
moveCaretLeft (false, true);
}
moveCaretLeft (false, true);
}
const String selected (getTextInRange (getHighlightedRegion()));
const String selected (getTextInRange (getHighlightedRegion()));
if (selected.isNotEmpty() && selected.trim().isEmpty())
{
cut();
return true;
if (selected.isNotEmpty() && selected.trim().isEmpty())
{
cut();
return true;
}
} }
return false; return false;
@@ -776,8 +761,8 @@ void CodeEditorComponent::indentSelectedLines (const int spacesToAdd)
if (nonWhitespaceStart > 0 || lineText.trimStart().isNotEmpty()) if (nonWhitespaceStart > 0 || lineText.trimStart().isNotEmpty())
{ {
const CodeDocument::Position wsStart (&document, line, 0);
const CodeDocument::Position wsEnd (&document, line, nonWhitespaceStart);
const CodeDocument::Position wsStart (document, line, 0);
const CodeDocument::Position wsEnd (document, line, nonWhitespaceStart);
const int numLeadingSpaces = indexToColumn (line, wsEnd.getIndexInLine()); const int numLeadingSpaces = indexToColumn (line, wsEnd.getIndexInLine());
const int newNumLeadingSpaces = jmax (0, numLeadingSpaces + spacesToAdd); const int newNumLeadingSpaces = jmax (0, numLeadingSpaces + spacesToAdd);
@@ -803,7 +788,6 @@ void CodeEditorComponent::cut()
bool CodeEditorComponent::copyToClipboard() bool CodeEditorComponent::copyToClipboard()
{ {
newTransaction(); newTransaction();
const String selection (document.getTextBetween (selectionStart, selectionEnd)); const String selection (document.getTextBetween (selectionStart, selectionEnd));
if (selection.isNotEmpty()) if (selection.isNotEmpty())
@@ -876,7 +860,7 @@ bool CodeEditorComponent::moveCaretDown (const bool selecting)
newTransaction(); newTransaction();
if (caretPos.getLineNumber() == document.getNumLines() - 1) if (caretPos.getLineNumber() == document.getNumLines() - 1)
moveCaretTo (CodeDocument::Position (&document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), selecting);
moveCaretTo (CodeDocument::Position (document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), selecting);
else else
moveLineDelta (1, selecting); moveLineDelta (1, selecting);
@@ -888,7 +872,7 @@ bool CodeEditorComponent::moveCaretUp (const bool selecting)
newTransaction(); newTransaction();
if (caretPos.getLineNumber() == 0) if (caretPos.getLineNumber() == 0)
moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting);
moveCaretTo (CodeDocument::Position (document, 0, 0), selecting);
else else
moveLineDelta (-1, selecting); moveLineDelta (-1, selecting);
@@ -936,7 +920,7 @@ bool CodeEditorComponent::scrollDown()
bool CodeEditorComponent::moveCaretToTop (const bool selecting) bool CodeEditorComponent::moveCaretToTop (const bool selecting)
{ {
newTransaction(); newTransaction();
moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting);
moveCaretTo (CodeDocument::Position (document, 0, 0), selecting);
return true; return true;
} }
@@ -949,21 +933,21 @@ bool CodeEditorComponent::moveCaretToStartOfLine (const bool selecting)
if (index >= caretPos.getIndexInLine() && caretPos.getIndexInLine() > 0) if (index >= caretPos.getIndexInLine() && caretPos.getIndexInLine() > 0)
index = 0; index = 0;
moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), index), selecting);
moveCaretTo (CodeDocument::Position (document, caretPos.getLineNumber(), index), selecting);
return true; return true;
} }
bool CodeEditorComponent::moveCaretToEnd (const bool selecting) bool CodeEditorComponent::moveCaretToEnd (const bool selecting)
{ {
newTransaction(); newTransaction();
moveCaretTo (CodeDocument::Position (&document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), selecting);
moveCaretTo (CodeDocument::Position (document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), selecting);
return true; return true;
} }
bool CodeEditorComponent::moveCaretToEndOfLine (const bool selecting) bool CodeEditorComponent::moveCaretToEndOfLine (const bool selecting)
{ {
newTransaction(); newTransaction();
moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), std::numeric_limits<int>::max()), selecting);
moveCaretTo (CodeDocument::Position (document, caretPos.getLineNumber(), std::numeric_limits<int>::max()), selecting);
return true; return true;
} }
@@ -1031,8 +1015,8 @@ bool CodeEditorComponent::deleteForwards (const bool moveInWholeWordSteps)
bool CodeEditorComponent::selectAll() bool CodeEditorComponent::selectAll()
{ {
newTransaction(); newTransaction();
moveCaretTo (CodeDocument::Position (&document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), false);
moveCaretTo (CodeDocument::Position (&document, 0, 0), true);
moveCaretTo (CodeDocument::Position (document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), false);
moveCaretTo (CodeDocument::Position (document, 0, 0), true);
return true; return true;
} }
@@ -1070,14 +1054,14 @@ Range<int> CodeEditorComponent::getHighlightedRegion() const
void CodeEditorComponent::setHighlightedRegion (const Range<int>& newRange) void CodeEditorComponent::setHighlightedRegion (const Range<int>& newRange)
{ {
moveCaretTo (CodeDocument::Position (&document, newRange.getStart()), false);
moveCaretTo (CodeDocument::Position (&document, newRange.getEnd()), true);
moveCaretTo (CodeDocument::Position (document, newRange.getStart()), false);
moveCaretTo (CodeDocument::Position (document, newRange.getEnd()), true);
} }
String CodeEditorComponent::getTextInRange (const Range<int>& range) const String CodeEditorComponent::getTextInRange (const Range<int>& range) const
{ {
return document.getTextBetween (CodeDocument::Position (&document, range.getStart()),
CodeDocument::Position (&document, range.getEnd()));
return document.getTextBetween (CodeDocument::Position (document, range.getStart()),
CodeDocument::Position (document, range.getEnd()));
} }
//============================================================================== //==============================================================================
@@ -1379,7 +1363,7 @@ void CodeEditorComponent::updateCachedIterators (int maxLineNum)
const int linesBetweenCachedSources = jmax (10, document.getNumLines() / maxNumCachedPositions); const int linesBetweenCachedSources = jmax (10, document.getNumLines() / maxNumCachedPositions);
if (cachedIterators.size() == 0) if (cachedIterators.size() == 0)
cachedIterators.add (new CodeDocument::Iterator (&document));
cachedIterators.add (new CodeDocument::Iterator (document));
if (codeTokeniser != nullptr) if (codeTokeniser != nullptr)
{ {
@@ -1458,8 +1442,8 @@ CodeEditorComponent::State::State (const State& other) noexcept
void CodeEditorComponent::State::restoreState (CodeEditorComponent& editor) const void CodeEditorComponent::State::restoreState (CodeEditorComponent& editor) const
{ {
editor.moveCaretTo (CodeDocument::Position (&editor.getDocument(), lastSelectionEnd), false);
editor.moveCaretTo (CodeDocument::Position (&editor.getDocument(), lastCaretPos), true);
editor.moveCaretTo (CodeDocument::Position (editor.getDocument(), lastSelectionEnd), false);
editor.moveCaretTo (CodeDocument::Position (editor.getDocument(), lastCaretPos), true);
if (lastTopLine > 0 && lastTopLine < editor.getDocument().getNumLines()) if (lastTopLine > 0 && lastTopLine < editor.getDocument().getNumLines())
editor.scrollToLine (lastTopLine); editor.scrollToLine (lastTopLine);


Loading…
Cancel
Save