1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * text-editor-iterable.c
4 * Copyright (C) 2000 Kh. Naba Kumar Singh
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
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>
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
74 struct _TextEditorCellPrivate
{
77 /* byte position in editor */
80 /* Character position */
81 /* gint char_position; */
84 CellStyle
* styles_pool
[TEXT_CELL_MAX_STYLES
];
87 /* Style processing */
89 static const CellStyle
* text_editor_cell_get_style (TextEditorCell
*cell
, gint style
);
92 cell_style_destroy (CellStyle
*pis
) {
94 if (pis
->font_desc
) g_free (pis
->font_desc
);
95 if (pis
->font_name
) g_free (pis
->font_name
);
101 IntFromHexDigit(const char ch
) {
104 else if (ch
>= 'A' && ch
<= 'F')
105 return ch
- 'A' + 10;
106 else if (ch
>= 'a' && ch
<= 'f')
107 return ch
- 'a' + 10;
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]);
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
);
132 font_desc
= g_strconcat (tmp
, " Bold", NULL
);
138 font_desc
= g_strconcat (tmp
, " Italic", NULL
);
144 font_desc
= g_strdup_printf ("%s %d", tmp
, pis
->size
);
147 g_free (pis
->font_desc
);
148 pis
->font_desc
= font_desc
;
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
);
159 if (!style_string
) return;
161 val
= g_strdup(style_string
);
165 char *cpComma
, *colon
;
167 cpComma
= strchr(opt
, ',');
170 colon
= strchr(opt
, ':');
174 if (0 == strcmp(opt
, "italics"))
176 if (0 == strcmp(opt
, "notitalics"))
177 pis
->italics
= FALSE
;
178 if (0 == strcmp(opt
, "bold"))
180 if (0 == strcmp(opt
, "notbold"))
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
);
198 g_free(style_string
);
202 cell_style_new (PropsID prop
, gchar
* lang
, guint style
, gint font_zoom_factor
)
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
);
213 pis
->italics
= FALSE
;
214 pis
->size
= TEXT_CELL_FONT_SIZE_BODY_DEFAULT
;
217 pis
->fore_color
.red
= 0;
218 pis
->fore_color
.green
= 0;
219 pis
->fore_color
.blue
= 0;
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
);
243 static const CellStyle
*
244 text_editor_cell_get_style (TextEditorCell
*cell
, gint style
)
248 pis
= cell
->priv
->styles_pool
[style
];
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
);
266 /* TextEditorCell implementation */
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
;
277 text_editor_cell_instance_init (TextEditorCell
*obj
)
279 obj
->priv
= g_new0(TextEditorCellPrivate
, 1);
280 /* Initialize private members, etc. */
284 text_editor_cell_finalize (GObject
*object
)
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
]);
298 if (G_OBJECT_CLASS(parent_class
)->finalize
)
299 G_OBJECT_CLASS(parent_class
)->finalize(object
);
303 text_editor_cell_new (TextEditor
* editor
, gint position
)
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
);
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
;
326 text_editor_cell_set_position (TextEditorCell
*cell
, gint position
)
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
),
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
),
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 */
359 icell_get_character (IAnjutaEditorCell
* icell
, GError
** e
)
362 TextEditorCell
* cell
= TEXT_EDITOR_CELL(icell
);
363 position_end
= scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
365 cell
->priv
->position
, 0);
366 return (gchar
*) scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
367 SCI_GETTEXT
, cell
->priv
->position
,
372 icell_get_length (IAnjutaEditorCell
* icell
, GError
** e
)
375 TextEditorCell
* cell
= TEXT_EDITOR_CELL(icell
);
376 position_end
= scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
378 cell
->priv
->position
, 0);
379 return position_end
- cell
->priv
->position
;
383 icell_get_char (IAnjutaEditorCell
* icell
, gint index
, GError
** e
)
386 TextEditorCell
* cell
= TEXT_EDITOR_CELL(icell
);
387 c
= scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
388 SCI_GETCHARAT
, cell
->priv
->position
, 0);
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
);
401 case TEXT_EDITOR_ATTRIB_TEXT
:
402 attrib
= IANJUTA_EDITOR_TEXT
;
404 case TEXT_EDITOR_ATTRIB_COMMENT
:
405 attrib
= IANJUTA_EDITOR_COMMENT
;
407 case TEXT_EDITOR_ATTRIB_KEYWORD
:
408 attrib
= IANJUTA_EDITOR_KEYWORD
;
410 case TEXT_EDITOR_ATTRIB_STRING
:
411 attrib
= IANJUTA_EDITOR_STRING
;
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
;
427 icell_style_get_font_description (IAnjutaEditorCellStyle
* icell_style
, GError
** e
)
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
);
441 icell_style_get_color (IAnjutaEditorCellStyle
* icell_style
, GError
** e
)
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
);
457 icell_style_get_background_color (IAnjutaEditorCellStyle
* icell_style
, GError
** e
)
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
);
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 */
483 iiter_first (IAnjutaIterable
* iter
, GError
** e
)
485 TextEditorCell
* cell
= TEXT_EDITOR_CELL(iter
);
486 cell
->priv
->position
= 0;
491 iiter_next (IAnjutaIterable
* iter
, GError
** e
)
493 TextEditorCell
* cell
= TEXT_EDITOR_CELL(iter
);
496 old_position
= cell
->priv
->position
;
497 cell
->priv
->position
= scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
498 SCI_POSITIONAFTER
, old_position
,
500 if (old_position
== cell
->priv
->position
)
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)
517 cell
->priv
->position
= scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
519 cell
->priv
->position
,
522 DEBUG_PRINT ("Iterator position changed from %d to %d", saved_pos,
523 cell->priv->position);
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);
539 iiter_foreach (IAnjutaIterable
* iter
, GFunc callback
, gpointer data
, GError
** e
)
541 TextEditorCell
* cell
= TEXT_EDITOR_CELL(iter
);
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
;
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
);
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
)
575 pos
= g_utf8_offset_to_pointer (buffer
, position
);
576 new_byte_position
= pos
- buffer
;
581 within_range
= FALSE
;
587 /* Set to end-iter (length of the doc) */
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
);
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)
609 (gchar
*) aneditor_command (TEXT_EDITOR
610 (cell
->priv
->editor
)->editor_id
,
612 cell
->priv
->position
);
613 char_position
= g_utf8_strlen (data
, -1);
616 DEBUG_PRINT ("Byte pos = %d, char position = %d", cell
->priv
->position
,
618 return char_position
;
622 iiter_get_length (IAnjutaIterable
* iter
, GError
** e
)
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);
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);
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
);
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
;
665 iiter_compare (IAnjutaIterable
*iter
, IAnjutaIterable
*iter2
, GError
**e
)
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);
675 iiter_diff (IAnjutaIterable
*iter
, IAnjutaIterable
*iter2
, GError
**e
)
678 TextEditorCell
*cell
= TEXT_EDITOR_CELL (iter
);
679 TextEditorCell
*cell2
= TEXT_EDITOR_CELL (iter2
);
681 if (cell
->priv
->position
== cell2
->priv
->position
)
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
)
694 scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
695 SCI_POSITIONAFTER
, byte_position
, 0);
701 gint byte_position
= cell
->priv
->position
;
702 while (byte_position
< cell2
->priv
->position
)
705 scintilla_send_message (SCINTILLA (cell
->priv
->editor
->scintilla
),
706 SCI_POSITIONAFTER
, byte_position
, 0);
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
);