1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * anjuta-token-list.c
4  * Copyright (C) Sébastien Granjoux 2009 <seb.sfo@free.fr>
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "anjuta-token-list.h"
21 
22 #include "libanjuta/anjuta-debug.h"
23 
24 #include <string.h>
25 #include <stdio.h>
26 
27 /* Type definition
28  *---------------------------------------------------------------------------*/
29 
30 typedef struct _AnjutaTokenStyleSeparator AnjutaTokenStyleSeparator;
31 
32 struct _AnjutaTokenStyleSeparator
33 {
34 	guint count;
35 	gchar *value;
36 	gboolean eol;
37 };
38 
39 struct _AnjutaTokenStyle
40 {
41 	guint max_width;
42 	GHashTable *separator;
43 	AnjutaTokenStyle *base;
44 };
45 
46 /* Private functions
47  *---------------------------------------------------------------------------*/
48 
49 static void
free_separator(AnjutaTokenStyleSeparator * sep,gpointer user_data)50 free_separator (AnjutaTokenStyleSeparator *sep, gpointer user_data)
51 {
52 	g_free (sep->value);
53 	g_slice_free (AnjutaTokenStyleSeparator, sep);
54 }
55 
56 static void
free_separator_list(guint key,GList * value,gpointer user_data)57 free_separator_list (guint key, GList *value, gpointer user_data)
58 {
59 	/* Free list elements */
60 	g_list_foreach (value, (GFunc)free_separator, NULL);
61 	g_list_free (value);
62 }
63 
64 static AnjutaTokenStyleSeparator*
anjuta_token_style_insert_separator(AnjutaTokenStyle * style,guint key,const gchar * value)65 anjuta_token_style_insert_separator (AnjutaTokenStyle *style, guint key, const gchar *value)
66 {
67 	GList *list;
68 	GList *last = NULL;
69 	GList *sibling = NULL;
70 	AnjutaTokenStyleSeparator *sep;
71 
72 
73 	/* Look the separator is already registered */
74 	list = (GList *)g_hash_table_lookup (style->separator, GINT_TO_POINTER (key));
75 	if (list != NULL)
76 	{
77 		for (sibling = list; sibling != NULL; sibling = g_list_next(sibling))
78 		{
79 			sep = (AnjutaTokenStyleSeparator *)sibling->data;
80 
81 			/* Keep the first separator with count = 1, to insert the new one if
82 			 * not found */
83 			if ((last == NULL) && (sep->count == 1)) last = sibling;
84 
85 			if (value == NULL)
86 			{
87 				if (sep->value == NULL)
88 				{
89 					sep->count++;
90 					break;
91 				}
92 			}
93 			else if ((sep->value != NULL) && (strcmp (sep->value, value) == 0))
94 			{
95 				sep->count++;
96 				break;
97 			}
98 		}
99 	}
100 
101 	if (sibling != NULL)
102 	{
103 		/* Increment the separator count, Move it if needed */
104 		for (last = g_list_previous (sibling); last != NULL; last = g_list_previous (sibling))
105 		{
106 			if (((AnjutaTokenStyleSeparator *)sibling->data)->count >= ((AnjutaTokenStyleSeparator *)last->data)->count)
107 			{
108 				last->next = sibling->next;
109 				sibling->next = last;
110 				sibling->prev = last->prev;
111 				last->prev = sibling;
112 			}
113 			else
114 			{
115 				break;
116 			}
117 		}
118 
119 		if (last == NULL)
120 		{
121 			/* Update the list head */
122 			list = sibling;
123 			g_hash_table_replace (style->separator, GINT_TO_POINTER (key), list);
124 		}
125 
126 		return (AnjutaTokenStyleSeparator *)sibling->data;
127 	}
128 	else
129 	{
130 		/* Create a new separator */
131 		sep = g_slice_new0 (AnjutaTokenStyleSeparator);
132 		sep->count = 1;
133 		sep->value = g_strdup (value);
134 		sep->eol = value == NULL ? FALSE : strchr (value, '\n') != NULL;
135 		list = g_list_insert_before (list, last, sep);
136 		g_hash_table_replace (style->separator, GINT_TO_POINTER (key), list);
137 
138 		return sep;
139 	}
140 }
141 
142 static AnjutaTokenStyleSeparator*
anjuta_token_style_insert_separator_between(AnjutaTokenStyle * style,gint next,gint prev,const gchar * value)143 anjuta_token_style_insert_separator_between (AnjutaTokenStyle *style, gint next, gint prev, const gchar *value)
144 {
145 	return anjuta_token_style_insert_separator (style, ((guint)prev & 0xFFFF) | (((guint)next & 0xFFFF) << 16), value);
146 }
147 
148 static AnjutaToken*
anjuta_token_style_lookup(AnjutaTokenStyle * style,AnjutaTokenType type,gboolean eol)149 anjuta_token_style_lookup (AnjutaTokenStyle *style, AnjutaTokenType type, gboolean eol)
150 {
151 	GList *list;
152 
153 	list = g_hash_table_lookup (style->separator, GINT_TO_POINTER (type));
154 	if ((list == NULL) && (style->base != NULL))
155 	{
156 		return anjuta_token_style_lookup (style->base, type, eol);
157 	}
158 	else
159 	{
160 		return anjuta_token_new_string (ANJUTA_TOKEN_NAME, ((AnjutaTokenStyleSeparator *)list->data)->value);
161 	}
162 }
163 
164 /* Public style functions
165  *---------------------------------------------------------------------------*/
166 
167 void
anjuta_token_style_update(AnjutaTokenStyle * style,AnjutaToken * list)168 anjuta_token_style_update (AnjutaTokenStyle *style, AnjutaToken *list)
169 {
170 	AnjutaToken *token;
171 	AnjutaToken *next_token;
172 	guint prev = 0;
173 	guint next = 0;
174 	guint line_width = 0;
175 	guint sep_count = 0;
176 
177 	/* Initialize first line width */
178 	for (token = list; token != NULL; token = anjuta_token_previous (token))
179 	{
180 		gchar *value;
181 		gchar *eol = NULL;
182 		gsize len = 0;
183 
184 		value = anjuta_token_evaluate (token);
185 		if (value != NULL)
186 		{
187 			eol = strrchr (value, '\n');
188 			len = strlen (value);
189 			g_free (value);
190 		}
191 
192 		if (eol != NULL)
193 		{
194 			line_width = value + len - eol;
195 			break;
196 		}
197 
198 		line_width += len;
199 	}
200 
201 	for (token = anjuta_token_first_item (list); token != NULL; token = next_token)
202 	{
203 		gchar *value = NULL;
204 		const gchar *eol;
205 		gsize len;
206 		gint type;
207 
208 		next_token = anjuta_token_next_item (token);
209 		type = anjuta_token_get_type (token);
210 		next = next_token == NULL ? 0 : anjuta_token_get_type (next_token);
211 
212 		value = anjuta_token_evaluate (token);
213 		if (value == NULL) continue;
214 
215 		len = strlen (value);
216 		eol = strrchr (value, '\n');
217 		if (eol != NULL) len -= (eol - value);
218 		g_free (value);
219 
220 		line_width += len;
221 
222 		switch (type)
223 		{
224 			case ANJUTA_TOKEN_START:
225 			case ANJUTA_TOKEN_LAST:
226 			case ANJUTA_TOKEN_NEXT:
227 				break;
228 			default:
229 				if (eol != NULL)
230 				{
231 					line_width = len;
232 					sep_count = 0;
233 				}
234 				continue;
235 		}
236 
237 		value = anjuta_token_evaluate (token);
238 		anjuta_token_style_insert_separator_between (style, 0, type, value);
239 		if (type == ANJUTA_TOKEN_NEXT)
240 		{
241 			anjuta_token_style_insert_separator_between (style, next, prev, value);
242 			anjuta_token_style_insert_separator_between (style, next, ANJUTA_TOKEN_ANY, value);
243 			anjuta_token_style_insert_separator_between (style, ANJUTA_TOKEN_ANY, prev, value);
244 		}
245 		g_free (value);
246 
247 		if (eol == NULL)
248 		{
249 			sep_count++;
250 		}
251 		else
252 		{
253 			if ((sep_count > 1) && (line_width > style->max_width))
254 			{
255 				style->max_width = line_width;
256 			}
257 			sep_count = 0;
258 			line_width = len;
259 		}
260 	}
261 }
262 
263 void
anjuta_token_style_format(AnjutaTokenStyle * style,AnjutaToken * list)264 anjuta_token_style_format (AnjutaTokenStyle *style, AnjutaToken *list)
265 {
266 	AnjutaToken *item;
267 	AnjutaToken *last;
268 	AnjutaToken *text;
269 	AnjutaToken *prev;
270 
271 	/* Find following tokens */
272 	for (last = list; last != NULL; last = anjuta_token_next (last))
273 	{
274 		/* Get all tokens in group */
275 		last = anjuta_token_last (last);
276 
277 		gint flags = anjuta_token_get_flags (last);
278 		if (!(flags & (ANJUTA_TOKEN_ADDED | ANJUTA_TOKEN_REMOVED))) break;
279 	}
280 
281 	/* Find previous token */
282 	for (prev = list; prev != NULL; prev = anjuta_token_previous (prev))
283 	{
284 		gint flags = anjuta_token_get_flags (prev);
285 		if ((anjuta_token_get_length (prev) != 0) && !(flags & (ANJUTA_TOKEN_ADDED | ANJUTA_TOKEN_REMOVED))) break;
286 		list = prev;
287 	}
288 
289 	for (item = list; (item != NULL) && (item != last); item = anjuta_token_next (item))
290 	{
291 		if ((anjuta_token_get_flags (item) & ANJUTA_TOKEN_ADDED) &&
292 			!(anjuta_token_get_flags (item) & ANJUTA_TOKEN_REMOVED))
293 		{
294 			switch (anjuta_token_get_type (item))
295 			{
296 			case ANJUTA_TOKEN_START:
297 				text = anjuta_token_style_lookup (style, ANJUTA_TOKEN_START, FALSE);
298 				anjuta_token_set_flags (text, ANJUTA_TOKEN_ADDED);
299 				anjuta_token_insert_after (item, text);
300 				anjuta_token_merge (item, text);
301 				item = text;
302 				break;
303 			case ANJUTA_TOKEN_NEXT:
304 				text = anjuta_token_style_lookup (style, ANJUTA_TOKEN_NEXT, FALSE);
305 				anjuta_token_set_flags (text, ANJUTA_TOKEN_ADDED);
306 				anjuta_token_insert_after (item, text);
307 				anjuta_token_merge (item, text);
308 				item = text;
309 				break;
310 			case ANJUTA_TOKEN_LAST:
311 				text = anjuta_token_style_lookup (style, ANJUTA_TOKEN_LAST, FALSE);
312 				anjuta_token_set_flags (text, ANJUTA_TOKEN_ADDED);
313 				anjuta_token_insert_after (item, text);
314 				anjuta_token_merge (item, text);
315 				item = text;
316 				break;
317 			default:
318 				break;
319 			}
320 		}
321 	}
322 }
323 
324 /* Word functions
325  *---------------------------------------------------------------------------*/
326 
327 /**
328  * anjuta_token_first_word:
329  * @list: a #AnjutaToken object being a list
330  *
331  * Get the first word of the list. A word is an item in the list which is not
332  * a space or a separator.
333  *
334  * Return value: A #AnjutaToken representing the first word or %NULL.
335  */
336 AnjutaToken *
anjuta_token_first_word(AnjutaToken * list)337 anjuta_token_first_word (AnjutaToken *list)
338 {
339 	AnjutaToken *item;
340 
341 	for (item = anjuta_token_first_item (list); item != NULL; item = anjuta_token_next_item (item))
342 	{
343 		if (anjuta_token_list (item) != list)
344 		{
345 			item = NULL;
346 			break;
347 		}
348 		switch (anjuta_token_get_type (item))
349 		{
350 		case ANJUTA_TOKEN_START:
351 		case ANJUTA_TOKEN_NEXT:
352 			continue;
353 		case ANJUTA_TOKEN_LAST:
354 			item = NULL;
355 			break;
356 		default:
357 			if (anjuta_token_is_empty (item) || (anjuta_token_get_flags(item) & ANJUTA_TOKEN_REMOVED)) continue;
358 			break;
359 		}
360 		break;
361 	}
362 
363 	return item;
364 }
365 
366 AnjutaToken *
anjuta_token_next_word(AnjutaToken * item)367 anjuta_token_next_word (AnjutaToken *item)
368 {
369 	AnjutaToken *next;
370 
371 	for (next = anjuta_token_next_item (item); next != NULL; next = anjuta_token_next_item (next))
372 	{
373 		if (anjuta_token_list (item) != anjuta_token_list (next))
374 		{
375 			next = NULL;
376 			break;
377 		}
378 		switch (anjuta_token_get_type (next))
379 		{
380 		case ANJUTA_TOKEN_START:
381 		case ANJUTA_TOKEN_NEXT:
382 			continue;
383 		case ANJUTA_TOKEN_LAST:
384 			next = NULL;
385 			break;
386 		default:
387 			if (anjuta_token_is_empty (next) || (anjuta_token_get_flags(next) & ANJUTA_TOKEN_REMOVED)) continue;
388 			break;
389 		}
390 		break;
391 	}
392 
393 	return next;
394 }
395 
396 AnjutaToken *
anjuta_token_nth_word(AnjutaToken * list,guint n)397 anjuta_token_nth_word (AnjutaToken *list, guint n)
398 {
399 	AnjutaToken *item;
400 	gboolean no_item = TRUE;
401 
402 	for (item = anjuta_token_first_item (list); item != NULL; item = anjuta_token_next_item (item))
403 	{
404 		if (anjuta_token_list (item) != list)
405 		{
406 			item = NULL;
407 			break;
408 		}
409 		switch (anjuta_token_get_type (item))
410 		{
411 		case ANJUTA_TOKEN_START:
412 			break;
413 		case ANJUTA_TOKEN_NEXT:
414 			if (no_item)
415 			{
416 				if (n == 0) return NULL;
417 				n--;
418 			}
419 			no_item = TRUE;
420 			break;
421 		case ANJUTA_TOKEN_LAST:
422 			return NULL;
423 		default:
424 			if (n == 0) return item;
425 			n--;
426 			no_item = FALSE;
427 			break;
428 		}
429 	}
430 
431 	return NULL;
432 }
433 
434 AnjutaToken *
anjuta_token_replace_nth_word(AnjutaToken * list,guint n,AnjutaToken * item)435 anjuta_token_replace_nth_word (AnjutaToken *list, guint n, AnjutaToken *item)
436 {
437 	AnjutaToken *token;
438 	gboolean no_item = TRUE;
439 
440 	token = anjuta_token_first_item (list);
441 	if (token == NULL)
442 	{
443 		token = anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_LAST | ANJUTA_TOKEN_ADDED, NULL));
444 		anjuta_token_merge (list, token);
445 	}
446 
447 	for (n++;;)
448 	{
449 		AnjutaToken *next;
450 
451 		switch (anjuta_token_get_type (token))
452 		{
453 		case ANJUTA_TOKEN_LAST:
454 			if (no_item)
455 			{
456 				n--;
457 				if (n == 0)
458 				{
459 					token = anjuta_token_insert_before (token, item);
460 					return token;
461 				}
462 			}
463 			token = anjuta_token_insert_before (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
464 			no_item = TRUE;
465 			break;
466 		case ANJUTA_TOKEN_NEXT:
467 			if (no_item)
468 			{
469 				n--;
470 				if (n == 0)
471 				{
472 					token = anjuta_token_insert_before (token, item);
473 					return token;
474 				}
475 			}
476 			no_item = TRUE;
477 			break;
478 		case ANJUTA_TOKEN_ITEM:
479 			n--;
480 			if (n == 0)
481 			{
482 				anjuta_token_set_flags (token, ANJUTA_TOKEN_REMOVED);
483 				token = anjuta_token_insert_before (token, item);
484 				return token;
485 			}
486 			no_item = FALSE;
487 			break;
488 		default:
489 			break;
490 		}
491 
492 		next = anjuta_token_next_item (token);
493 		if (next == NULL)
494 		{
495 			token = anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_LAST | ANJUTA_TOKEN_ADDED, NULL));
496 			anjuta_token_merge (list, token);
497 		}
498 		else
499 		{
500 			token = next;
501 		}
502 	}
503 }
504 
505 AnjutaToken *
anjuta_token_insert_word_before(AnjutaToken * list,AnjutaToken * sibling,AnjutaToken * item)506 anjuta_token_insert_word_before (AnjutaToken *list, AnjutaToken *sibling, AnjutaToken *item)
507 {
508 	AnjutaToken *token;
509 
510 	if (list == NULL) list = anjuta_token_list (sibling);
511 
512 	for (token = anjuta_token_first_item (list); token != NULL;)
513 	{
514 		AnjutaToken *next;
515 
516 		switch (anjuta_token_get_type (token))
517 		{
518 		case ANJUTA_TOKEN_LAST:
519 			anjuta_token_insert_before (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
520 			anjuta_token_insert_before (token, item);
521 			return item;
522 		case ANJUTA_TOKEN_START:
523 			if (token == sibling)
524 			{
525 				anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
526 				anjuta_token_insert_after (token, item);
527 				return item;
528 			}
529 			break;
530 		case ANJUTA_TOKEN_NEXT:
531 			if (token == sibling)
532 			{
533 				token = anjuta_token_insert_before (token, item);
534 				anjuta_token_insert_before (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
535 				return item;
536 			}
537 			break;
538 		default:
539 			if (token == sibling)
540 			{
541 				anjuta_token_insert_before (token, item);
542 				anjuta_token_insert_before (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
543 				return item;
544 			}
545 			break;
546 		}
547 
548 		next = anjuta_token_next_item (token);
549 		if (next == NULL)
550 		{
551 			token = anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
552 			anjuta_token_insert_after (token, item);
553 			return item;
554 		}
555 		token = next;
556 	}
557 
558 	anjuta_token_prepend_items (list, item);
559 
560 	return item;
561 }
562 
563 AnjutaToken *
anjuta_token_insert_word_after(AnjutaToken * list,AnjutaToken * sibling,AnjutaToken * item)564 anjuta_token_insert_word_after (AnjutaToken *list, AnjutaToken *sibling, AnjutaToken *item)
565 {
566 	AnjutaToken *token;
567 
568 	if (list == NULL) list = anjuta_token_list (sibling);
569 
570 	for (token = anjuta_token_first_item (list); token != NULL;)
571 	{
572 		AnjutaToken *next;
573 
574 		next = anjuta_token_next_item (token);
575 
576 		switch (anjuta_token_get_type (token))
577 		{
578 		case ANJUTA_TOKEN_LAST:
579 			anjuta_token_insert_before (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
580 			anjuta_token_insert_before (token, item);
581 			return item;
582 		case ANJUTA_TOKEN_START:
583 			if ((sibling == NULL) || (token == sibling))
584 			{
585 				if (next != NULL) anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
586 				anjuta_token_insert_after (token, item);
587 				return item;
588 			}
589 			break;
590 		case ANJUTA_TOKEN_NEXT:
591 			if (token == sibling)
592 			{
593 				token = anjuta_token_insert_after (token, item);
594 				anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
595 				return item;
596 			}
597 			break;
598 		default:
599 			if (token == sibling)
600 			{
601 				token = anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
602 				anjuta_token_insert_after (token, item);
603 				return item;
604 			}
605 			break;
606 		}
607 
608 		if (next == NULL)
609 		{
610 			token = anjuta_token_insert_after (token, anjuta_token_new_static (ANJUTA_TOKEN_NEXT | ANJUTA_TOKEN_ADDED, NULL));
611 			anjuta_token_insert_after (token, item);
612 			return item;
613 		}
614 		token = next;
615 	}
616 
617 	anjuta_token_prepend_items (list, item);
618 
619 	return item;
620 }
621 
622 AnjutaToken*
anjuta_token_remove_word(AnjutaToken * token)623 anjuta_token_remove_word (AnjutaToken *token)
624 {
625 	AnjutaToken *next;
626 
627 	anjuta_token_set_flags (token, ANJUTA_TOKEN_REMOVED);
628 	next = anjuta_token_next_item (token);
629 	if ((next != NULL) && (anjuta_token_list (token) == anjuta_token_list (next)) && (anjuta_token_get_type (next) == ANJUTA_TOKEN_NEXT))
630 	{
631 		/* Remove following separator */
632 		anjuta_token_set_flags (next, ANJUTA_TOKEN_REMOVED);
633 	}
634 	else
635 	{
636 		next = anjuta_token_previous_item (token);
637 		if ((next != NULL) && (anjuta_token_list (token) == anjuta_token_list (next)) && (anjuta_token_get_type (next) == ANJUTA_TOKEN_NEXT))
638 		{
639 			/* Remove previous separator */
640 			anjuta_token_set_flags (next, ANJUTA_TOKEN_REMOVED);
641 		}
642 		else
643 		{
644 			next = NULL;
645 		}
646 	}
647 
648 	return next;
649 }
650 
651 /**
652  * anjuta_token_remove_list:
653  * @token: a #AnjutaToken corresponding to a list
654  *
655  * Remove a complete list of token.
656  *
657  * Return value: A #AnjutaToken representing the following token
658  */
659 AnjutaToken *
anjuta_token_remove_list(AnjutaToken * list)660 anjuta_token_remove_list (AnjutaToken *list)
661 {
662 	AnjutaToken *next;
663 	AnjutaToken *prev;
664 
665 	if (!(anjuta_token_get_flags(list) & ANJUTA_TOKEN_REMOVED))
666 	{
667 		anjuta_token_set_flags (list, ANJUTA_TOKEN_REMOVED);
668 
669 		prev = anjuta_token_previous_item (list);
670 		if (prev != NULL)
671 		{
672 			if (anjuta_token_get_type (prev) == ANJUTA_TOKEN_EOL)
673 			{
674 				/* Remove line above if empty */
675 				AnjutaToken *prev_prev = anjuta_token_previous_item (prev);
676 
677 				if ((prev_prev == NULL) || (anjuta_token_get_type (prev_prev) == ANJUTA_TOKEN_EOL) || (anjuta_token_get_type (prev_prev) == ANJUTA_TOKEN_COMMENT))
678 				{
679 					anjuta_token_set_flags (prev, ANJUTA_TOKEN_REMOVED);
680 				}
681 			}
682 			else if (anjuta_token_get_type (prev) == ANJUTA_TOKEN_COMMENT)
683 			{
684 				/* Remove comment above if there is an empty line after it */
685 				do
686 				{
687 					prev = anjuta_token_previous_item (prev);
688 				}
689 				while ((prev != NULL) && (anjuta_token_get_type (prev) == ANJUTA_TOKEN_COMMENT));
690 
691 				if ((prev != NULL) && (anjuta_token_get_type (prev) == ANJUTA_TOKEN_EOL))
692 				{
693 					prev = list;
694 					do
695 					{
696 						anjuta_token_set_flags (prev, ANJUTA_TOKEN_REMOVED);
697 						prev = anjuta_token_previous_item (prev);
698 					}
699 					while ((prev != NULL) && (anjuta_token_get_type (prev) == ANJUTA_TOKEN_COMMENT));
700 				}
701 			}
702 		}
703 	}
704 
705 	next = anjuta_token_next_item (list);
706 	if (next != NULL)
707 	{
708 		if (anjuta_token_get_type (next) == ANJUTA_TOKEN_EOL)
709 		{
710 			anjuta_token_set_flags (next, ANJUTA_TOKEN_REMOVED);
711 		}
712 		next = anjuta_token_next_item (next);
713 	}
714 
715 	return next;
716 }
717 
718 AnjutaToken *
anjuta_token_insert_token_list(gboolean after,AnjutaToken * pos,...)719 anjuta_token_insert_token_list (gboolean after, AnjutaToken *pos,...)
720 {
721 	AnjutaToken *first = NULL;
722 	GList *group = NULL;
723 	va_list args;
724 	gint type;
725 
726 	va_start (args, pos);
727 
728 	for (type = va_arg (args, gint); type != 0; type = va_arg (args, gint))
729 	{
730 		gchar *string = va_arg (args, gchar *);
731 		AnjutaToken *token;
732 
733 		if (pos == NULL)
734 		{
735 			pos = token = anjuta_token_new_string (type | ANJUTA_TOKEN_ADDED, string);
736 			after = TRUE;
737 		}
738 		else
739 		{
740 			if (after)
741 			{
742 				pos = token = anjuta_token_insert_after (pos, anjuta_token_new_string (type | ANJUTA_TOKEN_ADDED, string));
743 			}
744 			else
745 			{
746 				token = anjuta_token_insert_before (pos, anjuta_token_new_string (type | ANJUTA_TOKEN_ADDED, string));
747 			}
748 		}
749 		if (first == NULL) first = token;
750 
751 		if (group != NULL)
752 		{
753 			anjuta_token_merge ((AnjutaToken *)group->data, token);
754 		}
755 
756 		if (string == NULL)
757 		{
758 			switch (type)
759 			{
760 			case ANJUTA_TOKEN_LIST:
761 				break;
762 			default:
763 				group = g_list_delete_link (group, group);
764 				break;
765 			}
766 			group = g_list_prepend (group, token);
767 		}
768 	}
769 	g_list_free (group);
770 
771 	va_end (args);
772 
773 	return first;
774 }
775 
776 AnjutaToken *
anjuta_token_find_type(AnjutaToken * list,gint flags,AnjutaTokenType * types)777 anjuta_token_find_type (AnjutaToken *list, gint flags, AnjutaTokenType* types)
778 {
779 	AnjutaToken *tok;
780 	AnjutaToken *last = NULL;
781 
782 	for (tok = list; tok != NULL; tok = anjuta_token_next (tok))
783 	{
784 		AnjutaTokenType *type;
785 		for (type = types; *type != 0; type++)
786 		{
787 			if (anjuta_token_get_type (tok) == *type)
788 			{
789 				last = tok;
790 				if (flags & ANJUTA_TOKEN_SEARCH_NOT) break;
791 				if (!(flags & ANJUTA_TOKEN_SEARCH_LAST)) break;
792 			}
793 		}
794 		if ((flags & ANJUTA_TOKEN_SEARCH_NOT) && (*type == 0)) break;
795 	}
796 
797 	return last;
798 }
799 
800 AnjutaToken *
anjuta_token_skip_comment(AnjutaToken * token)801 anjuta_token_skip_comment (AnjutaToken *token)
802 {
803 	if (token == NULL) return NULL;
804 
805 	for (;;)
806 	{
807 		for (;;)
808 		{
809 			AnjutaToken *next = anjuta_token_next (token);
810 
811 			if (next == NULL) return token;
812 
813 			switch (anjuta_token_get_type (token))
814 			{
815 			case ANJUTA_TOKEN_FILE:
816 			case ANJUTA_TOKEN_SPACE:
817 				token = next;
818 				continue;
819 			case ANJUTA_TOKEN_COMMENT:
820 				token = next;
821 				break;
822 			default:
823 				return token;
824 			}
825 			break;
826 		}
827 
828 		for (;;)
829 		{
830 			AnjutaToken *next = anjuta_token_next (token);
831 
832 			if (next == NULL) return token;
833 			token = next;
834 			if (anjuta_token_get_type (token) == ANJUTA_TOKEN_EOL) break;
835 		}
836 	}
837 }
838 
839 /* Constructor & Destructor
840  *---------------------------------------------------------------------------*/
841 
842 AnjutaTokenStyle *
anjuta_token_style_new(const gchar * start,const gchar * next,const gchar * eol,const gchar * last,guint max_width)843 anjuta_token_style_new (const gchar *start, const gchar *next, const gchar *eol, const gchar *last, guint max_width)
844 {
845 	AnjutaTokenStyle *style;
846 
847 	style = g_slice_new0 (AnjutaTokenStyle);
848 	style->max_width = max_width;
849 
850 	style->separator = g_hash_table_new (g_direct_hash, NULL);
851 	anjuta_token_style_insert_separator (style, ANJUTA_TOKEN_START, start);
852 	anjuta_token_style_insert_separator (style, ANJUTA_TOKEN_NEXT, next);
853 	anjuta_token_style_insert_separator (style, ANJUTA_TOKEN_NEXT, eol);
854 	anjuta_token_style_insert_separator (style, ANJUTA_TOKEN_LAST, last);
855 
856 	return style;
857 }
858 
859 AnjutaTokenStyle *
anjuta_token_style_new_from_base(AnjutaTokenStyle * base)860 anjuta_token_style_new_from_base (AnjutaTokenStyle *base)
861 {
862 	AnjutaTokenStyle *style;
863 
864 	style = g_slice_new0 (AnjutaTokenStyle);
865 	style->max_width = base->max_width;
866 	style->base = base;
867 
868 	style->separator = g_hash_table_new (g_direct_hash, NULL);
869 
870 	return style;
871 }
872 
873 void
anjuta_token_style_free(AnjutaTokenStyle * style)874 anjuta_token_style_free (AnjutaTokenStyle *style)
875 {
876 	g_hash_table_foreach (style->separator, (GHFunc)free_separator_list, NULL);
877 	g_hash_table_destroy (style->separator);
878 	g_slice_free (AnjutaTokenStyle, style);
879 }
880