1 /****************************************************************************
2 **
3 ** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
4 **
5 ** This file is part of the Edyuk project <http://edyuk.org>
6 **
7 ** This file may be used under the terms of the GNU General Public License
8 ** version 3 as published by the Free Software Foundation and appearing in the
9 ** file GPL.txt included in the packaging of this file.
10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 **
14 ****************************************************************************/
15 
16 #include "qlanguagedefinition.h"
17 
18 /*!
19 	\file qlanguagedefinition.cpp
20 	\brief Implementation of QLanguageDefinition
21 
22 	\see QLanguageDefinition
23 */
24 
25 /*!
26 	\ingroup language
27 	@{
28 
29 	\class QLanguageDefinition
30 	\brief Interface for language definition.
31 
32 	This class is meant to be subclassed, see \see QGenericDefinition for more
33 	informations, and added to a QLanguageFactory.
34 
35 	A language definition is a wrapper that creates interfaces for a given file
36 	extension from internally handled data (XML files in the case of
37 	QGenericDefinition)
38 
39 	\see QLanguageFactory
40 */
41 
42 #include "qdocument.h"
43 #include "qdocumentcursor.h"
44 #include "qdocumentline.h"
45 #include "qlanguagefactory.h"
46 
47 /*!
48 	\brief Empty constructor
49 */
QLanguageDefinition()50 QLanguageDefinition::QLanguageDefinition()
51 {
52 }
53 
54 /*!
55 	\brief Empty destructor
56 */
~QLanguageDefinition()57 QLanguageDefinition::~QLanguageDefinition()
58 {
59 }
60 
61 /*!
62 	\fn QLanguageDefinition::language()
63 
64 	\return The language supported by this definition
65 */
66 
67 /*!
68 	\fn QLanguageDefinition::extensions()
69 
70 	\return the file extensions corrseponding to the supported language
71 
72 	\see language()
73 	\see QFileInfo::completeSuffix()
74 */
75 
76 /*!
77 	\brief Entry point for syntax highlighting
78 */
tokenize(QDocument * d,int line,int count)79 int QLanguageDefinition::tokenize(QDocument *d, int line, int count)
80 {
81 	Q_UNUSED(d)
82 	Q_UNUSED(line)
83 
84 	return count;
85 }
86 
87 /*!
88 	\brief Return the string starting a single line comment, if any offered by the language
89 */
singleLineComment() const90 QString QLanguageDefinition::singleLineComment() const
91 {
92 	return QString();
93 }
94 
95 
96 /*!
97 	\brief Let language specify which line mark should be toggled by left clicking a line mark panel
98 */
defaultLineMark() const99 QString QLanguageDefinition::defaultLineMark() const
100 {
101 	return QString();
102 }
103 
parenthesisWeight(int id) const104 int QLanguageDefinition::parenthesisWeight(int id) const{
105 	Q_UNUSED(id)
106 	return 0;
107 }
108 
possibleEndingOfOpeningParenthesis(const QString & text) const109 bool QLanguageDefinition::possibleEndingOfOpeningParenthesis(const QString& text) const{
110 	Q_UNUSED(text)
111 	return false;
112 }
113 /*!
114 	\brief Brace matching entry point
115 */
clearMatches(QDocument * d)116 void QLanguageDefinition::clearMatches(QDocument *d)
117 {
118 	Q_UNUSED(d)
119 }
120 
121 /*!
122 	\brief Brace matching entry point
123 */
match(QDocumentCursor & c)124 void QLanguageDefinition::match(QDocumentCursor& c)
125 {
126 	Q_UNUSED(c)
127 }
128 
129 /*!
130 	\brief Return the indent to use when inserting a line at a given cursor position
131 */
indent(const QDocumentCursor & c,int * indentCount)132 QString QLanguageDefinition::indent(const QDocumentCursor& c, int* indentCount)
133 {
134 	Q_UNUSED(c)
135 	Q_UNUSED(indentCount)
136 
137 	return QString();
138 }
139 
140 /*!
141 	\brief Determines whether the given key event at the given position should cause unindent to happen
142 */
unindent(const QDocumentCursor & c,const QString & ktxt)143 bool QLanguageDefinition::unindent (const QDocumentCursor& c, const QString& ktxt)
144 {
145 	Q_UNUSED(c)
146 	Q_UNUSED(ktxt)
147 
148 	return false;
149 }
150 
151 /*!
152 	\brief Expand a collapsed block at a given line
153 */
expand(QDocument * d,int line)154 void QLanguageDefinition::expand(QDocument *d, int line)
155 {
156 	Q_UNUSED(d)
157 	Q_UNUSED(line)
158 }
159 
160 /*!
161 	\brief Collapse a text block at a given line
162 */
collapse(QDocument * d,int line)163 void QLanguageDefinition::collapse(QDocument *d, int line)
164 {
165 	Q_UNUSED(d)
166 	Q_UNUSED(line)
167 }
168 
correctFolding(QDocument * d)169 bool QLanguageDefinition::correctFolding(QDocument *d){
170 	Q_UNUSED(d)
171 
172 	return false;
173 }
174 
foldedLineIterator(QDocument * d,int line) const175 QFoldedLineIterator QLanguageDefinition::foldedLineIterator(QDocument *d, int line) const{
176 	QFoldedLineIterator fli;
177 	fli.doc=d;
178 	fli.def=this;
179 	fli.hidden=false;
180 	fli.hiddenDepth=0;
181 	for (fli.lineNr=-1;fli.lineNr<line;++fli);
182 	return fli;
183 }
184 
operator ++()185 QFoldedLineIterator& QFoldedLineIterator::operator++(){
186 	open = 0;
187 	close = 0;
188 	lineNr++;
189 	line=doc->line(lineNr);
190 	if (!line.isValid())
191 		return *this;
192 	int oldHiddenDepth=hiddenDepth;
193 	int maxClosedParenthesisWeight=0, maxClosedHiddenParenthesisWeight=0;
194 	collapsedBlockStart=line.hasFlag(QDocumentLine::CollapsedBlockStart);
195 	foreach (const QParenthesis& par, line.parentheses()){
196 		if (!(par.role & QParenthesis::Fold))
197 			continue;
198 		if (par.role & QParenthesis::Close && !openParentheses.empty()) {
199 			if (openParentheses.last().id==par.id) {
200 				//Close last bracket
201 				if (openParentheses.last().line != lineNr) {
202 					close++;
203 					if (openParentheses.last().hiding) {
204 						hiddenDepth--;
205 						maxClosedHiddenParenthesisWeight=qMax(maxClosedHiddenParenthesisWeight, openParentheses.last().weight);
206 					} else
207 						maxClosedParenthesisWeight=qMax(maxClosedHiddenParenthesisWeight, openParentheses.last().weight);
208 				} else open--;
209 				openParentheses.removeLast();
210 			} else {
211 				//Close a matching bracket if there are only "lighter" brackets in-between
212 				int weight=def->parenthesisWeight(par.id);
213 				int removedHidingBrackets=0;
214 				int removedOwnBrackets=0;
215 				int removedMaxClosedPW = 0;
216 				int removedMaxClosedHiddenPW = 0;
217 				for (int i=openParentheses.size()-1;i>=0;i--){
218 					if (openParentheses[i].weight>weight) break;
219 					if (openParentheses[i].line == lineNr) removedOwnBrackets++;
220 					else if (openParentheses[i].hiding) {
221 						removedHidingBrackets++;
222 						removedMaxClosedHiddenPW=qMax(removedMaxClosedHiddenPW, openParentheses[i].weight);
223 					} else
224 						removedMaxClosedPW=qMax(removedMaxClosedPW, openParentheses[i].weight);
225 					if ( openParentheses[i].weight==weight ) {
226 						if ( openParentheses[i].id!=par.id ) break;
227 						open-=removedOwnBrackets;
228 						close+=(openParentheses.size()-i) - removedOwnBrackets;
229 						hiddenDepth-=removedHidingBrackets;
230 						openParentheses.erase(openParentheses.begin()+i,openParentheses.end());
231 						maxClosedParenthesisWeight=qMax(maxClosedParenthesisWeight, removedMaxClosedPW);
232 						maxClosedHiddenParenthesisWeight=qMax(maxClosedHiddenParenthesisWeight, removedMaxClosedHiddenPW);
233 						break;
234 					}
235 				}
236 			}
237 		}
238 		if (par.role & QParenthesis::Open){
239 			//Open new bracket
240 			openParentheses << FoldedParenthesis(lineNr, par.id, def->parenthesisWeight(par.id), collapsedBlockStart );
241 			open++;
242 		}
243 	}
244 
245 	collapsedBlockStart = collapsedBlockStart  && open;
246 	collapsedBlockEnd = hiddenDepth!=oldHiddenDepth;
247 	hiddenCollapsedBlockEnd = oldHiddenDepth>0 && !open && maxClosedParenthesisWeight <= maxClosedHiddenParenthesisWeight;
248 
249 	hidden = (hiddenDepth>0) || //line contained in a hidden block
250 		 (hiddenDepth==0 && hiddenCollapsedBlockEnd); //a closing bracket is hidden iff there is no new block to open
251 
252 	if (collapsedBlockStart)
253 		hiddenDepth+=open;
254 
255 	return *this;
256 }
257 
lineFlagsInvalid() const258 bool QFoldedLineIterator::lineFlagsInvalid() const{
259 	return line.hasFlag(QDocumentLine::Hidden) != hidden ||
260 	       line.hasFlag(QDocumentLine::CollapsedBlockStart) != collapsedBlockStart ||
261 	       line.hasFlag(QDocumentLine::CollapsedBlockEnd) != collapsedBlockEnd;
262 
263 }
264 
incrementUntilBlockEnd()265 void QFoldedLineIterator::incrementUntilBlockEnd(){
266 	int firstParenthesisPos = openParentheses.size() - open;
267 	const FoldedParenthesis firstParenthesis = openParentheses[firstParenthesisPos];
268 
269 	while ( lineNr < doc->lines() &&
270 		firstParenthesisPos < openParentheses.size() &&
271 		openParentheses[firstParenthesisPos] == firstParenthesis ){
272 		++(*this);
273 	}
274 }
275 
276 /*! @} */
277