language-support-cpp-java: prepared support for new SymbolManager ifaces.
[anjuta.git] / plugins / language-support-cpp-java / plugin.c
blob8164950c78a9a90412d3c26a84abadfc5ced304a
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 plugin.c
4 Copyright (C) 2000 Naba Kumar
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 #include <config.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <libanjuta/anjuta-shell.h>
25 #include <libanjuta/anjuta-debug.h>
26 #include <libanjuta/anjuta-pkg-config-chooser.h>
27 #include <libanjuta/interfaces/ianjuta-iterable.h>
28 #include <libanjuta/interfaces/ianjuta-document.h>
29 #include <libanjuta/interfaces/ianjuta-document-manager.h>
30 #include <libanjuta/interfaces/ianjuta-editor.h>
31 #include <libanjuta/interfaces/ianjuta-file.h>
32 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
33 #include <libanjuta/interfaces/ianjuta-editor-language.h>
34 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
35 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
36 #include <libanjuta/interfaces/ianjuta-editor-tip.h>
37 #include <libanjuta/interfaces/ianjuta-preferences.h>
38 #include <libanjuta/interfaces/ianjuta-symbol.h>
39 #include <libanjuta/interfaces/ianjuta-language.h>
41 #include "plugin.h"
42 #include "cpp-java-utils.h"
44 /* Pixmaps */
45 #define ANJUTA_PIXMAP_SWAP "anjuta-swap"
46 #define ANJUTA_PIXMAP_AUTOINDENT "anjuta-indent-auto"
47 #define ANJUTA_STOCK_SWAP "anjuta-swap"
48 #define ANJUTA_STOCK_COMPLETE "anjuta-complete"
49 #define ANJUTA_STOCK_AUTOINDENT "anjuta-indent"
51 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-language-support-cpp-java.xml"
52 #define PREFS_BUILDER PACKAGE_DATA_DIR"/glade/anjuta-language-cpp-java.ui"
53 #define ICON_FILE "anjuta-language-cpp-java-plugin.png"
55 #define FIXME_DEFAULT_PACKAGE_VERSION "1.0"
57 /* Preferences keys */
59 #define PREF_INDENT_AUTOMATIC "language.cpp.indent.automatic"
60 #define PREF_INDENT_STATEMENT_SIZE "language.cpp.indent.statement.size"
61 #define PREF_INDENT_BRACE_SIZE "language.cpp.indent.brace.size"
62 #define PREF_INDENT_PARANTHESE_LINEUP "language.cpp.indent.paranthese.lineup"
63 #define PREF_INDENT_PARANTHESE_SIZE "language.cpp.indent.paranthese.size"
64 #define PREF_BRACE_AUTOCOMPLETION "language.cpp.brace.autocompletion"
66 #define TAB_SIZE (ianjuta_editor_get_tabsize (editor, NULL))
68 #define USE_SPACES_FOR_INDENTATION (ianjuta_editor_get_use_spaces (editor, NULL))
70 #define INDENT_SIZE \
71 (plugin->param_statement_indentation >= 0? \
72 plugin->param_statement_indentation : \
73 anjuta_preferences_get_int (plugin->prefs, PREF_INDENT_STATEMENT_SIZE))
75 #define BRACE_INDENT \
76 (plugin->param_brace_indentation >= 0? \
77 plugin->param_brace_indentation : \
78 anjuta_preferences_get_int (plugin->prefs, PREF_INDENT_BRACE_SIZE))
80 #define CASE_INDENT (INDENT_SIZE)
81 #define LABEL_INDENT (INDENT_SIZE)
83 static gpointer parent_class;
85 static gboolean
86 iter_is_newline (IAnjutaIterable *iter, gchar ch)
88 if (ch == '\n' || ch == '\r')
89 return TRUE;
90 return FALSE;
93 /* Returns TRUE if iter was moved */
94 static gboolean
95 skip_iter_to_newline_head (IAnjutaIterable *iter, gchar ch)
97 gboolean ret_val = FALSE;
99 if (ch == '\n')
101 /* Possibly at tail */
102 if (ianjuta_iterable_previous (iter, NULL))
104 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
105 0, NULL);
106 if (ch != '\r')
107 /* Already at head, undo iter */
108 ianjuta_iterable_next (iter, NULL);
109 else
110 /* Correctly at head */
111 ret_val = TRUE;
114 return ret_val;
117 /* Returns TRUE if iter was moved */
118 static gboolean
119 skip_iter_to_newline_tail (IAnjutaIterable *iter, gchar ch)
121 gboolean ret_val = FALSE;
123 if (ch == '\r')
125 /* Possibly at head */
126 if (ianjuta_iterable_previous (iter, NULL))
128 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
129 0, NULL);
130 if (ch != '\n')
131 /* Already at tail, undo iter */
132 ianjuta_iterable_next (iter, NULL);
133 else
134 /* Correctly at tail */
135 ret_val = TRUE;
138 return ret_val;
141 /* Jumps to the reverse matching brace of the given brace character */
143 static gint
144 get_line_indentation (IAnjutaEditor *editor, gint line_num)
146 IAnjutaIterable *line_begin, *line_end;
147 gchar *line_string, *idx;
148 gint line_indent = 0;
150 line_begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
151 line_end = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
153 DEBUG_PRINT ("%s: line begin = %d, line end = %d", __FUNCTION__,
154 line_begin, line_end);
156 if (ianjuta_iterable_compare (line_begin, line_end, NULL) == 0)
158 g_object_unref (line_begin);
159 g_object_unref (line_end);
160 return 0;
163 line_string = ianjuta_editor_get_text (editor, line_begin, line_end,
164 NULL);
165 g_object_unref (line_begin);
166 g_object_unref (line_end);
168 /* DEBUG_PRINT ("line_string = '%s'", line_string); */
170 if (!line_string)
171 return 0;
173 idx = line_string;
175 /* Find first non-white space */
176 while (*idx != '\0' && isspace (*idx))
178 if (*idx == '\t')
179 line_indent += TAB_SIZE;
180 else
181 line_indent++;
182 idx++; /* Since we are looking for first non-space char, simple
183 * increment of the utf8 chars would do */
185 g_free (line_string);
186 return line_indent;
189 static gchar *
190 get_line_indentation_string (IAnjutaEditor *editor, gint spaces, gint line_indent_spaces)
192 gint i;
193 gchar *indent_string;
195 if ((spaces + line_indent_spaces) <= 0)
196 return NULL;
198 if (USE_SPACES_FOR_INDENTATION)
200 indent_string = g_new0 (gchar, spaces + line_indent_spaces + 1);
201 for (i = 0; i < (spaces + line_indent_spaces); i++)
202 indent_string[i] = ' ';
204 else
206 gint num_tabs = spaces / TAB_SIZE;
207 gint num_spaces = spaces % TAB_SIZE;
208 indent_string = g_new0 (gchar, num_tabs + num_spaces + line_indent_spaces + 1);
210 for (i = 0; i < num_tabs; i++)
211 indent_string[i] = '\t';
212 for (; i < num_tabs + (num_spaces + line_indent_spaces); i++)
213 indent_string[i] = ' ';
215 return indent_string;
218 /* Sets the iter to line end of previous line and TRUE is returned.
219 * If there is no previous line, iter is set to first character in the
220 * buffer and FALSE is returned.
222 static gboolean
223 skip_iter_to_previous_line (IAnjutaEditor *editor, IAnjutaIterable *iter)
225 gboolean found = FALSE;
226 gchar ch;
228 while (ianjuta_iterable_previous (iter, NULL))
230 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
231 if (iter_is_newline (iter, ch))
233 skip_iter_to_newline_head (iter, ch);
234 found = TRUE;
235 break;
238 return found;
241 /* Returns TRUE if the line is continuation of previous line (that is, it is
242 * part of the same logical line).
244 static gboolean
245 line_is_continuation (IAnjutaEditor *editor, IAnjutaIterable *iter)
247 int is_continuation = FALSE;
249 IAnjutaIterable *new_iter = ianjuta_iterable_clone (iter, NULL);
250 if (skip_iter_to_previous_line (editor, new_iter))
252 while (ianjuta_iterable_previous (new_iter, NULL))
254 gchar ch = ianjuta_editor_cell_get_char
255 (IANJUTA_EDITOR_CELL (new_iter), 0, NULL);
256 if (ch == ' ' || ch == '\t')
257 continue;
259 if (ch == '\\')
261 is_continuation = TRUE;
262 break;
265 if (iter_is_newline (new_iter, ch))
266 break;
269 g_object_unref (new_iter);
270 return is_continuation;
273 /* Sets the iter to line end of previous logical line and TRUE is returned.
274 * If there is no previous logical line, iter is set to first character in the
275 * buffer and FALSE is returned. logical line is defined as one or more
276 * real lines that are joined with line escapes ('\' at the end of real
277 * lines.
279 static gboolean
280 skip_iter_to_previous_logical_line (IAnjutaEditor *editor,
281 IAnjutaIterable *iter)
283 gboolean found = TRUE;
285 while (line_is_continuation (editor, iter))
288 DEBUG_PRINT ("Line %d is continuation line .. Skipping",
289 ianjuta_editor_get_line_from_position (editor, iter, NULL));
291 found = skip_iter_to_previous_line (editor, iter);
292 if (!found)
293 break;
296 DEBUG_PRINT ("Line %d is *not* continuation line .. Breaking",
297 ianjuta_editor_get_line_from_position (editor, iter, NULL));
299 if (found)
300 found = skip_iter_to_previous_line (editor, iter);
302 DEBUG_PRINT ("Line %d is next logical line",
303 ianjuta_editor_get_line_from_position (editor, iter, NULL));
305 return found;
308 static gboolean
309 line_is_preprocessor (IAnjutaEditor *editor, IAnjutaIterable *iter)
311 gboolean is_preprocessor = FALSE;
312 IAnjutaIterable *new_iter = ianjuta_iterable_clone (iter, NULL);
314 if (skip_iter_to_previous_logical_line (editor, new_iter))
316 /* Forward the newline char and point to line begin of next line */
317 gchar ch;
318 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (new_iter),
319 0, NULL);
320 skip_iter_to_newline_tail (new_iter, ch);
321 ianjuta_iterable_next (new_iter, NULL);
323 /* else, line is already pointed at first char of the line */
327 gchar ch;
328 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (new_iter),
329 0, NULL);
330 if (ch == '#')
332 is_preprocessor = TRUE;
333 break;
335 if (iter_is_newline (new_iter, ch) || !isspace (ch))
336 break;
338 while (ianjuta_iterable_next (new_iter, NULL));
340 g_object_unref (new_iter);
342 return is_preprocessor;
345 /* Skips to the end-of-line of previous non-preprocessor line. Any multiple
346 * preprocessor lines are skipped. If current
347 * line is not preprocessor line, nothing happens. If there is no previous
348 * non-preprocessor line (we are at first line of the document which happens
349 * to be preprocessor line), iter is set to the first character in the
350 * document. It returns TRUE if the line is preprocessor line, otherwise
351 * FALSE.
353 static gboolean
354 skip_preprocessor_lines (IAnjutaEditor *editor, IAnjutaIterable *iter)
356 gboolean line_found = FALSE;
357 gboolean preprocessor_found = FALSE;
358 IAnjutaIterable *new_iter = ianjuta_iterable_clone (iter, NULL);
362 gboolean is_preprocessor = FALSE;
363 if (skip_iter_to_previous_logical_line (editor, new_iter))
365 gchar ch;
366 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (new_iter),
367 0, NULL);
368 skip_iter_to_newline_tail (new_iter, ch);
369 ianjuta_iterable_next (new_iter, NULL);
373 gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (new_iter),
374 0, NULL);
375 if (ch == '#')
377 is_preprocessor = TRUE;
379 DEBUG_PRINT ("Line %d is preprocessor line .. Skipping",
380 ianjuta_editor_get_line_from_position
381 (editor, new_iter, NULL));
383 break;
385 if (iter_is_newline (new_iter, ch) || !isspace (ch))
387 skip_iter_to_newline_tail (new_iter, ch);
388 break;
391 while (ianjuta_iterable_next (new_iter, NULL));
393 if (is_preprocessor)
395 line_found = skip_iter_to_previous_line (editor, new_iter);
396 ianjuta_iterable_assign (iter, new_iter, NULL);
397 preprocessor_found = TRUE;
399 else
402 DEBUG_PRINT ("Line %d is *not* preprocessor line .. Breaking",
403 ianjuta_editor_get_line_from_position
404 (editor, new_iter, NULL));
406 break;
409 while (line_found);
411 g_object_unref (new_iter);
412 return preprocessor_found;
415 static void
416 set_indentation_param_emacs (CppJavaPlugin* plugin, const gchar *param,
417 const gchar *value)
419 //DEBUG_PRINT ("Setting indent param: %s = %s", param, value);
420 if (strcasecmp (param, "indent-tabs-mode") == 0)
422 if (strcasecmp (value, "t") == 0)
424 plugin->param_use_spaces = 0;
425 ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
426 FALSE, NULL);
428 else if (strcasecmp (value, "nil") == 0)
430 plugin->param_use_spaces = 1;
431 ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
432 TRUE, NULL);
435 else if (strcasecmp (param, "c-basic-offset") == 0)
437 plugin->param_statement_indentation = atoi (value);
439 else if (strcasecmp (param, "tab-width") == 0)
441 plugin->param_tab_size = atoi (value);
442 ianjuta_editor_set_tabsize (IANJUTA_EDITOR (plugin->current_editor),
443 plugin->param_tab_size, NULL);
447 static void
448 set_indentation_param_vim (CppJavaPlugin* plugin, const gchar *param,
449 const gchar *value)
451 //DEBUG_PRINT ("Setting indent param: %s = %s", param, value);
452 if (g_str_equal (param, "expandtab") ||
453 g_str_equal (param, "et"))
455 plugin->param_use_spaces = 1;
456 ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
457 TRUE, NULL);
459 else if (g_str_equal (param, "noexpandtabs") ||
460 g_str_equal (param, "noet"))
462 plugin->param_use_spaces = 0;
463 ianjuta_editor_set_use_spaces (IANJUTA_EDITOR (plugin->current_editor),
464 FALSE, NULL);
466 if (!value)
467 return;
468 else if (g_str_equal (param, "shiftwidth") ||
469 g_str_equal (param, "sw"))
471 plugin->param_statement_indentation = atoi (value);
473 else if (g_str_equal (param, "softtabstop") ||
474 g_str_equal (param, "sts") ||
475 g_str_equal (param, "tabstop") ||
476 g_str_equal (param, "ts"))
478 plugin->param_tab_size = atoi (value);
479 ianjuta_editor_set_tabsize (IANJUTA_EDITOR (plugin->current_editor),
480 plugin->param_tab_size, NULL);
484 static void
485 parse_mode_line_emacs (CppJavaPlugin *plugin, const gchar *modeline)
487 gchar **strv, **ptr;
489 strv = g_strsplit (modeline, ";", -1);
490 ptr = strv;
491 while (*ptr)
493 gchar **keyval;
494 keyval = g_strsplit (*ptr, ":", 2);
495 if (keyval[0] && keyval[1])
497 g_strstrip (keyval[0]);
498 g_strstrip (keyval[1]);
499 set_indentation_param_emacs (plugin, g_strchug (keyval[0]),
500 g_strchug (keyval[1]));
502 g_strfreev (keyval);
503 ptr++;
505 g_strfreev (strv);
508 static void
509 parse_mode_line_vim (CppJavaPlugin *plugin, const gchar *modeline)
511 gchar **strv, **ptr;
513 strv = g_strsplit_set (modeline, " \t:", -1);
514 ptr = strv;
515 while (*ptr)
517 gchar **keyval;
518 keyval = g_strsplit (*ptr, "=", 2);
519 if (keyval[0])
521 g_strstrip (keyval[0]);
522 if (keyval[1])
524 g_strstrip (keyval[1]);
525 set_indentation_param_vim (plugin, g_strchug (keyval[0]),
526 g_strchug (keyval[1]));
528 else
529 set_indentation_param_vim (plugin, g_strchug (keyval[0]),
530 NULL);
532 g_strfreev (keyval);
533 ptr++;
535 g_strfreev (strv);
538 static gchar *
539 extract_mode_line (const gchar *comment_text, gboolean* vim)
541 /* Search for emacs-like modelines */
542 gchar *begin_modeline, *end_modeline;
543 begin_modeline = strstr (comment_text, "-*-");
544 if (begin_modeline)
546 begin_modeline += 3;
547 end_modeline = strstr (begin_modeline, "-*-");
548 if (end_modeline)
550 *vim = FALSE;
551 return g_strndup (begin_modeline, end_modeline - begin_modeline);
554 /* Search for vim-like modelines */
555 begin_modeline = strstr (comment_text, "vim:");
556 if (begin_modeline)
558 begin_modeline += strlen ("vim:");
559 end_modeline = strstr (begin_modeline, "*/");
560 /* Check for escape characters */
561 while (end_modeline)
563 if (!g_str_equal ((end_modeline - 1), "\\"))
564 break;
565 end_modeline++;
566 end_modeline = strstr (end_modeline, "*/");
568 if (end_modeline)
570 gchar* vim_modeline = g_strndup (begin_modeline, end_modeline - begin_modeline);
571 *vim = TRUE;
572 return vim_modeline;
575 return NULL;
578 #define MINI_BUFFER_SIZE 3
580 static void
581 initialize_indentation_params (CppJavaPlugin *plugin)
583 IAnjutaIterable *iter;
584 GString *comment_text;
585 gboolean comment_begun = FALSE;
586 gboolean line_comment = FALSE;
587 gchar mini_buffer[MINI_BUFFER_SIZE] = {0};
589 plugin->smart_indentation = anjuta_preferences_get_bool (plugin->prefs, PREF_INDENT_AUTOMATIC);
590 /* Disable editor intern auto-indent if smart indentation is enabled */
591 ianjuta_editor_set_auto_indent (IANJUTA_EDITOR(plugin->current_editor),
592 !plugin->smart_indentation, NULL);
594 /* Initialize indentation parameters */
595 plugin->param_tab_size = -1;
596 plugin->param_statement_indentation = -1;
597 plugin->param_brace_indentation = -1;
598 plugin->param_case_indentation = -1;
599 plugin->param_label_indentation = -1;
600 plugin->param_use_spaces = -1;
602 /* Find the first comment text in the buffer */
603 comment_text = g_string_new (NULL);
604 iter = ianjuta_editor_get_start_position (IANJUTA_EDITOR (plugin->current_editor),
605 NULL);
608 gboolean shift_buffer = TRUE;
609 gint i;
610 gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
611 0, NULL);
613 for (i = 0; i < MINI_BUFFER_SIZE - 1; i++)
615 if (mini_buffer[i] == '\0')
617 mini_buffer[i] = ch;
618 shift_buffer = FALSE;
619 break;
622 if (shift_buffer == TRUE)
624 /* Shift buffer and add */
625 for (i = 0; i < MINI_BUFFER_SIZE - 1; i++)
626 mini_buffer [i] = mini_buffer[i+1];
627 mini_buffer[i] = ch;
630 if (!comment_begun && strncmp (mini_buffer, "/*", 2) == 0)
632 comment_begun = TRUE;
633 /* Reset buffer */
634 mini_buffer[0] = mini_buffer[1] = '\0';
636 else if (!comment_begun && strncmp (mini_buffer, "//", 2) == 0)
638 comment_begun = TRUE;
639 line_comment = TRUE;
641 else if (!comment_begun && mini_buffer[1] != '\0')
643 /* The buffer doesn't begin with a comment */
644 break;
646 else if (comment_begun)
648 if ((line_comment && ch == '\n') ||
649 (!line_comment && strncmp (mini_buffer, "*/", 2) == 0))
651 break;
655 if (comment_begun)
656 g_string_append_c (comment_text, ch);
659 while (ianjuta_iterable_next (iter, NULL));
661 /* DEBUG_PRINT ("Comment text: %s", comment_text->str);*/
662 if (comment_text->len > 0)
665 /* First comment found */
666 gboolean vim;
667 gchar *modeline = extract_mode_line (comment_text->str, &vim);
668 if (modeline)
670 if (!vim)
671 parse_mode_line_emacs (plugin, modeline);
672 else
673 parse_mode_line_vim (plugin, modeline);
674 g_free (modeline);
677 g_string_free (comment_text, TRUE);
678 g_object_unref (iter);
681 static gint
682 set_line_indentation (IAnjutaEditor *editor, gint line_num, gint indentation, gint line_indent_spaces)
684 IAnjutaIterable *line_begin, *line_end, *indent_position;
685 IAnjutaIterable *current_pos;
686 gint carat_offset, nchars = 0, nchars_removed = 0;
687 gchar *old_indent_string = NULL, *indent_string = NULL;
689 /* DEBUG_PRINT ("In %s()", __FUNCTION__); */
690 line_begin = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
691 line_end = ianjuta_editor_get_line_end_position (editor, line_num, NULL);
694 DEBUG_PRINT ("line begin = %d, line end = %d, current_pos = %d",
695 line_begin, line_end, current_pos);
697 indent_position = ianjuta_iterable_clone (line_begin, NULL);
699 if (ianjuta_iterable_compare (line_end, line_begin, NULL) > 0)
701 gchar *idx;
702 gchar *line_string = ianjuta_editor_get_text (editor, line_begin,
703 line_end, NULL);
705 //DEBUG_PRINT ("line_string = '%s'", line_string);
706 if (line_string)
708 idx = line_string;
710 /* Find first non-white space */
711 while (*idx != '\0' && isspace (*idx))
713 idx = g_utf8_find_next_char (idx, NULL);
714 ianjuta_iterable_next (indent_position, NULL);
716 g_free (line_string);
719 /* Indent iter defined at this point, Identify how much is current
720 * position is beyound this point. We need to restore it later after
721 * indentation
723 current_pos = ianjuta_editor_get_position (editor, NULL);
724 carat_offset = ianjuta_iterable_diff (indent_position, current_pos, NULL);
725 //DEBUG_PRINT ("carat offset is = %d", carat_offset);
727 /* Set new indentation */
728 if ((indentation + line_indent_spaces) > 0)
730 indent_string = get_line_indentation_string (editor, indentation, line_indent_spaces);
731 nchars = indent_string ? g_utf8_strlen (indent_string, -1) : 0;
733 /* Only indent if there is something to indent with */
734 if (indent_string)
736 /* Get existing indentation */
737 if (ianjuta_iterable_compare (indent_position, line_begin, NULL) > 0)
739 old_indent_string =
740 ianjuta_editor_get_text (editor, line_begin,
741 indent_position, NULL);
743 //DEBUG_PRINT ("old_indent_string = '%s'", old_indent_string);
744 nchars_removed = g_utf8_strlen (old_indent_string, -1);
747 /* Only indent if there was no indentation before or old
748 * indentation string was different from the new indent string
750 if (old_indent_string == NULL ||
751 strcmp (old_indent_string, indent_string) != 0)
753 /* Remove the old indentation string, if there is any */
754 if (old_indent_string)
755 ianjuta_editor_erase (editor, line_begin,
756 indent_position, NULL);
758 /* Insert the new indentation string */
759 ianjuta_editor_insert (editor, line_begin,
760 indent_string, -1, NULL);
765 /* If indentation == 0, we really didn't enter the previous code block,
766 * but we may need to clear existing indentation.
768 if ((indentation + line_indent_spaces) == 0)
770 /* Get existing indentation */
771 if (ianjuta_iterable_compare (indent_position, line_begin, NULL) > 0)
773 old_indent_string =
774 ianjuta_editor_get_text (editor, line_begin,
775 indent_position, NULL);
776 nchars_removed = g_utf8_strlen (old_indent_string, -1);
778 if (old_indent_string)
779 ianjuta_editor_erase (editor, line_begin, indent_position, NULL);
782 /* Restore current position */
783 if (carat_offset >= 0)
785 /* If the cursor was not before the first non-space character in
786 * the line, restore it's position after indentation.
788 gint i;
789 IAnjutaIterable *pos = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
790 for (i = 0; i < nchars + carat_offset; i++)
791 ianjuta_iterable_next (pos, NULL);
792 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
793 ianjuta_editor_goto_position (editor, pos, NULL);
794 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
795 g_object_unref (pos);
797 else /* cursor_offset < 0 */
799 /* If the cursor was somewhere in the old indentation spaces,
800 * home the cursor to first non-space character in the line (or
801 * end of line if there is no non-space characters in the line.
803 gint i;
804 IAnjutaIterable *pos = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
805 for (i = 0; i < nchars; i++)
806 ianjuta_iterable_next (pos, NULL);
807 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
808 ianjuta_editor_goto_position (editor, pos, NULL);
809 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
810 g_object_unref (pos);
813 g_object_unref (current_pos);
814 g_object_unref (indent_position);
815 g_object_unref (line_begin);
816 g_object_unref (line_end);
818 g_free (old_indent_string);
819 g_free (indent_string);
820 return nchars;
823 /* incomplete_statement:
824 * 1 == COMPLETE STATEMENT
825 * 0 == INCOMPLETE STATEMENT
826 * -1 == UNKNOWN
828 static gint
829 get_line_indentation_base (CppJavaPlugin *plugin,
830 IAnjutaEditor *editor,
831 gint line_num,
832 gint *incomplete_statement,
833 gint *line_indent_spaces,
834 gboolean *colon_indent)
836 IAnjutaIterable *iter;
837 gchar point_ch;
838 gint line_indent = 0;
839 gint extra_indent = 0;
840 gboolean looking_at_just_next_line = TRUE;
841 gboolean current_line_is_preprocessor = FALSE;
842 gboolean current_line_is_continuation = FALSE;
843 gboolean line_checked_for_comment = FALSE;
845 *incomplete_statement = -1;
846 *line_indent_spaces = 0;
848 if (line_num <= 1)
849 return 0;
851 /* DEBUG_PRINT ("In %s()", __FUNCTION__); */
853 iter = ianjuta_editor_get_line_begin_position (editor, line_num, NULL);
855 current_line_is_preprocessor = line_is_preprocessor (editor, iter);
856 current_line_is_continuation =
857 line_is_continuation (editor, iter);
859 DEBUG_PRINT ("Current line is preprocessor = %d",
860 current_line_is_preprocessor);
861 DEBUG_PRINT ("Current line is continuation = %d",
862 current_line_is_continuation);
864 /* line_indent = get_line_indentation (editor, line_num - 1); */
866 if (current_line_is_preprocessor && current_line_is_continuation)
868 /* Continuation of preprocessor line -- just maintain indentation */
869 g_object_unref (iter);
870 return get_line_indentation (editor, line_num - 1);
872 else if (current_line_is_preprocessor)
874 /* Preprocessor line -- indentation should be 0 */
875 g_object_unref (iter);
876 return 0;
879 while (ianjuta_iterable_previous (iter, NULL))
881 /* Skip strings */
882 IAnjutaEditorAttribute attrib =
883 ianjuta_editor_cell_get_attribute (IANJUTA_EDITOR_CELL (iter), NULL);
884 if (attrib == IANJUTA_EDITOR_STRING)
885 continue;
887 point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0,
888 NULL);
890 /* DEBUG_PRINT("point_ch = %c", point_ch); */
892 /* Check for line comment comment */
893 if (!line_checked_for_comment && !isspace(point_ch))
895 gboolean comment = FALSE;
896 IAnjutaIterable* new_iter = ianjuta_iterable_clone (iter, NULL);
899 gchar c;
900 c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (new_iter), 0,
901 NULL);
902 if (iter_is_newline (new_iter, c))
904 line_checked_for_comment = TRUE;
905 break;
907 if (c == '/')
909 IAnjutaIterable* tmp_iter = ianjuta_iterable_clone (new_iter, NULL);
910 if (!ianjuta_iterable_previous (tmp_iter, NULL))
912 g_object_unref (tmp_iter);
913 break;
915 c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (tmp_iter), 0,
916 NULL);
917 if (c == '/')
919 /* is a line comment, skip until begin of comment */
920 comment = TRUE;
921 g_object_unref (tmp_iter);
922 break;
924 g_object_unref (tmp_iter);
926 } while (ianjuta_iterable_previous (new_iter, NULL));
927 if (comment)
929 ianjuta_iterable_assign (iter, new_iter, NULL);
930 ianjuta_iterable_previous (iter, NULL);
931 g_object_unref (new_iter);
932 continue;
934 g_object_unref (new_iter);
936 /* Check if we are inside a comment */
937 if (point_ch == '/' || point_ch == '*')
939 gboolean comment = FALSE;
940 gboolean comment_end = FALSE;
941 IAnjutaIterable* new_iter = ianjuta_iterable_clone (iter, NULL);
944 gchar c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL(new_iter),
945 0, NULL);
946 if (!comment_end && iter_is_newline (new_iter, c))
948 break;
950 if (c == '*')
952 IAnjutaIterable* prev = ianjuta_iterable_clone (new_iter, NULL);
953 IAnjutaIterable* next = ianjuta_iterable_clone (new_iter, NULL);
954 ianjuta_iterable_previous (prev, NULL);
955 ianjuta_iterable_next (next, NULL);
956 gchar prev_c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (prev), 0,
957 NULL);
958 gchar next_c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (next), 0,
959 NULL);
960 if (prev_c == '/')
962 /* starts comment */
963 comment = TRUE;
964 if (!comment_end)
966 extra_indent++;
967 /* In the middle of a comment we can't know
968 * if the statement is incomplete
970 *incomplete_statement = -1;
971 /* ":" have to be ignored inside comments */
972 if (*colon_indent)
974 *colon_indent = FALSE;
975 extra_indent -= INDENT_SIZE;
978 g_object_unref (prev);
979 g_object_unref (next);
980 break;
983 else if (next_c == '/')
985 /* ends comment: */
986 comment_end = TRUE;
987 g_object_unref (prev);
988 g_object_unref (next);
989 continue;
991 /* Possibly continued comment */
992 else if (isspace(prev_c))
994 gboolean possible_comment = FALSE;
995 while (ianjuta_iterable_previous (prev, NULL))
997 prev_c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (prev), 0,
998 NULL);
999 if (!isspace(prev_c))
1000 break;
1001 if (iter_is_newline (prev, prev_c))
1003 possible_comment = TRUE;
1004 break;
1007 if (possible_comment)
1009 ianjuta_iterable_assign (new_iter, prev, NULL);
1010 g_object_unref (prev);
1011 g_object_unref (next);
1012 continue;
1015 g_object_unref (prev);
1016 g_object_unref (next);
1018 } while (ianjuta_iterable_previous (new_iter, NULL));
1019 if (comment)
1021 ianjuta_iterable_assign (iter, new_iter, NULL);
1022 ianjuta_iterable_previous (iter, NULL);
1023 g_object_unref (new_iter);
1024 continue;
1026 g_object_unref (new_iter);
1028 if (point_ch == ')' || point_ch == ']' || point_ch == '}')
1030 gint line_saved;
1032 line_saved = ianjuta_editor_get_line_from_position (editor, iter,
1033 NULL);
1035 /* If we encounter a block-end before anything else, the
1036 * statement could hardly be incomplte.
1038 if (point_ch == '}' && *incomplete_statement == -1)
1039 *incomplete_statement = 0;
1041 /* If at level 0 indentation, encoutered a
1042 * block end, don't bother going further
1044 if (point_ch == '}' && get_line_indentation (editor, line_saved) <= 0)
1046 line_indent = 0;
1047 line_indent += extra_indent;
1048 break;
1051 /* Find matching brace and continue */
1052 if (!cpp_java_util_jump_to_matching_brace (iter, point_ch, -1))
1054 line_indent = get_line_indentation (editor, line_saved);
1055 line_indent += extra_indent;
1056 break;
1059 else if (point_ch == '{')
1061 gint line_for_indent =
1062 ianjuta_editor_get_line_from_position (editor, iter, NULL);
1063 line_indent = get_line_indentation (editor, line_for_indent);
1064 /* Increase line indentation */
1065 line_indent += INDENT_SIZE;
1066 line_indent += extra_indent;
1068 /* If we encounter a block-start before anything else, the
1069 * statement could hardly be incomplte.
1071 if (point_ch == '{' && *incomplete_statement == -1)
1072 *incomplete_statement = 0;
1074 break;
1076 else if (point_ch == '(' || point_ch == '[')
1078 line_indent = 0;
1079 if (anjuta_preferences_get_bool (plugin->prefs,
1080 PREF_INDENT_PARANTHESE_LINEUP))
1082 while (ianjuta_iterable_previous (iter, NULL))
1084 gchar dummy_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0,
1085 NULL);
1086 if (iter_is_newline (iter, dummy_ch))
1088 skip_iter_to_newline_head (iter, dummy_ch);
1089 break;
1091 if (dummy_ch == '\t')
1092 line_indent += TAB_SIZE;
1093 else
1094 (*line_indent_spaces)++;
1096 (*line_indent_spaces)++;
1097 line_indent += extra_indent;
1099 else
1101 gint line_for_indent =
1102 ianjuta_editor_get_line_from_position (editor, iter, NULL);
1103 line_indent = get_line_indentation (editor, line_for_indent);
1104 line_indent += extra_indent;
1106 (*line_indent_spaces) += anjuta_preferences_get_int (plugin->prefs,
1107 PREF_INDENT_PARANTHESE_SIZE);
1110 /* Although statement is incomplete at this point, we don't
1111 * set it to incomplete and just leave it to unknown to avaoid
1112 * increating indentation for it, because incomplete braces,
1113 * overrides any existing indentation
1115 *incomplete_statement = -1;
1116 break;
1118 else if (point_ch == ';' || point_ch == ',')
1120 /* If we encounter statement-end before any non-whitespace
1121 * char, the statement is complete.
1123 if (*incomplete_statement == -1)
1124 *incomplete_statement = 0;
1126 else if (point_ch == ':' && *colon_indent == FALSE)
1128 /* This is a forward reference, all lines below should have
1129 * increased indentation until the next statement has
1130 * a ':'
1131 * If current line indentation is zero, that we don't indent
1133 IAnjutaIterable* new_iter = ianjuta_iterable_clone (iter, NULL);
1134 IAnjutaIterable* line_begin;
1135 gboolean indent = FALSE;
1136 gchar c;
1138 /* Is the last non-whitespace in line */
1139 while (ianjuta_iterable_next (new_iter, NULL))
1141 c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (new_iter),
1142 0, NULL);
1143 if (!isspace(c))
1144 break;
1145 if (iter_is_newline (new_iter, c))
1147 indent = TRUE;
1148 break;
1151 line_begin = ianjuta_editor_get_line_begin_position(editor,
1152 ianjuta_editor_get_line_from_position(editor, iter, NULL),
1153 NULL);
1154 c = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (line_begin),
1155 0, NULL);
1156 if (indent)
1158 *colon_indent = TRUE;
1159 if (*incomplete_statement == -1)
1160 *incomplete_statement = 0;
1162 if (indent && isspace(c))
1164 extra_indent += INDENT_SIZE;
1166 g_object_unref (new_iter);
1167 g_object_unref (line_begin);
1169 else if (iter_is_newline (iter, point_ch))
1171 skip_iter_to_newline_head (iter, point_ch);
1173 /* We just crossed a line boundary. Skip any preprocessor lines,
1174 * and ensure that line_indent is updated with correct real
1175 * previous non-preprocessor line.
1177 if (skip_preprocessor_lines (editor, iter) &&
1178 looking_at_just_next_line)
1181 gint line = ianjuta_editor_get_line_from_position (editor, iter, NULL);
1182 line_indent = get_line_indentation (editor, line);
1185 looking_at_just_next_line = FALSE;
1186 line_checked_for_comment = FALSE;
1188 else if (!isspace (point_ch))
1190 /* If we encounter any non-whitespace char before any of the
1191 * statement-complete indicators, the statement is basically
1192 * incomplete
1194 if (*incomplete_statement == -1)
1195 *incomplete_statement = 1;
1198 if (!line_indent && extra_indent)
1200 line_indent += extra_indent;
1202 g_object_unref (iter);
1204 return line_indent;
1207 /* Check if iter is inside string. Begining of string
1208 * is not counted as inside.
1210 static gboolean
1211 is_iter_inside_string (IAnjutaIterable *iter)
1213 IAnjutaEditorAttribute attrib;
1215 attrib = ianjuta_editor_cell_get_attribute (IANJUTA_EDITOR_CELL (iter),
1216 NULL);
1217 /* Check if we are *inside* string. Begining
1218 * of string does not count as inside.
1220 if (attrib == IANJUTA_EDITOR_STRING)
1222 /* Peek previous attrib and see what it was */
1223 if (ianjuta_iterable_previous (iter, NULL))
1225 attrib = ianjuta_editor_cell_get_attribute (IANJUTA_EDITOR_CELL
1226 (iter), NULL);
1227 if (attrib == IANJUTA_EDITOR_STRING)
1229 /* We are inside string */
1230 return TRUE;
1232 else
1234 /* The string just began, not inside.
1235 * Restore iter from the peek
1237 ianjuta_iterable_next (iter, NULL);
1240 /* else, there is no previous and so we can't be inside string
1243 return FALSE;
1246 static gboolean
1247 spaces_only (IAnjutaEditor* editor, IAnjutaIterable* begin, IAnjutaIterable* end)
1249 gboolean empty = TRUE;
1250 gchar* idx;
1251 gchar* text = ianjuta_editor_get_text (editor, begin, end, NULL);
1253 if (text == NULL)
1254 return TRUE;
1257 for (idx = text; *idx != '\0'; idx++)
1259 if (!isspace(*idx))
1261 empty = FALSE;
1262 break;
1265 g_free(text);
1266 return empty;
1269 static gint
1270 get_line_auto_indentation (CppJavaPlugin *plugin, IAnjutaEditor *editor,
1271 gint line, gint *line_indent_spaces)
1273 IAnjutaIterable *iter;
1274 IAnjutaIterable *end_iter;
1275 gint line_indent = 0;
1276 gint incomplete_statement = -1;
1277 gboolean colon_indent = FALSE;
1279 g_return_val_if_fail (line > 0, 0);
1281 /* be sure to set a default if we're in the first line otherwise
1282 * the pointer'll be left hanging with no value.
1284 *line_indent_spaces = 0;
1286 if (line == 1) /* First line */
1288 return 0;
1290 else
1292 IAnjutaIterable* begin = ianjuta_editor_get_line_begin_position (editor, line -1 , NULL);
1293 IAnjutaIterable* end = ianjuta_editor_get_line_end_position (editor, line -1 , NULL);
1295 if (spaces_only (editor, begin, end))
1297 set_line_indentation (editor, line -1, 0, 0);
1299 g_object_unref (begin);
1300 g_object_unref (end);
1303 iter = ianjuta_editor_get_line_begin_position (editor, line, NULL);
1305 if (is_iter_inside_string (iter))
1307 line_indent = get_line_indentation (editor, line - 1);
1309 else
1311 line_indent = get_line_indentation_base (plugin, editor, line,
1312 &incomplete_statement,
1313 line_indent_spaces,
1314 &colon_indent);
1317 if (colon_indent)
1319 /* If the last non-whitespace character in the line is ":" then
1320 * we remove the extra colon_indent
1322 end_iter = ianjuta_editor_get_line_end_position (editor, line, NULL);
1323 gchar ch;
1324 while (ianjuta_iterable_previous (end_iter, NULL))
1326 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (end_iter),
1327 0, NULL);
1328 if (ch == ':')
1330 line_indent -= INDENT_SIZE;
1331 break;
1333 if (!isspace(ch) || iter_is_newline (end_iter, ch))
1334 break;
1336 g_object_unref (end_iter);
1339 /* Determine what the first non-white char in the line is */
1342 gchar ch;
1343 /* Check if we are *inside* comment or string. Begining of comment
1344 * or string does not count as inside. If inside, just align with
1345 * previous indentation.
1347 if (is_iter_inside_string (iter))
1349 line_indent = get_line_indentation (editor, line - 1);
1350 break;
1352 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
1353 0, NULL);
1354 if (iter_is_newline (iter, ch))
1356 skip_iter_to_newline_tail (iter, ch);
1358 /* First levels are excused from incomplete statement indent */
1359 if (incomplete_statement == 1 && line_indent > 0)
1360 line_indent += INDENT_SIZE;
1361 break;
1364 if (ch == '{')
1366 if (line_indent > 0)
1368 /* The first level braces are excused from brace indentation */
1370 DEBUG_PRINT ("Increasing indent level from %d to %d",
1371 line_indent,
1372 line_indent + BRACE_INDENT);
1374 line_indent += BRACE_INDENT;
1375 /* It looks ugly to add extra indent after case: so remove that */
1376 if (colon_indent)
1377 line_indent -= INDENT_SIZE;
1379 break;
1381 else if (ch == '}')
1383 ianjuta_iterable_previous (iter, NULL);
1384 if (cpp_java_util_jump_to_matching_brace (iter, ch, -1))
1386 gint line = ianjuta_editor_get_line_from_position (editor,
1387 iter,
1388 NULL);
1389 line_indent = get_line_indentation (editor, line);
1391 break;
1393 else if (ch == '#')
1395 line_indent = 0;
1396 *line_indent_spaces = 0;
1398 else if (!isspace (ch))
1400 /* First levels are excused from incomplete statement indent */
1401 if (incomplete_statement == 1 && line_indent > 0)
1402 line_indent += INDENT_SIZE;
1403 break;
1406 while (ianjuta_iterable_next (iter, NULL));
1407 g_object_unref (iter);
1409 return line_indent;
1412 static void
1413 on_editor_char_inserted_cpp (IAnjutaEditor *editor,
1414 IAnjutaIterable *insert_pos,
1415 gchar ch,
1416 CppJavaPlugin *plugin)
1418 IAnjutaEditorAttribute attrib;
1419 IAnjutaIterable *iter;
1420 gboolean should_auto_indent = FALSE;
1422 iter = ianjuta_iterable_clone (insert_pos, NULL);
1424 /* If autoindent is enabled*/
1425 if (plugin->smart_indentation)
1428 /* DEBUG_PRINT ("Char added at position %d: '%c'", insert_pos, ch); */
1430 if (iter_is_newline (iter, ch))
1432 skip_iter_to_newline_head (iter, ch);
1433 /* All newline entries means enable indenting */
1434 should_auto_indent = TRUE;
1436 else if (ch == '{' || ch == '}' || ch == '#')
1438 /* Indent only when it's the first non-white space char in the line */
1440 /* Don't bother if we are inside string */
1441 attrib = ianjuta_editor_cell_get_attribute (IANJUTA_EDITOR_CELL (iter),
1442 NULL);
1443 if (attrib != IANJUTA_EDITOR_STRING)
1445 /* Iterate backwards till the begining of the line and disable
1446 * indenting if any non-white space char is encountered
1449 /* Begin by assuming it should be indented */
1450 should_auto_indent = TRUE;
1452 while (ianjuta_iterable_previous (iter, NULL))
1454 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
1455 0, NULL);
1457 //DEBUG_PRINT ("Looking at char '%c'", ch);
1459 /* Break on begining of line (== end of previous line) */
1460 if (iter_is_newline (iter, ch))
1462 skip_iter_to_newline_head (iter, ch);
1463 break;
1465 /* If a non-white space char is encountered, disabled indenting */
1466 if (!isspace (ch))
1468 should_auto_indent = FALSE;
1469 break;
1474 if (should_auto_indent)
1476 gint insert_line;
1477 gint line_indent;
1478 gint line_indent_spaces;
1480 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
1481 initialize_indentation_params (plugin);
1483 insert_line = ianjuta_editor_get_lineno (editor, NULL);
1484 line_indent = get_line_auto_indentation (plugin, editor, insert_line, &line_indent_spaces);
1485 set_line_indentation (editor, insert_line, line_indent, line_indent_spaces);
1486 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
1490 if (anjuta_preferences_get_bool (plugin->prefs, PREF_BRACE_AUTOCOMPLETION))
1492 if (ch == '[' || ch == '(')
1494 gchar *prev_char;
1495 IAnjutaIterable *previous;
1497 previous = ianjuta_iterable_clone (iter, NULL);
1498 ianjuta_iterable_previous (previous, NULL);
1499 prev_char = ianjuta_editor_get_text (editor, previous, iter, NULL);
1501 /* If the previous char is a ' we don't have to autocomplete */
1502 if (*prev_char != '\'')
1504 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (editor), NULL);
1505 ianjuta_iterable_next (iter, NULL);
1506 switch (ch)
1508 case '[':
1509 ianjuta_editor_insert (editor, iter,
1510 "]", 1, NULL);
1511 break;
1512 case '(':
1513 ianjuta_editor_insert (editor, iter,
1514 ")", 1, NULL);
1515 break;
1516 default:
1517 break;
1519 ianjuta_editor_goto_position (editor, iter, NULL);
1520 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (editor), NULL);
1522 g_object_unref (previous);
1524 else if (ch == '"' || ch == '\'')
1526 gchar *prev_char;
1527 IAnjutaIterable *previous;
1529 previous = ianjuta_iterable_clone (iter, NULL);
1530 ianjuta_iterable_previous (previous, NULL);
1531 prev_char = ianjuta_editor_get_text (editor, previous, iter, NULL);
1533 /* First iter*/
1534 ianjuta_iterable_next (iter, NULL);
1537 * If the character is " we have to decide if we need insert
1538 * another " or we have to skip the character
1540 if (ch == '"' || ch == '\'')
1543 * Now we have to detect if we want to manage " as a char
1545 if (*prev_char != '\'' && *prev_char != '\\')
1547 gchar *c;
1549 if (ch == '"')
1550 c = g_strdup ("\"");
1551 else c = g_strdup ("'");
1553 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (editor), NULL);
1554 ianjuta_editor_insert (editor, iter, c, 1, NULL);
1555 ianjuta_editor_goto_position (editor, iter, NULL);
1556 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (editor), NULL);
1558 g_free (c);
1560 g_object_unref (previous);
1561 g_object_unref (iter);
1562 return;
1564 g_object_unref (previous);
1567 g_object_unref (iter);
1570 static void
1571 on_editor_char_inserted_java (IAnjutaEditor *editor,
1572 IAnjutaIterable *insert_pos,
1573 gchar ch,
1574 CppJavaPlugin *plugin)
1576 on_editor_char_inserted_cpp (editor, insert_pos, ch, plugin);
1579 static void
1580 install_support (CppJavaPlugin *lang_plugin)
1582 IAnjutaLanguage* lang_manager =
1583 anjuta_shell_get_interface (ANJUTA_PLUGIN (lang_plugin)->shell,
1584 IAnjutaLanguage, NULL);
1586 if (!lang_manager)
1587 return;
1589 if (lang_plugin->support_installed)
1590 return;
1592 lang_plugin->current_language =
1593 ianjuta_language_get_name_from_editor (lang_manager,
1594 IANJUTA_EDITOR_LANGUAGE (lang_plugin->current_editor), NULL);
1596 DEBUG_PRINT("Language support installed for: %s",
1597 lang_plugin->current_language);
1599 if (lang_plugin->current_language &&
1600 (g_str_equal (lang_plugin->current_language, "C")
1601 || g_str_equal (lang_plugin->current_language, "C++")
1602 || g_str_equal (lang_plugin->current_language, "Vala")))
1604 g_signal_connect (lang_plugin->current_editor,
1605 "char-added",
1606 G_CALLBACK (on_editor_char_inserted_cpp),
1607 lang_plugin);
1609 else if (lang_plugin->current_language &&
1610 (g_str_equal (lang_plugin->current_language, "Java")))
1612 g_signal_connect (lang_plugin->current_editor,
1613 "char-added",
1614 G_CALLBACK (on_editor_char_inserted_java),
1615 lang_plugin);
1617 else
1619 return;
1622 initialize_indentation_params (lang_plugin);
1624 if (!g_str_equal (lang_plugin->current_language, "Vala"))
1626 CppJavaAssist *assist;
1628 g_assert (lang_plugin->assist == NULL);
1630 assist = cpp_java_assist_new (IANJUTA_EDITOR (lang_plugin->current_editor),
1631 anjuta_shell_get_interface (ANJUTA_PLUGIN (lang_plugin)->shell,
1632 IAnjutaSymbolManager,
1633 NULL),
1634 lang_plugin->prefs);
1635 lang_plugin->assist = assist;
1638 lang_plugin->support_installed = TRUE;
1641 static void
1642 uninstall_support (CppJavaPlugin *lang_plugin)
1644 if (!lang_plugin->support_installed)
1645 return;
1647 if (lang_plugin->current_language &&
1648 (g_str_equal (lang_plugin->current_language, "C")
1649 || g_str_equal (lang_plugin->current_language, "C++")
1650 || g_str_equal (lang_plugin->current_language, "Vala")))
1652 g_signal_handlers_disconnect_by_func (lang_plugin->current_editor,
1653 G_CALLBACK (on_editor_char_inserted_cpp),
1654 lang_plugin);
1656 else if (lang_plugin->current_language &&
1657 (g_str_equal (lang_plugin->current_language, "Java")))
1659 g_signal_handlers_disconnect_by_func (lang_plugin->current_editor,
1660 G_CALLBACK (on_editor_char_inserted_java),
1661 lang_plugin);
1664 if (lang_plugin->assist)
1666 g_object_unref (lang_plugin->assist);
1667 lang_plugin->assist = NULL;
1670 lang_plugin->support_installed = FALSE;
1673 static void
1674 on_editor_language_changed (IAnjutaEditor *editor,
1675 const gchar *new_language,
1676 CppJavaPlugin *plugin)
1678 uninstall_support (plugin);
1679 install_support (plugin);
1682 static void
1683 on_value_added_current_editor (AnjutaPlugin *plugin, const gchar *name,
1684 const GValue *value, gpointer data)
1686 CppJavaPlugin *lang_plugin;
1687 IAnjutaDocument* doc = IANJUTA_DOCUMENT(g_value_get_object (value));
1688 lang_plugin = ANJUTA_PLUGIN_CPP_JAVA (plugin);
1689 if (IANJUTA_IS_EDITOR(doc))
1690 lang_plugin->current_editor = G_OBJECT(doc);
1691 else
1693 lang_plugin->current_editor = NULL;
1694 return;
1696 if (IANJUTA_IS_EDITOR(lang_plugin->current_editor))
1697 install_support (lang_plugin);
1698 g_signal_connect (lang_plugin->current_editor, "language-changed",
1699 G_CALLBACK (on_editor_language_changed),
1700 plugin);
1703 static void
1704 on_value_removed_current_editor (AnjutaPlugin *plugin, const gchar *name,
1705 gpointer data)
1707 CppJavaPlugin *lang_plugin;
1708 lang_plugin = ANJUTA_PLUGIN_CPP_JAVA (plugin);
1709 if (lang_plugin->current_editor)
1710 g_signal_handlers_disconnect_by_func (lang_plugin->current_editor,
1711 G_CALLBACK (on_editor_language_changed),
1712 plugin);
1713 if (IANJUTA_IS_EDITOR(lang_plugin->current_editor))
1714 uninstall_support (lang_plugin);
1715 lang_plugin->current_editor = NULL;
1718 const gchar* SOURCE_EXT[] =
1720 ".c",
1721 ".cc",
1722 ".C",
1723 ".cpp",
1724 ".cxx",
1725 ".ccg",
1726 NULL
1729 const gchar* HEADER_EXT[] =
1731 ".h",
1732 ".hh",
1733 ".H",
1734 ".hpp",
1735 ".hxx",
1736 ".hg",
1737 NULL
1740 static void
1741 on_swap_activate (GtkAction* action, gpointer data)
1743 GFile* file;
1744 GFile* parent;
1745 gchar* parent_uri;
1746 gchar* basename;
1747 gchar* ext;
1748 CppJavaPlugin *lang_plugin = ANJUTA_PLUGIN_CPP_JAVA (data);
1749 IAnjutaDocumentManager* docman =
1750 anjuta_shell_get_interface (ANJUTA_PLUGIN(lang_plugin)->shell,
1751 IAnjutaDocumentManager,
1752 NULL);
1753 if (!lang_plugin->current_editor || !docman)
1754 return;
1756 file = ianjuta_file_get_file (IANJUTA_FILE (lang_plugin->current_editor),
1757 NULL);
1758 parent = g_file_get_parent (file);
1759 parent_uri = g_file_get_uri (parent);
1760 basename = g_file_get_basename (file);
1761 g_object_unref (file);
1762 g_object_unref (parent);
1763 ext = strstr (basename, ".");
1764 if (ext)
1766 int i;
1767 for (i = 0; SOURCE_EXT[i] != NULL; i++)
1769 if (g_str_equal (ext, SOURCE_EXT[i]))
1771 int j;
1772 for (j = 0; HEADER_EXT[j] != NULL; j++)
1774 gchar* filename;
1775 gchar* uri;
1776 GFile* new_file;
1777 *ext = '\0';
1778 filename = g_strdup_printf ("%s%s", basename, HEADER_EXT[j]);
1779 uri = g_build_filename (parent_uri, filename, NULL);
1780 new_file = g_file_new_for_uri (uri);
1781 g_free (uri);
1782 g_free(filename);
1783 if (g_file_query_exists (new_file, NULL))
1785 ianjuta_document_manager_goto_file_line (docman,
1786 new_file,
1788 NULL);
1789 g_object_unref (new_file);
1790 break;
1792 g_object_unref (new_file);
1794 break;
1796 if (g_str_equal (ext, HEADER_EXT[i]))
1798 int j;
1799 for (j = 0; SOURCE_EXT[j] != NULL; j++)
1801 gchar* filename;
1802 gchar* uri;
1803 GFile* new_file;
1804 *ext = '\0';
1805 filename = g_strdup_printf ("%s%s", basename, SOURCE_EXT[j]);
1806 uri = g_build_filename (parent_uri, filename, NULL);
1807 new_file = g_file_new_for_uri (uri);
1808 g_free (uri);
1809 g_free(filename);
1810 if (g_file_query_exists (new_file, NULL))
1812 ianjuta_document_manager_goto_file_line (docman,
1813 new_file,
1815 NULL);
1816 g_object_unref (new_file);
1817 break;
1819 g_object_unref (new_file);
1821 break;
1825 g_free(basename);
1826 g_free (parent_uri);
1829 static void
1830 on_auto_indent (GtkAction *action, gpointer data)
1832 gint line_start, line_end;
1833 gint insert_line;
1834 gint line_indent;
1835 gboolean has_selection;
1837 CppJavaPlugin *lang_plugin;
1838 IAnjutaEditor *editor;
1839 lang_plugin = ANJUTA_PLUGIN_CPP_JAVA (data);
1840 editor = IANJUTA_EDITOR (lang_plugin->current_editor);
1842 has_selection = ianjuta_editor_selection_has_selection
1843 (IANJUTA_EDITOR_SELECTION (editor), NULL);
1844 if (has_selection)
1846 IAnjutaIterable *sel_start, *sel_end;
1847 sel_start = ianjuta_editor_selection_get_start (IANJUTA_EDITOR_SELECTION (editor),
1848 NULL);
1849 sel_end = ianjuta_editor_selection_get_end (IANJUTA_EDITOR_SELECTION (editor),
1850 NULL);
1851 line_start = ianjuta_editor_get_line_from_position (editor, sel_start, NULL);
1852 line_end = ianjuta_editor_get_line_from_position (editor, sel_end, NULL);
1853 g_object_unref (sel_start);
1854 g_object_unref (sel_end);
1856 else
1858 line_start = ianjuta_editor_get_lineno (IANJUTA_EDITOR(editor), NULL);
1859 line_end = line_start;
1861 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor), NULL);
1862 initialize_indentation_params (lang_plugin);
1864 for (insert_line = line_start; insert_line <= line_end; insert_line++)
1866 gint line_indent_spaces = 0;
1867 line_indent = get_line_auto_indentation (lang_plugin, editor,
1868 insert_line,
1869 &line_indent_spaces);
1870 /* DEBUG_PRINT ("Line indent for line %d = %d", insert_line, line_indent); */
1871 set_line_indentation (editor, insert_line, line_indent, line_indent_spaces);
1873 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor), NULL);
1876 static GtkActionEntry actions[] = {
1878 "ActionMenuEdit",
1879 NULL, N_("_Edit"),
1880 NULL, NULL, NULL
1883 "ActionEditAutoindent",
1884 ANJUTA_STOCK_AUTOINDENT,
1885 N_("Auto-Indent"), "<control>i",
1886 N_("Auto-indent current line or selection based on indentation settings"),
1887 G_CALLBACK (on_auto_indent)
1889 { "ActionFileSwap",
1890 ANJUTA_STOCK_SWAP,
1891 N_("Swap .h/.c"), NULL,
1892 N_("Swap C header and source files"),
1893 G_CALLBACK (on_swap_activate)
1897 static void
1898 register_stock_icons (AnjutaPlugin *plugin)
1900 static gboolean registered = FALSE;
1902 if (registered)
1903 return;
1904 registered = TRUE;
1906 /* Register stock icons */
1907 BEGIN_REGISTER_ICON (plugin);
1908 REGISTER_ICON_FULL (ANJUTA_PIXMAP_SWAP, ANJUTA_STOCK_SWAP);
1909 REGISTER_ICON_FULL (ANJUTA_PIXMAP_AUTOINDENT, ANJUTA_STOCK_AUTOINDENT);
1910 END_REGISTER_ICON;
1913 static gboolean
1914 cpp_java_plugin_activate_plugin (AnjutaPlugin *plugin)
1916 AnjutaUI *ui;
1917 CppJavaPlugin *lang_plugin;
1918 static gboolean initialized = FALSE;
1920 lang_plugin = ANJUTA_PLUGIN_CPP_JAVA (plugin);
1922 DEBUG_PRINT ("%s", "AnjutaLanguageCppJavaPlugin: Activating plugin ...");
1924 if (!initialized)
1926 register_stock_icons (plugin);
1929 lang_plugin->prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
1930 ui = anjuta_shell_get_ui (plugin->shell, NULL);
1931 lang_plugin->action_group =
1932 anjuta_ui_add_action_group_entries (ui, "ActionGroupCppJavaAssist",
1933 _("C++/Java Assistance"),
1934 actions,
1935 G_N_ELEMENTS (actions),
1936 GETTEXT_PACKAGE, TRUE,
1937 plugin);
1938 lang_plugin->uiid = anjuta_ui_merge (ui, UI_FILE);
1940 lang_plugin->editor_watch_id =
1941 anjuta_plugin_add_watch (plugin,
1942 IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT,
1943 on_value_added_current_editor,
1944 on_value_removed_current_editor,
1945 plugin);
1946 initialized = FALSE;
1947 return TRUE;
1950 static gboolean
1951 cpp_java_plugin_deactivate_plugin (AnjutaPlugin *plugin)
1953 AnjutaUI *ui;
1954 CppJavaPlugin *lang_plugin;
1955 lang_plugin = ANJUTA_PLUGIN_CPP_JAVA (plugin);
1957 anjuta_plugin_remove_watch (plugin,
1958 lang_plugin->editor_watch_id,
1959 TRUE);
1961 ui = anjuta_shell_get_ui (plugin->shell, NULL);
1962 anjuta_ui_unmerge (ui, lang_plugin->uiid);
1963 anjuta_ui_remove_action_group (ui, lang_plugin->action_group);
1965 lang_plugin->action_group = NULL;
1966 lang_plugin->uiid = 0;
1967 DEBUG_PRINT ("%s", "AnjutaLanguageCppJavaPlugin: Deactivated plugin.");
1968 return TRUE;
1971 static void
1972 cpp_java_plugin_finalize (GObject *obj)
1974 /* CppJavaPlugin* plugin = ANJUTA_PLUGIN_CPP_JAVA (obj); */
1976 /* Finalization codes here */
1977 G_OBJECT_CLASS (parent_class)->finalize (obj);
1980 static void
1981 cpp_java_plugin_dispose (GObject *obj)
1983 /* Disposition codes */
1984 G_OBJECT_CLASS (parent_class)->dispose (obj);
1987 static void
1988 cpp_java_plugin_instance_init (GObject *obj)
1990 CppJavaPlugin *plugin = ANJUTA_PLUGIN_CPP_JAVA (obj);
1991 plugin->action_group = NULL;
1992 plugin->current_editor = NULL;
1993 plugin->current_language = NULL;
1994 plugin->editor_watch_id = 0;
1995 plugin->uiid = 0;
1996 plugin->assist = NULL;
1999 static void
2000 cpp_java_plugin_class_init (GObjectClass *klass)
2002 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
2004 parent_class = g_type_class_peek_parent (klass);
2006 plugin_class->activate = cpp_java_plugin_activate_plugin;
2007 plugin_class->deactivate = cpp_java_plugin_deactivate_plugin;
2008 klass->finalize = cpp_java_plugin_finalize;
2009 klass->dispose = cpp_java_plugin_dispose;
2012 #define PREF_WIDGET_SPACE "preferences_toggle:bool:1:1:language.cpp.code.completion.space.after.func"
2013 #define PREF_WIDGET_BRACE "preferences_toggle:bool:1:1:language.cpp.code.completion.brace.after.func"
2014 #define PREF_WIDGET_AUTO "preferences_toggle:bool:1:1:language.cpp.code.completion.enable"
2015 #define PREF_WIDGET_PKG_CONFIG "pkg_config_chooser1"
2018 static void
2019 on_autocompletion_toggled (GtkToggleButton* button,
2020 GtkBuilder* bxml)
2022 GtkWidget* widget;
2023 gboolean sensitive = gtk_toggle_button_get_active (button);
2025 widget = GTK_WIDGET (gtk_builder_get_object (bxml, PREF_WIDGET_SPACE));
2026 gtk_widget_set_sensitive (widget, sensitive);
2027 widget = GTK_WIDGET (gtk_builder_get_object (bxml, PREF_WIDGET_BRACE));
2028 gtk_widget_set_sensitive (widget, sensitive);
2031 static void
2032 on_package_activated (AnjutaPkgConfigChooser *self, const gchar* package,
2033 gpointer data)
2035 CppJavaPlugin* plugin;
2036 IAnjutaSymbolManager *isymbol_manager;
2038 plugin = ANJUTA_PLUGIN_CPP_JAVA (data);
2040 DEBUG_PRINT ("activated %s", package);
2041 isymbol_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
2042 IAnjutaSymbolManager,
2043 NULL);
2045 ianjuta_symbol_manager_activate_package (isymbol_manager,
2046 package,
2047 FIXME_DEFAULT_PACKAGE_VERSION,
2048 NULL);
2052 static void
2053 on_package_deactivated (AnjutaPkgConfigChooser *self, const gchar* package,
2054 gpointer data)
2056 CppJavaPlugin* plugin;
2057 IAnjutaSymbolManager *isymbol_manager;
2059 plugin = ANJUTA_PLUGIN_CPP_JAVA (data);
2061 DEBUG_PRINT ("deactivated %s", package);
2063 isymbol_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
2064 IAnjutaSymbolManager,
2065 NULL);
2066 ianjuta_symbol_manager_deactivate_package (isymbol_manager,
2067 package,
2068 FIXME_DEFAULT_PACKAGE_VERSION,
2069 NULL);
2072 static void
2073 ipreferences_merge (IAnjutaPreferences* ipref, AnjutaPreferences* prefs,
2074 GError** e)
2076 GError* error = NULL;
2077 CppJavaPlugin* plugin = ANJUTA_PLUGIN_CPP_JAVA (ipref);
2078 plugin->bxml = gtk_builder_new ();
2079 GtkWidget* toggle;
2080 GtkWidget* pkg_config;
2082 /* Add preferences */
2083 if (!gtk_builder_add_from_file (plugin->bxml, PREFS_BUILDER, &error))
2085 g_warning ("Couldn't load builder file: %s", error->message);
2086 g_error_free (error);
2088 anjuta_preferences_add_from_builder (prefs,
2089 plugin->bxml, "preferences", _("C/C++/Java/Vala"),
2090 ICON_FILE);
2091 toggle = GTK_WIDGET (gtk_builder_get_object (plugin->bxml, PREF_WIDGET_AUTO));
2092 g_signal_connect (toggle, "toggled", G_CALLBACK (on_autocompletion_toggled),
2093 plugin->bxml);
2094 on_autocompletion_toggled (GTK_TOGGLE_BUTTON (toggle), plugin->bxml);
2096 pkg_config = GTK_WIDGET (gtk_builder_get_object (plugin->bxml, PREF_WIDGET_PKG_CONFIG));
2097 anjuta_pkg_config_chooser_show_active_column (ANJUTA_PKG_CONFIG_CHOOSER (pkg_config),
2098 TRUE);
2099 g_signal_connect (G_OBJECT (pkg_config), "package-activated",
2100 G_CALLBACK (on_package_activated), plugin);
2102 g_signal_connect (G_OBJECT (pkg_config), "package-deactivated",
2103 G_CALLBACK (on_package_deactivated), plugin);
2105 gtk_widget_show_all (pkg_config);
2108 static void
2109 ipreferences_unmerge (IAnjutaPreferences* ipref, AnjutaPreferences* prefs,
2110 GError** e)
2112 CppJavaPlugin* plugin = ANJUTA_PLUGIN_CPP_JAVA (ipref);
2113 anjuta_preferences_remove_page(prefs, _("C/C++/Java/Vala"));
2114 g_object_unref (plugin->bxml);
2117 static void
2118 ipreferences_iface_init (IAnjutaPreferencesIface* iface)
2120 iface->merge = ipreferences_merge;
2121 iface->unmerge = ipreferences_unmerge;
2124 ANJUTA_PLUGIN_BEGIN (CppJavaPlugin, cpp_java_plugin);
2125 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES);
2126 ANJUTA_PLUGIN_END;
2128 ANJUTA_SIMPLE_PLUGIN (CppJavaPlugin, cpp_java_plugin);