migrating to the latest JUCE version
This commit is contained in:
@ -1,74 +1,74 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
CPlusPlusCodeTokeniser::CPlusPlusCodeTokeniser() {}
|
||||
CPlusPlusCodeTokeniser::~CPlusPlusCodeTokeniser() {}
|
||||
|
||||
int CPlusPlusCodeTokeniser::readNextToken (CodeDocument::Iterator& source)
|
||||
{
|
||||
return CppTokeniserFunctions::readNextToken (source);
|
||||
}
|
||||
|
||||
CodeEditorComponent::ColourScheme CPlusPlusCodeTokeniser::getDefaultColourScheme()
|
||||
{
|
||||
struct Type
|
||||
{
|
||||
const char* name;
|
||||
uint32 colour;
|
||||
};
|
||||
|
||||
const Type types[] =
|
||||
{
|
||||
{ "Error", 0xffcc0000 },
|
||||
{ "Comment", 0xff00aa00 },
|
||||
{ "Keyword", 0xff0000cc },
|
||||
{ "Operator", 0xff225500 },
|
||||
{ "Identifier", 0xff000000 },
|
||||
{ "Integer", 0xff880000 },
|
||||
{ "Float", 0xff885500 },
|
||||
{ "String", 0xff990099 },
|
||||
{ "Bracket", 0xff000055 },
|
||||
{ "Punctuation", 0xff004400 },
|
||||
{ "Preprocessor Text", 0xff660000 }
|
||||
};
|
||||
|
||||
CodeEditorComponent::ColourScheme cs;
|
||||
|
||||
for (auto& t : types)
|
||||
cs.set (t.name, Colour (t.colour));
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) noexcept
|
||||
{
|
||||
return CppTokeniserFunctions::isReservedKeyword (token.getCharPointer(), token.length());
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
CPlusPlusCodeTokeniser::CPlusPlusCodeTokeniser() {}
|
||||
CPlusPlusCodeTokeniser::~CPlusPlusCodeTokeniser() {}
|
||||
|
||||
int CPlusPlusCodeTokeniser::readNextToken (CodeDocument::Iterator& source)
|
||||
{
|
||||
return CppTokeniserFunctions::readNextToken (source);
|
||||
}
|
||||
|
||||
CodeEditorComponent::ColourScheme CPlusPlusCodeTokeniser::getDefaultColourScheme()
|
||||
{
|
||||
struct Type
|
||||
{
|
||||
const char* name;
|
||||
uint32 colour;
|
||||
};
|
||||
|
||||
const Type types[] =
|
||||
{
|
||||
{ "Error", 0xffcc0000 },
|
||||
{ "Comment", 0xff00aa00 },
|
||||
{ "Keyword", 0xff0000cc },
|
||||
{ "Operator", 0xff225500 },
|
||||
{ "Identifier", 0xff000000 },
|
||||
{ "Integer", 0xff880000 },
|
||||
{ "Float", 0xff885500 },
|
||||
{ "String", 0xff990099 },
|
||||
{ "Bracket", 0xff000055 },
|
||||
{ "Punctuation", 0xff004400 },
|
||||
{ "Preprocessor Text", 0xff660000 }
|
||||
};
|
||||
|
||||
CodeEditorComponent::ColourScheme cs;
|
||||
|
||||
for (auto& t : types)
|
||||
cs.set (t.name, Colour (t.colour));
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) noexcept
|
||||
{
|
||||
return CppTokeniserFunctions::isReservedKeyword (token.getCharPointer(), token.length());
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,72 +1,72 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A simple lexical analyser for syntax colouring of C++ code.
|
||||
|
||||
@see CodeEditorComponent, CodeDocument
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CPlusPlusCodeTokeniser : public CodeTokeniser
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
CPlusPlusCodeTokeniser();
|
||||
~CPlusPlusCodeTokeniser() override;
|
||||
|
||||
//==============================================================================
|
||||
int readNextToken (CodeDocument::Iterator&) override;
|
||||
CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
|
||||
|
||||
/** This is a handy method for checking whether a string is a c++ reserved keyword. */
|
||||
static bool isReservedKeyword (const String& token) noexcept;
|
||||
|
||||
/** The token values returned by this tokeniser. */
|
||||
enum TokenType
|
||||
{
|
||||
tokenType_error = 0,
|
||||
tokenType_comment,
|
||||
tokenType_keyword,
|
||||
tokenType_operator,
|
||||
tokenType_identifier,
|
||||
tokenType_integer,
|
||||
tokenType_float,
|
||||
tokenType_string,
|
||||
tokenType_bracket,
|
||||
tokenType_punctuation,
|
||||
tokenType_preprocessor
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JUCE_LEAK_DETECTOR (CPlusPlusCodeTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A simple lexical analyser for syntax colouring of C++ code.
|
||||
|
||||
@see CodeEditorComponent, CodeDocument
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CPlusPlusCodeTokeniser : public CodeTokeniser
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
CPlusPlusCodeTokeniser();
|
||||
~CPlusPlusCodeTokeniser() override;
|
||||
|
||||
//==============================================================================
|
||||
int readNextToken (CodeDocument::Iterator&) override;
|
||||
CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
|
||||
|
||||
/** This is a handy method for checking whether a string is a c++ reserved keyword. */
|
||||
static bool isReservedKeyword (const String& token) noexcept;
|
||||
|
||||
/** The token values returned by this tokeniser. */
|
||||
enum TokenType
|
||||
{
|
||||
tokenType_error = 0,
|
||||
tokenType_comment,
|
||||
tokenType_keyword,
|
||||
tokenType_operator,
|
||||
tokenType_identifier,
|
||||
tokenType_integer,
|
||||
tokenType_float,
|
||||
tokenType_string,
|
||||
tokenType_bracket,
|
||||
tokenType_punctuation,
|
||||
tokenType_preprocessor
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JUCE_LEAK_DETECTOR (CPlusPlusCodeTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,450 +1,450 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class CodeDocumentLine;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class for storing and manipulating a source code file.
|
||||
|
||||
When using a CodeEditorComponent, it takes one of these as its source object.
|
||||
|
||||
The CodeDocument stores its content as an array of lines, which makes it
|
||||
quick to insert and delete.
|
||||
|
||||
@see CodeEditorComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CodeDocument
|
||||
{
|
||||
public:
|
||||
/** Creates a new, empty document. */
|
||||
CodeDocument();
|
||||
|
||||
/** Destructor. */
|
||||
~CodeDocument();
|
||||
|
||||
//==============================================================================
|
||||
/** A position in a code document.
|
||||
|
||||
Using this class you can find a position in a code document and quickly get its
|
||||
character position, line, and index. By calling setPositionMaintained (true), the
|
||||
position is automatically updated when text is inserted or deleted in the document,
|
||||
so that it maintains its original place in the text.
|
||||
*/
|
||||
class JUCE_API Position
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised position.
|
||||
Don't attempt to call any methods on this until you've given it an owner document
|
||||
to refer to!
|
||||
*/
|
||||
Position() noexcept;
|
||||
|
||||
/** Creates a position based on a line and index in a document.
|
||||
|
||||
Note that this index is NOT the column number, it's the number of characters from the
|
||||
start of the line. The "column" number isn't quite the same, because if the line
|
||||
contains any tab characters, the relationship of the index to its visual column depends on
|
||||
the number of spaces per tab being used!
|
||||
|
||||
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.
|
||||
*/
|
||||
Position (const CodeDocument& ownerDocument,
|
||||
int line, int indexInLine) noexcept;
|
||||
|
||||
/** Creates a position based on a character index in a document.
|
||||
This position is placed at the specified number of characters from the start of the
|
||||
document. The line and column are auto-calculated.
|
||||
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
*/
|
||||
Position (const CodeDocument& ownerDocument,
|
||||
int charactersFromStartOfDocument) noexcept;
|
||||
|
||||
/** Creates a copy of another position.
|
||||
|
||||
This will copy the position, but the new object will not be set to maintain its position,
|
||||
even if the source object was set to do so.
|
||||
*/
|
||||
Position (const Position&) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~Position();
|
||||
|
||||
Position& operator= (const Position&);
|
||||
|
||||
bool operator== (const Position&) const noexcept;
|
||||
bool operator!= (const Position&) const noexcept;
|
||||
|
||||
/** Points this object at a new position within the document.
|
||||
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
@see getPosition, setLineAndIndex
|
||||
*/
|
||||
void setPosition (int charactersFromStartOfDocument);
|
||||
|
||||
/** Returns the position as the number of characters from the start of the document.
|
||||
@see setPosition, getLineNumber, getIndexInLine
|
||||
*/
|
||||
int getPosition() const noexcept { return characterPos; }
|
||||
|
||||
/** Moves the position to a new line and index within the line.
|
||||
|
||||
Note that the index is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
|
||||
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.
|
||||
*/
|
||||
void setLineAndIndex (int newLineNumber, int newIndexInLine);
|
||||
|
||||
/** Returns the line number of this position.
|
||||
The first line in the document is numbered zero, not one!
|
||||
*/
|
||||
int getLineNumber() const noexcept { return line; }
|
||||
|
||||
/** Returns the number of characters from the start of the line.
|
||||
|
||||
Note that this value is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
*/
|
||||
int getIndexInLine() const noexcept { return indexInLine; }
|
||||
|
||||
/** Allows the position to be automatically updated when the document changes.
|
||||
|
||||
If this is set to true, the position will register with its document so that
|
||||
when the document has text inserted or deleted, this position will be automatically
|
||||
moved to keep it at the same position in the text.
|
||||
*/
|
||||
void setPositionMaintained (bool isMaintained);
|
||||
|
||||
//==============================================================================
|
||||
/** Moves the position forwards or backwards by the specified number of characters.
|
||||
@see movedBy
|
||||
*/
|
||||
void moveBy (int characterDelta);
|
||||
|
||||
/** Returns a position which is the same as this one, moved by the specified number of
|
||||
characters.
|
||||
@see moveBy
|
||||
*/
|
||||
Position movedBy (int characterDelta) const;
|
||||
|
||||
/** Returns a position which is the same as this one, moved up or down by the specified
|
||||
number of lines.
|
||||
@see movedBy
|
||||
*/
|
||||
Position movedByLines (int deltaLines) const;
|
||||
|
||||
/** Returns the character in the document at this position.
|
||||
@see getLineText
|
||||
*/
|
||||
juce_wchar getCharacter() const;
|
||||
|
||||
/** Returns the line from the document that this position is within.
|
||||
@see getCharacter, getLineNumber
|
||||
*/
|
||||
String getLineText() const;
|
||||
|
||||
private:
|
||||
CodeDocument* owner = nullptr;
|
||||
int characterPos = 0, line = 0, indexInLine = 0;
|
||||
bool positionMaintained = false;
|
||||
|
||||
friend class CodeDocument;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the full text of the document. */
|
||||
String getAllContent() const;
|
||||
|
||||
/** Returns a section of the document's text. */
|
||||
String getTextBetween (const Position& start, const Position& end) const;
|
||||
|
||||
/** Returns a line from the document. */
|
||||
String getLine (int lineIndex) const noexcept;
|
||||
|
||||
/** Returns the number of characters in the document. */
|
||||
int getNumCharacters() const noexcept;
|
||||
|
||||
/** Returns the number of lines in the document. */
|
||||
int getNumLines() const noexcept { return lines.size(); }
|
||||
|
||||
/** Returns the number of characters in the longest line of the document. */
|
||||
int getMaximumLineLength() noexcept;
|
||||
|
||||
/** Deletes a section of the text.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void deleteSection (const Position& startPosition, const Position& endPosition);
|
||||
|
||||
/** Deletes a section of the text.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void deleteSection (int startIndex, int endIndex);
|
||||
|
||||
/** Inserts some text into the document at a given position.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void insertText (const Position& position, const String& text);
|
||||
|
||||
/** Inserts some text into the document at a given position.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void insertText (int insertIndex, const String& text);
|
||||
|
||||
/** Replaces a section of the text with a new string.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void replaceSection (int startIndex, int endIndex, const String& newText);
|
||||
|
||||
/** Clears the document and replaces it with some new text.
|
||||
|
||||
This operation is undoable - if you're trying to completely reset the document, you
|
||||
might want to also call clearUndoHistory() and setSavePoint() after using this method.
|
||||
*/
|
||||
void replaceAllContent (const String& newContent);
|
||||
|
||||
/** Analyses the changes between the current content and some new text, and applies
|
||||
those changes.
|
||||
*/
|
||||
void applyChanges (const String& newContent);
|
||||
|
||||
/** Replaces the editor's contents with the contents of a stream.
|
||||
This will also reset the undo history and save point marker.
|
||||
*/
|
||||
bool loadFromStream (InputStream& stream);
|
||||
|
||||
/** Writes the editor's current contents to a stream. */
|
||||
bool writeToStream (OutputStream& stream);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the preferred new-line characters for the document.
|
||||
This will be either "\\n", "\\r\\n", or (rarely) "\\r".
|
||||
@see setNewLineCharacters
|
||||
*/
|
||||
String getNewLineCharacters() const noexcept { return newLineChars; }
|
||||
|
||||
/** Sets the new-line characters that the document should use.
|
||||
The string must be either "\\n", "\\r\\n", or (rarely) "\\r".
|
||||
@see getNewLineCharacters
|
||||
*/
|
||||
void setNewLineCharacters (const String& newLineCharacters) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Begins a new undo transaction.
|
||||
|
||||
The document itself will not call this internally, so relies on whatever is using the
|
||||
document to periodically call this to break up the undo sequence into sensible chunks.
|
||||
@see UndoManager::beginNewTransaction
|
||||
*/
|
||||
void newTransaction();
|
||||
|
||||
/** Undo the last operation.
|
||||
@see UndoManager::undo
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/** Redo the last operation.
|
||||
@see UndoManager::redo
|
||||
*/
|
||||
void redo();
|
||||
|
||||
/** Clears the undo history.
|
||||
@see UndoManager::clearUndoHistory
|
||||
*/
|
||||
void clearUndoHistory();
|
||||
|
||||
/** Returns the document's UndoManager */
|
||||
UndoManager& getUndoManager() noexcept { return undoManager; }
|
||||
|
||||
//==============================================================================
|
||||
/** Makes a note that the document's current state matches the one that is saved.
|
||||
|
||||
After this has been called, hasChangedSinceSavePoint() will return false until
|
||||
the document has been altered, and then it'll start returning true. If the document is
|
||||
altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
|
||||
will again return false.
|
||||
|
||||
@see hasChangedSinceSavePoint
|
||||
*/
|
||||
void setSavePoint() noexcept;
|
||||
|
||||
/** Returns true if the state of the document differs from the state it was in when
|
||||
setSavePoint() was last called.
|
||||
|
||||
@see setSavePoint
|
||||
*/
|
||||
bool hasChangedSinceSavePoint() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Searches for a word-break. */
|
||||
Position findWordBreakAfter (const Position& position) const noexcept;
|
||||
/** Searches for a word-break. */
|
||||
Position findWordBreakBefore (const Position& position) const noexcept;
|
||||
/** Finds the token that contains the given position. */
|
||||
void findTokenContaining (const Position& pos, Position& start, Position& end) const noexcept;
|
||||
/** Finds the line that contains the given position. */
|
||||
void findLineContaining (const Position& pos, Position& start, Position& end) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** An object that receives callbacks from the CodeDocument when its text changes.
|
||||
@see CodeDocument::addListener, CodeDocument::removeListener
|
||||
*/
|
||||
class JUCE_API Listener
|
||||
{
|
||||
public:
|
||||
Listener() = default;
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** Called by a CodeDocument when text is added. */
|
||||
virtual void codeDocumentTextInserted (const String& newText, int insertIndex) = 0;
|
||||
|
||||
/** Called by a CodeDocument when text is deleted. */
|
||||
virtual void codeDocumentTextDeleted (int startIndex, int endIndex) = 0;
|
||||
};
|
||||
|
||||
/** Registers a listener object to receive callbacks when the document changes.
|
||||
If the listener is already registered, this method has no effect.
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* listener);
|
||||
|
||||
/** Deregisters a listener.
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** Iterates the text in a CodeDocument.
|
||||
|
||||
This class lets you read characters from a CodeDocument. It's designed to be used
|
||||
by a CodeTokeniser object.
|
||||
|
||||
@see CodeDocument
|
||||
*/
|
||||
class JUCE_API Iterator
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised iterator.
|
||||
Don't attempt to call any methods on this until you've given it an
|
||||
owner document to refer to!
|
||||
*/
|
||||
Iterator() noexcept;
|
||||
|
||||
Iterator (const CodeDocument& document) noexcept;
|
||||
Iterator (CodeDocument::Position) noexcept;
|
||||
~Iterator() noexcept;
|
||||
|
||||
Iterator (const Iterator&) = default;
|
||||
Iterator& operator= (const Iterator&) = default;
|
||||
|
||||
/** Reads the next character and returns it. Returns 0 if you try to
|
||||
read past the document's end.
|
||||
@see peekNextChar, previousChar
|
||||
*/
|
||||
juce_wchar nextChar() noexcept;
|
||||
|
||||
/** Reads the next character without moving the current position. */
|
||||
juce_wchar peekNextChar() const noexcept;
|
||||
|
||||
/** Reads the previous character and returns it. Returns 0 if you try to
|
||||
read past the document's start.
|
||||
@see isSOF, peekPreviousChar, nextChar
|
||||
*/
|
||||
juce_wchar previousChar() noexcept;
|
||||
|
||||
/** Reads the next character without moving the current position. */
|
||||
juce_wchar peekPreviousChar() const noexcept;
|
||||
|
||||
/** Advances the position by one character. */
|
||||
void skip() noexcept;
|
||||
|
||||
/** Returns the position as the number of characters from the start of the document. */
|
||||
int getPosition() const noexcept { return position; }
|
||||
|
||||
/** Skips over any whitespace characters until the next character is non-whitespace. */
|
||||
void skipWhitespace() noexcept;
|
||||
|
||||
/** Skips forward until the next character will be the first character on the next line */
|
||||
void skipToEndOfLine() noexcept;
|
||||
|
||||
/** Skips backward until the next character will be the first character on this line */
|
||||
void skipToStartOfLine() noexcept;
|
||||
|
||||
/** Returns the line number of the next character. */
|
||||
int getLine() const noexcept { return line; }
|
||||
|
||||
/** Returns true if the iterator has reached the end of the document. */
|
||||
bool isEOF() const noexcept;
|
||||
|
||||
/** Returns true if the iterator is at the start of the document. */
|
||||
bool isSOF() const noexcept;
|
||||
|
||||
/** Convert this iterator to a CodeDocument::Position. */
|
||||
CodeDocument::Position toPosition() const;
|
||||
|
||||
private:
|
||||
bool reinitialiseCharPtr() const;
|
||||
|
||||
const CodeDocument* document;
|
||||
mutable String::CharPointerType charPointer { nullptr };
|
||||
int line = 0, position = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct InsertAction;
|
||||
struct DeleteAction;
|
||||
friend class Iterator;
|
||||
friend class Position;
|
||||
|
||||
OwnedArray<CodeDocumentLine> lines;
|
||||
Array<Position*> positionsToMaintain;
|
||||
UndoManager undoManager;
|
||||
int currentActionIndex = 0, indexOfSavedState = -1;
|
||||
int maximumLineLength = -1;
|
||||
ListenerList<Listener> listeners;
|
||||
String newLineChars { "\r\n" };
|
||||
|
||||
void insert (const String& text, int insertPos, bool undoable);
|
||||
void remove (int startPos, int endPos, bool undoable);
|
||||
void checkLastLineStatus();
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeDocument)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class CodeDocumentLine;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class for storing and manipulating a source code file.
|
||||
|
||||
When using a CodeEditorComponent, it takes one of these as its source object.
|
||||
|
||||
The CodeDocument stores its content as an array of lines, which makes it
|
||||
quick to insert and delete.
|
||||
|
||||
@see CodeEditorComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CodeDocument
|
||||
{
|
||||
public:
|
||||
/** Creates a new, empty document. */
|
||||
CodeDocument();
|
||||
|
||||
/** Destructor. */
|
||||
~CodeDocument();
|
||||
|
||||
//==============================================================================
|
||||
/** A position in a code document.
|
||||
|
||||
Using this class you can find a position in a code document and quickly get its
|
||||
character position, line, and index. By calling setPositionMaintained (true), the
|
||||
position is automatically updated when text is inserted or deleted in the document,
|
||||
so that it maintains its original place in the text.
|
||||
*/
|
||||
class JUCE_API Position
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised position.
|
||||
Don't attempt to call any methods on this until you've given it an owner document
|
||||
to refer to!
|
||||
*/
|
||||
Position() noexcept;
|
||||
|
||||
/** Creates a position based on a line and index in a document.
|
||||
|
||||
Note that this index is NOT the column number, it's the number of characters from the
|
||||
start of the line. The "column" number isn't quite the same, because if the line
|
||||
contains any tab characters, the relationship of the index to its visual column depends on
|
||||
the number of spaces per tab being used!
|
||||
|
||||
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.
|
||||
*/
|
||||
Position (const CodeDocument& ownerDocument,
|
||||
int line, int indexInLine) noexcept;
|
||||
|
||||
/** Creates a position based on a character index in a document.
|
||||
This position is placed at the specified number of characters from the start of the
|
||||
document. The line and column are auto-calculated.
|
||||
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
*/
|
||||
Position (const CodeDocument& ownerDocument,
|
||||
int charactersFromStartOfDocument) noexcept;
|
||||
|
||||
/** Creates a copy of another position.
|
||||
|
||||
This will copy the position, but the new object will not be set to maintain its position,
|
||||
even if the source object was set to do so.
|
||||
*/
|
||||
Position (const Position&) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~Position();
|
||||
|
||||
Position& operator= (const Position&);
|
||||
|
||||
bool operator== (const Position&) const noexcept;
|
||||
bool operator!= (const Position&) const noexcept;
|
||||
|
||||
/** Points this object at a new position within the document.
|
||||
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
@see getPosition, setLineAndIndex
|
||||
*/
|
||||
void setPosition (int charactersFromStartOfDocument);
|
||||
|
||||
/** Returns the position as the number of characters from the start of the document.
|
||||
@see setPosition, getLineNumber, getIndexInLine
|
||||
*/
|
||||
int getPosition() const noexcept { return characterPos; }
|
||||
|
||||
/** Moves the position to a new line and index within the line.
|
||||
|
||||
Note that the index is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
|
||||
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.
|
||||
*/
|
||||
void setLineAndIndex (int newLineNumber, int newIndexInLine);
|
||||
|
||||
/** Returns the line number of this position.
|
||||
The first line in the document is numbered zero, not one!
|
||||
*/
|
||||
int getLineNumber() const noexcept { return line; }
|
||||
|
||||
/** Returns the number of characters from the start of the line.
|
||||
|
||||
Note that this value is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
*/
|
||||
int getIndexInLine() const noexcept { return indexInLine; }
|
||||
|
||||
/** Allows the position to be automatically updated when the document changes.
|
||||
|
||||
If this is set to true, the position will register with its document so that
|
||||
when the document has text inserted or deleted, this position will be automatically
|
||||
moved to keep it at the same position in the text.
|
||||
*/
|
||||
void setPositionMaintained (bool isMaintained);
|
||||
|
||||
//==============================================================================
|
||||
/** Moves the position forwards or backwards by the specified number of characters.
|
||||
@see movedBy
|
||||
*/
|
||||
void moveBy (int characterDelta);
|
||||
|
||||
/** Returns a position which is the same as this one, moved by the specified number of
|
||||
characters.
|
||||
@see moveBy
|
||||
*/
|
||||
Position movedBy (int characterDelta) const;
|
||||
|
||||
/** Returns a position which is the same as this one, moved up or down by the specified
|
||||
number of lines.
|
||||
@see movedBy
|
||||
*/
|
||||
Position movedByLines (int deltaLines) const;
|
||||
|
||||
/** Returns the character in the document at this position.
|
||||
@see getLineText
|
||||
*/
|
||||
juce_wchar getCharacter() const;
|
||||
|
||||
/** Returns the line from the document that this position is within.
|
||||
@see getCharacter, getLineNumber
|
||||
*/
|
||||
String getLineText() const;
|
||||
|
||||
private:
|
||||
CodeDocument* owner = nullptr;
|
||||
int characterPos = 0, line = 0, indexInLine = 0;
|
||||
bool positionMaintained = false;
|
||||
|
||||
friend class CodeDocument;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the full text of the document. */
|
||||
String getAllContent() const;
|
||||
|
||||
/** Returns a section of the document's text. */
|
||||
String getTextBetween (const Position& start, const Position& end) const;
|
||||
|
||||
/** Returns a line from the document. */
|
||||
String getLine (int lineIndex) const noexcept;
|
||||
|
||||
/** Returns the number of characters in the document. */
|
||||
int getNumCharacters() const noexcept;
|
||||
|
||||
/** Returns the number of lines in the document. */
|
||||
int getNumLines() const noexcept { return lines.size(); }
|
||||
|
||||
/** Returns the number of characters in the longest line of the document. */
|
||||
int getMaximumLineLength() noexcept;
|
||||
|
||||
/** Deletes a section of the text.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void deleteSection (const Position& startPosition, const Position& endPosition);
|
||||
|
||||
/** Deletes a section of the text.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void deleteSection (int startIndex, int endIndex);
|
||||
|
||||
/** Inserts some text into the document at a given position.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void insertText (const Position& position, const String& text);
|
||||
|
||||
/** Inserts some text into the document at a given position.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void insertText (int insertIndex, const String& text);
|
||||
|
||||
/** Replaces a section of the text with a new string.
|
||||
This operation is undoable.
|
||||
*/
|
||||
void replaceSection (int startIndex, int endIndex, const String& newText);
|
||||
|
||||
/** Clears the document and replaces it with some new text.
|
||||
|
||||
This operation is undoable - if you're trying to completely reset the document, you
|
||||
might want to also call clearUndoHistory() and setSavePoint() after using this method.
|
||||
*/
|
||||
void replaceAllContent (const String& newContent);
|
||||
|
||||
/** Analyses the changes between the current content and some new text, and applies
|
||||
those changes.
|
||||
*/
|
||||
void applyChanges (const String& newContent);
|
||||
|
||||
/** Replaces the editor's contents with the contents of a stream.
|
||||
This will also reset the undo history and save point marker.
|
||||
*/
|
||||
bool loadFromStream (InputStream& stream);
|
||||
|
||||
/** Writes the editor's current contents to a stream. */
|
||||
bool writeToStream (OutputStream& stream);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the preferred new-line characters for the document.
|
||||
This will be either "\\n", "\\r\\n", or (rarely) "\\r".
|
||||
@see setNewLineCharacters
|
||||
*/
|
||||
String getNewLineCharacters() const noexcept { return newLineChars; }
|
||||
|
||||
/** Sets the new-line characters that the document should use.
|
||||
The string must be either "\\n", "\\r\\n", or (rarely) "\\r".
|
||||
@see getNewLineCharacters
|
||||
*/
|
||||
void setNewLineCharacters (const String& newLineCharacters) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Begins a new undo transaction.
|
||||
|
||||
The document itself will not call this internally, so relies on whatever is using the
|
||||
document to periodically call this to break up the undo sequence into sensible chunks.
|
||||
@see UndoManager::beginNewTransaction
|
||||
*/
|
||||
void newTransaction();
|
||||
|
||||
/** Undo the last operation.
|
||||
@see UndoManager::undo
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/** Redo the last operation.
|
||||
@see UndoManager::redo
|
||||
*/
|
||||
void redo();
|
||||
|
||||
/** Clears the undo history.
|
||||
@see UndoManager::clearUndoHistory
|
||||
*/
|
||||
void clearUndoHistory();
|
||||
|
||||
/** Returns the document's UndoManager */
|
||||
UndoManager& getUndoManager() noexcept { return undoManager; }
|
||||
|
||||
//==============================================================================
|
||||
/** Makes a note that the document's current state matches the one that is saved.
|
||||
|
||||
After this has been called, hasChangedSinceSavePoint() will return false until
|
||||
the document has been altered, and then it'll start returning true. If the document is
|
||||
altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
|
||||
will again return false.
|
||||
|
||||
@see hasChangedSinceSavePoint
|
||||
*/
|
||||
void setSavePoint() noexcept;
|
||||
|
||||
/** Returns true if the state of the document differs from the state it was in when
|
||||
setSavePoint() was last called.
|
||||
|
||||
@see setSavePoint
|
||||
*/
|
||||
bool hasChangedSinceSavePoint() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Searches for a word-break. */
|
||||
Position findWordBreakAfter (const Position& position) const noexcept;
|
||||
/** Searches for a word-break. */
|
||||
Position findWordBreakBefore (const Position& position) const noexcept;
|
||||
/** Finds the token that contains the given position. */
|
||||
void findTokenContaining (const Position& pos, Position& start, Position& end) const noexcept;
|
||||
/** Finds the line that contains the given position. */
|
||||
void findLineContaining (const Position& pos, Position& start, Position& end) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** An object that receives callbacks from the CodeDocument when its text changes.
|
||||
@see CodeDocument::addListener, CodeDocument::removeListener
|
||||
*/
|
||||
class JUCE_API Listener
|
||||
{
|
||||
public:
|
||||
Listener() = default;
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** Called by a CodeDocument when text is added. */
|
||||
virtual void codeDocumentTextInserted (const String& newText, int insertIndex) = 0;
|
||||
|
||||
/** Called by a CodeDocument when text is deleted. */
|
||||
virtual void codeDocumentTextDeleted (int startIndex, int endIndex) = 0;
|
||||
};
|
||||
|
||||
/** Registers a listener object to receive callbacks when the document changes.
|
||||
If the listener is already registered, this method has no effect.
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* listener);
|
||||
|
||||
/** Deregisters a listener.
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** Iterates the text in a CodeDocument.
|
||||
|
||||
This class lets you read characters from a CodeDocument. It's designed to be used
|
||||
by a CodeTokeniser object.
|
||||
|
||||
@see CodeDocument
|
||||
*/
|
||||
class JUCE_API Iterator
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised iterator.
|
||||
Don't attempt to call any methods on this until you've given it an
|
||||
owner document to refer to!
|
||||
*/
|
||||
Iterator() noexcept;
|
||||
|
||||
Iterator (const CodeDocument& document) noexcept;
|
||||
Iterator (CodeDocument::Position) noexcept;
|
||||
~Iterator() noexcept;
|
||||
|
||||
Iterator (const Iterator&) = default;
|
||||
Iterator& operator= (const Iterator&) = default;
|
||||
|
||||
/** Reads the next character and returns it. Returns 0 if you try to
|
||||
read past the document's end.
|
||||
@see peekNextChar, previousChar
|
||||
*/
|
||||
juce_wchar nextChar() noexcept;
|
||||
|
||||
/** Reads the next character without moving the current position. */
|
||||
juce_wchar peekNextChar() const noexcept;
|
||||
|
||||
/** Reads the previous character and returns it. Returns 0 if you try to
|
||||
read past the document's start.
|
||||
@see isSOF, peekPreviousChar, nextChar
|
||||
*/
|
||||
juce_wchar previousChar() noexcept;
|
||||
|
||||
/** Reads the next character without moving the current position. */
|
||||
juce_wchar peekPreviousChar() const noexcept;
|
||||
|
||||
/** Advances the position by one character. */
|
||||
void skip() noexcept;
|
||||
|
||||
/** Returns the position as the number of characters from the start of the document. */
|
||||
int getPosition() const noexcept { return position; }
|
||||
|
||||
/** Skips over any whitespace characters until the next character is non-whitespace. */
|
||||
void skipWhitespace() noexcept;
|
||||
|
||||
/** Skips forward until the next character will be the first character on the next line */
|
||||
void skipToEndOfLine() noexcept;
|
||||
|
||||
/** Skips backward until the next character will be the first character on this line */
|
||||
void skipToStartOfLine() noexcept;
|
||||
|
||||
/** Returns the line number of the next character. */
|
||||
int getLine() const noexcept { return line; }
|
||||
|
||||
/** Returns true if the iterator has reached the end of the document. */
|
||||
bool isEOF() const noexcept;
|
||||
|
||||
/** Returns true if the iterator is at the start of the document. */
|
||||
bool isSOF() const noexcept;
|
||||
|
||||
/** Convert this iterator to a CodeDocument::Position. */
|
||||
CodeDocument::Position toPosition() const;
|
||||
|
||||
private:
|
||||
bool reinitialiseCharPtr() const;
|
||||
|
||||
const CodeDocument* document;
|
||||
mutable String::CharPointerType charPointer { nullptr };
|
||||
int line = 0, position = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct InsertAction;
|
||||
struct DeleteAction;
|
||||
friend class Iterator;
|
||||
friend class Position;
|
||||
|
||||
OwnedArray<CodeDocumentLine> lines;
|
||||
Array<Position*> positionsToMaintain;
|
||||
UndoManager undoManager;
|
||||
int currentActionIndex = 0, indexOfSavedState = -1;
|
||||
int maximumLineLength = -1;
|
||||
ListenerList<Listener> listeners;
|
||||
String newLineChars { "\r\n" };
|
||||
|
||||
void insert (const String& text, int insertPos, bool undoable);
|
||||
void remove (int startPos, int endPos, bool undoable);
|
||||
void checkLastLineStatus();
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeDocument)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,456 +1,476 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class CodeTokeniser;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A text editor component designed specifically for source code.
|
||||
|
||||
This is designed to handle syntax highlighting and fast editing of very large
|
||||
files.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CodeEditorComponent : public Component,
|
||||
public ApplicationCommandTarget,
|
||||
public TextInputTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an editor for a document.
|
||||
|
||||
The tokeniser object is optional - pass nullptr to disable syntax highlighting.
|
||||
The object that you pass in is not owned or deleted by the editor - you must
|
||||
make sure that it doesn't get deleted while this component is still using it.
|
||||
|
||||
@see CodeDocument
|
||||
*/
|
||||
CodeEditorComponent (CodeDocument& document,
|
||||
CodeTokeniser* codeTokeniser);
|
||||
|
||||
/** Destructor. */
|
||||
~CodeEditorComponent() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the code document that this component is editing. */
|
||||
CodeDocument& getDocument() const noexcept { return document; }
|
||||
|
||||
/** Loads the given content into the document.
|
||||
This will completely reset the CodeDocument object, clear its undo history,
|
||||
and fill it with this text.
|
||||
*/
|
||||
void loadContent (const String& newContent);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the standard character width. */
|
||||
float getCharWidth() const noexcept { return charWidth; }
|
||||
|
||||
/** Returns the height of a line of text, in pixels. */
|
||||
int getLineHeight() const noexcept { return lineHeight; }
|
||||
|
||||
/** Returns the number of whole lines visible on the screen,
|
||||
This doesn't include a cut-off line that might be visible at the bottom if the
|
||||
component's height isn't an exact multiple of the line-height.
|
||||
*/
|
||||
int getNumLinesOnScreen() const noexcept { return linesOnScreen; }
|
||||
|
||||
/** Returns the index of the first line that's visible at the top of the editor. */
|
||||
int getFirstLineOnScreen() const noexcept { return firstLineOnScreen; }
|
||||
|
||||
/** Returns the number of whole columns visible on the screen.
|
||||
This doesn't include any cut-off columns at the right-hand edge.
|
||||
*/
|
||||
int getNumColumnsOnScreen() const noexcept { return columnsOnScreen; }
|
||||
|
||||
/** Returns the current caret position. */
|
||||
CodeDocument::Position getCaretPos() const { return caretPos; }
|
||||
|
||||
/** Returns the position of the caret, relative to the editor's origin. */
|
||||
Rectangle<int> getCaretRectangle() override;
|
||||
|
||||
/** Moves the caret.
|
||||
If selecting is true, the section of the document between the current
|
||||
caret position and the new one will become selected. If false, any currently
|
||||
selected region will be deselected.
|
||||
*/
|
||||
void moveCaretTo (const CodeDocument::Position& newPos, bool selecting);
|
||||
|
||||
/** Returns the on-screen position of a character in the document.
|
||||
The rectangle returned is relative to this component's top-left origin.
|
||||
*/
|
||||
Rectangle<int> getCharacterBounds (const CodeDocument::Position& pos) const;
|
||||
|
||||
/** Finds the character at a given on-screen position.
|
||||
The coordinates are relative to this component's top-left origin.
|
||||
*/
|
||||
CodeDocument::Position getPositionAt (int x, int y) const;
|
||||
|
||||
/** Returns the start of the selection as a position. */
|
||||
CodeDocument::Position getSelectionStart() const { return selectionStart; }
|
||||
|
||||
/** Returns the end of the selection as a position. */
|
||||
CodeDocument::Position getSelectionEnd() const { return selectionEnd; }
|
||||
|
||||
/** Enables or disables the line-number display in the gutter. */
|
||||
void setLineNumbersShown (bool shouldBeShown);
|
||||
|
||||
//==============================================================================
|
||||
bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting);
|
||||
bool moveCaretRight (bool moveInWholeWordSteps, bool selecting);
|
||||
bool moveCaretUp (bool selecting);
|
||||
bool moveCaretDown (bool selecting);
|
||||
bool scrollDown();
|
||||
bool scrollUp();
|
||||
bool pageUp (bool selecting);
|
||||
bool pageDown (bool selecting);
|
||||
bool moveCaretToTop (bool selecting);
|
||||
bool moveCaretToStartOfLine (bool selecting);
|
||||
bool moveCaretToEnd (bool selecting);
|
||||
bool moveCaretToEndOfLine (bool selecting);
|
||||
bool deleteBackwards (bool moveInWholeWordSteps);
|
||||
bool deleteForwards (bool moveInWholeWordSteps);
|
||||
bool deleteWhitespaceBackwardsToTabStop();
|
||||
virtual bool copyToClipboard();
|
||||
virtual bool cutToClipboard();
|
||||
virtual bool pasteFromClipboard();
|
||||
bool undo();
|
||||
bool redo();
|
||||
|
||||
void selectRegion (const CodeDocument::Position& start, const CodeDocument::Position& end);
|
||||
bool selectAll();
|
||||
void deselectAll();
|
||||
|
||||
void scrollToLine (int newFirstLineOnScreen);
|
||||
void scrollBy (int deltaLines);
|
||||
void scrollToColumn (int newFirstColumnOnScreen);
|
||||
void scrollToKeepCaretOnScreen();
|
||||
void scrollToKeepLinesOnScreen (Range<int> linesToShow);
|
||||
|
||||
void insertTextAtCaret (const String& textToInsert) override;
|
||||
void insertTabAtCaret();
|
||||
|
||||
void indentSelection();
|
||||
void unindentSelection();
|
||||
|
||||
//==============================================================================
|
||||
Range<int> getHighlightedRegion() const override;
|
||||
bool isHighlightActive() const noexcept;
|
||||
void setHighlightedRegion (const Range<int>& newRange) override;
|
||||
String getTextInRange (const Range<int>& range) const override;
|
||||
|
||||
//==============================================================================
|
||||
/** Can be used to save and restore the editor's caret position, selection state, etc. */
|
||||
struct State
|
||||
{
|
||||
/** Creates an object containing the state of the given editor. */
|
||||
State (const CodeEditorComponent&);
|
||||
/** Creates a state object from a string that was previously created with toString(). */
|
||||
State (const String& stringifiedVersion);
|
||||
State (const State&) noexcept;
|
||||
|
||||
/** Updates the given editor with this saved state. */
|
||||
void restoreState (CodeEditorComponent&) const;
|
||||
|
||||
/** Returns a stringified version of this state that can be used to recreate it later. */
|
||||
String toString() const;
|
||||
|
||||
private:
|
||||
int lastTopLine, lastCaretPos, lastSelectionEnd;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the current tab settings.
|
||||
This lets you change the tab size and whether pressing the tab key inserts a
|
||||
tab character, or its equivalent number of spaces.
|
||||
*/
|
||||
void setTabSize (int numSpacesPerTab, bool insertSpacesInsteadOfTabCharacters);
|
||||
|
||||
/** Returns the current number of spaces per tab.
|
||||
@see setTabSize
|
||||
*/
|
||||
int getTabSize() const noexcept { return spacesPerTab; }
|
||||
|
||||
/** Returns true if the tab key will insert spaces instead of actual tab characters.
|
||||
@see setTabSize
|
||||
*/
|
||||
bool areSpacesInsertedForTabs() const { return useSpacesForTabs; }
|
||||
|
||||
/** Returns a string containing spaces or tab characters to generate the given number of spaces. */
|
||||
String getTabString (int numSpaces) const;
|
||||
|
||||
/** Changes the font.
|
||||
Make sure you only use a fixed-width font, or this component will look pretty nasty!
|
||||
*/
|
||||
void setFont (const Font& newFont);
|
||||
|
||||
/** Returns the font that the editor is using. */
|
||||
const Font& getFont() const noexcept { return font; }
|
||||
|
||||
/** Makes the editor read-only. */
|
||||
void setReadOnly (bool shouldBeReadOnly) noexcept;
|
||||
|
||||
/** Returns true if the editor is set to be read-only. */
|
||||
bool isReadOnly() const noexcept { return readOnly; }
|
||||
|
||||
//==============================================================================
|
||||
/** Defines a syntax highlighting colour scheme */
|
||||
struct JUCE_API ColourScheme
|
||||
{
|
||||
/** Defines a colour for a token type */
|
||||
struct TokenType
|
||||
{
|
||||
String name;
|
||||
Colour colour;
|
||||
};
|
||||
|
||||
Array<TokenType> types;
|
||||
|
||||
void set (const String& name, Colour colour);
|
||||
};
|
||||
|
||||
/** Changes the syntax highlighting scheme.
|
||||
The token type values are dependent on the tokeniser being used - use
|
||||
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
||||
@see getColourForTokenType
|
||||
*/
|
||||
void setColourScheme (const ColourScheme& scheme);
|
||||
|
||||
/** Returns the current syntax highlighting colour scheme. */
|
||||
const ColourScheme& getColourScheme() const noexcept { return colourScheme; }
|
||||
|
||||
/** Returns one the syntax highlighting colour for the given token.
|
||||
The token type values are dependent on the tokeniser being used.
|
||||
@see setColourScheme
|
||||
*/
|
||||
Colour getColourForTokenType (int tokenType) const;
|
||||
|
||||
/** Rebuilds the syntax highlighting for a section of text.
|
||||
|
||||
This happens automatically any time the CodeDocument is edited, but this
|
||||
method lets you change text colours even when the CodeDocument hasn't changed.
|
||||
|
||||
For example, you could use this to highlight tokens as the cursor moves.
|
||||
To do so you'll need to tell your custom CodeTokeniser where the token you
|
||||
want to highlight is, and make it return a special type of token. Then you
|
||||
should call this method supplying the range of the highlighted text.
|
||||
@see CodeTokeniser
|
||||
*/
|
||||
void retokenise (int startIndex, int endIndex);
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the editor.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x1004500, /**< A colour to use to fill the editor's background. */
|
||||
highlightColourId = 0x1004502, /**< The colour to use for the highlighted background under selected text. */
|
||||
defaultTextColourId = 0x1004503, /**< The colour to use for text when no syntax colouring is enabled. */
|
||||
lineNumberBackgroundId = 0x1004504, /**< The colour to use for filling the background of the line-number gutter. */
|
||||
lineNumberTextId = 0x1004505, /**< The colour to use for drawing the line numbers. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the size of the scrollbars. */
|
||||
void setScrollbarThickness (int thickness);
|
||||
|
||||
/** Returns the thickness of the scrollbars. */
|
||||
int getScrollbarThickness() const noexcept { return scrollbarThickness; }
|
||||
|
||||
//==============================================================================
|
||||
/** Called when the return key is pressed - this can be overridden for custom behaviour. */
|
||||
virtual void handleReturnKey();
|
||||
/** Called when the tab key is pressed - this can be overridden for custom behaviour. */
|
||||
virtual void handleTabKey();
|
||||
/** Called when the escape key is pressed - this can be overridden for custom behaviour. */
|
||||
virtual void handleEscapeKey();
|
||||
|
||||
/** Called when the view position is scrolled horizontally or vertically. */
|
||||
virtual void editorViewportPositionChanged();
|
||||
|
||||
/** Called when the caret position moves. */
|
||||
virtual void caretPositionMoved();
|
||||
|
||||
//==============================================================================
|
||||
/** This adds the items to the popup menu.
|
||||
|
||||
By default it adds the cut/copy/paste items, but you can override this if
|
||||
you need to replace these with your own items.
|
||||
|
||||
If you want to add your own items to the existing ones, you can override this,
|
||||
call the base class's addPopupMenuItems() method, then append your own items.
|
||||
|
||||
When the menu has been shown, performPopupMenuAction() will be called to
|
||||
perform the item that the user has chosen.
|
||||
|
||||
If this was triggered by a mouse-click, the mouseClickEvent parameter will be
|
||||
a pointer to the info about it, or may be null if the menu is being triggered
|
||||
by some other means.
|
||||
|
||||
@see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled
|
||||
*/
|
||||
virtual void addPopupMenuItems (PopupMenu& menuToAddTo,
|
||||
const MouseEvent* mouseClickEvent);
|
||||
|
||||
/** This is called to perform one of the items that was shown on the popup menu.
|
||||
|
||||
If you've overridden addPopupMenuItems(), you should also override this
|
||||
to perform the actions that you've added.
|
||||
|
||||
If you've overridden addPopupMenuItems() but have still left the default items
|
||||
on the menu, remember to call the superclass's performPopupMenuAction()
|
||||
so that it can perform the default actions if that's what the user clicked on.
|
||||
|
||||
@see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled
|
||||
*/
|
||||
virtual void performPopupMenuAction (int menuItemID);
|
||||
|
||||
/** Specifies a command-manager which the editor will notify whenever the state
|
||||
of any of its commands changes.
|
||||
If you're making use of the editor's ApplicationCommandTarget interface, then
|
||||
you should also use this to tell it which command manager it should use. Make
|
||||
sure that the manager does not go out of scope while the editor is using it. You
|
||||
can pass a nullptr here to disable this.
|
||||
*/
|
||||
void setCommandManager (ApplicationCommandManager* newManager) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
/** @internal */
|
||||
bool keyPressed (const KeyPress&) override;
|
||||
/** @internal */
|
||||
void mouseDown (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseDrag (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseUp (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseDoubleClick (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override;
|
||||
/** @internal */
|
||||
void focusGained (FocusChangeType) override;
|
||||
/** @internal */
|
||||
void focusLost (FocusChangeType) override;
|
||||
/** @internal */
|
||||
bool isTextInputActive() const override;
|
||||
/** @internal */
|
||||
void setTemporaryUnderlining (const Array<Range<int>>&) override;
|
||||
/** @internal */
|
||||
ApplicationCommandTarget* getNextCommandTarget() override;
|
||||
/** @internal */
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
/** @internal */
|
||||
void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
|
||||
/** @internal */
|
||||
bool perform (const InvocationInfo&) override;
|
||||
/** @internal */
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
CodeDocument& document;
|
||||
|
||||
Font font;
|
||||
int firstLineOnScreen = 0, spacesPerTab = 4;
|
||||
float charWidth = 0;
|
||||
int lineHeight = 0, linesOnScreen = 0, columnsOnScreen = 0;
|
||||
int scrollbarThickness = 16, columnToTryToMaintain = -1;
|
||||
bool readOnly = false, useSpacesForTabs = true, showLineNumbers = false, shouldFollowDocumentChanges = false;
|
||||
double xOffset = 0;
|
||||
CodeDocument::Position caretPos, selectionStart, selectionEnd;
|
||||
|
||||
std::unique_ptr<CaretComponent> caret;
|
||||
ScrollBar verticalScrollBar { true }, horizontalScrollBar { false };
|
||||
ApplicationCommandManager* appCommandManager = nullptr;
|
||||
|
||||
class Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
class GutterComponent;
|
||||
std::unique_ptr<GutterComponent> gutter;
|
||||
|
||||
class CodeEditorAccessibilityHandler;
|
||||
|
||||
enum DragType
|
||||
{
|
||||
notDragging,
|
||||
draggingSelectionStart,
|
||||
draggingSelectionEnd
|
||||
};
|
||||
|
||||
DragType dragType = notDragging;
|
||||
|
||||
//==============================================================================
|
||||
CodeTokeniser* codeTokeniser;
|
||||
ColourScheme colourScheme;
|
||||
|
||||
class CodeEditorLine;
|
||||
OwnedArray<CodeEditorLine> lines;
|
||||
void rebuildLineTokens();
|
||||
void rebuildLineTokensAsync();
|
||||
void codeDocumentChanged (int start, int end);
|
||||
|
||||
Array<CodeDocument::Iterator> cachedIterators;
|
||||
void clearCachedIterators (int firstLineToBeInvalid);
|
||||
void updateCachedIterators (int maxLineNum);
|
||||
void getIteratorForPosition (int position, CodeDocument::Iterator&);
|
||||
|
||||
void moveLineDelta (int delta, bool selecting);
|
||||
int getGutterSize() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
|
||||
void insertText (const String&);
|
||||
virtual void updateCaretPosition();
|
||||
void updateScrollBars();
|
||||
void scrollToLineInternal (int line);
|
||||
void scrollToColumnInternal (double column);
|
||||
void newTransaction();
|
||||
void cut();
|
||||
void indentSelectedLines (int spacesToAdd);
|
||||
bool skipBackwardsToPreviousTab();
|
||||
bool performCommand (CommandID);
|
||||
void setSelection (CodeDocument::Position, CodeDocument::Position);
|
||||
|
||||
int indexToColumn (int line, int index) const noexcept;
|
||||
int columnToIndex (int line, int column) const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeEditorComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class CodeTokeniser;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A text editor component designed specifically for source code.
|
||||
|
||||
This is designed to handle syntax highlighting and fast editing of very large
|
||||
files.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CodeEditorComponent : public Component,
|
||||
public ApplicationCommandTarget,
|
||||
public TextInputTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an editor for a document.
|
||||
|
||||
The tokeniser object is optional - pass nullptr to disable syntax highlighting.
|
||||
The object that you pass in is not owned or deleted by the editor - you must
|
||||
make sure that it doesn't get deleted while this component is still using it.
|
||||
|
||||
@see CodeDocument
|
||||
*/
|
||||
CodeEditorComponent (CodeDocument& document,
|
||||
CodeTokeniser* codeTokeniser);
|
||||
|
||||
/** Destructor. */
|
||||
~CodeEditorComponent() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the code document that this component is editing. */
|
||||
CodeDocument& getDocument() const noexcept { return document; }
|
||||
|
||||
/** Loads the given content into the document.
|
||||
This will completely reset the CodeDocument object, clear its undo history,
|
||||
and fill it with this text.
|
||||
*/
|
||||
void loadContent (const String& newContent);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the standard character width. */
|
||||
float getCharWidth() const noexcept { return charWidth; }
|
||||
|
||||
/** Returns the height of a line of text, in pixels. */
|
||||
int getLineHeight() const noexcept { return lineHeight; }
|
||||
|
||||
/** Returns the number of whole lines visible on the screen,
|
||||
This doesn't include a cut-off line that might be visible at the bottom if the
|
||||
component's height isn't an exact multiple of the line-height.
|
||||
*/
|
||||
int getNumLinesOnScreen() const noexcept { return linesOnScreen; }
|
||||
|
||||
/** Returns the index of the first line that's visible at the top of the editor. */
|
||||
int getFirstLineOnScreen() const noexcept { return firstLineOnScreen; }
|
||||
|
||||
/** Returns the number of whole columns visible on the screen.
|
||||
This doesn't include any cut-off columns at the right-hand edge.
|
||||
*/
|
||||
int getNumColumnsOnScreen() const noexcept { return columnsOnScreen; }
|
||||
|
||||
/** Returns the current caret position. */
|
||||
CodeDocument::Position getCaretPos() const { return caretPos; }
|
||||
|
||||
/** Returns the total number of codepoints in the string. */
|
||||
int getTotalNumChars() const override { return document.getNumCharacters(); }
|
||||
|
||||
/** Moves the caret.
|
||||
If selecting is true, the section of the document between the current
|
||||
caret position and the new one will become selected. If false, any currently
|
||||
selected region will be deselected.
|
||||
*/
|
||||
void moveCaretTo (const CodeDocument::Position& newPos, bool selecting);
|
||||
|
||||
/** Returns the on-screen position of a character in the document.
|
||||
The rectangle returned is relative to this component's top-left origin.
|
||||
*/
|
||||
Rectangle<int> getCharacterBounds (const CodeDocument::Position& pos) const;
|
||||
|
||||
/** Finds the character at a given on-screen position.
|
||||
The coordinates are relative to this component's top-left origin.
|
||||
*/
|
||||
CodeDocument::Position getPositionAt (int x, int y) const;
|
||||
|
||||
/** Returns the start of the selection as a position. */
|
||||
CodeDocument::Position getSelectionStart() const { return selectionStart; }
|
||||
|
||||
/** Returns the end of the selection as a position. */
|
||||
CodeDocument::Position getSelectionEnd() const { return selectionEnd; }
|
||||
|
||||
/** Enables or disables the line-number display in the gutter. */
|
||||
void setLineNumbersShown (bool shouldBeShown);
|
||||
|
||||
/** Returns the number of characters from the beginning of the document to the caret. */
|
||||
int getCaretPosition() const override { return getCaretPos().getPosition(); }
|
||||
|
||||
/** @see getPositionAt */
|
||||
int getCharIndexForPoint (Point<int> point) const override;
|
||||
|
||||
/** Returns the bounds of the caret at a particular location in the text. */
|
||||
Rectangle<int> getCaretRectangleForCharIndex (int index) const override
|
||||
{
|
||||
return getCharacterBounds ({ document, index });
|
||||
}
|
||||
|
||||
/** Returns the bounding box for a range of text in the editor. As the range may span
|
||||
multiple lines, this method returns a RectangleList.
|
||||
|
||||
The bounds are relative to the component's top-left and may extend beyond the bounds
|
||||
of the component if the text is long and word wrapping is disabled.
|
||||
*/
|
||||
RectangleList<int> getTextBounds (Range<int> textRange) const override;
|
||||
|
||||
//==============================================================================
|
||||
bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting);
|
||||
bool moveCaretRight (bool moveInWholeWordSteps, bool selecting);
|
||||
bool moveCaretUp (bool selecting);
|
||||
bool moveCaretDown (bool selecting);
|
||||
bool scrollDown();
|
||||
bool scrollUp();
|
||||
bool pageUp (bool selecting);
|
||||
bool pageDown (bool selecting);
|
||||
bool moveCaretToTop (bool selecting);
|
||||
bool moveCaretToStartOfLine (bool selecting);
|
||||
bool moveCaretToEnd (bool selecting);
|
||||
bool moveCaretToEndOfLine (bool selecting);
|
||||
bool deleteBackwards (bool moveInWholeWordSteps);
|
||||
bool deleteForwards (bool moveInWholeWordSteps);
|
||||
bool deleteWhitespaceBackwardsToTabStop();
|
||||
virtual bool copyToClipboard();
|
||||
virtual bool cutToClipboard();
|
||||
virtual bool pasteFromClipboard();
|
||||
bool undo();
|
||||
bool redo();
|
||||
|
||||
void selectRegion (const CodeDocument::Position& start, const CodeDocument::Position& end);
|
||||
bool selectAll();
|
||||
void deselectAll();
|
||||
|
||||
void scrollToLine (int newFirstLineOnScreen);
|
||||
void scrollBy (int deltaLines);
|
||||
void scrollToColumn (int newFirstColumnOnScreen);
|
||||
void scrollToKeepCaretOnScreen();
|
||||
void scrollToKeepLinesOnScreen (Range<int> linesToShow);
|
||||
|
||||
void insertTextAtCaret (const String& textToInsert) override;
|
||||
void insertTabAtCaret();
|
||||
|
||||
void indentSelection();
|
||||
void unindentSelection();
|
||||
|
||||
//==============================================================================
|
||||
Range<int> getHighlightedRegion() const override;
|
||||
bool isHighlightActive() const noexcept;
|
||||
void setHighlightedRegion (const Range<int>& newRange) override;
|
||||
String getTextInRange (const Range<int>& range) const override;
|
||||
|
||||
//==============================================================================
|
||||
/** Can be used to save and restore the editor's caret position, selection state, etc. */
|
||||
struct State
|
||||
{
|
||||
/** Creates an object containing the state of the given editor. */
|
||||
State (const CodeEditorComponent&);
|
||||
/** Creates a state object from a string that was previously created with toString(). */
|
||||
State (const String& stringifiedVersion);
|
||||
State (const State&) noexcept;
|
||||
|
||||
/** Updates the given editor with this saved state. */
|
||||
void restoreState (CodeEditorComponent&) const;
|
||||
|
||||
/** Returns a stringified version of this state that can be used to recreate it later. */
|
||||
String toString() const;
|
||||
|
||||
private:
|
||||
int lastTopLine, lastCaretPos, lastSelectionEnd;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the current tab settings.
|
||||
This lets you change the tab size and whether pressing the tab key inserts a
|
||||
tab character, or its equivalent number of spaces.
|
||||
*/
|
||||
void setTabSize (int numSpacesPerTab, bool insertSpacesInsteadOfTabCharacters);
|
||||
|
||||
/** Returns the current number of spaces per tab.
|
||||
@see setTabSize
|
||||
*/
|
||||
int getTabSize() const noexcept { return spacesPerTab; }
|
||||
|
||||
/** Returns true if the tab key will insert spaces instead of actual tab characters.
|
||||
@see setTabSize
|
||||
*/
|
||||
bool areSpacesInsertedForTabs() const { return useSpacesForTabs; }
|
||||
|
||||
/** Returns a string containing spaces or tab characters to generate the given number of spaces. */
|
||||
String getTabString (int numSpaces) const;
|
||||
|
||||
/** Changes the font.
|
||||
Make sure you only use a fixed-width font, or this component will look pretty nasty!
|
||||
*/
|
||||
void setFont (const Font& newFont);
|
||||
|
||||
/** Returns the font that the editor is using. */
|
||||
const Font& getFont() const noexcept { return font; }
|
||||
|
||||
/** Makes the editor read-only. */
|
||||
void setReadOnly (bool shouldBeReadOnly) noexcept;
|
||||
|
||||
/** Returns true if the editor is set to be read-only. */
|
||||
bool isReadOnly() const noexcept { return readOnly; }
|
||||
|
||||
//==============================================================================
|
||||
/** Defines a syntax highlighting colour scheme */
|
||||
struct JUCE_API ColourScheme
|
||||
{
|
||||
/** Defines a colour for a token type */
|
||||
struct TokenType
|
||||
{
|
||||
String name;
|
||||
Colour colour;
|
||||
};
|
||||
|
||||
Array<TokenType> types;
|
||||
|
||||
void set (const String& name, Colour colour);
|
||||
};
|
||||
|
||||
/** Changes the syntax highlighting scheme.
|
||||
The token type values are dependent on the tokeniser being used - use
|
||||
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
||||
@see getColourForTokenType
|
||||
*/
|
||||
void setColourScheme (const ColourScheme& scheme);
|
||||
|
||||
/** Returns the current syntax highlighting colour scheme. */
|
||||
const ColourScheme& getColourScheme() const noexcept { return colourScheme; }
|
||||
|
||||
/** Returns one the syntax highlighting colour for the given token.
|
||||
The token type values are dependent on the tokeniser being used.
|
||||
@see setColourScheme
|
||||
*/
|
||||
Colour getColourForTokenType (int tokenType) const;
|
||||
|
||||
/** Rebuilds the syntax highlighting for a section of text.
|
||||
|
||||
This happens automatically any time the CodeDocument is edited, but this
|
||||
method lets you change text colours even when the CodeDocument hasn't changed.
|
||||
|
||||
For example, you could use this to highlight tokens as the cursor moves.
|
||||
To do so you'll need to tell your custom CodeTokeniser where the token you
|
||||
want to highlight is, and make it return a special type of token. Then you
|
||||
should call this method supplying the range of the highlighted text.
|
||||
@see CodeTokeniser
|
||||
*/
|
||||
void retokenise (int startIndex, int endIndex);
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the editor.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x1004500, /**< A colour to use to fill the editor's background. */
|
||||
highlightColourId = 0x1004502, /**< The colour to use for the highlighted background under selected text. */
|
||||
defaultTextColourId = 0x1004503, /**< The colour to use for text when no syntax colouring is enabled. */
|
||||
lineNumberBackgroundId = 0x1004504, /**< The colour to use for filling the background of the line-number gutter. */
|
||||
lineNumberTextId = 0x1004505, /**< The colour to use for drawing the line numbers. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the size of the scrollbars. */
|
||||
void setScrollbarThickness (int thickness);
|
||||
|
||||
/** Returns the thickness of the scrollbars. */
|
||||
int getScrollbarThickness() const noexcept { return scrollbarThickness; }
|
||||
|
||||
//==============================================================================
|
||||
/** Called when the return key is pressed - this can be overridden for custom behaviour. */
|
||||
virtual void handleReturnKey();
|
||||
/** Called when the tab key is pressed - this can be overridden for custom behaviour. */
|
||||
virtual void handleTabKey();
|
||||
/** Called when the escape key is pressed - this can be overridden for custom behaviour. */
|
||||
virtual void handleEscapeKey();
|
||||
|
||||
/** Called when the view position is scrolled horizontally or vertically. */
|
||||
virtual void editorViewportPositionChanged();
|
||||
|
||||
/** Called when the caret position moves. */
|
||||
virtual void caretPositionMoved();
|
||||
|
||||
//==============================================================================
|
||||
/** This adds the items to the popup menu.
|
||||
|
||||
By default it adds the cut/copy/paste items, but you can override this if
|
||||
you need to replace these with your own items.
|
||||
|
||||
If you want to add your own items to the existing ones, you can override this,
|
||||
call the base class's addPopupMenuItems() method, then append your own items.
|
||||
|
||||
When the menu has been shown, performPopupMenuAction() will be called to
|
||||
perform the item that the user has chosen.
|
||||
|
||||
If this was triggered by a mouse-click, the mouseClickEvent parameter will be
|
||||
a pointer to the info about it, or may be null if the menu is being triggered
|
||||
by some other means.
|
||||
|
||||
@see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled
|
||||
*/
|
||||
virtual void addPopupMenuItems (PopupMenu& menuToAddTo,
|
||||
const MouseEvent* mouseClickEvent);
|
||||
|
||||
/** This is called to perform one of the items that was shown on the popup menu.
|
||||
|
||||
If you've overridden addPopupMenuItems(), you should also override this
|
||||
to perform the actions that you've added.
|
||||
|
||||
If you've overridden addPopupMenuItems() but have still left the default items
|
||||
on the menu, remember to call the superclass's performPopupMenuAction()
|
||||
so that it can perform the default actions if that's what the user clicked on.
|
||||
|
||||
@see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled
|
||||
*/
|
||||
virtual void performPopupMenuAction (int menuItemID);
|
||||
|
||||
/** Specifies a command-manager which the editor will notify whenever the state
|
||||
of any of its commands changes.
|
||||
If you're making use of the editor's ApplicationCommandTarget interface, then
|
||||
you should also use this to tell it which command manager it should use. Make
|
||||
sure that the manager does not go out of scope while the editor is using it. You
|
||||
can pass a nullptr here to disable this.
|
||||
*/
|
||||
void setCommandManager (ApplicationCommandManager* newManager) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
/** @internal */
|
||||
bool keyPressed (const KeyPress&) override;
|
||||
/** @internal */
|
||||
void mouseDown (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseDrag (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseUp (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseDoubleClick (const MouseEvent&) override;
|
||||
/** @internal */
|
||||
void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override;
|
||||
/** @internal */
|
||||
void focusGained (FocusChangeType) override;
|
||||
/** @internal */
|
||||
void focusLost (FocusChangeType) override;
|
||||
/** @internal */
|
||||
bool isTextInputActive() const override;
|
||||
/** @internal */
|
||||
void setTemporaryUnderlining (const Array<Range<int>>&) override;
|
||||
/** @internal */
|
||||
ApplicationCommandTarget* getNextCommandTarget() override;
|
||||
/** @internal */
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
/** @internal */
|
||||
void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
|
||||
/** @internal */
|
||||
bool perform (const InvocationInfo&) override;
|
||||
/** @internal */
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
CodeDocument& document;
|
||||
|
||||
Font font;
|
||||
int firstLineOnScreen = 0, spacesPerTab = 4;
|
||||
float charWidth = 0;
|
||||
int lineHeight = 0, linesOnScreen = 0, columnsOnScreen = 0;
|
||||
int scrollbarThickness = 16, columnToTryToMaintain = -1;
|
||||
bool readOnly = false, useSpacesForTabs = true, showLineNumbers = false, shouldFollowDocumentChanges = false;
|
||||
double xOffset = 0;
|
||||
CodeDocument::Position caretPos, selectionStart, selectionEnd;
|
||||
|
||||
std::unique_ptr<CaretComponent> caret;
|
||||
ScrollBar verticalScrollBar { true }, horizontalScrollBar { false };
|
||||
ApplicationCommandManager* appCommandManager = nullptr;
|
||||
|
||||
class Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
class GutterComponent;
|
||||
std::unique_ptr<GutterComponent> gutter;
|
||||
|
||||
class CodeEditorAccessibilityHandler;
|
||||
|
||||
enum DragType
|
||||
{
|
||||
notDragging,
|
||||
draggingSelectionStart,
|
||||
draggingSelectionEnd
|
||||
};
|
||||
|
||||
DragType dragType = notDragging;
|
||||
|
||||
//==============================================================================
|
||||
CodeTokeniser* codeTokeniser;
|
||||
ColourScheme colourScheme;
|
||||
|
||||
class CodeEditorLine;
|
||||
OwnedArray<CodeEditorLine> lines;
|
||||
void rebuildLineTokens();
|
||||
void rebuildLineTokensAsync();
|
||||
void codeDocumentChanged (int start, int end);
|
||||
|
||||
Array<CodeDocument::Iterator> cachedIterators;
|
||||
void clearCachedIterators (int firstLineToBeInvalid);
|
||||
void updateCachedIterators (int maxLineNum);
|
||||
void getIteratorForPosition (int position, CodeDocument::Iterator&);
|
||||
|
||||
void moveLineDelta (int delta, bool selecting);
|
||||
int getGutterSize() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
|
||||
void insertText (const String&);
|
||||
virtual void updateCaretPosition();
|
||||
void updateScrollBars();
|
||||
void scrollToLineInternal (int line);
|
||||
void scrollToColumnInternal (double column);
|
||||
void newTransaction();
|
||||
void cut();
|
||||
void indentSelectedLines (int spacesToAdd);
|
||||
bool skipBackwardsToPreviousTab();
|
||||
bool performCommand (CommandID);
|
||||
void setSelection (CodeDocument::Position, CodeDocument::Position);
|
||||
|
||||
int indexToColumn (int line, int index) const noexcept;
|
||||
int columnToIndex (int line, int column) const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeEditorComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,59 +1,59 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A base class for tokenising code so that the syntax can be displayed in a
|
||||
code editor.
|
||||
|
||||
@see CodeDocument, CodeEditorComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CodeTokeniser
|
||||
{
|
||||
public:
|
||||
CodeTokeniser() = default;
|
||||
virtual ~CodeTokeniser() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Reads the next token from the source and returns its token type.
|
||||
|
||||
This must leave the source pointing to the first character in the
|
||||
next token.
|
||||
*/
|
||||
virtual int readNextToken (CodeDocument::Iterator& source) = 0;
|
||||
|
||||
/** Returns a suggested syntax highlighting colour scheme. */
|
||||
virtual CodeEditorComponent::ColourScheme getDefaultColourScheme() = 0;
|
||||
|
||||
private:
|
||||
JUCE_LEAK_DETECTOR (CodeTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A base class for tokenising code so that the syntax can be displayed in a
|
||||
code editor.
|
||||
|
||||
@see CodeDocument, CodeEditorComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API CodeTokeniser
|
||||
{
|
||||
public:
|
||||
CodeTokeniser() = default;
|
||||
virtual ~CodeTokeniser() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Reads the next token from the source and returns its token type.
|
||||
|
||||
This must leave the source pointing to the first character in the
|
||||
next token.
|
||||
*/
|
||||
virtual int readNextToken (CodeDocument::Iterator& source) = 0;
|
||||
|
||||
/** Returns a suggested syntax highlighting colour scheme. */
|
||||
virtual CodeEditorComponent::ColourScheme getDefaultColourScheme() = 0;
|
||||
|
||||
private:
|
||||
JUCE_LEAK_DETECTOR (CodeTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,239 +1,239 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct LuaTokeniserFunctions
|
||||
{
|
||||
static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
|
||||
{
|
||||
static const char* const keywords2Char[] =
|
||||
{ "if", "or", "in", "do", nullptr };
|
||||
|
||||
static const char* const keywords3Char[] =
|
||||
{ "and", "end", "for", "nil", "not", nullptr };
|
||||
|
||||
static const char* const keywords4Char[] =
|
||||
{ "then", "true", "else", nullptr };
|
||||
|
||||
static const char* const keywords5Char[] =
|
||||
{ "false", "local", "until", "while", "break", nullptr };
|
||||
|
||||
static const char* const keywords6Char[] =
|
||||
{ "repeat", "return", "elseif", nullptr};
|
||||
|
||||
static const char* const keywordsOther[] =
|
||||
{ "function", "@interface", "@end", "@synthesize", "@dynamic", "@public",
|
||||
"@private", "@property", "@protected", "@class", nullptr };
|
||||
|
||||
const char* const* k;
|
||||
|
||||
switch (tokenLength)
|
||||
{
|
||||
case 2: k = keywords2Char; break;
|
||||
case 3: k = keywords3Char; break;
|
||||
case 4: k = keywords4Char; break;
|
||||
case 5: k = keywords5Char; break;
|
||||
case 6: k = keywords6Char; break;
|
||||
|
||||
default:
|
||||
if (tokenLength < 2 || tokenLength > 16)
|
||||
return false;
|
||||
|
||||
k = keywordsOther;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; k[i] != nullptr; ++i)
|
||||
if (token.compare (CharPointer_ASCII (k[i])) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static int parseIdentifier (Iterator& source) noexcept
|
||||
{
|
||||
int tokenLength = 0;
|
||||
String::CharPointerType::CharType possibleIdentifier[100];
|
||||
String::CharPointerType possible (possibleIdentifier);
|
||||
|
||||
while (CppTokeniserFunctions::isIdentifierBody (source.peekNextChar()))
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (tokenLength < 20)
|
||||
possible.write (c);
|
||||
|
||||
++tokenLength;
|
||||
}
|
||||
|
||||
if (tokenLength > 1 && tokenLength <= 16)
|
||||
{
|
||||
possible.writeNull();
|
||||
|
||||
if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
|
||||
return LuaTokeniser::tokenType_keyword;
|
||||
}
|
||||
|
||||
return LuaTokeniser::tokenType_identifier;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static int readNextToken (Iterator& source)
|
||||
{
|
||||
source.skipWhitespace();
|
||||
|
||||
auto firstChar = source.peekNextChar();
|
||||
|
||||
switch (firstChar)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case '.':
|
||||
{
|
||||
auto result = CppTokeniserFunctions::parseNumber (source);
|
||||
|
||||
if (result == LuaTokeniser::tokenType_error)
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (firstChar == '.')
|
||||
return LuaTokeniser::tokenType_punctuation;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case ',':
|
||||
case ';':
|
||||
case ':':
|
||||
source.skip();
|
||||
return LuaTokeniser::tokenType_punctuation;
|
||||
|
||||
case '(': case ')':
|
||||
case '{': case '}':
|
||||
case '[': case ']':
|
||||
source.skip();
|
||||
return LuaTokeniser::tokenType_bracket;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
CppTokeniserFunctions::skipQuotedString (source);
|
||||
return LuaTokeniser::tokenType_string;
|
||||
|
||||
case '+':
|
||||
source.skip();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '+', '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
case '-':
|
||||
{
|
||||
source.skip();
|
||||
auto result = CppTokeniserFunctions::parseNumber (source);
|
||||
|
||||
if (source.peekNextChar() == '-')
|
||||
{
|
||||
source.skipToEndOfLine();
|
||||
return LuaTokeniser::tokenType_comment;
|
||||
}
|
||||
|
||||
if (result == LuaTokeniser::tokenType_error)
|
||||
{
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '-', '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case '*': case '%':
|
||||
case '=': case '!':
|
||||
source.skip();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
case '?':
|
||||
case '~':
|
||||
source.skip();
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
case '<': case '>':
|
||||
case '|': case '&': case '^':
|
||||
source.skip();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, firstChar);
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
default:
|
||||
if (CppTokeniserFunctions::isIdentifierStart (firstChar))
|
||||
return parseIdentifier (source);
|
||||
|
||||
source.skip();
|
||||
break;
|
||||
}
|
||||
|
||||
return LuaTokeniser::tokenType_error;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
LuaTokeniser::LuaTokeniser() {}
|
||||
LuaTokeniser::~LuaTokeniser() {}
|
||||
|
||||
int LuaTokeniser::readNextToken (CodeDocument::Iterator& source)
|
||||
{
|
||||
return LuaTokeniserFunctions::readNextToken (source);
|
||||
}
|
||||
|
||||
CodeEditorComponent::ColourScheme LuaTokeniser::getDefaultColourScheme()
|
||||
{
|
||||
static const CodeEditorComponent::ColourScheme::TokenType types[] =
|
||||
{
|
||||
{ "Error", Colour (0xffcc0000) },
|
||||
{ "Comment", Colour (0xff3c3c3c) },
|
||||
{ "Keyword", Colour (0xff0000cc) },
|
||||
{ "Operator", Colour (0xff225500) },
|
||||
{ "Identifier", Colour (0xff000000) },
|
||||
{ "Integer", Colour (0xff880000) },
|
||||
{ "Float", Colour (0xff885500) },
|
||||
{ "String", Colour (0xff990099) },
|
||||
{ "Bracket", Colour (0xff000055) },
|
||||
{ "Punctuation", Colour (0xff004400) }
|
||||
};
|
||||
|
||||
CodeEditorComponent::ColourScheme cs;
|
||||
|
||||
for (auto& t : types)
|
||||
cs.set (t.name, Colour (t.colour));
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct LuaTokeniserFunctions
|
||||
{
|
||||
static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
|
||||
{
|
||||
static const char* const keywords2Char[] =
|
||||
{ "if", "or", "in", "do", nullptr };
|
||||
|
||||
static const char* const keywords3Char[] =
|
||||
{ "and", "end", "for", "nil", "not", nullptr };
|
||||
|
||||
static const char* const keywords4Char[] =
|
||||
{ "then", "true", "else", nullptr };
|
||||
|
||||
static const char* const keywords5Char[] =
|
||||
{ "false", "local", "until", "while", "break", nullptr };
|
||||
|
||||
static const char* const keywords6Char[] =
|
||||
{ "repeat", "return", "elseif", nullptr};
|
||||
|
||||
static const char* const keywordsOther[] =
|
||||
{ "function", "@interface", "@end", "@synthesize", "@dynamic", "@public",
|
||||
"@private", "@property", "@protected", "@class", nullptr };
|
||||
|
||||
const char* const* k;
|
||||
|
||||
switch (tokenLength)
|
||||
{
|
||||
case 2: k = keywords2Char; break;
|
||||
case 3: k = keywords3Char; break;
|
||||
case 4: k = keywords4Char; break;
|
||||
case 5: k = keywords5Char; break;
|
||||
case 6: k = keywords6Char; break;
|
||||
|
||||
default:
|
||||
if (tokenLength < 2 || tokenLength > 16)
|
||||
return false;
|
||||
|
||||
k = keywordsOther;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; k[i] != nullptr; ++i)
|
||||
if (token.compare (CharPointer_ASCII (k[i])) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static int parseIdentifier (Iterator& source) noexcept
|
||||
{
|
||||
int tokenLength = 0;
|
||||
String::CharPointerType::CharType possibleIdentifier[100] = {};
|
||||
String::CharPointerType possible (possibleIdentifier);
|
||||
|
||||
while (CppTokeniserFunctions::isIdentifierBody (source.peekNextChar()))
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (tokenLength < 20)
|
||||
possible.write (c);
|
||||
|
||||
++tokenLength;
|
||||
}
|
||||
|
||||
if (tokenLength > 1 && tokenLength <= 16)
|
||||
{
|
||||
possible.writeNull();
|
||||
|
||||
if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
|
||||
return LuaTokeniser::tokenType_keyword;
|
||||
}
|
||||
|
||||
return LuaTokeniser::tokenType_identifier;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static int readNextToken (Iterator& source)
|
||||
{
|
||||
source.skipWhitespace();
|
||||
|
||||
auto firstChar = source.peekNextChar();
|
||||
|
||||
switch (firstChar)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case '.':
|
||||
{
|
||||
auto result = CppTokeniserFunctions::parseNumber (source);
|
||||
|
||||
if (result == LuaTokeniser::tokenType_error)
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (firstChar == '.')
|
||||
return LuaTokeniser::tokenType_punctuation;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case ',':
|
||||
case ';':
|
||||
case ':':
|
||||
source.skip();
|
||||
return LuaTokeniser::tokenType_punctuation;
|
||||
|
||||
case '(': case ')':
|
||||
case '{': case '}':
|
||||
case '[': case ']':
|
||||
source.skip();
|
||||
return LuaTokeniser::tokenType_bracket;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
CppTokeniserFunctions::skipQuotedString (source);
|
||||
return LuaTokeniser::tokenType_string;
|
||||
|
||||
case '+':
|
||||
source.skip();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '+', '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
case '-':
|
||||
{
|
||||
source.skip();
|
||||
auto result = CppTokeniserFunctions::parseNumber (source);
|
||||
|
||||
if (source.peekNextChar() == '-')
|
||||
{
|
||||
source.skipToEndOfLine();
|
||||
return LuaTokeniser::tokenType_comment;
|
||||
}
|
||||
|
||||
if (result == LuaTokeniser::tokenType_error)
|
||||
{
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '-', '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case '*': case '%':
|
||||
case '=': case '!':
|
||||
source.skip();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
case '?':
|
||||
case '~':
|
||||
source.skip();
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
case '<': case '>':
|
||||
case '|': case '&': case '^':
|
||||
source.skip();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, firstChar);
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
|
||||
return LuaTokeniser::tokenType_operator;
|
||||
|
||||
default:
|
||||
if (CppTokeniserFunctions::isIdentifierStart (firstChar))
|
||||
return parseIdentifier (source);
|
||||
|
||||
source.skip();
|
||||
break;
|
||||
}
|
||||
|
||||
return LuaTokeniser::tokenType_error;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
LuaTokeniser::LuaTokeniser() {}
|
||||
LuaTokeniser::~LuaTokeniser() {}
|
||||
|
||||
int LuaTokeniser::readNextToken (CodeDocument::Iterator& source)
|
||||
{
|
||||
return LuaTokeniserFunctions::readNextToken (source);
|
||||
}
|
||||
|
||||
CodeEditorComponent::ColourScheme LuaTokeniser::getDefaultColourScheme()
|
||||
{
|
||||
static const CodeEditorComponent::ColourScheme::TokenType types[] =
|
||||
{
|
||||
{ "Error", Colour (0xffcc0000) },
|
||||
{ "Comment", Colour (0xff3c3c3c) },
|
||||
{ "Keyword", Colour (0xff0000cc) },
|
||||
{ "Operator", Colour (0xff225500) },
|
||||
{ "Identifier", Colour (0xff000000) },
|
||||
{ "Integer", Colour (0xff880000) },
|
||||
{ "Float", Colour (0xff885500) },
|
||||
{ "String", Colour (0xff990099) },
|
||||
{ "Bracket", Colour (0xff000055) },
|
||||
{ "Punctuation", Colour (0xff004400) }
|
||||
};
|
||||
|
||||
CodeEditorComponent::ColourScheme cs;
|
||||
|
||||
for (auto& t : types)
|
||||
cs.set (t.name, Colour (t.colour));
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,65 +1,65 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API LuaTokeniser : public CodeTokeniser
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
LuaTokeniser();
|
||||
~LuaTokeniser() override;
|
||||
|
||||
//==============================================================================
|
||||
int readNextToken (CodeDocument::Iterator&) override;
|
||||
CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
|
||||
|
||||
/** The token values returned by this tokeniser. */
|
||||
enum TokenType
|
||||
{
|
||||
tokenType_error = 0,
|
||||
tokenType_comment,
|
||||
tokenType_keyword,
|
||||
tokenType_operator,
|
||||
tokenType_identifier,
|
||||
tokenType_integer,
|
||||
tokenType_float,
|
||||
tokenType_string,
|
||||
tokenType_bracket,
|
||||
tokenType_punctuation
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LuaTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API LuaTokeniser : public CodeTokeniser
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
LuaTokeniser();
|
||||
~LuaTokeniser() override;
|
||||
|
||||
//==============================================================================
|
||||
int readNextToken (CodeDocument::Iterator&) override;
|
||||
CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
|
||||
|
||||
/** The token values returned by this tokeniser. */
|
||||
enum TokenType
|
||||
{
|
||||
tokenType_error = 0,
|
||||
tokenType_comment,
|
||||
tokenType_keyword,
|
||||
tokenType_operator,
|
||||
tokenType_identifier,
|
||||
tokenType_integer,
|
||||
tokenType_float,
|
||||
tokenType_string,
|
||||
tokenType_bracket,
|
||||
tokenType_punctuation
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LuaTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,172 +1,172 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
XmlTokeniser::XmlTokeniser() {}
|
||||
XmlTokeniser::~XmlTokeniser() {}
|
||||
|
||||
CodeEditorComponent::ColourScheme XmlTokeniser::getDefaultColourScheme()
|
||||
{
|
||||
struct Type
|
||||
{
|
||||
const char* name;
|
||||
uint32 colour;
|
||||
};
|
||||
|
||||
const Type types[] =
|
||||
{
|
||||
{ "Error", 0xffcc0000 },
|
||||
{ "Comment", 0xff00aa00 },
|
||||
{ "Keyword", 0xff0000cc },
|
||||
{ "Operator", 0xff225500 },
|
||||
{ "Identifier", 0xff000000 },
|
||||
{ "String", 0xff990099 },
|
||||
{ "Bracket", 0xff000055 },
|
||||
{ "Punctuation", 0xff004400 },
|
||||
{ "Preprocessor Text", 0xff660000 }
|
||||
};
|
||||
|
||||
CodeEditorComponent::ColourScheme cs;
|
||||
|
||||
for (auto& t : types)
|
||||
cs.set (t.name, Colour (t.colour));
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipToEndOfXmlDTD (Iterator& source) noexcept
|
||||
{
|
||||
bool lastWasQuestionMark = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c == 0 || (c == '>' && lastWasQuestionMark))
|
||||
break;
|
||||
|
||||
lastWasQuestionMark = (c == '?');
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipToEndOfXmlComment (Iterator& source) noexcept
|
||||
{
|
||||
juce_wchar last[2] = {};
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c == 0 || (c == '>' && last[0] == '-' && last[1] == '-'))
|
||||
break;
|
||||
|
||||
last[1] = last[0];
|
||||
last[0] = c;
|
||||
}
|
||||
}
|
||||
|
||||
int XmlTokeniser::readNextToken (CodeDocument::Iterator& source)
|
||||
{
|
||||
source.skipWhitespace();
|
||||
auto firstChar = source.peekNextChar();
|
||||
|
||||
switch (firstChar)
|
||||
{
|
||||
case 0: break;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
CppTokeniserFunctions::skipQuotedString (source);
|
||||
return tokenType_string;
|
||||
|
||||
case '<':
|
||||
{
|
||||
source.skip();
|
||||
source.skipWhitespace();
|
||||
auto nextChar = source.peekNextChar();
|
||||
|
||||
if (nextChar == '?')
|
||||
{
|
||||
source.skip();
|
||||
skipToEndOfXmlDTD (source);
|
||||
return tokenType_preprocessor;
|
||||
}
|
||||
|
||||
if (nextChar == '!')
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (source.peekNextChar() == '-')
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (source.peekNextChar() == '-')
|
||||
{
|
||||
skipToEndOfXmlComment (source);
|
||||
return tokenType_comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
|
||||
CppTokeniserFunctions::parseIdentifier (source);
|
||||
source.skipWhitespace();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
|
||||
source.skipWhitespace();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
|
||||
return tokenType_keyword;
|
||||
}
|
||||
|
||||
case '>':
|
||||
source.skip();
|
||||
return tokenType_keyword;
|
||||
|
||||
case '/':
|
||||
source.skip();
|
||||
source.skipWhitespace();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
|
||||
return tokenType_keyword;
|
||||
|
||||
case '=':
|
||||
case ':':
|
||||
source.skip();
|
||||
return tokenType_operator;
|
||||
|
||||
default:
|
||||
if (CppTokeniserFunctions::isIdentifierStart (firstChar))
|
||||
CppTokeniserFunctions::parseIdentifier (source);
|
||||
|
||||
source.skip();
|
||||
break;
|
||||
};
|
||||
|
||||
return tokenType_identifier;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
XmlTokeniser::XmlTokeniser() {}
|
||||
XmlTokeniser::~XmlTokeniser() {}
|
||||
|
||||
CodeEditorComponent::ColourScheme XmlTokeniser::getDefaultColourScheme()
|
||||
{
|
||||
struct Type
|
||||
{
|
||||
const char* name;
|
||||
uint32 colour;
|
||||
};
|
||||
|
||||
const Type types[] =
|
||||
{
|
||||
{ "Error", 0xffcc0000 },
|
||||
{ "Comment", 0xff00aa00 },
|
||||
{ "Keyword", 0xff0000cc },
|
||||
{ "Operator", 0xff225500 },
|
||||
{ "Identifier", 0xff000000 },
|
||||
{ "String", 0xff990099 },
|
||||
{ "Bracket", 0xff000055 },
|
||||
{ "Punctuation", 0xff004400 },
|
||||
{ "Preprocessor Text", 0xff660000 }
|
||||
};
|
||||
|
||||
CodeEditorComponent::ColourScheme cs;
|
||||
|
||||
for (auto& t : types)
|
||||
cs.set (t.name, Colour (t.colour));
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipToEndOfXmlDTD (Iterator& source) noexcept
|
||||
{
|
||||
bool lastWasQuestionMark = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c == 0 || (c == '>' && lastWasQuestionMark))
|
||||
break;
|
||||
|
||||
lastWasQuestionMark = (c == '?');
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipToEndOfXmlComment (Iterator& source) noexcept
|
||||
{
|
||||
juce_wchar last[2] = {};
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c == 0 || (c == '>' && last[0] == '-' && last[1] == '-'))
|
||||
break;
|
||||
|
||||
last[1] = last[0];
|
||||
last[0] = c;
|
||||
}
|
||||
}
|
||||
|
||||
int XmlTokeniser::readNextToken (CodeDocument::Iterator& source)
|
||||
{
|
||||
source.skipWhitespace();
|
||||
auto firstChar = source.peekNextChar();
|
||||
|
||||
switch (firstChar)
|
||||
{
|
||||
case 0: break;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
CppTokeniserFunctions::skipQuotedString (source);
|
||||
return tokenType_string;
|
||||
|
||||
case '<':
|
||||
{
|
||||
source.skip();
|
||||
source.skipWhitespace();
|
||||
auto nextChar = source.peekNextChar();
|
||||
|
||||
if (nextChar == '?')
|
||||
{
|
||||
source.skip();
|
||||
skipToEndOfXmlDTD (source);
|
||||
return tokenType_preprocessor;
|
||||
}
|
||||
|
||||
if (nextChar == '!')
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (source.peekNextChar() == '-')
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (source.peekNextChar() == '-')
|
||||
{
|
||||
skipToEndOfXmlComment (source);
|
||||
return tokenType_comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
|
||||
CppTokeniserFunctions::parseIdentifier (source);
|
||||
source.skipWhitespace();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
|
||||
source.skipWhitespace();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
|
||||
return tokenType_keyword;
|
||||
}
|
||||
|
||||
case '>':
|
||||
source.skip();
|
||||
return tokenType_keyword;
|
||||
|
||||
case '/':
|
||||
source.skip();
|
||||
source.skipWhitespace();
|
||||
CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
|
||||
return tokenType_keyword;
|
||||
|
||||
case '=':
|
||||
case ':':
|
||||
source.skip();
|
||||
return tokenType_operator;
|
||||
|
||||
default:
|
||||
if (CppTokeniserFunctions::isIdentifierStart (firstChar))
|
||||
CppTokeniserFunctions::parseIdentifier (source);
|
||||
|
||||
source.skip();
|
||||
break;
|
||||
};
|
||||
|
||||
return tokenType_identifier;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,63 +1,63 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API XmlTokeniser : public CodeTokeniser
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
XmlTokeniser();
|
||||
~XmlTokeniser() override;
|
||||
|
||||
//==============================================================================
|
||||
int readNextToken (CodeDocument::Iterator&) override;
|
||||
CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
|
||||
|
||||
/** The token values returned by this tokeniser. */
|
||||
enum TokenType
|
||||
{
|
||||
tokenType_error = 0,
|
||||
tokenType_comment,
|
||||
tokenType_keyword,
|
||||
tokenType_operator,
|
||||
tokenType_identifier,
|
||||
tokenType_string,
|
||||
tokenType_bracket,
|
||||
tokenType_punctuation,
|
||||
tokenType_preprocessor
|
||||
};
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API XmlTokeniser : public CodeTokeniser
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
XmlTokeniser();
|
||||
~XmlTokeniser() override;
|
||||
|
||||
//==============================================================================
|
||||
int readNextToken (CodeDocument::Iterator&) override;
|
||||
CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
|
||||
|
||||
/** The token values returned by this tokeniser. */
|
||||
enum TokenType
|
||||
{
|
||||
tokenType_error = 0,
|
||||
tokenType_comment,
|
||||
tokenType_keyword,
|
||||
tokenType_operator,
|
||||
tokenType_identifier,
|
||||
tokenType_string,
|
||||
tokenType_bracket,
|
||||
tokenType_punctuation,
|
||||
tokenType_preprocessor
|
||||
};
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlTokeniser)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
Reference in New Issue
Block a user