4 * Copyright (C) 2011 - Johannes Schmid
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, see <http://www.gnu.org/licenses/>.
23 #include <libanjuta/anjuta-shell.h>
24 #include <libanjuta/anjuta-debug.h>
25 #include <libanjuta/anjuta-launcher.h>
26 #include <libanjuta/anjuta-preferences.h>
27 #include <libanjuta/anjuta-modeline.h>
28 #include <libanjuta/interfaces/ianjuta-iterable.h>
29 #include <libanjuta/interfaces/ianjuta-document.h>
30 #include <libanjuta/interfaces/ianjuta-document-manager.h>
31 #include <libanjuta/interfaces/ianjuta-editor.h>
32 #include <libanjuta/interfaces/ianjuta-file.h>
33 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
34 #include <libanjuta/interfaces/ianjuta-editor-language.h>
35 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
36 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
37 #include <libanjuta/interfaces/ianjuta-preferences.h>
38 #include <libanjuta/interfaces/ianjuta-symbol.h>
39 #include <libanjuta/interfaces/ianjuta-language.h>
41 #include "python-indentation.h"
43 #define PREF_INDENT_AUTOMATIC "indent-automatic"
44 #define PREF_INDENT_ADAPTIVE "indent-adaptive"
45 #define PREF_INDENT_TAB_INDENTS "indent-tab-indents"
46 #define PREF_INDENT_BRACE_SIZE "indent-brace-size"
48 #define TAB_SIZE (ianjuta_editor_get_tabsize (editor, NULL))
50 #define USE_SPACES_FOR_INDENTATION (ianjuta_editor_get_use_spaces (editor, NULL))
52 #define INDENT_SIZE (ianjuta_editor_get_indentsize (editor, NULL))
54 #define BRACE_INDENT \
55 (plugin->param_brace_indentation >= 0? \
56 plugin->param_brace_indentation : \
57 g_settings_get_int (plugin->settings, PREF_INDENT_BRACE_SIZE))
59 #define CASE_INDENT (INDENT_SIZE)
60 #define LABEL_INDENT (INDENT_SIZE)
63 iter_is_newline (IAnjutaIterable
*iter
, gchar ch
)
65 if (ch
== '\n' || ch
== '\r')
70 /* Returns TRUE if iter was moved */
72 skip_iter_to_newline_head (IAnjutaIterable
*iter
, gchar ch
)
74 gboolean ret_val
= FALSE
;
78 /* Possibly at tail */
79 if (ianjuta_iterable_previous (iter
, NULL
))
81 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
),
84 /* Already at head, undo iter */
85 ianjuta_iterable_next (iter
, NULL
);
87 /* Correctly at head */
94 /* Returns TRUE if iter was moved */
96 skip_iter_to_newline_tail (IAnjutaIterable
*iter
, gchar ch
)
98 gboolean ret_val
= FALSE
;
102 /* Possibly at head */
103 if (ianjuta_iterable_previous (iter
, NULL
))
105 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
),
108 /* Already at tail, undo iter */
109 ianjuta_iterable_next (iter
, NULL
);
111 /* Correctly at tail */
118 /* Jumps to the reverse matching brace of the given brace character */
121 get_line_indentation (IAnjutaEditor
*editor
, gint line_num
)
123 IAnjutaIterable
*line_begin
, *line_end
;
124 gchar
*line_string
, *idx
;
125 gint line_indent
= 0;
127 line_begin
= ianjuta_editor_get_line_begin_position (editor
, line_num
, NULL
);
128 line_end
= ianjuta_editor_get_line_end_position (editor
, line_num
, NULL
);
130 DEBUG_PRINT ("%s: line begin = %d, line end = %d", __FUNCTION__,
131 line_begin, line_end);
133 if (ianjuta_iterable_compare (line_begin
, line_end
, NULL
) == 0)
135 g_object_unref (line_begin
);
136 g_object_unref (line_end
);
140 line_string
= ianjuta_editor_get_text (editor
, line_begin
, line_end
,
142 g_object_unref (line_begin
);
143 g_object_unref (line_end
);
145 /* DEBUG_PRINT ("line_string = '%s'", line_string); */
152 /* Find first non-white space */
153 while (*idx
!= '\0' && isspace (*idx
))
156 line_indent
+= TAB_SIZE
;
159 idx
++; /* Since we are looking for first non-space char, simple
160 * increment of the utf8 chars would do */
162 g_free (line_string
);
167 get_line_indentation_string (IAnjutaEditor
*editor
, gint spaces
, gint line_indent_spaces
)
170 gchar
*indent_string
;
172 if ((spaces
+ line_indent_spaces
) <= 0)
175 if (USE_SPACES_FOR_INDENTATION
)
177 indent_string
= g_new0 (gchar
, spaces
+ line_indent_spaces
+ 1);
178 for (i
= 0; i
< (spaces
+ line_indent_spaces
); i
++)
179 indent_string
[i
] = ' ';
183 gint num_tabs
= spaces
/ TAB_SIZE
;
184 gint num_spaces
= spaces
% TAB_SIZE
;
185 indent_string
= g_new0 (gchar
, num_tabs
+ num_spaces
+ line_indent_spaces
+ 1);
187 for (i
= 0; i
< num_tabs
; i
++)
188 indent_string
[i
] = '\t';
189 for (; i
< num_tabs
+ (num_spaces
+ line_indent_spaces
); i
++)
190 indent_string
[i
] = ' ';
192 return indent_string
;
197 python_indent_init (IndentPythonPlugin
* plugin
)
200 /* Initialize indentation parameters */
201 plugin
->param_brace_indentation
= -1;
202 plugin
->param_case_indentation
= -1;
203 plugin
->param_label_indentation
= -1;
205 anjuta_apply_modeline (IANJUTA_EDITOR (plugin
->current_editor
));
209 set_line_indentation (IAnjutaEditor
*editor
, gint line_num
, gint indentation
, gint line_indent_spaces
)
211 IAnjutaIterable
*line_begin
, *line_end
, *indent_position
;
212 IAnjutaIterable
*current_pos
;
213 gint carat_offset
, nchars
= 0;
214 gchar
*old_indent_string
= NULL
, *indent_string
= NULL
;
216 /* DEBUG_PRINT ("In %s()", __FUNCTION__); */
217 line_begin
= ianjuta_editor_get_line_begin_position (editor
, line_num
, NULL
);
218 line_end
= ianjuta_editor_get_line_end_position (editor
, line_num
, NULL
);
221 DEBUG_PRINT ("line begin = %d, line end = %d, current_pos = %d",
222 line_begin, line_end, current_pos);
224 indent_position
= ianjuta_iterable_clone (line_begin
, NULL
);
226 if (ianjuta_iterable_compare (line_end
, line_begin
, NULL
) > 0)
229 gchar
*line_string
= ianjuta_editor_get_text (editor
, line_begin
,
232 //DEBUG_PRINT ("line_string = '%s'", line_string);
237 /* Find first non-white space */
238 while (*idx
!= '\0' && isspace (*idx
))
240 idx
= g_utf8_find_next_char (idx
, NULL
);
241 ianjuta_iterable_next (indent_position
, NULL
);
243 g_free (line_string
);
246 /* Indent iter defined at this point, Identify how much is current
247 * position is beyound this point. We need to restore it later after
250 current_pos
= ianjuta_editor_get_position (editor
, NULL
);
251 carat_offset
= ianjuta_iterable_diff (indent_position
, current_pos
, NULL
);
252 //DEBUG_PRINT ("carat offset is = %d", carat_offset);
254 /* Set new indentation */
255 if ((indentation
+ line_indent_spaces
) > 0)
257 indent_string
= get_line_indentation_string (editor
, indentation
, line_indent_spaces
);
258 nchars
= indent_string
? g_utf8_strlen (indent_string
, -1) : 0;
260 /* Only indent if there is something to indent with */
263 /* Get existing indentation */
264 if (ianjuta_iterable_compare (indent_position
, line_begin
, NULL
) > 0)
267 ianjuta_editor_get_text (editor
, line_begin
,
268 indent_position
, NULL
);
270 //DEBUG_PRINT ("old_indent_string = '%s'", old_indent_string);
273 /* Only indent if there was no indentation before or old
274 * indentation string was different from the new indent string
276 if (old_indent_string
== NULL
||
277 strcmp (old_indent_string
, indent_string
) != 0)
279 /* Remove the old indentation string, if there is any */
280 if (old_indent_string
)
281 ianjuta_editor_erase (editor
, line_begin
,
282 indent_position
, NULL
);
284 /* Insert the new indentation string */
285 ianjuta_editor_insert (editor
, line_begin
,
286 indent_string
, -1, NULL
);
291 /* If indentation == 0, we really didn't enter the previous code block,
292 * but we may need to clear existing indentation.
294 if ((indentation
+ line_indent_spaces
) == 0)
296 /* Get existing indentation */
297 if (ianjuta_iterable_compare (indent_position
, line_begin
, NULL
) > 0)
300 ianjuta_editor_get_text (editor
, line_begin
,
301 indent_position
, NULL
);
303 if (old_indent_string
)
304 ianjuta_editor_erase (editor
, line_begin
, indent_position
, NULL
);
307 /* Restore current position */
308 if (carat_offset
>= 0)
310 /* If the cursor was not before the first non-space character in
311 * the line, restore it's position after indentation.
314 IAnjutaIterable
*pos
= ianjuta_editor_get_line_begin_position (editor
, line_num
, NULL
);
315 for (i
= 0; i
< nchars
+ carat_offset
; i
++)
316 ianjuta_iterable_next (pos
, NULL
);
317 ianjuta_editor_goto_position (editor
, pos
, NULL
);
318 g_object_unref (pos
);
320 else /* cursor_offset < 0 */
322 /* If the cursor was somewhere in the old indentation spaces,
323 * home the cursor to first non-space character in the line (or
324 * end of line if there is no non-space characters in the line.
327 IAnjutaIterable
*pos
= ianjuta_editor_get_line_begin_position (editor
, line_num
, NULL
);
328 for (i
= 0; i
< nchars
; i
++)
329 ianjuta_iterable_next (pos
, NULL
);
330 ianjuta_editor_goto_position (editor
, pos
, NULL
);
331 g_object_unref (pos
);
334 g_object_unref (current_pos
);
335 g_object_unref (indent_position
);
336 g_object_unref (line_begin
);
337 g_object_unref (line_end
);
339 g_free (old_indent_string
);
340 g_free (indent_string
);
344 /* incomplete_statement:
345 * 1 == COMPLETE STATEMENT
346 * 0 == INCOMPLETE STATEMENT
351 get_current_statement (IAnjutaEditor
*editor
, gint line_num
)
354 IAnjutaIterable
*iter
= ianjuta_editor_get_line_begin_position (editor
, line_num
, NULL
);
355 GString
* statement
= g_string_new (NULL
);
359 point_ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
), 0, NULL
);
361 if (!ianjuta_iterable_next (iter
, NULL
) )
364 while (g_ascii_isspace (point_ch
) && point_ch
!= '\n');
366 if (!ianjuta_iterable_previous (iter
, NULL
))
368 g_object_unref (iter
);
369 g_string_free (statement
, TRUE
);
375 point_ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
), 0, NULL
);
376 g_string_append_c (statement
, point_ch
);
378 if (!ianjuta_iterable_next (iter
, NULL
) )
381 while (g_ascii_isalpha(point_ch
) || g_ascii_isdigit(point_ch
));
383 g_object_unref (iter
);
384 return g_string_free (statement
, FALSE
);
388 get_last_char (IAnjutaEditor
*editor
, gint line_num
, gint
*found_line_num
)
391 IAnjutaIterable
*iter
= ianjuta_editor_get_line_end_position (editor
, line_num
, NULL
);
395 if (ianjuta_iterable_previous (iter
, NULL
) )
397 point_ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
), 0,
403 while (point_ch
== ' ' || point_ch
== '\n' || point_ch
== '\r' || point_ch
== '\t'); // Whitespace
405 *found_line_num
= ianjuta_editor_get_line_from_position (editor
, iter
, NULL
);
406 g_object_unref (iter
);
411 spaces_only (IAnjutaEditor
* editor
, IAnjutaIterable
* begin
, IAnjutaIterable
* end
);
414 is_spaces_only (IAnjutaEditor
*editor
, gint line_num
)
416 IAnjutaIterable
* begin
= ianjuta_editor_get_line_begin_position (editor
, line_num
, NULL
);
417 IAnjutaIterable
* end
= ianjuta_editor_get_line_end_position (editor
, line_num
, NULL
);
419 if (spaces_only (editor
, begin
, end
))
428 get_line_indentation_base (IndentPythonPlugin
*plugin
,
429 IAnjutaEditor
*editor
,
431 gint
*incomplete_statement
,
432 gint
*line_indent_spaces
,
433 gboolean
*colon_indent
)
436 gint line_indent
= 0;
437 gint currentline
= line_num
- 1;
439 gchar
*current_statement
;
441 *incomplete_statement
= 0;
442 *line_indent_spaces
= 0;
444 if (currentline
<= 1)
447 point_ch
= get_last_char (editor
, currentline
, ¤tline
);
448 statement
= get_current_statement (editor
, currentline
);
449 current_statement
= get_current_statement (editor
, line_num
);
451 if (g_str_equal(statement
, "return") ||
452 g_str_equal(statement
, "break") ||
453 g_str_equal(statement
, "pass") ||
454 g_str_equal(statement
, "raise") ||
455 g_str_equal(statement
, "continue"))
457 if (get_line_indentation (editor
, currentline
)>= INDENT_SIZE
)
458 line_indent
= get_line_indentation (editor
, currentline
) - INDENT_SIZE
;
461 else if ((g_str_has_prefix(current_statement
, "def") && point_ch
!= ':') ||
462 g_str_has_prefix(current_statement
, "else") ||
463 g_str_has_prefix(current_statement
, "elif") ||
464 g_str_has_prefix(current_statement
, "except") ||
465 g_str_has_prefix(current_statement
, "finally"))
467 if (get_line_indentation (editor
, currentline
)>= INDENT_SIZE
)
468 line_indent
= get_line_indentation (editor
, currentline
) - INDENT_SIZE
;
470 else if (point_ch
== ':')
472 line_indent
= get_line_indentation (editor
, currentline
) + INDENT_SIZE
;
476 gint line
= currentline
;
477 while (is_spaces_only(editor
, line
) && line
>= 0)
479 line_indent
= get_line_indentation (editor
, line
);
483 g_free (current_statement
);
489 spaces_only (IAnjutaEditor
* editor
, IAnjutaIterable
* begin
, IAnjutaIterable
* end
)
491 gboolean empty
= TRUE
;
493 gchar
* text
= ianjuta_editor_get_text (editor
, begin
, end
, NULL
);
499 for (idx
= text
; *idx
!= '\0'; idx
++)
512 get_line_auto_indentation (IndentPythonPlugin
*plugin
, IAnjutaEditor
*editor
,
513 gint line
, gint
*line_indent_spaces
)
515 IAnjutaIterable
*iter
;
516 gint line_indent
= 0;
517 gint incomplete_statement
= -1;
518 gboolean colon_indent
= FALSE
;
520 g_return_val_if_fail (line
> 0, 0);
522 if (line
== 1) /* First line */
528 IAnjutaIterable
* begin
= ianjuta_editor_get_line_begin_position (editor
, line
-1 , NULL
);
529 IAnjutaIterable
* end
= ianjuta_editor_get_line_end_position (editor
, line
-1 , NULL
);
531 if (spaces_only (editor
, begin
, end
))
533 set_line_indentation (editor
, line
-1, 0, 0);
535 g_object_unref (begin
);
536 g_object_unref (end
);
539 iter
= ianjuta_editor_get_line_begin_position (editor
, line
, NULL
);
541 line_indent
= get_line_indentation_base (plugin
, editor
, line
,
542 &incomplete_statement
,
546 /* Determine what the first non-white char in the line is */
550 /* Check if we are *inside* comment or string. Begining of comment
551 * or string does not count as inside. If inside, just align with
552 * previous indentation.
554 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
),
556 if (iter_is_newline (iter
, ch
))
558 skip_iter_to_newline_tail (iter
, ch
);
560 /* First levels are excused from incomplete statement indent */
561 if (incomplete_statement
== 1 && line_indent
> 0)
562 line_indent
+= INDENT_SIZE
;
566 else if (!isspace (ch
))
568 /* First levels are excused from incomplete statement indent */
569 if (incomplete_statement
== 1 && line_indent
> 0)
570 line_indent
+= INDENT_SIZE
;
575 while (ianjuta_iterable_next (iter
, NULL
));
576 g_object_unref (iter
);
582 python_indent (IndentPythonPlugin
*plugin
,
583 IAnjutaEditor
*editor
,
584 IAnjutaIterable
*insert_pos
,
587 IAnjutaIterable
*iter
;
588 gboolean should_auto_indent
= FALSE
;
590 iter
= ianjuta_iterable_clone (insert_pos
, NULL
);
592 /* If autoindent is enabled*/
593 if (g_settings_get_boolean (plugin
->settings
, PREF_INDENT_AUTOMATIC
))
595 if (iter_is_newline (iter
, ch
))
597 skip_iter_to_newline_head (iter
, ch
);
598 /* All newline entries means enable indenting */
599 should_auto_indent
= TRUE
;
602 if (should_auto_indent
)
606 gint line_indent_spaces
;
608 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor
), NULL
);
609 python_indent_init (plugin
);
611 insert_line
= ianjuta_editor_get_lineno (editor
, NULL
);
612 line_indent
= get_line_auto_indentation (plugin
, editor
, insert_line
, &line_indent_spaces
);
613 set_line_indentation (editor
, insert_line
, line_indent
, line_indent_spaces
);
614 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor
), NULL
);
619 g_object_unref (iter
);
623 python_indent_auto (IndentPythonPlugin
* lang_plugin
,
624 IAnjutaIterable
* start
,
625 IAnjutaIterable
* end
)
627 gint line_start
, line_end
;
630 gboolean has_selection
;
632 IAnjutaEditor
*editor
;
633 editor
= IANJUTA_EDITOR (lang_plugin
->current_editor
);
637 has_selection
= ianjuta_editor_selection_has_selection
638 (IANJUTA_EDITOR_SELECTION (editor
), NULL
);
641 IAnjutaIterable
*sel_start
, *sel_end
;
642 sel_start
= ianjuta_editor_selection_get_start (IANJUTA_EDITOR_SELECTION (editor
),
644 sel_end
= ianjuta_editor_selection_get_end (IANJUTA_EDITOR_SELECTION (editor
),
646 line_start
= ianjuta_editor_get_line_from_position (editor
, sel_start
, NULL
);
647 line_end
= ianjuta_editor_get_line_from_position (editor
, sel_end
, NULL
);
648 g_object_unref (sel_start
);
649 g_object_unref (sel_end
);
653 line_start
= ianjuta_editor_get_lineno (IANJUTA_EDITOR(editor
), NULL
);
654 line_end
= line_start
;
659 line_start
= ianjuta_editor_get_line_from_position (editor
, start
, NULL
);
660 line_end
= ianjuta_editor_get_line_from_position (editor
, end
, NULL
);
662 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT(editor
), NULL
);
663 python_indent_init (lang_plugin
);
665 for (insert_line
= line_start
; insert_line
<= line_end
; insert_line
++)
667 gint line_indent_spaces
= 0;
668 line_indent
= get_line_auto_indentation (lang_plugin
, editor
,
670 &line_indent_spaces
);
671 set_line_indentation (editor
, insert_line
, line_indent
, line_indent_spaces
);
673 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT(editor
), NULL
);