1 /**
2 * Yudit Unicode Editor Source File
3 *
4 * GNU Copyright (C) 1997-2006 Gaspar Sinai <gaspar@yudit.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2,
8 * dated June 1991. See file COPYYING for details.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "stoolkit/syntax/SSyntaxMarker.h"
21 #include "stoolkit/syntax/SSyntax.h"
22
23
24 /**
25 * The _textData and _lines arrays should be in sync, they
26 * should have the same sizes.
27 * @param _around is around which we should mark unmarked in our buffer.
28 */
SSyntaxMarker(SSyntaxData & _lines,const SUnicodeData & _ulines,const STextIndex & _around)29 SSyntaxMarker::SSyntaxMarker (SSyntaxData& _lines, const SUnicodeData& _ulines,
30 const STextIndex& _around)
31 : syntaxLines (_lines), dataLines (_ulines)
32 {
33 STextIndex first = _around;
34 // look backwards for a sync
35 if (decrement(&first)) while ((getSyntaxAt (first) & SGC_BEGIN_MARK) == 0)
36 {
37 if (!decrement(&first)) break;
38 }
39 // hack, commment this out if you have a proper parser.
40 // FIXME FIXME
41 //first = STextIndex (0,0);
42 // fprintf (stderr, "SGC syntax started around=%u,%u found=%u,%u\n",
43 // _around.line, _around.index, first.line, first.index);
44
45 startIndex = first;
46 unsigned int firstLineSize = getLineSize (startIndex.line)
47 - startIndex.index;
48 // linesizes always contains 1 more lines than real lines.
49 lineSizes.append (0);
50 lineSizes.append (firstLineSize);
51 /*
52 fprintf (stderr, "firstLineSize=%u getLineSize=%u\n",
53 firstLineSize, getLineSize (startIndex.line));
54 */
55
56 isStarted = true;
57 actionMap.put ("none", ((int) SSyntax::SD_NONE) << 8);
58 actionMap.put ("error", ((int) SSyntax::SD_ERROR) << 8);
59 actionMap.put ("number", ((int) SSyntax::SD_NUMBER) << 8);
60 actionMap.put ("string", ((int) SSyntax::SD_STRING) << 8);
61 actionMap.put ("comment", ((int) SSyntax::SD_COMMENT) << 8);
62 actionMap.put ("keyword", ((int) SSyntax::SD_KEYWORD) << 8);
63 actionMap.put ("variable", ((int) SSyntax::SD_VARIABLE) << 8);
64 actionMap.put ("define", ((int) SSyntax::SD_DEFINE) << 8);
65 actionMap.put ("control", ((int) SSyntax::SD_CONTROL) << 8);
66 actionMap.put ("other", ((int) SSyntax::SD_OTHER) << 8);
67 }
68
~SSyntaxMarker()69 SSyntaxMarker::~SSyntaxMarker ()
70 {
71 }
72
73 /* SMatcherIterator */
74 // FIXME FIXME FIXME
75 int
getNextCharacter()76 SSyntaxMarker::getNextCharacter ()
77 {
78 if (isStarted)
79 {
80 currentIndex = startIndex;
81 isStarted = false;
82 if (isEOD (currentIndex)) return -1;
83 }
84 else
85 {
86 if (!increment (¤tIndex)) return -1;
87 }
88 // lineSizes keeps track of incremental sizes.
89 if (currentIndex.line - startIndex.line == lineSizes.size()-1)
90 {
91 lineSizes.append (getLineSize (currentIndex.line)
92 + lineSizes[currentIndex.line - startIndex.line ]);
93 }
94 return getCharAt (currentIndex);
95 }
96
97 bool
isEOD(const STextIndex & idx) const98 SSyntaxMarker::isEOD (const STextIndex& idx) const
99 {
100 if (idx.line >= dataLines.size()) return true;
101 if (idx.index >= getLineSize(idx.line)) return true;
102 return false;
103 }
104
105 void
beginActionBlock()106 SSyntaxMarker::beginActionBlock ()
107 {
108 minModified = STextIndex (dataLines.size(), 0);
109 maxModified = STextIndex (0, 0);
110 }
111
112
113 /* SMatcherAction */
114 // Apply action from from till till exclusive
115 // 1. Mark shadow syntax
116 // 2. modify minModified and maxModified
117 void
applyAction(const SString & name,unsigned int markFrom,unsigned int markTill)118 SSyntaxMarker::applyAction (const SString& name,
119 unsigned int markFrom, unsigned int markTill)
120 {
121 STextIndex from = position2Index (markFrom);
122 STextIndex till = position2Index (markTill);
123
124 #if DEBUG_PARSER
125 fprintf (stderr, "applyAction %*.*s %u..%u %u.%u..%u,%u\n",
126 SSARGS(name), markFrom, markTill,
127 from.line, from.index, till.line, till.index);
128 #endif
129 if (from < minModified)
130 {
131 minModified = from;
132 }
133 if (till > maxModified)
134 {
135 maxModified = till;
136 }
137 int shadow = actionMap.get (name);
138 while (from < till)
139 {
140 int old = getSyntaxAt (from);
141 shadow = (old & 0xff) | shadow;
142 // This will wipe out extra marks
143 setSyntaxAt (from, shadow);
144 if (!increment (&from)) break;
145 }
146 }
147
148 // 1. move shadow syntax to real
149 // 2. update minModified and maxModified
150 // 3. update the minLimits and minLimits to know where stuff changed.
151 void
endActionBlock()152 SSyntaxMarker::endActionBlock ()
153 {
154 #if DEBUG_PARSER
155 fprintf (stderr, "finish %u.%u..%u,%u\n",
156 minModified.line, minModified.index,
157 maxModified.line, maxModified.index);
158 #endif
159
160 STextIndex min = STextIndex (dataLines.size(), 0);
161 STextIndex max = STextIndex (0, 0);
162
163 STextIndex from = minModified;
164 while (from < maxModified)
165 {
166 int vle = getSyntaxAt (from);
167 int o = (vle & 0xff);
168 int n = (vle & 0xff00) >> 8;
169 if (o == n)
170 {
171 if (!increment (&from)) break;
172 continue;
173 }
174 if (from < min) min = from;
175 if (from > max) max = from;
176 setSyntaxAt (from, n);
177 if (!increment (&from)) break;
178 }
179 // multiline, scrolled editor. write yuko in Hungarian kmap
180 // yuko is not first line. o is not error with test SPattern.
181 // dont know why...
182 // minModified = min;
183 // maxModified = max;
184 }
185
186 // Increment the in index
187 // return false if in is already at the end
188 // For non expanded lines we generate virtual new index if
189 // it is has a proper ending.
190 bool
decrement(STextIndex * in)191 SSyntaxMarker::decrement (STextIndex* in)
192 {
193 if (in->line == 0 && in->index==0) return false;
194 if (in->index == 0)
195 {
196 in->line--;
197 in->index = getLineSize (in->line);
198 if (in->index==0)
199 {
200 #if DEBUG_PARSER
201 fprintf (stderr, "SSyntaxMarker::decrement: empty line detected.\n");
202 #endif
203 return false;
204 }
205 }
206 // There can be no empty lines in the middle of the file
207 in->index = in->index-1;
208 return true;
209 }
210
211 // Decrement the in index
212 // return false if in is already at the end
213 // For non expanded lines we generate virtual new index if
214 // it is has a proper ending.
215 bool
increment(STextIndex * in)216 SSyntaxMarker::increment (STextIndex* in)
217 {
218 if (in->line >= dataLines.size()) return false;
219 unsigned int ls = getLineSize (in->line);
220 if (in->index+1 == ls)
221 {
222 in->line++;
223 in->index=0;
224 if (in->line >= dataLines.size()) return false;
225 ls = getLineSize (in->line);
226 if (ls == 0) return false;
227 return true;
228 }
229 in->index++;
230 if (in->index >= ls) return false;
231 return true;
232 }
233
234 // Get character at the index.
235 // return -1 if in is out of bounds.
236 int
getCharAt(const STextIndex & in) const237 SSyntaxMarker::getCharAt (const STextIndex& in) const
238 {
239 if (in.line >= dataLines.size()) return -1;
240 if (in.index >= dataLines[in.line]->size()) return -1;
241 // todo sanity check here
242 SS_UCS4 ret = dataLines[in.line]->peek (in.index);
243 // Paragraph separator
244 //fprintf (stderr, "%u,%u=[%c]", in.line, in.index, (char) ret);
245 if (ret == 0x2029) return (int) '\n';
246 return (int) ret;
247 }
248
249 // Get character at the index.
250 // return -1 if in is out of bounds.
251 int
getSyntaxAt(const STextIndex & in) const252 SSyntaxMarker::getSyntaxAt (const STextIndex& in) const
253 {
254 if (in.line >= syntaxLines.size()) return -1;
255 if (in.index >= syntaxLines[in.line]->size()) return -1;
256 // todo sanity check here
257 return syntaxLines[in.line]->peek (in.index);
258 }
259
260 // Get character at the index.
261 // return false if in is out of bounds.
262 bool
setSyntaxAt(const STextIndex & in,int syn)263 SSyntaxMarker::setSyntaxAt (const STextIndex& in, int syn)
264 {
265 if (in.line >= syntaxLines.size()) return false;
266 if (in.index >= syntaxLines[in.line]->size()) return false;
267 syntaxLines[in.line]->replace (in.index, syn);
268 return true;
269 }
270
271 // get the line size, adjusted for non-expanded chanacters.
272 // an extra functionality is to sync expanded lines, as
273 // they are not always reported elsewhere.
274 unsigned int
getLineSize(unsigned int lineno) const275 SSyntaxMarker::getLineSize (unsigned int lineno) const
276 {
277 if (lineno >= dataLines.size()) return 0;
278 // line is expaned
279 return dataLines[lineno]->size();
280 }
281
282 // linsizes[line] contain the accumulated number of characters
283 // from startIndex at the end of the line.
284 STextIndex
position2Index(unsigned int position)285 SSyntaxMarker::position2Index (unsigned int position)
286 {
287 if (position < lineSizes[1])
288 {
289 return STextIndex (startIndex.line, startIndex.index + position);
290 }
291 // This can return a bigger value
292 unsigned int mapIndex = lineSizes.findSorted (position);
293 if (mapIndex>=lineSizes.size())
294 {
295 return STextIndex (startIndex.line+lineSizes.size()-1, 0);
296 }
297 while (position < lineSizes[mapIndex] && mapIndex > 0) mapIndex--;
298 unsigned int addValue = lineSizes[mapIndex];
299 return STextIndex (mapIndex+startIndex.line, position-addValue);
300 }
301