git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
74
deps/juce/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.cpp
vendored
Normal file
74
deps/juce/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.cpp
vendored
Normal file
@ -0,0 +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
|
72
deps/juce/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.h
vendored
Normal file
72
deps/juce/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.h
vendored
Normal file
@ -0,0 +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
|
674
deps/juce/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniserFunctions.h
vendored
Normal file
674
deps/juce/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniserFunctions.h
vendored
Normal file
@ -0,0 +1,674 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 containing some basic functions for simple tokenising of C++ code.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
struct CppTokeniserFunctions
|
||||
{
|
||||
static bool isIdentifierStart (const juce_wchar c) noexcept
|
||||
{
|
||||
return CharacterFunctions::isLetter (c)
|
||||
|| c == '_' || c == '@';
|
||||
}
|
||||
|
||||
static bool isIdentifierBody (const juce_wchar c) noexcept
|
||||
{
|
||||
return CharacterFunctions::isLetterOrDigit (c)
|
||||
|| c == '_' || c == '@';
|
||||
}
|
||||
|
||||
static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
|
||||
{
|
||||
static const char* const keywords2Char[] =
|
||||
{ "do", "if", "or", nullptr };
|
||||
|
||||
static const char* const keywords3Char[] =
|
||||
{ "and", "asm", "for", "int", "new", "not", "try", "xor", nullptr };
|
||||
|
||||
static const char* const keywords4Char[] =
|
||||
{ "auto", "bool", "case", "char", "else", "enum", "goto",
|
||||
"long", "this", "true", "void", nullptr };
|
||||
|
||||
static const char* const keywords5Char[] =
|
||||
{ "bitor", "break", "catch", "class", "compl", "const", "false", "final",
|
||||
"float", "or_eq", "short", "throw", "union", "using", "while", nullptr };
|
||||
|
||||
static const char* const keywords6Char[] =
|
||||
{ "and_eq", "bitand", "delete", "double", "export", "extern", "friend",
|
||||
"import", "inline", "module", "not_eq", "public", "return", "signed",
|
||||
"sizeof", "static", "struct", "switch", "typeid", "xor_eq", nullptr };
|
||||
|
||||
static const char* const keywords7Char[] =
|
||||
{ "__cdecl", "_Pragma", "alignas", "alignof", "concept", "default",
|
||||
"mutable", "nullptr", "private", "typedef", "uint8_t", "virtual",
|
||||
"wchar_t", nullptr };
|
||||
|
||||
static const char* const keywordsOther[] =
|
||||
{ "@class", "@dynamic", "@end", "@implementation", "@interface", "@public",
|
||||
"@private", "@protected", "@property", "@synthesize", "__fastcall", "__stdcall",
|
||||
"atomic_cancel", "atomic_commit", "atomic_noexcept", "char16_t", "char32_t",
|
||||
"co_await", "co_return", "co_yield", "const_cast", "constexpr", "continue",
|
||||
"decltype", "dynamic_cast", "explicit", "namespace", "noexcept", "operator", "override",
|
||||
"protected", "register", "reinterpret_cast", "requires", "static_assert",
|
||||
"static_cast", "synchronized", "template", "thread_local", "typename", "unsigned",
|
||||
"volatile", 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;
|
||||
case 7: k = keywords7Char; 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 (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 CPlusPlusCodeTokeniser::tokenType_keyword;
|
||||
}
|
||||
|
||||
return CPlusPlusCodeTokeniser::tokenType_identifier;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static bool skipNumberSuffix (Iterator& source)
|
||||
{
|
||||
auto c = source.peekNextChar();
|
||||
|
||||
if (c == 'l' || c == 'L' || c == 'u' || c == 'U')
|
||||
source.skip();
|
||||
|
||||
if (CharacterFunctions::isLetterOrDigit (source.peekNextChar()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isHexDigit (const juce_wchar c) noexcept
|
||||
{
|
||||
return (c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static bool parseHexLiteral (Iterator& source) noexcept
|
||||
{
|
||||
if (source.peekNextChar() == '-')
|
||||
source.skip();
|
||||
|
||||
if (source.nextChar() != '0')
|
||||
return false;
|
||||
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c != 'x' && c != 'X')
|
||||
return false;
|
||||
|
||||
int numDigits = 0;
|
||||
|
||||
while (isHexDigit (source.peekNextChar()))
|
||||
{
|
||||
++numDigits;
|
||||
source.skip();
|
||||
}
|
||||
|
||||
if (numDigits == 0)
|
||||
return false;
|
||||
|
||||
return skipNumberSuffix (source);
|
||||
}
|
||||
|
||||
static bool isOctalDigit (const juce_wchar c) noexcept
|
||||
{
|
||||
return c >= '0' && c <= '7';
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static bool parseOctalLiteral (Iterator& source) noexcept
|
||||
{
|
||||
if (source.peekNextChar() == '-')
|
||||
source.skip();
|
||||
|
||||
if (source.nextChar() != '0')
|
||||
return false;
|
||||
|
||||
if (! isOctalDigit (source.nextChar()))
|
||||
return false;
|
||||
|
||||
while (isOctalDigit (source.peekNextChar()))
|
||||
source.skip();
|
||||
|
||||
return skipNumberSuffix (source);
|
||||
}
|
||||
|
||||
static bool isDecimalDigit (const juce_wchar c) noexcept
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static bool parseDecimalLiteral (Iterator& source) noexcept
|
||||
{
|
||||
if (source.peekNextChar() == '-')
|
||||
source.skip();
|
||||
|
||||
int numChars = 0;
|
||||
while (isDecimalDigit (source.peekNextChar()))
|
||||
{
|
||||
++numChars;
|
||||
source.skip();
|
||||
}
|
||||
|
||||
if (numChars == 0)
|
||||
return false;
|
||||
|
||||
return skipNumberSuffix (source);
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static bool parseFloatLiteral (Iterator& source) noexcept
|
||||
{
|
||||
if (source.peekNextChar() == '-')
|
||||
source.skip();
|
||||
|
||||
int numDigits = 0;
|
||||
|
||||
while (isDecimalDigit (source.peekNextChar()))
|
||||
{
|
||||
source.skip();
|
||||
++numDigits;
|
||||
}
|
||||
|
||||
const bool hasPoint = (source.peekNextChar() == '.');
|
||||
|
||||
if (hasPoint)
|
||||
{
|
||||
source.skip();
|
||||
|
||||
while (isDecimalDigit (source.peekNextChar()))
|
||||
{
|
||||
source.skip();
|
||||
++numDigits;
|
||||
}
|
||||
}
|
||||
|
||||
if (numDigits == 0)
|
||||
return false;
|
||||
|
||||
auto c = source.peekNextChar();
|
||||
bool hasExponent = (c == 'e' || c == 'E');
|
||||
|
||||
if (hasExponent)
|
||||
{
|
||||
source.skip();
|
||||
c = source.peekNextChar();
|
||||
|
||||
if (c == '+' || c == '-')
|
||||
source.skip();
|
||||
|
||||
int numExpDigits = 0;
|
||||
|
||||
while (isDecimalDigit (source.peekNextChar()))
|
||||
{
|
||||
source.skip();
|
||||
++numExpDigits;
|
||||
}
|
||||
|
||||
if (numExpDigits == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
c = source.peekNextChar();
|
||||
|
||||
if (c == 'f' || c == 'F')
|
||||
source.skip();
|
||||
else if (! (hasExponent || hasPoint))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static int parseNumber (Iterator& source)
|
||||
{
|
||||
const Iterator original (source);
|
||||
|
||||
if (parseFloatLiteral (source)) return CPlusPlusCodeTokeniser::tokenType_float;
|
||||
source = original;
|
||||
|
||||
if (parseHexLiteral (source)) return CPlusPlusCodeTokeniser::tokenType_integer;
|
||||
source = original;
|
||||
|
||||
if (parseOctalLiteral (source)) return CPlusPlusCodeTokeniser::tokenType_integer;
|
||||
source = original;
|
||||
|
||||
if (parseDecimalLiteral (source)) return CPlusPlusCodeTokeniser::tokenType_integer;
|
||||
source = original;
|
||||
|
||||
return CPlusPlusCodeTokeniser::tokenType_error;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipQuotedString (Iterator& source) noexcept
|
||||
{
|
||||
auto quote = source.nextChar();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c == quote || c == 0)
|
||||
break;
|
||||
|
||||
if (c == '\\')
|
||||
source.skip();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipComment (Iterator& source) noexcept
|
||||
{
|
||||
bool lastWasStar = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.nextChar();
|
||||
|
||||
if (c == 0 || (c == '/' && lastWasStar))
|
||||
break;
|
||||
|
||||
lastWasStar = (c == '*');
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipPreprocessorLine (Iterator& source) noexcept
|
||||
{
|
||||
bool lastWasBackslash = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = source.peekNextChar();
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
skipQuotedString (source);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '/')
|
||||
{
|
||||
Iterator next (source);
|
||||
next.skip();
|
||||
auto c2 = next.peekNextChar();
|
||||
|
||||
if (c2 == '/' || c2 == '*')
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
if (c == '\n' || c == '\r')
|
||||
{
|
||||
source.skipToEndOfLine();
|
||||
|
||||
if (lastWasBackslash)
|
||||
skipPreprocessorLine (source);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lastWasBackslash = (c == '\\');
|
||||
source.skip();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipIfNextCharMatches (Iterator& source, const juce_wchar c) noexcept
|
||||
{
|
||||
if (source.peekNextChar() == c)
|
||||
source.skip();
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void skipIfNextCharMatches (Iterator& source, const juce_wchar c1, const juce_wchar c2) noexcept
|
||||
{
|
||||
auto c = source.peekNextChar();
|
||||
|
||||
if (c == c1 || c == c2)
|
||||
source.skip();
|
||||
}
|
||||
|
||||
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 = parseNumber (source);
|
||||
|
||||
if (result == CPlusPlusCodeTokeniser::tokenType_error)
|
||||
{
|
||||
source.skip();
|
||||
|
||||
if (firstChar == '.')
|
||||
return CPlusPlusCodeTokeniser::tokenType_punctuation;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case ',':
|
||||
case ';':
|
||||
case ':':
|
||||
source.skip();
|
||||
return CPlusPlusCodeTokeniser::tokenType_punctuation;
|
||||
|
||||
case '(': case ')':
|
||||
case '{': case '}':
|
||||
case '[': case ']':
|
||||
source.skip();
|
||||
return CPlusPlusCodeTokeniser::tokenType_bracket;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
skipQuotedString (source);
|
||||
return CPlusPlusCodeTokeniser::tokenType_string;
|
||||
|
||||
case '+':
|
||||
source.skip();
|
||||
skipIfNextCharMatches (source, '+', '=');
|
||||
return CPlusPlusCodeTokeniser::tokenType_operator;
|
||||
|
||||
case '-':
|
||||
{
|
||||
source.skip();
|
||||
auto result = parseNumber (source);
|
||||
|
||||
if (result == CPlusPlusCodeTokeniser::tokenType_error)
|
||||
{
|
||||
skipIfNextCharMatches (source, '-', '=');
|
||||
return CPlusPlusCodeTokeniser::tokenType_operator;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case '*': case '%':
|
||||
case '=': case '!':
|
||||
source.skip();
|
||||
skipIfNextCharMatches (source, '=');
|
||||
return CPlusPlusCodeTokeniser::tokenType_operator;
|
||||
|
||||
case '/':
|
||||
{
|
||||
source.skip();
|
||||
auto nextChar = source.peekNextChar();
|
||||
|
||||
if (nextChar == '/')
|
||||
{
|
||||
source.skipToEndOfLine();
|
||||
return CPlusPlusCodeTokeniser::tokenType_comment;
|
||||
}
|
||||
|
||||
if (nextChar == '*')
|
||||
{
|
||||
source.skip();
|
||||
skipComment (source);
|
||||
return CPlusPlusCodeTokeniser::tokenType_comment;
|
||||
}
|
||||
|
||||
if (nextChar == '=')
|
||||
source.skip();
|
||||
|
||||
return CPlusPlusCodeTokeniser::tokenType_operator;
|
||||
}
|
||||
|
||||
case '?':
|
||||
case '~':
|
||||
source.skip();
|
||||
return CPlusPlusCodeTokeniser::tokenType_operator;
|
||||
|
||||
case '<': case '>':
|
||||
case '|': case '&': case '^':
|
||||
source.skip();
|
||||
skipIfNextCharMatches (source, firstChar);
|
||||
skipIfNextCharMatches (source, '=');
|
||||
return CPlusPlusCodeTokeniser::tokenType_operator;
|
||||
|
||||
case '#':
|
||||
skipPreprocessorLine (source);
|
||||
return CPlusPlusCodeTokeniser::tokenType_preprocessor;
|
||||
|
||||
default:
|
||||
if (isIdentifierStart (firstChar))
|
||||
return parseIdentifier (source);
|
||||
|
||||
source.skip();
|
||||
break;
|
||||
}
|
||||
|
||||
return CPlusPlusCodeTokeniser::tokenType_error;
|
||||
}
|
||||
|
||||
/** A class that can be passed to the CppTokeniserFunctions functions in order to
|
||||
parse a String.
|
||||
*/
|
||||
struct StringIterator
|
||||
{
|
||||
StringIterator (const String& s) noexcept : t (s.getCharPointer()) {}
|
||||
StringIterator (String::CharPointerType s) noexcept : t (s) {}
|
||||
|
||||
juce_wchar nextChar() noexcept { if (isEOF()) return 0; ++numChars; return t.getAndAdvance(); }
|
||||
juce_wchar peekNextChar()noexcept { return *t; }
|
||||
void skip() noexcept { if (! isEOF()) { ++t; ++numChars; } }
|
||||
void skipWhitespace() noexcept { while (t.isWhitespace()) skip(); }
|
||||
void skipToEndOfLine() noexcept { while (*t != '\r' && *t != '\n' && *t != 0) skip(); }
|
||||
bool isEOF() const noexcept { return t.isEmpty(); }
|
||||
|
||||
String::CharPointerType t;
|
||||
int numChars = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Takes a UTF8 string and writes it to a stream using standard C++ escape sequences for any
|
||||
non-ascii bytes.
|
||||
|
||||
Although not strictly a tokenising function, this is still a function that often comes in
|
||||
handy when working with C++ code!
|
||||
|
||||
Note that addEscapeChars() is easier to use than this function if you're working with Strings.
|
||||
|
||||
@see addEscapeChars
|
||||
*/
|
||||
static void writeEscapeChars (OutputStream& out, const char* utf8, const int numBytesToRead,
|
||||
const int maxCharsOnLine, const bool breakAtNewLines,
|
||||
const bool replaceSingleQuotes, const bool allowStringBreaks)
|
||||
{
|
||||
int charsOnLine = 0;
|
||||
bool lastWasHexEscapeCode = false;
|
||||
bool trigraphDetected = false;
|
||||
|
||||
for (int i = 0; i < numBytesToRead || numBytesToRead < 0; ++i)
|
||||
{
|
||||
auto c = (unsigned char) utf8[i];
|
||||
bool startNewLine = false;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
|
||||
case '\t': out << "\\t"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
|
||||
case '\r': out << "\\r"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
|
||||
case '\n': out << "\\n"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; startNewLine = breakAtNewLines; break;
|
||||
case '\\': out << "\\\\"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
|
||||
case '\"': out << "\\\""; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
|
||||
|
||||
case '?':
|
||||
if (trigraphDetected)
|
||||
{
|
||||
out << "\\?";
|
||||
charsOnLine++;
|
||||
trigraphDetected = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "?";
|
||||
trigraphDetected = true;
|
||||
}
|
||||
|
||||
lastWasHexEscapeCode = false;
|
||||
charsOnLine++;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (numBytesToRead < 0)
|
||||
return;
|
||||
|
||||
out << "\\0";
|
||||
lastWasHexEscapeCode = true;
|
||||
trigraphDetected = false;
|
||||
charsOnLine += 2;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
if (replaceSingleQuotes)
|
||||
{
|
||||
out << "\\\'";
|
||||
lastWasHexEscapeCode = false;
|
||||
trigraphDetected = false;
|
||||
charsOnLine += 2;
|
||||
break;
|
||||
}
|
||||
// deliberate fall-through...
|
||||
JUCE_FALLTHROUGH
|
||||
|
||||
default:
|
||||
if (c >= 32 && c < 127 && ! (lastWasHexEscapeCode // (have to avoid following a hex escape sequence with a valid hex digit)
|
||||
&& CharacterFunctions::getHexDigitValue (c) >= 0))
|
||||
{
|
||||
out << (char) c;
|
||||
lastWasHexEscapeCode = false;
|
||||
trigraphDetected = false;
|
||||
++charsOnLine;
|
||||
}
|
||||
else if (allowStringBreaks && lastWasHexEscapeCode && c >= 32 && c < 127)
|
||||
{
|
||||
out << "\"\"" << (char) c;
|
||||
lastWasHexEscapeCode = false;
|
||||
trigraphDetected = false;
|
||||
charsOnLine += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << (c < 16 ? "\\x0" : "\\x") << String::toHexString ((int) c);
|
||||
lastWasHexEscapeCode = true;
|
||||
trigraphDetected = false;
|
||||
charsOnLine += 4;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((startNewLine || (maxCharsOnLine > 0 && charsOnLine >= maxCharsOnLine))
|
||||
&& (numBytesToRead < 0 || i < numBytesToRead - 1))
|
||||
{
|
||||
charsOnLine = 0;
|
||||
out << "\"" << newLine << "\"";
|
||||
lastWasHexEscapeCode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Takes a string and returns a version of it where standard C++ escape sequences have been
|
||||
used to replace any non-ascii bytes.
|
||||
|
||||
Although not strictly a tokenising function, this is still a function that often comes in
|
||||
handy when working with C++ code!
|
||||
|
||||
@see writeEscapeChars
|
||||
*/
|
||||
static String addEscapeChars (const String& s)
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
writeEscapeChars (mo, s.toRawUTF8(), -1, -1, false, true, true);
|
||||
return mo.toString();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace juce
|
1297
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp
vendored
Normal file
1297
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
450
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeDocument.h
vendored
Normal file
450
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeDocument.h
vendored
Normal file
@ -0,0 +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
|
1839
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp
vendored
Normal file
1839
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
456
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h
vendored
Normal file
456
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
59
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeTokeniser.h
vendored
Normal file
59
deps/juce/modules/juce_gui_extra/code_editor/juce_CodeTokeniser.h
vendored
Normal file
@ -0,0 +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
|
239
deps/juce/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.cpp
vendored
Normal file
239
deps/juce/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.cpp
vendored
Normal file
@ -0,0 +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
|
65
deps/juce/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.h
vendored
Normal file
65
deps/juce/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.h
vendored
Normal file
@ -0,0 +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
|
172
deps/juce/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.cpp
vendored
Normal file
172
deps/juce/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.cpp
vendored
Normal file
@ -0,0 +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
|
63
deps/juce/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h
vendored
Normal file
63
deps/juce/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h
vendored
Normal file
@ -0,0 +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
|
Reference in New Issue
Block a user