mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-21 03:21:43 -06:00
Merge branch 'json_cell_edit'
This commit is contained in:
298
libs/qscintilla/Qt4Qt5/qscilexerjson.cpp
Normal file
298
libs/qscintilla/Qt4Qt5/qscilexerjson.cpp
Normal file
@@ -0,0 +1,298 @@
|
||||
// This module implements the QsciLexerJSON class.
|
||||
//
|
||||
// Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
//
|
||||
// This file is part of QScintilla.
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public License
|
||||
// version 3.0 as published by the Free Software Foundation and appearing in
|
||||
// the file LICENSE included in the packaging of this file. Please review the
|
||||
// following information to ensure the GNU General Public License version 3.0
|
||||
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
|
||||
//
|
||||
// If you do not wish to use this file under the terms of the GPL version 3.0
|
||||
// then you may purchase a commercial license. For more information contact
|
||||
// info@riverbankcomputing.com.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
#include "Qsci/qscilexerjson.h"
|
||||
|
||||
#include <qcolor.h>
|
||||
#include <qfont.h>
|
||||
#include <qsettings.h>
|
||||
|
||||
|
||||
// The ctor.
|
||||
QsciLexerJSON::QsciLexerJSON(QObject *parent)
|
||||
: QsciLexer(parent),
|
||||
allow_comments(true), escape_sequence(true), fold_compact(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// The dtor.
|
||||
QsciLexerJSON::~QsciLexerJSON()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Returns the language name.
|
||||
const char *QsciLexerJSON::language() const
|
||||
{
|
||||
return "JSON";
|
||||
}
|
||||
|
||||
|
||||
// Returns the lexer name.
|
||||
const char *QsciLexerJSON::lexer() const
|
||||
{
|
||||
return "json";
|
||||
}
|
||||
|
||||
|
||||
// Returns the foreground colour of the text for a style.
|
||||
QColor QsciLexerJSON::defaultColor(int style) const
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case UnclosedString:
|
||||
case Error:
|
||||
return QColor(0xff, 0xff, 0xff);
|
||||
|
||||
case Number:
|
||||
return QColor(0x00, 0x7f, 0x7f);
|
||||
|
||||
case String:
|
||||
return QColor(0x7f, 0x00, 0x00);
|
||||
|
||||
case Property:
|
||||
return QColor(0x88, 0x0a, 0xe8);
|
||||
|
||||
case EscapeSequence:
|
||||
return QColor(0x0b, 0x98, 0x2e);
|
||||
|
||||
case CommentLine:
|
||||
case CommentBlock:
|
||||
return QColor(0x05, 0xbb, 0xae);
|
||||
|
||||
case Operator:
|
||||
return QColor(0x18, 0x64, 0x4a);
|
||||
|
||||
case IRI:
|
||||
return QColor(0x00, 0x00, 0xff);
|
||||
|
||||
case IRICompact:
|
||||
return QColor(0xd1, 0x37, 0xc1);
|
||||
|
||||
case Keyword:
|
||||
return QColor(0x0b, 0xce, 0xa7);
|
||||
|
||||
case KeywordLD:
|
||||
return QColor(0xec, 0x28, 0x06);
|
||||
}
|
||||
|
||||
return QsciLexer::defaultColor(style);
|
||||
}
|
||||
|
||||
|
||||
// Returns the end-of-line fill for a style.
|
||||
bool QsciLexerJSON::defaultEolFill(int style) const
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case UnclosedString:
|
||||
return true;
|
||||
}
|
||||
|
||||
return QsciLexer::defaultEolFill(style);
|
||||
}
|
||||
|
||||
|
||||
// Returns the font of the text for a style.
|
||||
QFont QsciLexerJSON::defaultFont(int style) const
|
||||
{
|
||||
QFont f;
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case CommentLine:
|
||||
f = QsciLexer::defaultFont(style);
|
||||
f.setItalic(true);
|
||||
break;
|
||||
|
||||
case Keyword:
|
||||
f = QsciLexer::defaultFont(style);
|
||||
f.setBold(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
f = QsciLexer::defaultFont(style);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
// Returns the set of keywords.
|
||||
const char *QsciLexerJSON::keywords(int set) const
|
||||
{
|
||||
if (set == 1)
|
||||
return "false true null";
|
||||
|
||||
if (set == 2)
|
||||
return
|
||||
"@id @context @type @value @language @container @list @set "
|
||||
"@reverse @index @base @vocab @graph";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the user name of a style.
|
||||
QString QsciLexerJSON::description(int style) const
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case Default:
|
||||
return tr("Default");
|
||||
|
||||
case Number:
|
||||
return tr("Number");
|
||||
|
||||
case String:
|
||||
return tr("String");
|
||||
|
||||
case UnclosedString:
|
||||
return tr("Unclosed string");
|
||||
|
||||
case Property:
|
||||
return tr("Property");
|
||||
|
||||
case EscapeSequence:
|
||||
return tr("Escape sequence");
|
||||
|
||||
case CommentLine:
|
||||
return tr("Line comment");
|
||||
|
||||
case CommentBlock:
|
||||
return tr("Block comment");
|
||||
|
||||
case Operator:
|
||||
return tr("Operator");
|
||||
|
||||
case IRI:
|
||||
return tr("IRI");
|
||||
|
||||
case IRICompact:
|
||||
return tr("JSON-LD compact IRI");
|
||||
|
||||
case Keyword:
|
||||
return tr("JSON keyword");
|
||||
|
||||
case KeywordLD:
|
||||
return tr("JSON-LD keyword");
|
||||
|
||||
case Error:
|
||||
return tr("Parsing error");
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
// Returns the background colour of the text for a style.
|
||||
QColor QsciLexerJSON::defaultPaper(int style) const
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case UnclosedString:
|
||||
case Error:
|
||||
return QColor(0xff, 0x00, 0x00);
|
||||
}
|
||||
|
||||
return QsciLexer::defaultPaper(style);
|
||||
}
|
||||
|
||||
|
||||
// Refresh all properties.
|
||||
void QsciLexerJSON::refreshProperties()
|
||||
{
|
||||
setAllowCommentsProp();
|
||||
setEscapeSequenceProp();
|
||||
setCompactProp();
|
||||
}
|
||||
|
||||
|
||||
// Read properties from the settings.
|
||||
bool QsciLexerJSON::readProperties(QSettings &qs,const QString &prefix)
|
||||
{
|
||||
allow_comments = qs.value(prefix + "allowcomments", true).toBool();
|
||||
escape_sequence = qs.value(prefix + "escapesequence", true).toBool();
|
||||
fold_compact = qs.value(prefix + "foldcompact", true).toBool();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Write properties to the settings.
|
||||
bool QsciLexerJSON::writeProperties(QSettings &qs,const QString &prefix) const
|
||||
{
|
||||
qs.setValue(prefix + "allowcomments", allow_comments);
|
||||
qs.setValue(prefix + "escapesequence", escape_sequence);
|
||||
qs.setValue(prefix + "foldcompact", fold_compact);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Set if comments are highlighted
|
||||
void QsciLexerJSON::setHighlightComments(bool highlight)
|
||||
{
|
||||
allow_comments = highlight;
|
||||
|
||||
setAllowCommentsProp();
|
||||
}
|
||||
|
||||
|
||||
// Set the "lexer.json.allow.comments" property.
|
||||
void QsciLexerJSON::setAllowCommentsProp()
|
||||
{
|
||||
emit propertyChanged("lexer.json.allow.comments",
|
||||
(allow_comments ? "1" : "0"));
|
||||
}
|
||||
|
||||
|
||||
// Set if escape sequences are highlighted.
|
||||
void QsciLexerJSON::setHighlightEscapeSequences(bool highlight)
|
||||
{
|
||||
escape_sequence = highlight;
|
||||
|
||||
setEscapeSequenceProp();
|
||||
}
|
||||
|
||||
|
||||
// Set the "lexer.json.escape.sequence" property.
|
||||
void QsciLexerJSON::setEscapeSequenceProp()
|
||||
{
|
||||
emit propertyChanged("lexer.json.escape.sequence",
|
||||
(escape_sequence ? "1" : "0"));
|
||||
}
|
||||
|
||||
|
||||
// Set if folds are compact.
|
||||
void QsciLexerJSON::setFoldCompact(bool fold)
|
||||
{
|
||||
fold_compact = fold;
|
||||
|
||||
setCompactProp();
|
||||
}
|
||||
|
||||
|
||||
// Set the "fold.compact" property.
|
||||
void QsciLexerJSON::setCompactProp()
|
||||
{
|
||||
emit propertyChanged("fold.compact", (fold_compact ? "1" : "0"));
|
||||
}
|
||||
497
libs/qscintilla/lexers/LexJSON.cpp
Normal file
497
libs/qscintilla/lexers/LexJSON.cpp
Normal file
@@ -0,0 +1,497 @@
|
||||
// Scintilla source code edit control
|
||||
/**
|
||||
* @file LexJSON.cxx
|
||||
* @date February 19, 2016
|
||||
* @brief Lexer for JSON and JSON-LD formats
|
||||
* @author nkmathew
|
||||
*
|
||||
* The License.txt file describes the conditions under which this software may
|
||||
* be distributed.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "ILexer.h"
|
||||
#include "Scintilla.h"
|
||||
#include "SciLexer.h"
|
||||
#include "WordList.h"
|
||||
#include "LexAccessor.h"
|
||||
#include "StyleContext.h"
|
||||
#include "CharacterSet.h"
|
||||
#include "LexerModule.h"
|
||||
#include "OptionSet.h"
|
||||
|
||||
#ifdef SCI_NAMESPACE
|
||||
using namespace Scintilla;
|
||||
#endif
|
||||
|
||||
static const char *const JSONWordListDesc[] = {
|
||||
"JSON Keywords",
|
||||
"JSON-LD Keywords",
|
||||
0
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to detect compact IRI/URLs in JSON-LD without first looking ahead for the
|
||||
* colon separating the prefix and suffix
|
||||
*
|
||||
* https://www.w3.org/TR/json-ld/#dfn-compact-iri
|
||||
*/
|
||||
struct CompactIRI {
|
||||
int colonCount;
|
||||
bool foundInvalidChar;
|
||||
CharacterSet setCompactIRI;
|
||||
CompactIRI() {
|
||||
colonCount = 0;
|
||||
foundInvalidChar = false;
|
||||
setCompactIRI = CharacterSet(CharacterSet::setAlpha, "$_-");
|
||||
}
|
||||
void resetState() {
|
||||
colonCount = 0;
|
||||
foundInvalidChar = false;
|
||||
}
|
||||
void checkChar(int ch) {
|
||||
if (ch == ':') {
|
||||
colonCount++;
|
||||
} else {
|
||||
foundInvalidChar |= !setCompactIRI.Contains(ch);
|
||||
}
|
||||
}
|
||||
bool shouldHighlight() const {
|
||||
return !foundInvalidChar && colonCount == 1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeps track of escaped characters in strings as per:
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc7159#section-7
|
||||
*/
|
||||
struct EscapeSequence {
|
||||
int digitsLeft;
|
||||
CharacterSet setHexDigits;
|
||||
CharacterSet setEscapeChars;
|
||||
EscapeSequence() {
|
||||
digitsLeft = 0;
|
||||
setHexDigits = CharacterSet(CharacterSet::setDigits, "ABCDEFabcdef");
|
||||
setEscapeChars = CharacterSet(CharacterSet::setNone, "\\\"tnbfru/");
|
||||
}
|
||||
// Returns true if the following character is a valid escaped character
|
||||
bool newSequence(int nextChar) {
|
||||
digitsLeft = 0;
|
||||
if (nextChar == 'u') {
|
||||
digitsLeft = 5;
|
||||
} else if (!setEscapeChars.Contains(nextChar)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool atEscapeEnd() const {
|
||||
return digitsLeft <= 0;
|
||||
}
|
||||
bool isInvalidChar(int currChar) const {
|
||||
return !setHexDigits.Contains(currChar);
|
||||
}
|
||||
};
|
||||
|
||||
struct OptionsJSON {
|
||||
bool foldCompact;
|
||||
bool fold;
|
||||
bool allowComments;
|
||||
bool escapeSequence;
|
||||
OptionsJSON() {
|
||||
foldCompact = false;
|
||||
fold = false;
|
||||
allowComments = false;
|
||||
escapeSequence = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct OptionSetJSON : public OptionSet<OptionsJSON> {
|
||||
OptionSetJSON() {
|
||||
DefineProperty("lexer.json.escape.sequence", &OptionsJSON::escapeSequence,
|
||||
"Set to 1 to enable highlighting of escape sequences in strings");
|
||||
|
||||
DefineProperty("lexer.json.allow.comments", &OptionsJSON::allowComments,
|
||||
"Set to 1 to enable highlighting of line/block comments in JSON");
|
||||
|
||||
DefineProperty("fold.compact", &OptionsJSON::foldCompact);
|
||||
DefineProperty("fold", &OptionsJSON::fold);
|
||||
DefineWordListSets(JSONWordListDesc);
|
||||
}
|
||||
};
|
||||
|
||||
class LexerJSON : public ILexer {
|
||||
OptionsJSON options;
|
||||
OptionSetJSON optSetJSON;
|
||||
EscapeSequence escapeSeq;
|
||||
WordList keywordsJSON;
|
||||
WordList keywordsJSONLD;
|
||||
CharacterSet setOperators;
|
||||
CharacterSet setURL;
|
||||
CharacterSet setKeywordJSONLD;
|
||||
CharacterSet setKeywordJSON;
|
||||
CompactIRI compactIRI;
|
||||
|
||||
static bool IsNextNonWhitespace(LexAccessor &styler, Sci_Position start, char ch) {
|
||||
Sci_Position i = 0;
|
||||
while (i < 50) {
|
||||
i++;
|
||||
char curr = styler.SafeGetCharAt(start+i, '\0');
|
||||
char next = styler.SafeGetCharAt(start+i+1, '\0');
|
||||
bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
|
||||
if (curr == ch) {
|
||||
return true;
|
||||
} else if (!isspacechar(curr) || atEOL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for the colon following the end quote
|
||||
*
|
||||
* Assumes property names of lengths no longer than a 100 characters.
|
||||
* The colon is also expected to be less than 50 spaces after the end
|
||||
* quote for the string to be considered a property name
|
||||
*/
|
||||
static bool AtPropertyName(LexAccessor &styler, Sci_Position start) {
|
||||
Sci_Position i = 0;
|
||||
bool escaped = false;
|
||||
while (i < 100) {
|
||||
i++;
|
||||
char curr = styler.SafeGetCharAt(start+i, '\0');
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
escaped = curr == '\\';
|
||||
if (curr == '"') {
|
||||
return IsNextNonWhitespace(styler, start+i, ':');
|
||||
} else if (!curr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsNextWordInList(WordList &keywordList, CharacterSet wordSet,
|
||||
StyleContext &context, LexAccessor &styler) {
|
||||
char word[51];
|
||||
Sci_Position currPos = (Sci_Position) context.currentPos;
|
||||
int i = 0;
|
||||
while (i < 50) {
|
||||
char ch = styler.SafeGetCharAt(currPos + i);
|
||||
if (!wordSet.Contains(ch)) {
|
||||
break;
|
||||
}
|
||||
word[i] = ch;
|
||||
i++;
|
||||
}
|
||||
word[i] = '\0';
|
||||
return keywordList.InList(word);
|
||||
}
|
||||
|
||||
public:
|
||||
LexerJSON() :
|
||||
setOperators(CharacterSet::setNone, "[{}]:,"),
|
||||
setURL(CharacterSet::setAlphaNum, "-._~:/?#[]@!$&'()*+,),="),
|
||||
setKeywordJSONLD(CharacterSet::setAlpha, ":@"),
|
||||
setKeywordJSON(CharacterSet::setAlpha, "$_") {
|
||||
}
|
||||
virtual ~LexerJSON() {}
|
||||
virtual int SCI_METHOD Version() const {
|
||||
return lvOriginal;
|
||||
}
|
||||
virtual void SCI_METHOD Release() {
|
||||
delete this;
|
||||
}
|
||||
virtual const char *SCI_METHOD PropertyNames() {
|
||||
return optSetJSON.PropertyNames();
|
||||
}
|
||||
virtual int SCI_METHOD PropertyType(const char *name) {
|
||||
return optSetJSON.PropertyType(name);
|
||||
}
|
||||
virtual const char *SCI_METHOD DescribeProperty(const char *name) {
|
||||
return optSetJSON.DescribeProperty(name);
|
||||
}
|
||||
virtual Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) {
|
||||
if (optSetJSON.PropertySet(&options, key, val)) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
virtual Sci_Position SCI_METHOD WordListSet(int n, const char *wl) {
|
||||
WordList *wordListN = 0;
|
||||
switch (n) {
|
||||
case 0:
|
||||
wordListN = &keywordsJSON;
|
||||
break;
|
||||
case 1:
|
||||
wordListN = &keywordsJSONLD;
|
||||
break;
|
||||
}
|
||||
Sci_Position firstModification = -1;
|
||||
if (wordListN) {
|
||||
WordList wlNew;
|
||||
wlNew.Set(wl);
|
||||
if (*wordListN != wlNew) {
|
||||
wordListN->Set(wl);
|
||||
firstModification = 0;
|
||||
}
|
||||
}
|
||||
return firstModification;
|
||||
}
|
||||
virtual void *SCI_METHOD PrivateCall(int, void *) {
|
||||
return 0;
|
||||
}
|
||||
static ILexer *LexerFactoryJSON() {
|
||||
return new LexerJSON;
|
||||
}
|
||||
virtual const char *SCI_METHOD DescribeWordListSets() {
|
||||
return optSetJSON.DescribeWordListSets();
|
||||
}
|
||||
virtual void SCI_METHOD Lex(Sci_PositionU startPos,
|
||||
Sci_Position length,
|
||||
int initStyle,
|
||||
IDocument *pAccess);
|
||||
virtual void SCI_METHOD Fold(Sci_PositionU startPos,
|
||||
Sci_Position length,
|
||||
int initStyle,
|
||||
IDocument *pAccess);
|
||||
};
|
||||
|
||||
void SCI_METHOD LexerJSON::Lex(Sci_PositionU startPos,
|
||||
Sci_Position length,
|
||||
int initStyle,
|
||||
IDocument *pAccess) {
|
||||
LexAccessor styler(pAccess);
|
||||
StyleContext context(startPos, length, initStyle, styler);
|
||||
int stringStyleBefore = SCE_JSON_STRING;
|
||||
while (context.More()) {
|
||||
switch (context.state) {
|
||||
case SCE_JSON_BLOCKCOMMENT:
|
||||
if (context.Match("*/")) {
|
||||
context.Forward();
|
||||
context.ForwardSetState(SCE_JSON_DEFAULT);
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_LINECOMMENT:
|
||||
if (context.atLineEnd) {
|
||||
context.SetState(SCE_JSON_DEFAULT);
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_STRINGEOL:
|
||||
if (context.atLineStart) {
|
||||
context.SetState(SCE_JSON_DEFAULT);
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_ESCAPESEQUENCE:
|
||||
escapeSeq.digitsLeft--;
|
||||
if (!escapeSeq.atEscapeEnd()) {
|
||||
if (escapeSeq.isInvalidChar(context.ch)) {
|
||||
context.SetState(SCE_JSON_ERROR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (context.ch == '"') {
|
||||
context.SetState(stringStyleBefore);
|
||||
context.ForwardSetState(SCE_C_DEFAULT);
|
||||
} else if (context.ch == '\\') {
|
||||
if (!escapeSeq.newSequence(context.chNext)) {
|
||||
context.SetState(SCE_JSON_ERROR);
|
||||
}
|
||||
context.Forward();
|
||||
} else {
|
||||
context.SetState(stringStyleBefore);
|
||||
if (context.atLineEnd) {
|
||||
context.ChangeState(SCE_JSON_STRINGEOL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_PROPERTYNAME:
|
||||
case SCE_JSON_STRING:
|
||||
if (context.ch == '"') {
|
||||
if (compactIRI.shouldHighlight()) {
|
||||
context.ChangeState(SCE_JSON_COMPACTIRI);
|
||||
context.ForwardSetState(SCE_JSON_DEFAULT);
|
||||
compactIRI.resetState();
|
||||
} else {
|
||||
context.ForwardSetState(SCE_JSON_DEFAULT);
|
||||
}
|
||||
} else if (context.atLineEnd) {
|
||||
context.ChangeState(SCE_JSON_STRINGEOL);
|
||||
} else if (context.ch == '\\') {
|
||||
stringStyleBefore = context.state;
|
||||
if (options.escapeSequence) {
|
||||
context.SetState(SCE_JSON_ESCAPESEQUENCE);
|
||||
if (!escapeSeq.newSequence(context.chNext)) {
|
||||
context.SetState(SCE_JSON_ERROR);
|
||||
}
|
||||
}
|
||||
context.Forward();
|
||||
} else if (context.Match("https://") ||
|
||||
context.Match("http://") ||
|
||||
context.Match("ssh://") ||
|
||||
context.Match("git://") ||
|
||||
context.Match("svn://") ||
|
||||
context.Match("ftp://") ||
|
||||
context.Match("mailto:")) {
|
||||
// Handle most common URI schemes only
|
||||
stringStyleBefore = context.state;
|
||||
context.SetState(SCE_JSON_URI);
|
||||
} else if (context.ch == '@') {
|
||||
// https://www.w3.org/TR/json-ld/#dfn-keyword
|
||||
if (IsNextWordInList(keywordsJSONLD, setKeywordJSONLD, context, styler)) {
|
||||
stringStyleBefore = context.state;
|
||||
context.SetState(SCE_JSON_LDKEYWORD);
|
||||
}
|
||||
} else {
|
||||
compactIRI.checkChar(context.ch);
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_LDKEYWORD:
|
||||
case SCE_JSON_URI:
|
||||
if ((!setKeywordJSONLD.Contains(context.ch) &&
|
||||
(context.state == SCE_JSON_LDKEYWORD)) ||
|
||||
(!setURL.Contains(context.ch))) {
|
||||
context.SetState(stringStyleBefore);
|
||||
}
|
||||
if (context.ch == '"') {
|
||||
context.ForwardSetState(SCE_JSON_DEFAULT);
|
||||
} else if (context.atLineEnd) {
|
||||
context.ChangeState(SCE_JSON_STRINGEOL);
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_OPERATOR:
|
||||
case SCE_JSON_NUMBER:
|
||||
context.SetState(SCE_JSON_DEFAULT);
|
||||
break;
|
||||
case SCE_JSON_ERROR:
|
||||
if (context.atLineEnd) {
|
||||
context.SetState(SCE_JSON_DEFAULT);
|
||||
}
|
||||
break;
|
||||
case SCE_JSON_KEYWORD:
|
||||
if (!setKeywordJSON.Contains(context.ch)) {
|
||||
context.SetState(SCE_JSON_DEFAULT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (context.state == SCE_JSON_DEFAULT) {
|
||||
if (context.ch == '"') {
|
||||
compactIRI.resetState();
|
||||
context.SetState(SCE_JSON_STRING);
|
||||
Sci_Position currPos = static_cast<Sci_Position>(context.currentPos);
|
||||
if (AtPropertyName(styler, currPos)) {
|
||||
context.SetState(SCE_JSON_PROPERTYNAME);
|
||||
}
|
||||
} else if (setOperators.Contains(context.ch)) {
|
||||
context.SetState(SCE_JSON_OPERATOR);
|
||||
} else if (options.allowComments && context.Match("/*")) {
|
||||
context.SetState(SCE_JSON_BLOCKCOMMENT);
|
||||
context.Forward();
|
||||
} else if (options.allowComments && context.Match("//")) {
|
||||
context.SetState(SCE_JSON_LINECOMMENT);
|
||||
} else if (setKeywordJSON.Contains(context.ch)) {
|
||||
if (IsNextWordInList(keywordsJSON, setKeywordJSON, context, styler)) {
|
||||
context.SetState(SCE_JSON_KEYWORD);
|
||||
}
|
||||
}
|
||||
bool numberStart =
|
||||
IsADigit(context.ch) && (context.chPrev == '+'||
|
||||
context.chPrev == '-' ||
|
||||
context.atLineStart ||
|
||||
IsASpace(context.chPrev) ||
|
||||
setOperators.Contains(context.chPrev));
|
||||
bool exponentPart =
|
||||
tolower(context.ch) == 'e' &&
|
||||
IsADigit(context.chPrev) &&
|
||||
(IsADigit(context.chNext) ||
|
||||
context.chNext == '+' ||
|
||||
context.chNext == '-');
|
||||
bool signPart =
|
||||
(context.ch == '-' || context.ch == '+') &&
|
||||
((tolower(context.chPrev) == 'e' && IsADigit(context.chNext)) ||
|
||||
((IsASpace(context.chPrev) || setOperators.Contains(context.chPrev))
|
||||
&& IsADigit(context.chNext)));
|
||||
bool adjacentDigit =
|
||||
IsADigit(context.ch) && IsADigit(context.chPrev);
|
||||
bool afterExponent = IsADigit(context.ch) && tolower(context.chPrev) == 'e';
|
||||
bool dotPart = context.ch == '.' &&
|
||||
IsADigit(context.chPrev) &&
|
||||
IsADigit(context.chNext);
|
||||
bool afterDot = IsADigit(context.ch) && context.chPrev == '.';
|
||||
if (numberStart ||
|
||||
exponentPart ||
|
||||
signPart ||
|
||||
adjacentDigit ||
|
||||
dotPart ||
|
||||
afterExponent ||
|
||||
afterDot) {
|
||||
context.SetState(SCE_JSON_NUMBER);
|
||||
} else if (context.state == SCE_JSON_DEFAULT && !IsASpace(context.ch)) {
|
||||
context.SetState(SCE_JSON_ERROR);
|
||||
}
|
||||
}
|
||||
context.Forward();
|
||||
}
|
||||
context.Complete();
|
||||
}
|
||||
|
||||
void SCI_METHOD LexerJSON::Fold(Sci_PositionU startPos,
|
||||
Sci_Position length,
|
||||
int,
|
||||
IDocument *pAccess) {
|
||||
if (!options.fold) {
|
||||
return;
|
||||
}
|
||||
LexAccessor styler(pAccess);
|
||||
Sci_PositionU currLine = styler.GetLine(startPos);
|
||||
Sci_PositionU endPos = startPos + length;
|
||||
int currLevel = styler.LevelAt(currLine) & SC_FOLDLEVELNUMBERMASK;
|
||||
int nextLevel = currLevel;
|
||||
int visibleChars = 0;
|
||||
for (Sci_PositionU i = startPos; i < endPos; i++) {
|
||||
char curr = styler.SafeGetCharAt(i);
|
||||
char next = styler.SafeGetCharAt(i+1);
|
||||
bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n');
|
||||
if (styler.StyleAt(i) == SCE_JSON_OPERATOR) {
|
||||
if (curr == '{' || curr == '[') {
|
||||
nextLevel++;
|
||||
} else if (curr == '}' || curr == ']') {
|
||||
nextLevel--;
|
||||
}
|
||||
}
|
||||
if (atEOL || i == (endPos-1)) {
|
||||
int level = currLevel;
|
||||
if (!visibleChars && options.foldCompact) {
|
||||
level |= SC_FOLDLEVELWHITEFLAG;
|
||||
} else if (nextLevel > currLevel) {
|
||||
level |= SC_FOLDLEVELHEADERFLAG;
|
||||
}
|
||||
if (level != styler.LevelAt(currLine)) {
|
||||
styler.SetLevel(currLine, level);
|
||||
}
|
||||
currLine++;
|
||||
currLevel = nextLevel;
|
||||
visibleChars = 0;
|
||||
}
|
||||
if (!isspacechar(curr)) {
|
||||
visibleChars++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LexerModule lmJSON(SCLEX_JSON,
|
||||
LexerJSON::LexerFactoryJSON,
|
||||
"json",
|
||||
JSONWordListDesc);
|
||||
Reference in New Issue
Block a user