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