Browse Source

Fix for CodeDocument when opening files with a blank line at the end.

tags/2021-05-28
Julian Storer 16 years ago
parent
commit
f7636fe1a3
5 changed files with 163 additions and 126 deletions
  1. +76
    -59
      juce_amalgamated.cpp
  2. +6
    -4
      juce_amalgamated.h
  3. +70
    -54
      src/gui/components/code_editor/juce_CodeDocument.cpp
  4. +6
    -4
      src/gui/components/code_editor/juce_CodeDocument.h
  5. +5
    -5
      src/gui/components/code_editor/juce_CodeEditorComponent.cpp

+ 76
- 59
juce_amalgamated.cpp View File

@@ -43805,26 +43805,20 @@ class CodeDocumentLine
public:
CodeDocumentLine (const String& line_,
const int lineLength_,
const int lineStartInFile_) throw()
const int numNewLineChars,
const int lineStartInFile_)
: line (line_),
lineStartInFile (lineStartInFile_),
lineLength (lineLength_)
lineLength (lineLength_),
lineLengthWithoutNewLines (lineLength_ - numNewLineChars)
{
lineLengthWithoutNewLines = lineLength;

while (lineLengthWithoutNewLines > 0
&& (line [lineLengthWithoutNewLines - 1] == '\n'
|| line [lineLengthWithoutNewLines - 1] == '\r'))
{
--lineLengthWithoutNewLines;
}
}

~CodeDocumentLine() throw()
{
}

static void createLines (Array <CodeDocumentLine*>& newLines, const String& text) throw()
static void createLines (Array <CodeDocumentLine*>& newLines, const String& text)
{
const tchar* const t = (const tchar*) text;
int pos = 0;
@@ -43832,20 +43826,27 @@ public:
while (t [pos] != 0)
{
const int startOfLine = pos;
int numNewLineChars = 0;

while (t[pos] != 0)
{
if (t[pos] == T('\r'))
{
++numNewLineChars;
++pos;

if (t[pos] == T('\n'))
{
++numNewLineChars;
++pos;
}

break;
}

if (t[pos] == T('\n'))
{
++numNewLineChars;
++pos;
break;
}
@@ -43854,7 +43855,7 @@ public:
}

newLines.add (new CodeDocumentLine (String (t + startOfLine, pos - startOfLine),
pos - startOfLine,
pos - startOfLine, numNewLineChars,
startOfLine));
}

@@ -43882,17 +43883,19 @@ public:
int lineStartInFile, lineLength, lineLengthWithoutNewLines;
};

CodeDocument::Iterator::Iterator (CodeDocument* const document_) throw()
CodeDocument::Iterator::Iterator (CodeDocument* const document_)
: document (document_),
line (0),
position (0)
position (0),
currentLine (document_->lines[0])
{
}

CodeDocument::Iterator::Iterator (const CodeDocument::Iterator& other)
: document (other.document),
line (other.line),
position (other.position)
position (other.position),
currentLine (other.currentLine)
{
}

@@ -43901,6 +43904,7 @@ const CodeDocument::Iterator& CodeDocument::Iterator::operator= (const CodeDocum
document = other.document;
line = other.line;
position = other.position;
currentLine = other.currentLine;

return *this;
}
@@ -43909,73 +43913,63 @@ CodeDocument::Iterator::~Iterator() throw()
{
}

juce_wchar CodeDocument::Iterator::nextChar() throw()
juce_wchar CodeDocument::Iterator::nextChar()
{
if (line >= document->lines.size())
if (currentLine == 0)
return 0;

const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
jassert (currentLine == document->lines.getUnchecked (line));
const juce_wchar result = currentLine->line [position - currentLine->lineStartInFile];

if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
++line;

skip();
return result;
}

void CodeDocument::Iterator::skip() throw()
void CodeDocument::Iterator::skip()
{
if (line < document->lines.size())
if (currentLine != 0)
{
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
jassert (currentLine == document->lines.getUnchecked (line));

if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
{
++line;
currentLine = document->lines [line];
}
}
}

juce_wchar CodeDocument::Iterator::peekNextChar() const throw()
void CodeDocument::Iterator::skipToEndOfLine()
{
if (line >= document->lines.size())
return 0;
if (currentLine != 0)
{
jassert (currentLine == document->lines.getUnchecked (line));

const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
return currentLine->line [position - currentLine->lineStartInFile];
++line;
currentLine = document->lines [line];

if (currentLine != 0)
position = currentLine->lineStartInFile;
}
}

void CodeDocument::Iterator::skipWhitespace()
juce_wchar CodeDocument::Iterator::peekNextChar() const
{
while (line < document->lines.size())
{
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);

for (;;)
{
if (! CharacterFunctions::isWhitespace (currentLine->line [position - currentLine->lineStartInFile]))
return;
if (currentLine == 0)
return 0;

if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
{
++line;
break;
}
}
}
jassert (currentLine == document->lines.getUnchecked (line));
return currentLine->line [position - currentLine->lineStartInFile];
}

void CodeDocument::Iterator::skipToEndOfLine()
void CodeDocument::Iterator::skipWhitespace()
{
if (line < document->lines.size())
{
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
position = currentLine->lineStartInFile + currentLine->lineLength;
++line;
}
while (CharacterFunctions::isWhitespace (peekNextChar()))
skip();
}

bool CodeDocument::Iterator::isEOF() const throw()
{
return position >= document->getNumCharacters();
return currentLine == 0;
}

CodeDocument::Position::Position() throw()
@@ -44426,6 +44420,25 @@ const CodeDocument::Position CodeDocument::findWordBreakBefore (const Position&
return p;
}

void CodeDocument::checkLastLineStatus()
{
while (lines.size() > 0
&& lines.getLast()->lineLength == 0
&& (lines.size() == 1 || ! lines.getUnchecked (lines.size() - 2)->endsWithLineBreak()))
{
// remove any empty lines at the end if the preceding line doesn't end in a newline.
lines.removeLast();
}

const CodeDocumentLine* const lastLine = lines.getLast();

if (lastLine != 0 && lastLine->endsWithLineBreak())
{
// check that there's an empty line at the end if the preceding one ends in a newline..
lines.add (new CodeDocumentLine (String::empty, 0, 0, lastLine->lineStartInFile + lastLine->lineLength));
}
}

void CodeDocument::addListener (CodeDocument::Listener* const listener) throw()
{
listeners.addIfNotAlreadyThere (listener);
@@ -44540,6 +44553,8 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
lineStart += l->lineLength;
}

checkLastLineStatus();

const int newTextLength = text.length();
for (i = 0; i < positionsToMaintain.size(); ++i)
{
@@ -44640,6 +44655,8 @@ void CodeDocument::remove (const int startPos, const int endPos, const bool undo
l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
}

checkLastLineStatus();

const int totalChars = getNumCharacters();

for (i = 0; i < positionsToMaintain.size(); ++i)
@@ -45746,12 +45763,12 @@ const Colour CodeEditorComponent::getColourForTokenType (const int tokenType) co

void CodeEditorComponent::clearCachedIterators (const int firstLineToBeInvalid) throw()
{
for (int i = cachedIterators.size(); --i >= 0;)
if (cachedIterators.getUnchecked (i)->getLine() >= firstLineToBeInvalid)
cachedIterators.remove (i);
int i;
for (i = cachedIterators.size(); --i >= 0;)
if (cachedIterators.getUnchecked (i)->getLine() < firstLineToBeInvalid)
break;

// need to also clear the one before the invalid line
cachedIterators.removeLast();
cachedIterators.removeRange (jmax (0, i - 1), cachedIterators.size());
}

void CodeEditorComponent::updateCachedIterators (int maxLineNum)


+ 6
- 4
juce_amalgamated.h View File

@@ -20101,16 +20101,16 @@ public:
class Iterator
{
public:
Iterator (CodeDocument* const document) throw();
Iterator (CodeDocument* const document);
Iterator (const Iterator& other);
const Iterator& operator= (const Iterator& other) throw();
~Iterator() throw();

juce_wchar nextChar() throw();
juce_wchar nextChar();

juce_wchar peekNextChar() const throw();
juce_wchar peekNextChar() const;

void skip() throw();
void skip();

int getPosition() const throw() { return position; }

@@ -20124,6 +20124,7 @@ public:

private:
CodeDocument* document;
CodeDocumentLine* currentLine;
int line, position;
};

@@ -20147,6 +20148,7 @@ private:

void insert (const String& text, const int insertPos, const bool undoable);
void remove (const int startPos, const int endPos, const bool undoable);
void checkLastLineStatus();

CodeDocument (const CodeDocument&);
const CodeDocument& operator= (const CodeDocument&);


+ 70
- 54
src/gui/components/code_editor/juce_CodeDocument.cpp View File

@@ -36,26 +36,20 @@ class CodeDocumentLine
public:
CodeDocumentLine (const String& line_,
const int lineLength_,
const int lineStartInFile_) throw()
const int numNewLineChars,
const int lineStartInFile_)
: line (line_),
lineStartInFile (lineStartInFile_),
lineLength (lineLength_)
lineLength (lineLength_),
lineLengthWithoutNewLines (lineLength_ - numNewLineChars)
{
lineLengthWithoutNewLines = lineLength;
while (lineLengthWithoutNewLines > 0
&& (line [lineLengthWithoutNewLines - 1] == '\n'
|| line [lineLengthWithoutNewLines - 1] == '\r'))
{
--lineLengthWithoutNewLines;
}
}
~CodeDocumentLine() throw()
{
}
static void createLines (Array <CodeDocumentLine*>& newLines, const String& text) throw()
static void createLines (Array <CodeDocumentLine*>& newLines, const String& text)
{
const tchar* const t = (const tchar*) text;
int pos = 0;
@@ -63,20 +57,27 @@ public:
while (t [pos] != 0)
{
const int startOfLine = pos;
int numNewLineChars = 0;
while (t[pos] != 0)
{
if (t[pos] == T('\r'))
{
++numNewLineChars;
++pos;
if (t[pos] == T('\n'))
{
++numNewLineChars;
++pos;
}
break;
}
if (t[pos] == T('\n'))
{
++numNewLineChars;
++pos;
break;
}
@@ -85,7 +86,7 @@ public:
}
newLines.add (new CodeDocumentLine (String (t + startOfLine, pos - startOfLine),
pos - startOfLine,
pos - startOfLine, numNewLineChars,
startOfLine));
}
@@ -114,17 +115,19 @@ public:
};
//==============================================================================
CodeDocument::Iterator::Iterator (CodeDocument* const document_) throw()
CodeDocument::Iterator::Iterator (CodeDocument* const document_)
: document (document_),
line (0),
position (0)
position (0),
currentLine (document_->lines[0])
{
}
CodeDocument::Iterator::Iterator (const CodeDocument::Iterator& other)
: document (other.document),
line (other.line),
position (other.position)
position (other.position),
currentLine (other.currentLine)
{
}
@@ -133,6 +136,7 @@ const CodeDocument::Iterator& CodeDocument::Iterator::operator= (const CodeDocum
document = other.document;
line = other.line;
position = other.position;
currentLine = other.currentLine;
return *this;
}
@@ -141,73 +145,63 @@ CodeDocument::Iterator::~Iterator() throw()
{
}
juce_wchar CodeDocument::Iterator::nextChar() throw()
juce_wchar CodeDocument::Iterator::nextChar()
{
if (line >= document->lines.size())
if (currentLine == 0)
return 0;
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
jassert (currentLine == document->lines.getUnchecked (line));
const juce_wchar result = currentLine->line [position - currentLine->lineStartInFile];
if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
++line;
skip();
return result;
}
void CodeDocument::Iterator::skip() throw()
void CodeDocument::Iterator::skip()
{
if (line < document->lines.size())
if (currentLine != 0)
{
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
jassert (currentLine == document->lines.getUnchecked (line));
if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
{
++line;
currentLine = document->lines [line];
}
}
}
juce_wchar CodeDocument::Iterator::peekNextChar() const throw()
void CodeDocument::Iterator::skipToEndOfLine()
{
if (line >= document->lines.size())
return 0;
if (currentLine != 0)
{
jassert (currentLine == document->lines.getUnchecked (line));
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
return currentLine->line [position - currentLine->lineStartInFile];
++line;
currentLine = document->lines [line];
if (currentLine != 0)
position = currentLine->lineStartInFile;
}
}
void CodeDocument::Iterator::skipWhitespace()
juce_wchar CodeDocument::Iterator::peekNextChar() const
{
while (line < document->lines.size())
{
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
for (;;)
{
if (! CharacterFunctions::isWhitespace (currentLine->line [position - currentLine->lineStartInFile]))
return;
if (currentLine == 0)
return 0;
if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
{
++line;
break;
}
}
}
jassert (currentLine == document->lines.getUnchecked (line));
return currentLine->line [position - currentLine->lineStartInFile];
}
void CodeDocument::Iterator::skipToEndOfLine()
void CodeDocument::Iterator::skipWhitespace()
{
if (line < document->lines.size())
{
const CodeDocumentLine* const currentLine = document->lines.getUnchecked (line);
position = currentLine->lineStartInFile + currentLine->lineLength;
++line;
}
while (CharacterFunctions::isWhitespace (peekNextChar()))
skip();
}
bool CodeDocument::Iterator::isEOF() const throw()
{
return position >= document->getNumCharacters();
return currentLine == 0;
}
//==============================================================================
@@ -661,6 +655,24 @@ const CodeDocument::Position CodeDocument::findWordBreakBefore (const Position&
return p;
}
void CodeDocument::checkLastLineStatus()
{
while (lines.size() > 0
&& lines.getLast()->lineLength == 0
&& (lines.size() == 1 || ! lines.getUnchecked (lines.size() - 2)->endsWithLineBreak()))
{
// remove any empty lines at the end if the preceding line doesn't end in a newline.
lines.removeLast();
}
const CodeDocumentLine* const lastLine = lines.getLast();
if (lastLine != 0 && lastLine->endsWithLineBreak())
{
// check that there's an empty line at the end if the preceding one ends in a newline..
lines.add (new CodeDocumentLine (String::empty, 0, 0, lastLine->lineStartInFile + lastLine->lineLength));
}
}
//==============================================================================
void CodeDocument::addListener (CodeDocument::Listener* const listener) throw()
@@ -778,6 +790,8 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
lineStart += l->lineLength;
}
checkLastLineStatus();
const int newTextLength = text.length();
for (i = 0; i < positionsToMaintain.size(); ++i)
{
@@ -879,6 +893,8 @@ void CodeDocument::remove (const int startPos, const int endPos, const bool undo
l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
}
checkLastLineStatus();
const int totalChars = getNumCharacters();
for (i = 0; i < positionsToMaintain.size(); ++i)


+ 6
- 4
src/gui/components/code_editor/juce_CodeDocument.h View File

@@ -329,7 +329,7 @@ public:
class Iterator
{
public:
Iterator (CodeDocument* const document) throw();
Iterator (CodeDocument* const document);
Iterator (const Iterator& other);
const Iterator& operator= (const Iterator& other) throw();
~Iterator() throw();
@@ -337,13 +337,13 @@ public:
/** Reads the next character and returns it.
@see peekNextChar
*/
juce_wchar nextChar() throw();
juce_wchar nextChar();
/** Reads the next character without advancing the current position. */
juce_wchar peekNextChar() const throw();
juce_wchar peekNextChar() const;
/** Advances the position by one character. */
void skip() throw();
void skip();
/** Returns the position of the next character as its position within the
whole document.
@@ -364,6 +364,7 @@ public:
private:
CodeDocument* document;
CodeDocumentLine* currentLine;
int line, position;
};
@@ -388,6 +389,7 @@ private:
void insert (const String& text, const int insertPos, const bool undoable);
void remove (const int startPos, const int endPos, const bool undoable);
void checkLastLineStatus();
CodeDocument (const CodeDocument&);
const CodeDocument& operator= (const CodeDocument&);


+ 5
- 5
src/gui/components/code_editor/juce_CodeEditorComponent.cpp View File

@@ -1132,12 +1132,12 @@ const Colour CodeEditorComponent::getColourForTokenType (const int tokenType) co
void CodeEditorComponent::clearCachedIterators (const int firstLineToBeInvalid) throw()
{
for (int i = cachedIterators.size(); --i >= 0;)
if (cachedIterators.getUnchecked (i)->getLine() >= firstLineToBeInvalid)
cachedIterators.remove (i);
int i;
for (i = cachedIterators.size(); --i >= 0;)
if (cachedIterators.getUnchecked (i)->getLine() < firstLineToBeInvalid)
break;
// need to also clear the one before the invalid line
cachedIterators.removeLast();
cachedIterators.removeRange (jmax (0, i - 1), cachedIterators.size());
}
void CodeEditorComponent::updateCachedIterators (int maxLineNum)


Loading…
Cancel
Save