aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/desktop-utils/lumina-textedit/syntaxSupport.h
blob: 746df7509e10ccc73a011b494ba898cc741bb83a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//===========================================
//  Lumina-DE source code
//  Copyright (c) 2015, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#ifndef _LUMINA_SYNTAX_HIGHLIGHER_CPP_H
#define _LUMINA_SYNTAX_HIGHLIGHER_CPP_H

#include <QSyntaxHighlighter>
#include <QTextDocument>
#include <QTextCharFormat>
#include <QString>
#include <QSettings>
#include <QDebug>
#include <QDateTime>
#include <QJsonObject>
#include <QPlainTextEdit>


//Simple syntax rules
struct SyntaxRule{
  QRegExp pattern;  //single-line rule
  QRegExp startPattern, endPattern;  //multi-line rules
  QTextCharFormat format;
};
//Complicated/multi-line rules
struct SyntaxRuleSplit{
  QRegExp startPattern, endPattern;
  QTextCharFormat format;
};

class SyntaxFile{
private:
	QJsonObject metaObj;
	QJsonObject formatObj;

	QColor colorFromOption(QString opt, QSettings *settings);

public:
	QVector<SyntaxRule> rules;
	QDateTime lastLoaded;
	QString fileLoaded;

	SyntaxFile(){}

	QString name();
	int char_limit();
	bool highlight_excess_whitespace();	

	void SetupDocument(QPlainTextEdit *editor);
	bool supportsFile(QString file); //does this syntax set support the file?

	//Main Loading routine (run this before other functions)
	bool LoadFile(QString file, QSettings *settings);

	//Main function for finding/loading all syntax files
	static QList<SyntaxFile> availableFiles(QSettings *settings);
};

class Custom_Syntax : public QSyntaxHighlighter{
	Q_OBJECT
private:
	QSettings *settings;
	QString lasttype;
	QVector<SyntaxRule> rules;
	QVector<SyntaxRuleSplit> splitrules;

public:
	Custom_Syntax(QSettings *set, QTextDocument *parent = 0) : QSyntaxHighlighter(parent){
	  settings = set;
	}
	~Custom_Syntax(){}
		
	static QStringList availableRules();
	static QStringList knownColors();
	static void SetupDefaultColors(QSettings *settings);
	static QString ruleForFile(QString filename);
	void loadRules(QString type);
		
	void reloadRules(){
	  loadRules(lasttype);
	}
protected:
	void highlightBlock(const QString &text){
          //qDebug() << "Highlight Block:" << text;
	  //Now look for any multi-line patterns (starting/continuing/ending)
	  int start = 0;
	  int splitactive = previousBlockState();
	  if(splitactive>splitrules.length()-1){ splitactive = -1; } //just in case
	  while(start>=0 && start<=text.length()-1){
	    //qDebug() << "split check:" << start << splitactive;
	    if(splitactive>=0){
	      //Find the end of the current rule
	      int end = splitrules[splitactive].endPattern.indexIn(text, start);
	      if(end==-1){
                //qDebug() << "Highlight to end of line:" << text << start;
	        //rule did not finish - apply to all
                if(start>0){ setFormat(start-1, text.length()-start+1, splitrules[splitactive].format); }
                else{ setFormat(start, text.length()-start, splitrules[splitactive].format); }
		break; //stop looking for more multi-line patterns
	      }else{
		//Found end point within the same line
                //qDebug() << "Highlight to particular point:" << text << start << end;
		int len = end-start+splitrules[splitactive].endPattern.matchedLength();
                if(start>0){ start--; len++; } //need to include the first character as well
		setFormat(start, len , splitrules[splitactive].format);
		start+=len; //move pointer to the end of handled range
		splitactive = -1; //done with this rule
	      }
	    } //end check for end match
	    //Look for the start of any new split rule
	    for(int i=0; i<splitrules.length() && splitactive<0; i++){
              //qDebug() << "Look for start of split rule:" << splitrules[i].startPattern << splitactive;
	      int newstart = splitrules[i].startPattern.indexIn(text,start);
	      if(newstart>=start){
                //qDebug() << "Got Start of split rule:" << start << newstart << text;
		splitactive = i;
		start = newstart+1;
                if(start>=text.length()-1){
                  //qDebug() << "Special case: start now greater than line length";
                  //Need to apply highlighting to this section too - start matches the end of the line
                  setFormat(start-1, text.length()-start+1, splitrules[splitactive].format);
                }
	      }
	    }
	    if(splitactive<0){  break; } //no other rules found - go ahead and exit the loop
          }
	  setCurrentBlockState(splitactive);
          //Do all the single-line patterns
	  for(int i=0; i<rules.length(); i++){
	    QRegExp patt(rules[i].pattern); //need a copy of the rule's pattern (will be changing it below)
	    int index = patt.indexIn(text);
            if(splitactive>=0 || index<start){ continue; } //skip this one - falls within a multi-line pattern above
	    while(index>=0){
	      int len = patt.matchedLength();
	      if(format(index)==currentBlock().charFormat()){ setFormat(index, len, rules[i].format); } //only apply highlighting if not within a section already
	      index = patt.indexIn(text, index+len); //go to the next match
	    }
	  }//end loop over normal (single-line) patterns
	}
};
#endif
bgstack15