Replace deprecated types
[anjuta-extras.git] / plugins / scintilla / text-editor-iterable.c
blobfe7ad6fc7b3a9b8058ab6aaada6f4f3cfbe6d5a4
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * text-editor-iterable.c
4 * Copyright (C) 2000 Kh. Naba Kumar Singh
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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <libanjuta/anjuta-utils.h>
28 #include <libanjuta/anjuta-debug.h>
29 #include <libanjuta/interfaces/ianjuta-iterable.h>
30 #include <libanjuta/interfaces/ianjuta-editor.h>
31 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
32 #include <libanjuta/interfaces/ianjuta-editor-cell-style.h>
34 #define GTK
35 #undef PLAT_GTK
36 #define PLAT_GTK 1
38 #include <gtk/gtk.h>
39 #include "Scintilla.h"
40 #include "ScintillaWidget.h"
41 #include "properties.h"
42 #include "text-editor-iterable.h"
44 #define TEXT_CELL_FONT_BODY_DEFAULT "courier"
45 #define TEXT_CELL_FONT_HEADER_DEFAULT "helvetica"
46 #define TEXT_CELL_FONT_SIZE_BODY_DEFAULT 10
47 #define TEXT_CELL_FONT_SIZE_HEADER_DEFALT 10
48 #define TEXT_CELL_FONT_SIZE_NUMBERS_DEFAULT 6
49 #define TEXT_CELL_MAX_STYLES 256
50 #define TEXT_CELL_LINENUMBER_STYLE 33
51 #define TEXT_CELL_DEFAULT_TEXT_STYLE 32
52 #define TEXT_CELL_LINENUM_PADDING '0'
54 static void text_editor_cell_class_init(TextEditorCellClass *klass);
55 static void text_editor_cell_instance_init(TextEditorCell *sp);
56 static void text_editor_cell_finalize(GObject *object);
58 static gpointer parent_class;
60 typedef struct _CellStyle
62 gchar *font_desc;
64 gchar *font_name;
65 gboolean italics;
66 gboolean bold;
67 gint size;
69 GdkColor fore_color;
70 GdkColor back_color;
72 } CellStyle;
74 struct _TextEditorCellPrivate {
75 TextEditor *editor;
77 /* byte position in editor */
78 gint position;
80 /* Character position */
81 /* gint char_position; */
83 /* Styles cache */
84 CellStyle* styles_pool[TEXT_CELL_MAX_STYLES];
87 /* Style processing */
89 static const CellStyle* text_editor_cell_get_style (TextEditorCell *cell, gint style);
91 static void
92 cell_style_destroy (CellStyle *pis) {
93 if (pis) {
94 if (pis->font_desc) g_free (pis->font_desc);
95 if (pis->font_name) g_free (pis->font_name);
96 g_free(pis);
100 static int
101 IntFromHexDigit(const char ch) {
102 if (isdigit(ch))
103 return ch - '0';
104 else if (ch >= 'A' && ch <= 'F')
105 return ch - 'A' + 10;
106 else if (ch >= 'a' && ch <= 'f')
107 return ch - 'a' + 10;
108 else
109 return 0;
112 static void
113 string_to_color (const char *val, GdkColor* color)
115 /* g_print ("Color = %s\n", val); */
116 color->red = IntFromHexDigit(val[1]) * 16 + IntFromHexDigit(val[2]);
117 color->green = IntFromHexDigit(val[3]) * 16 + IntFromHexDigit(val[4]);
118 color->blue = IntFromHexDigit(val[5]) * 16 + IntFromHexDigit(val[6]);
121 static void
122 cell_style_load_font (CellStyle *pis)
124 gchar *font_desc, *tmp;
126 g_return_if_fail (pis->font_name);
128 font_desc = g_strdup (pis->font_name);
129 if (pis->bold)
131 tmp = font_desc;
132 font_desc = g_strconcat (tmp, " Bold", NULL);
133 g_free (tmp);
135 if (pis->italics)
137 tmp = font_desc;
138 font_desc = g_strconcat (tmp, " Italic", NULL);
139 g_free (tmp);
141 if (pis->size > 0)
143 tmp = font_desc;
144 font_desc = g_strdup_printf ("%s %d", tmp, pis->size);
145 g_free (tmp);
147 g_free (pis->font_desc);
148 pis->font_desc = font_desc;
151 static void
152 cell_style_init (CellStyle *pis, PropsID prop, gchar* lang, guint style)
154 gchar *style_key, *style_string, *val, *opt;
156 style_key = g_strdup_printf ("style.%s.%0d", lang, style);
157 style_string = sci_prop_get_expanded (prop, style_key);
158 g_free (style_key);
159 if (!style_string) return;
161 val = g_strdup(style_string);
162 opt = val;
164 while (opt) {
165 char *cpComma, *colon;
167 cpComma = strchr(opt, ',');
168 if (cpComma)
169 *cpComma = '\0';
170 colon = strchr(opt, ':');
171 if (colon)
172 *colon++ = '\0';
174 if (0 == strcmp(opt, "italics"))
175 pis->italics = TRUE;
176 if (0 == strcmp(opt, "notitalics"))
177 pis->italics = FALSE;
178 if (0 == strcmp(opt, "bold"))
179 pis->bold = TRUE;
180 if (0 == strcmp(opt, "notbold"))
181 pis->bold = FALSE;
182 if (0 == strcmp(opt, "font")) {
183 g_free (pis->font_name);
184 pis->font_name = g_strdup(colon);
186 if (0 == strcmp(opt, "fore"))
187 string_to_color(colon, &pis->fore_color);
188 if (0 == strcmp(opt, "back"))
189 string_to_color(colon, &pis->back_color);
190 if (0 == strcmp(opt, "size"))
191 pis->size = atoi(colon);
192 if (cpComma)
193 opt = cpComma + 1;
194 else
195 opt = 0;
197 g_free(val);
198 g_free(style_string);
201 static CellStyle*
202 cell_style_new (PropsID prop, gchar* lang, guint style, gint font_zoom_factor)
204 CellStyle* pis;
206 g_return_val_if_fail (prop > 0, NULL);
207 g_return_val_if_fail (style < 256, NULL);
209 pis = g_new0 (CellStyle, 1);
211 pis->font_name = g_strdup(TEXT_CELL_FONT_BODY_DEFAULT);
212 pis->bold = FALSE;
213 pis->italics = FALSE;
214 pis->size = TEXT_CELL_FONT_SIZE_BODY_DEFAULT;
216 /* Black */
217 pis->fore_color.red = 0;
218 pis->fore_color.green = 0;
219 pis->fore_color.blue = 0;
221 /* White */
222 pis->back_color.red = (gushort)(-1);
223 pis->back_color.green = (gushort)(-1);
224 pis->back_color.blue = (gushort)(-1);
226 /* Set default style first */
227 cell_style_init (pis, prop, "*", 32);
228 if (lang && strlen(lang) > 0) {
229 cell_style_init (pis, prop, lang, 32);
231 /* Then the specific style */
232 cell_style_init (pis, prop, "*", style);
233 if (lang && strlen(lang) > 0) {
234 cell_style_init (pis, prop, lang, style);
237 pis->size += font_zoom_factor;
239 cell_style_load_font (pis);
240 return pis;
243 static const CellStyle*
244 text_editor_cell_get_style (TextEditorCell *cell, gint style)
246 CellStyle* pis;
248 pis = cell->priv->styles_pool[style];
250 if (!pis)
252 gchar* language; /* should it be freed ?*/
253 language = (gchar*) aneditor_command(cell->priv->editor->editor_id,
254 ANE_GETLANGUAGE,0, 0);
255 cell_style_new (cell->priv->editor->props_base,
256 language, style, cell->priv->editor->zoom_factor);
257 cell->priv->styles_pool[style] = pis;
259 if (!pis && style != TEXT_CELL_DEFAULT_TEXT_STYLE) {
260 return text_editor_cell_get_style (cell, TEXT_CELL_DEFAULT_TEXT_STYLE);
262 return pis;
266 /* TextEditorCell implementation */
268 static void
269 text_editor_cell_class_init (TextEditorCellClass *klass)
271 GObjectClass *object_class = G_OBJECT_CLASS(klass);
272 parent_class = g_type_class_peek_parent (klass);
273 object_class->finalize = text_editor_cell_finalize;
276 static void
277 text_editor_cell_instance_init (TextEditorCell *obj)
279 obj->priv = g_new0(TextEditorCellPrivate, 1);
280 /* Initialize private members, etc. */
283 static void
284 text_editor_cell_finalize (GObject *object)
286 gint i;
287 TextEditorCell *cobj;
288 cobj = TEXT_EDITOR_CELL(object);
290 g_object_unref (cobj->priv->editor);
292 for (i = 0; i < TEXT_CELL_MAX_STYLES; i++)
294 if (cobj->priv->styles_pool[i])
295 cell_style_destroy (cobj->priv->styles_pool[i]);
297 g_free(cobj->priv);
298 if (G_OBJECT_CLASS(parent_class)->finalize)
299 G_OBJECT_CLASS(parent_class)->finalize(object);
302 TextEditorCell *
303 text_editor_cell_new (TextEditor* editor, gint position)
305 TextEditorCell *obj;
307 g_return_val_if_fail (IS_TEXT_EDITOR (editor), NULL);
308 g_return_val_if_fail (position >= 0, NULL);
310 obj = TEXT_EDITOR_CELL(g_object_new(TYPE_TEXT_EDITOR_CELL, NULL));
312 g_object_ref (editor);
313 obj->priv->editor = editor;
314 text_editor_cell_set_position (obj, position);
315 return obj;
318 TextEditor*
319 text_editor_cell_get_editor (TextEditorCell *cell)
321 g_return_val_if_fail (IS_TEXT_EDITOR_CELL(cell), NULL);
322 return cell->priv->editor;
325 void
326 text_editor_cell_set_position (TextEditorCell *cell, gint position)
328 guchar ch;
329 g_return_if_fail (IS_TEXT_EDITOR_CELL(cell));
330 g_return_if_fail (position >= 0);
332 cell->priv->position = position;
334 /* Ensure that utf character is properly aligned */
335 ch = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
336 SCI_GETCHARAT,
337 position, 0);
338 /* DEBUG_PRINT ("Iterator position set at %d where char '%c' is found", position, ch); */
339 if ((ch >= 0x80) && (ch < (0x80 + 0x40)))
341 /* un-aligned. Align it */
342 cell->priv->position = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
343 SCI_POSITIONBEFORE,
344 position,
349 gint
350 text_editor_cell_get_position (TextEditorCell *cell)
352 g_return_val_if_fail (IS_TEXT_EDITOR_CELL(cell), -1);
353 return cell->priv->position;
356 /* IAnjutaIterable implementation */
358 static gchar*
359 icell_get_character (IAnjutaEditorCell* icell, GError** e)
361 gint position_end;
362 TextEditorCell* cell = TEXT_EDITOR_CELL(icell);
363 position_end = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
364 SCI_POSITIONAFTER,
365 cell->priv->position, 0);
366 return (gchar*) scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
367 SCI_GETTEXT, cell->priv->position,
368 position_end);
371 static gint
372 icell_get_length (IAnjutaEditorCell* icell, GError** e)
374 gint position_end;
375 TextEditorCell* cell = TEXT_EDITOR_CELL(icell);
376 position_end = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
377 SCI_POSITIONAFTER,
378 cell->priv->position, 0);
379 return position_end - cell->priv->position;
382 static gchar
383 icell_get_char (IAnjutaEditorCell* icell, gint index, GError** e)
385 gint c;
386 TextEditorCell* cell = TEXT_EDITOR_CELL(icell);
387 c = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
388 SCI_GETCHARAT, cell->priv->position, 0);
389 return (gchar) (c);
392 static IAnjutaEditorAttribute
393 icell_get_attribute (IAnjutaEditorCell *icell, GError **e)
395 TextEditorCell* cell = TEXT_EDITOR_CELL(icell);
396 IAnjutaEditorAttribute attrib = IANJUTA_EDITOR_TEXT;
397 TextEditorAttrib text_attrib =
398 text_editor_get_attribute (cell->priv->editor, cell->priv->position);
399 switch (text_attrib)
401 case TEXT_EDITOR_ATTRIB_TEXT:
402 attrib = IANJUTA_EDITOR_TEXT;
403 break;
404 case TEXT_EDITOR_ATTRIB_COMMENT:
405 attrib = IANJUTA_EDITOR_COMMENT;
406 break;
407 case TEXT_EDITOR_ATTRIB_KEYWORD:
408 attrib = IANJUTA_EDITOR_KEYWORD;
409 break;
410 case TEXT_EDITOR_ATTRIB_STRING:
411 attrib = IANJUTA_EDITOR_STRING;
412 break;
414 return attrib;
417 static void
418 icell_iface_init (IAnjutaEditorCellIface* iface)
420 iface->get_character = icell_get_character;
421 iface->get_char = icell_get_char;
422 iface->get_attribute = icell_get_attribute;
423 iface->get_length = icell_get_length;
426 static gchar*
427 icell_style_get_font_description (IAnjutaEditorCellStyle* icell_style, GError ** e)
429 gint style;
430 const CellStyle *cell_style;
432 TextEditorCell* cell = TEXT_EDITOR_CELL(icell_style);
433 style = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
434 SCI_GETSTYLEAT, cell->priv->position, 0);
435 cell_style = text_editor_cell_get_style (cell, style);
437 return g_strdup (cell_style->font_desc);
440 static gchar*
441 icell_style_get_color (IAnjutaEditorCellStyle* icell_style, GError ** e)
443 gint style;
444 const CellStyle *cell_style;
446 TextEditorCell* cell = TEXT_EDITOR_CELL(icell_style);
447 style = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
448 SCI_GETSTYLEAT, cell->priv->position, 0);
449 cell_style = text_editor_cell_get_style (cell, style);
451 return anjuta_util_string_from_color (cell_style->fore_color.red,
452 cell_style->fore_color.green,
453 cell_style->fore_color.blue);
456 static gchar*
457 icell_style_get_background_color (IAnjutaEditorCellStyle* icell_style, GError ** e)
459 gint style;
460 const CellStyle *cell_style;
462 TextEditorCell* cell = TEXT_EDITOR_CELL(icell_style);
463 style = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
464 SCI_GETSTYLEAT, cell->priv->position, 0);
465 cell_style = text_editor_cell_get_style (cell, style);
467 return anjuta_util_string_from_color (cell_style->back_color.red,
468 cell_style->back_color.green,
469 cell_style->back_color.blue);
472 static void
473 icell_style_iface_init (IAnjutaEditorCellStyleIface* iface)
475 iface->get_font_description = icell_style_get_font_description;
476 iface->get_color = icell_style_get_color;
477 iface->get_background_color = icell_style_get_background_color;
480 /* IAnjutaIterable implementation */
482 static gboolean
483 iiter_first (IAnjutaIterable* iter, GError** e)
485 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
486 cell->priv->position = 0;
487 return TRUE;
490 static gboolean
491 iiter_next (IAnjutaIterable* iter, GError** e)
493 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
494 gint old_position;
496 old_position = cell->priv->position;
497 cell->priv->position = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
498 SCI_POSITIONAFTER, old_position,
499 0);
500 if (old_position == cell->priv->position)
501 return FALSE;
502 return TRUE;
505 static gboolean
506 iiter_previous (IAnjutaIterable* iter, GError** e)
508 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
510 gint saved_pos = cell->priv->position;
513 if (cell->priv->position <= 0)
515 return FALSE;
517 cell->priv->position = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
518 SCI_POSITIONBEFORE,
519 cell->priv->position,
522 DEBUG_PRINT ("Iterator position changed from %d to %d", saved_pos,
523 cell->priv->position);
525 return TRUE;
528 static gboolean
529 iiter_last (IAnjutaIterable* iter, GError** e)
531 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
532 cell->priv->position =
533 scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
534 SCI_GETLENGTH, 0, 0);
535 return TRUE;
538 static void
539 iiter_foreach (IAnjutaIterable* iter, GFunc callback, gpointer data, GError** e)
541 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
542 gint saved;
544 /* Save current position */
545 saved = cell->priv->position;
546 cell->priv->position = 0;
547 while (ianjuta_iterable_next (iter, NULL))
549 (*callback)(cell, data);
552 /* Restore current position */
553 cell->priv->position = saved;
556 static gboolean
557 iiter_set_position (IAnjutaIterable* iter, gint position, GError** e)
559 gboolean within_range = TRUE;
560 gint new_byte_position = 0;
561 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
563 if (position > 0)
565 const gchar *buffer;
566 glong length;
568 buffer = (const gchar *)scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla), SCI_GETCHARACTERPOINTER, 0, 0);
569 length = g_utf8_strlen (buffer, -1);
571 if (position < length)
573 gchar *pos;
575 pos = g_utf8_offset_to_pointer (buffer, position);
576 new_byte_position = pos - buffer;
578 else
580 position = -1;
581 within_range = FALSE;
585 if (position < 0)
587 /* Set to end-iter (length of the doc) */
588 new_byte_position =
589 scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
590 SCI_GETLENGTH, 0, 0);
593 cell->priv->position = new_byte_position;
594 DEBUG_PRINT ("Editor byte position set at: %d", cell->priv->position);
595 return within_range;
598 static gint
599 iiter_get_position (IAnjutaIterable* iter, GError** e)
601 gint char_position = 0;
603 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
605 /* FIXME: Find a more optimal solution */
606 if (cell->priv->position > 0)
608 gchar *data =
609 (gchar *) aneditor_command (TEXT_EDITOR
610 (cell->priv->editor)->editor_id,
611 ANE_GETTEXTRANGE, 0,
612 cell->priv->position);
613 char_position = g_utf8_strlen (data, -1);
614 g_free (data);
616 DEBUG_PRINT ("Byte pos = %d, char position = %d", cell->priv->position,
617 char_position);
618 return char_position;
621 static gint
622 iiter_get_length (IAnjutaIterable* iter, GError** e)
624 gint byte_length;
626 TextEditorCell* cell = TEXT_EDITOR_CELL(iter);
628 /* FIXME: Find a more optimal solution */
629 byte_length = scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
630 SCI_GETLENGTH, 0, 0);
631 if (byte_length > 0)
633 gchar *data;
634 gint char_length;
636 data = (gchar *) aneditor_command (TEXT_EDITOR
637 (cell->priv->editor)->editor_id,
638 ANE_GETTEXTRANGE, 0, byte_length);
639 char_length = g_utf8_strlen (data, -1);
640 g_free (data);
641 return char_length;
643 return 0;
646 static IAnjutaIterable *
647 iiter_clone (IAnjutaIterable *iter, GError **e)
649 TextEditorCell *src = TEXT_EDITOR_CELL (iter);
650 TextEditorCell *cell = text_editor_cell_new (src->priv->editor,
651 src->priv->position);
652 return IANJUTA_ITERABLE (cell);
655 static void
656 iiter_assign (IAnjutaIterable *iter, IAnjutaIterable *src_iter, GError **e)
658 TextEditorCell *cell = TEXT_EDITOR_CELL (iter);
659 TextEditorCell *src = TEXT_EDITOR_CELL (src_iter);
660 cell->priv->editor = src->priv->editor;
661 cell->priv->position = src->priv->position;
664 static gint
665 iiter_compare (IAnjutaIterable *iter, IAnjutaIterable *iter2, GError **e)
667 gint delta;
668 TextEditorCell *cell = TEXT_EDITOR_CELL (iter);
669 TextEditorCell *cell2 = TEXT_EDITOR_CELL (iter2);
670 delta = cell->priv->position - cell2->priv->position;
671 return (delta == 0)? 0 : ((delta > 0)? 1 : -1);
674 static gint
675 iiter_diff (IAnjutaIterable *iter, IAnjutaIterable *iter2, GError **e)
677 gint diff = 0;
678 TextEditorCell *cell = TEXT_EDITOR_CELL (iter);
679 TextEditorCell *cell2 = TEXT_EDITOR_CELL (iter2);
681 if (cell->priv->position == cell2->priv->position)
683 return 0;
686 /* FIXME: Find more optimal solution */
687 /* Iterate until we reach larger iter position */
688 if (cell->priv->position > cell2->priv->position)
690 gint byte_position = cell2->priv->position;
691 while (byte_position < cell->priv->position)
693 byte_position =
694 scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
695 SCI_POSITIONAFTER, byte_position, 0);
696 diff--;
699 else
701 gint byte_position = cell->priv->position;
702 while (byte_position < cell2->priv->position)
704 byte_position =
705 scintilla_send_message (SCINTILLA (cell->priv->editor->scintilla),
706 SCI_POSITIONAFTER, byte_position, 0);
707 diff++;
710 return diff;
713 static void
714 iiter_iface_init(IAnjutaIterableIface* iface)
716 iface->first = iiter_first;
717 iface->next = iiter_next;
718 iface->previous = iiter_previous;
719 iface->last = iiter_last;
720 iface->foreach = iiter_foreach;
721 iface->set_position = iiter_set_position;
722 iface->get_position = iiter_get_position;
723 iface->get_length = iiter_get_length;
724 iface->clone = iiter_clone;
725 iface->assign = iiter_assign;
726 iface->compare = iiter_compare;
727 iface->diff = iiter_diff;
730 ANJUTA_TYPE_BEGIN(TextEditorCell, text_editor_cell, G_TYPE_OBJECT);
731 ANJUTA_TYPE_ADD_INTERFACE(icell, IANJUTA_TYPE_EDITOR_CELL);
732 ANJUTA_TYPE_ADD_INTERFACE(icell_style, IANJUTA_TYPE_EDITOR_CELL_STYLE);
733 ANJUTA_TYPE_ADD_INTERFACE(iiter, IANJUTA_TYPE_ITERABLE);
734 ANJUTA_TYPE_END;