[geany/geany-plugins] 5b0f6d: Merge remote-tracking branch 'scriptum/autoclose-v0.2'

Frank Lanitz git-noreply at xxxxx
Mon Oct 21 07:08:52 UTC 2013


Branch:      refs/heads/master
Author:      Frank Lanitz <frank at frank.uvena.de>
Committer:   Frank Lanitz <frank at frank.uvena.de>
Date:        Mon, 21 Oct 2013 07:08:52 UTC
Commit:      5b0f6df2605f9a38bec19a8686889011d420ab5a
             https://github.com/geany/geany-plugins/commit/5b0f6df2605f9a38bec19a8686889011d420ab5a

Log Message:
-----------
Merge remote-tracking branch 'scriptum/autoclose-v0.2'


Modified Paths:
--------------
    MAINTAINERS
    autoclose/AUTHORS
    autoclose/ChangeLog
    autoclose/README
    autoclose/src/autoclose.c
    build/autoclose.m4

Modified: MAINTAINERS
4 files changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -18,8 +18,8 @@ W: http://plugins.geany.org/addons.html
 S: Maintained
 
 autoclose
-P: Pavel Roschin <rpg89 at post.ru>
-M: Pavel Roschin <rpg89 at post.ru>
+P: Pavel Roschin <rpg89(at)post(dot)ru>
+M: Pavel Roschin <rpg89(at)post(dot)ru>
 W:
 S: Maintained
 


Modified: autoclose/AUTHORS
2 files changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -1 +1 @@
-Pavel Roschin <rpg89 at post.ru>
+Pavel Roschin <rpg89(at)post(dot)ru>


Modified: autoclose/ChangeLog
11 files changed, 10 insertions(+), 1 deletions(-)
===================================================================
@@ -1 +1,10 @@
-
+2013-10-05 Pavel Roschin - version 0.2
+ * add removing pairing brace by Shift+BackSpace
+ * do not add semicolon in #define-s
+ * add semicolon after class and struct
+ * now works with GTK3+ (thanks Matthew Brush for patch http://pastebin.geany.org/r2VKS/)
+ * added scrollbar for settings
+ * improve semicolon completion
+ * added help
+ * added Tab jump to enclosed char (thanks Thomas Martitz:
+   https://github.com/kugel-/geany-plugins/commit/7f19c3035abf6f8a7fa66c7b4c1efe0851cb2f83)


Modified: autoclose/README
23 files changed, 15 insertions(+), 8 deletions(-)
===================================================================
@@ -1,12 +1,18 @@
 Auto-close brackets
-=================
+===================
+
+.. image:: http://dl.dropboxusercontent.com/u/59878867/geany-autoclose.gif
+   :width: 778
+   :alt: autoclose plugin
+   :align: right
 
 .. contents::
 
 About
 -----
 
-Plugin enables auto-closing features.
+This plugin enables auto-closing features. Auto-closing works while you typing 
+and intellectually helps you to write code.
 
 Features
 --------
@@ -27,16 +33,17 @@ Features
   covers lines you need to indent (works like TAB indentation)
 * fix auto-indent inside {} (makes full indent for this block)
 * auto-close curly bracket by pressing Enter
-* auto-close functions ("sin(|" -> "sin(|);") with doubling suppression
+* auto-close functions (``"sin(|" -> "sin(|);"``) with doubling suppression
   (for C/C++ languages only)
-* correctly set undo actions
+* remove paring brace when pressing Shift+BackSpace, unindent {}-blocks
+* add semicolon after ``struct {|};`` and ``class {|};``
+* move cursor to closed char by pressing Tab
 
 Usage
 -----
 
-After installed successfully, load the plugin in Geany's plugin manager
-and new menu items in the Edit menu will appear. You can
-change the keyboard shortcuts in Geany's preferences dialog.
+After installed successfully, load the plugin in Geany's plugin manager. You may
+change module preferences.
 
 Requirements
 ------------
@@ -46,4 +53,4 @@ Requirements
 Contact developers
 ------------------
 
-Pavel Roschin <rpg89 at post.ru>
+Pavel Roschin <rpg89(at)post(dot)ru>


Modified: autoclose/src/autoclose.c
892 files changed, 691 insertions(+), 201 deletions(-)
===================================================================
@@ -1,7 +1,7 @@
 /*
  *      autoclose.c
  *
- *      Copyright 2013 Pavel Roschin <rpg89 at post.ru>
+ *      Copyright 2013 Pavel Roschin <rpg89(at)post(dot)ru>
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -39,9 +39,9 @@
 #define AC_CONTINUE_ACTION FALSE
 #define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
 
-GeanyPlugin		*geany_plugin;
-GeanyData		*geany_data;
-GeanyFunctions		*geany_functions;
+GeanyPlugin	*geany_plugin;
+GeanyData	*geany_data;
+GeanyFunctions	*geany_functions;
 
 PLUGIN_VERSION_CHECK(216)
 PLUGIN_SET_TRANSLATABLE_INFO(
@@ -49,18 +49,20 @@
 	GETTEXT_PACKAGE,
 	_("Auto-close"),
 	_("Auto-close braces and brackets with lot of features"),
-	"0.1",
-	"Pavel Roschin <rpg89 at post.ru>")
+	"0.2",
+	"Pavel Roschin <rpg89(at)post(dot)ru>")
 
 typedef struct {
 	/* close chars */
 	gboolean parenthesis;
 	gboolean abracket;
+	gboolean abracket_htmlonly;
 	gboolean cbracket;
 	gboolean sbracket;
 	gboolean dquote;
 	gboolean squote;
 	gboolean backquote;
+	gboolean backquote_bashonly;
 	/* settings */
 	gboolean delete_pairing_brace;
 	gboolean suppress_doubling;
@@ -72,27 +74,149 @@
 	gboolean move_cursor_to_beginning;
 	gboolean improved_cbracket_indent;
 	gboolean close_functions;
+	gboolean bcksp_remove_pair;
+	gboolean jump_on_tab;
 	/* others */
 	gchar *config_file;
 } AutocloseInfo;
 
 static AutocloseInfo *ac_info = NULL;
 
+typedef struct {
+	/* used to place the caret after autoclosed items on tab (similar to eclipse) */
+	gint jump_on_tab;
+	/* used to reset jump_on_tab when needed */
+	gint last_caret;
+	/* used to reset jump_on_tab when needed */
+	gint last_line;
+	struct GeanyDocument *doc;
+} AutocloseUserData;
+
+static gint
+get_indent(ScintillaObject *sci, gint line)
+{
+	return (gint) SSM(sci, SCI_GETLINEINDENTPOSITION, (uptr_t) line, 0);
+}
+
+static gchar
+char_at(ScintillaObject *sci, gint pos)
+{
+	return sci_get_char_at(sci, pos);
+}
+
+static const gchar *
+get_char_range(ScintillaObject *sci, gint start, gint length)
+{
+	return (const gchar *) SSM(sci, SCI_GETRANGEPOINTER, start, length);
+}
+
+static gboolean
+blank_line(ScintillaObject *sci, gint line)
+{
+	return get_indent(sci, line) ==
+		sci_get_line_end_position(sci, line);
+}
+
+static void
+unindent_line(ScintillaObject *sci, gint line, gint indent_width)
+{
+	gint indent = sci_get_line_indentation(sci, line);
+	sci_set_line_indentation(sci, line, indent > 0 ? indent - indent_width : 0);
+}
+
+static void
+delete_line(ScintillaObject *sci, gint line)
+{
+	gint start = sci_get_position_from_line(sci, line);
+	gint len = sci_get_line_length(sci, line);
+	SSM(sci, SCI_DELETERANGE, start, len);
+}
+
+static gint
+get_lines_selected(ScintillaObject *sci)
+{
+	gint start = (gint) SSM(sci, SCI_GETSELECTIONSTART, 0, 0);
+	gint end = (gint) SSM(sci, SCI_GETSELECTIONEND, 0, 0);
+	gint line_start;
+	gint line_end;
+
+	if (start == end)
+		return 0; /* no selection */
+
+	line_start = (gint) SSM(sci, SCI_LINEFROMPOSITION, (uptr_t) start, 0);
+	line_end = (gint) SSM(sci, SCI_LINEFROMPOSITION, (uptr_t) end, 0);
+
+	return line_end - line_start + 1;
+}
+
+static void
+insert_text(ScintillaObject *sci, gint pos, const gchar *text)
+{
+	SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) text);
+}
+
+static gint
+get_selections(ScintillaObject *sci)
+{
+	return (gint) SSM(sci, SCI_GETSELECTIONS, 0, 0);
+}
+
+static gint
+get_caret_pos(ScintillaObject *sci, gint selection)
+{
+	return (gint) SSM(sci, SCI_GETSELECTIONNCARET, selection, 0);
+}
+
+static gint
+get_ancor_pos(ScintillaObject *sci, gint selection)
+{
+	return (gint) SSM(sci, SCI_GETSELECTIONNANCHOR, selection, 0);
+}
+
+static gboolean
+char_is_quote(gchar ch)
+{
+	return '\'' == ch || '"' == ch;
+}
+
 static gboolean
-lexer_has_braces(ScintillaObject *sci)
+char_is_curly_bracket(gchar ch)
 {
-	gint lexer = sci_get_lexer(sci);
+	return '{' == ch || '}' == ch;
+}
+
+static gboolean
+isspace_no_newline(gchar ch)
+{
+	return g_ascii_isspace(ch) && ch != '\n' && ch != '\r';
+}
 
+/**
+ * This function is based on Geany's source but has different meaning: check
+ * ability to enclose selection. Calls only for selected text so using
+ * sci_get_selection_start/end is ok here.
+ * */
+static gboolean
+lexer_has_braces(ScintillaObject *sci, gint lexer)
+{
+	gint sel_start;
 	switch (lexer)
 	{
 		case SCLEX_CPP:
 		case SCLEX_D:
+		case SCLEX_PASCAL:
+		case SCLEX_TCL:
+		case SCLEX_CSS:
+			return TRUE;
 		case SCLEX_HTML:	/* for PHP & JS */
-		case SCLEX_PASCAL:	/* for multiline comments? */
-		case SCLEX_BASH:
 		case SCLEX_PERL:
-		case SCLEX_TCL:
-		case SCLEX_CSS:		/* also useful for CSS */
+		case SCLEX_BASH:
+			/* PHP, Perl, bash has vars like ${var} */
+			if (get_lines_selected(sci) > 1)
+				return TRUE;
+			sel_start = sci_get_selection_start(sci);
+			if ('$' == char_at(sci, sel_start - 1))
+				return FALSE;
 			return TRUE;
 		default:
 			return FALSE;
@@ -102,60 +226,98 @@
 static gboolean
 lexer_cpp_like(gint lexer, gint style)
 {
-	if(lexer == SCLEX_CPP && style == SCE_C_IDENTIFIER)
+	if (lexer == SCLEX_CPP && style == SCE_C_IDENTIFIER)
 		return TRUE;
 	return FALSE;
 }
 
 static gboolean
-check_chars(gint ch, gchar *chars_left, gchar *chars_right)
+filetype_c_or_cpp(gint type)
+{
+	return type == GEANY_FILETYPES_C || type == GEANY_FILETYPES_CPP;
+}
+
+static gboolean
+filetype_cpp(gint type)
+{
+	return type == GEANY_FILETYPES_CPP;
+}
+
+static gint
+get_end_pos(ScintillaObject *sci, gint line)
 {
-	switch(ch)
+	gint end;
+	gchar ch;
+	end = sci_get_line_end_position(sci, line);
+	ch = char_at(sci, end - 1);
+	/* ignore spaces and "}" */
+	while(isspace_no_newline(ch) || '}' == ch)
+	{
+		end--;
+		ch = char_at(sci, end - 1);
+	}
+	return end;
+}
+
+static gboolean
+check_chars(
+	ScintillaObject *sci,
+	gint             ch,
+	gchar           *chars_left,
+	gchar           *chars_right)
+{
+	switch (ch)
 	{
 		case '(':
 		case ')':
-			if(!ac_info->parenthesis)
+			if (!ac_info->parenthesis)
 				return FALSE;
 			*chars_left = '(';
 			*chars_right = ')';
 			break;
 		case ';':
-			if(!ac_info->close_functions)
+			if (!ac_info->close_functions)
 				return FALSE;
 			break;
 		case '{':
 		case '}':
-			if(!ac_info->cbracket)
+			if (!ac_info->cbracket)
 				return FALSE;
 			*chars_left = '{';
 			*chars_right = '}';
 			break;
 		case '[':
 		case ']':
-			if(!ac_info->sbracket)
+			if (!ac_info->sbracket)
 				return FALSE;
 			*chars_left = '[';
 			*chars_right = ']';
 			break;
 		case '<':
 		case '>':
-			if(!ac_info->abracket)
+			if (!ac_info->abracket)
+				return FALSE;
+			if (ac_info->abracket_htmlonly &&
+					sci_get_lexer(sci) != SCLEX_HTML)
 				return FALSE;
 			*chars_left = '<';
 			*chars_right = '>';
 			break;
 		case '\'':
-			if(!ac_info->squote)
+			if (!ac_info->squote)
 				return FALSE;
 			*chars_left = *chars_right = ch;
 			break;
 		case '"':
-			if(!ac_info->dquote)
+			if (!ac_info->dquote)
 				return FALSE;
 			*chars_left = *chars_right = ch;
 			break;
 		case '`':
-			if(!ac_info->backquote)
+			if (!ac_info->backquote)
+				return FALSE;
+			if (ac_info->backquote_bashonly &&
+					sci_get_lexer(sci) != SCLEX_BASH)
 				return FALSE;
 			*chars_left = *chars_right = ch;
 			break;
@@ -166,28 +328,31 @@
 }
 
 static gboolean
-improve_indent(ScintillaObject *sci, GeanyEditor *editor, gint pos)
+improve_indent(
+	ScintillaObject *sci,
+	GeanyEditor     *editor,
+	gint             pos)
 {
 	gint ch, ch_next;
 	gint line;
 	gint indent, indent_width;
 	gint end_pos;
-	if(!ac_info->improved_cbracket_indent)
+	if (!ac_info->improved_cbracket_indent)
 		return AC_CONTINUE_ACTION;
-	ch = sci_get_char_at(sci, pos - 1);
-	if(ch != '{')
+	ch = char_at(sci, pos - 1);
+	if (ch != '{')
 		return AC_CONTINUE_ACTION;
 	/* if curly bracket completion is enabled - just make indents
 	 * but ensure that second "}" exists. If disabled - make indent
 	 * and complete second curly bracket */
-	ch_next = sci_get_char_at(sci, pos);
-	if(ac_info->cbracket && ch_next != '}')
+	ch_next = char_at(sci, pos);
+	if (ac_info->cbracket && ch_next != '}')
 		return AC_CONTINUE_ACTION;
 	line = sci_get_line_from_position(sci, pos);
 	indent = sci_get_line_indentation(sci, line);
 	indent_width = editor_get_indent_prefs(editor)->width;
 	sci_start_undo_action(sci);
-	if(ac_info->cbracket)
+	if (ac_info->cbracket)
 		SSM(sci, SCI_ADDTEXT, 2, (sptr_t)"\n\n");
 	else
 		SSM(sci, SCI_ADDTEXT, 3, (sptr_t)"\n\n}");
@@ -202,231 +367,499 @@
 }
 
 static gboolean
-auto_close_chars(GeanyDocument *doc, GdkEventKey *event)
+handle_backspace(
+	AutocloseUserData *data,
+	ScintillaObject   *sci,
+	gchar              ch,
+	gchar             *ch_left,
+	gchar             *ch_right,
+	GdkEventKey       *event,
+	gint               indent_width)
+{
+	gint pos = sci_get_current_position(sci);
+	gint end_pos;
+	gint line_start, line_end, line;
+	gint i;
+	if (!ac_info->delete_pairing_brace)
+		return AC_CONTINUE_ACTION;
+	ch = char_at(sci, pos - 1);
+
+	if (!check_chars(sci, ch, ch_left, ch_right))
+		return AC_CONTINUE_ACTION;
+
+	if (event->state & GDK_SHIFT_MASK)
+	{
+		if ((ch_left[0] == ch || ch_right[0] == ch) &&
+				ac_info->bcksp_remove_pair)
+		{
+			end_pos = sci_find_matching_brace(sci, pos - 1);
+			if (-1 == end_pos)
+				return AC_CONTINUE_ACTION;
+			sci_start_undo_action(sci);
+			line_start = sci_get_line_from_position(sci, pos);
+			line_end = sci_get_line_from_position(sci, end_pos);
+			SSM(sci, SCI_DELETERANGE, end_pos, 1);
+			if (end_pos < pos)
+				pos--;
+			SSM(sci, SCI_DELETERANGE, pos - 1, 1);
+			/* remove indentation magick */
+			if (char_is_curly_bracket(ch))
+			{
+				if (line_start == line_end)
+					return AC_CONTINUE_ACTION;
+				if (line_start > line_end)
+				{
+					line = line_end;
+					line_end = line_start;
+					line_start = line;
+				}
+				if (blank_line(sci, line_start))
+				{
+					delete_line(sci, line_start);
+					line_end--;
+				}
+				else
+					line_start++;
+				if (blank_line(sci, line_end))
+					delete_line(sci, line_end);
+				line_end--;
+				/* unindent */
+				for (i = line_start; i <= line_end; i++)
+				{
+					unindent_line(sci, i, indent_width);
+				}
+			}
+			sci_end_undo_action(sci);
+			return AC_STOP_ACTION;
+		}
+	}
+
+	/* handle \'|' situation */
+	if (char_is_quote(ch) && char_at(sci, pos - 2) == '\\')
+		return AC_CONTINUE_ACTION;
+
+	if (ch_left[0] == ch && ch_right[0] == char_at(sci, pos))
+	{
+		SSM(sci, SCI_DELETERANGE, pos, 1);
+		data->jump_on_tab = 0;
+		return AC_CONTINUE_ACTION;
+	}
+	return AC_CONTINUE_ACTION;
+}
+
+
+static gboolean
+enclose_selection(
+	AutocloseUserData *data,
+	ScintillaObject   *sci,
+	gchar              ch,
+	gint               lexer,
+	gint               style,
+	gchar             *chars_left,
+	gchar             *chars_right,
+	GeanyEditor       *editor)
+{
+	gint       i;
+	gint       start, end;
+	gboolean   in_comment;
+	gint       start_line, start_pos, end_line, text_end_pos;
+	gint       start_indent, indent_width, current_indent;
+
+	start = sci_get_selection_start(sci);
+	end = sci_get_selection_end(sci);
+
+	/* case if selection covers mixed style */
+	if (highlighting_is_code_style(lexer, sci_get_style_at(sci, start)) !=
+		 highlighting_is_code_style(lexer, sci_get_style_at(sci, end)))
+		in_comment = FALSE;
+	else
+		in_comment = !highlighting_is_code_style(lexer, style);
+	if (!ac_info->comments_enclose && in_comment)
+		return AC_CONTINUE_ACTION;
+
+	sci_start_undo_action(sci);
+
+
+	/* Insert {} block - special case: make indents, move cursor to beginning */
+	if (char_is_curly_bracket(ch) && lexer_has_braces(sci, lexer) &&
+			ac_info->make_indent_for_cbracket && !in_comment)
+	{
+		start_line = sci_get_line_from_position(sci, start);
+		start_pos = SSM(sci, SCI_GETLINEINDENTPOSITION, (uptr_t)start_line, 0);
+		insert_text(sci, start_pos, "{\n");
+
+		end_line = sci_get_line_from_position(sci, end);
+		start_indent = sci_get_line_indentation(sci, start_line);
+		indent_width = editor_get_indent_prefs(editor)->width;
+		sci_set_line_indentation(sci, start_line, start_indent);
+		sci_set_line_indentation(sci, start_line + 1, start_indent + indent_width);
+		for(i = start_line + 2; i <= end_line; i++)
+		{
+			current_indent = sci_get_line_indentation(sci, i);
+			sci_set_line_indentation(sci, i, current_indent + indent_width);
+		}
+		text_end_pos = sci_get_line_end_position(sci, i - 1);
+		sci_set_current_position(sci, text_end_pos, FALSE);
+		SSM(sci, SCI_ADDTEXT, 2, (sptr_t)"\n}");
+		sci_set_line_indentation(sci, i, start_indent);
+		if (ac_info->move_cursor_to_beginning)
+			sci_set_current_position(sci, start_pos, TRUE);
+	}
+	else
+	{
+		gint selections = get_selections(sci);
+		/* specially handle rectangular selection */
+		if (selections > 1)
+		{
+			gint *sels_left = g_malloc(selections * sizeof(gint));
+			gint *sels_right = g_malloc(selections * sizeof(gint));
+			gint caret = get_caret_pos(sci, 0);
+			gint anchor = get_ancor_pos(sci, 0);
+			gboolean caret_is_left = caret < anchor;
+			gint pos_first = get_caret_pos(sci, 0);
+			gint pos_second = get_caret_pos(sci, 1);
+			gboolean selection_is_up_down = pos_first < pos_second;
+			gint line;
+			/* looks like a forward loop but actually lines processed in reverse order */
+			for (i = 0; i < selections; i++)
+			{
+				if(selection_is_up_down)
+					line = selections - i - 1;
+				else
+					line = i;
+				if (caret_is_left)
+				{
+					sels_left[i]  = get_caret_pos(sci, line);
+					sels_right[i] = get_ancor_pos(sci, line) + 1;
+				}
+				else
+				{
+					sels_right[i] = get_caret_pos(sci, line) + 1;
+					sels_left[i]  = get_ancor_pos(sci, line);
+				}
+			}
+			for (i = 0; i < selections; i++)
+			{
+				insert_text(sci, sels_left[i],  chars_left);
+				insert_text(sci, sels_right[i], chars_right);
+				sels_left[i]  += (selections - i - 1) * 2 + 1;
+				sels_right[i] += (selections - i - 1) * 2 + 1;
+			}
+			if (ac_info->keep_selection)
+			{
+				i = 0;
+				SSM(sci, SCI_SETSELECTION, sels_left[i], sels_right[i] - 1);
+				for (i = 1; i < selections; i++)
+					SSM(sci, SCI_ADDSELECTION, sels_left[i], sels_right[i] - 1);
+			}
+			g_free(sels_left);
+			g_free(sels_right);
+		}
+		else /* normal selection */
+		{
+			insert_text(sci, start, chars_left);
+			insert_text(sci, end + 1, chars_right);
+			sci_set_current_position(sci, end + 1, TRUE);
+			data->jump_on_tab += strlen(chars_right);
+			data->last_caret = end + 1;
+			data->last_line = sci_get_current_line(sci);
+			if (ac_info->keep_selection)
+			{
+				sci_set_selection_start(sci, start + 1);
+				sci_set_selection_end(sci, end + 1);
+			}
+		}
+	}
+	sci_end_undo_action(sci);
+	return AC_STOP_ACTION;
+}
+
+static gboolean
+check_struct(
+	ScintillaObject *sci,
+	gint             pos,
+	const gchar     *str)
+{
+	gchar ch;
+	gint line, len;
+	ch = char_at(sci, pos - 1);
+	while(g_ascii_isspace(ch))
+	{
+		pos--;
+		ch = char_at(sci, pos - 1);
+	}
+	line = sci_get_line_from_position(sci, pos);
+	len = strlen(str);
+	const gchar *sci_buf = get_char_range(sci, get_indent(sci, line), len);
+	g_return_val_if_fail(NULL != sci_buf, FALSE);
+	if (strncmp(sci_buf, str, len) == 0)
+		return TRUE;
+	return FALSE;
+}
+
+static void
+struct_semicolon(
+	ScintillaObject *sci,
+	gint             pos,
+	gchar           *chars_right,
+	gint             filetype)
+{
+	if (filetype_c_or_cpp(filetype) && 
+	   (check_struct(sci, pos, "struct") || check_struct(sci, pos, "typedef struct")))
+	{
+		chars_right[1] = ';';
+		return;
+	}
+	if (filetype_cpp(filetype) && check_struct(sci, pos, "class"))
+	{
+		chars_right[1] = ';';
+		return;
+	}
+}
+
+static gboolean
+check_define(
+	ScintillaObject *sci,
+	gint             line)
+{
+	const gchar* sci_buf = get_char_range(sci, get_indent(sci, line), 7);
+	g_return_val_if_fail(NULL != sci_buf, FALSE);
+	if (strncmp(sci_buf, "#define", 7) == 0)
+		return TRUE;
+	return FALSE;
+}
+
+static gboolean
+auto_close_chars(
+	AutocloseUserData *data,
+	GdkEventKey       *event)
 {
 	ScintillaObject *sci;
 	GeanyEditor     *editor;
+	GeanyDocument   *doc;
 	gint             ch, ch_next, ch_buf;
 	gchar            chars_left[2]  = {0, 0};
 	gchar            chars_right[3] = {0, 0, 0};
-	gint             i;
 	gint             lexer, style;
-	gint             start_line, start_pos, end_line;
-	gint             start_indent, indent_width, current_indent;
-	gint             selection_start, selection_end;
-	gint             pos, text_end_pos, line_end_pos, pos_lex_offset;
+	gint             pos, line, lex_offset;
 	gboolean         has_sel;
-	gboolean         in_comment;
-	gint             file_type_id = 0;
+	gint             filetype = 0;
 
-	if(NULL == doc)
-		return AC_CONTINUE_ACTION;
+	g_return_val_if_fail(NULL != data, AC_CONTINUE_ACTION);
+	doc = data->doc;
+	g_return_val_if_fail(NULL != doc, AC_CONTINUE_ACTION);
 	editor = doc->editor;
-	if(NULL == editor)
-		return AC_CONTINUE_ACTION;
+	g_return_val_if_fail(NULL != editor, AC_CONTINUE_ACTION);
 	sci = editor->sci;
-	if(NULL == sci)
-		return AC_CONTINUE_ACTION;
-	if(doc->file_type)
-		file_type_id = doc->file_type->id;
+	g_return_val_if_fail(NULL != sci, AC_CONTINUE_ACTION);
+
+	if (doc->file_type)
+		filetype = doc->file_type->id;
 
 	pos = sci_get_current_position(sci);
+	line = sci_get_current_line(sci);
 	ch = event->keyval;
 
-	if(ch == GDK_BackSpace)
+	if (ch == GDK_BackSpace)
 	{
-		if(!ac_info->delete_pairing_brace)
-			return AC_CONTINUE_ACTION;
-		ch = sci_get_char_at(sci, pos - 1);
-		if(check_chars(ch, chars_left, chars_right))
-		{
-			if(chars_left [0] == ch &&
-			   chars_right[0] == sci_get_char_at(sci, pos))
-			{
-				SSM(sci, SCI_DELETERANGE, pos - 1, 2);
-				return AC_STOP_ACTION;
-			}
-			return AC_CONTINUE_ACTION;
-		}
-		else
-			return AC_CONTINUE_ACTION;
+		return handle_backspace(data, sci, ch, chars_left, chars_right,
+		                        event, editor_get_indent_prefs(editor)->width);
 	}
-	else if(ch == GDK_Return)
+	else if (ch == GDK_Return)
 	{
 		return improve_indent(sci, editor, pos);
 	}
+	else if (ch == GDK_Tab && ac_info->jump_on_tab)
+	{
+		/* jump behind inserted "); */
+		if (data->jump_on_tab == 0)
+			return AC_CONTINUE_ACTION;
+		sci_set_current_position(sci, pos + data->jump_on_tab, FALSE);
+		data->jump_on_tab = 0;
+		return AC_STOP_ACTION;
+	}
 
 	/* set up completion chars */
-	if(!check_chars(ch, chars_left, chars_right))
+	if (!check_chars(sci, ch, chars_left, chars_right))
 		return AC_CONTINUE_ACTION;
 
 	has_sel = sci_has_selection(sci);
 
+	/* do not suppress/complete in case: '\|' */
+	if (char_is_quote(ch) && char_at(sci, pos - 1) == '\\' && !has_sel)
+		return AC_CONTINUE_ACTION;
+
 	lexer = sci_get_lexer(sci);
 
 	/* in C-like languages - complete functions with ; */
-
-	pos_lex_offset = -1;
-	ch_buf = sci_get_char_at(sci, pos + pos_lex_offset);
-	while('\t' == ch_buf || ' ' == ch_buf)
+	lex_offset = -1;
+	ch_buf = char_at(sci, pos + lex_offset);
+	while (g_ascii_isspace(ch_buf))
 	{
-		--pos_lex_offset;
-		ch_buf = sci_get_char_at(sci, pos + pos_lex_offset);
+		--lex_offset;
+		ch_buf = char_at(sci, pos + lex_offset);
 	}
-	style = sci_get_style_at(sci, pos + pos_lex_offset);
-	line_end_pos = sci_get_line_end_position(sci, sci_get_current_line(sci));
 
-	if(lexer_cpp_like(lexer, style) &&
-	   chars_left[0] == '(' &&
-	  !has_sel && ac_info->close_functions &&
-	   pos == line_end_pos)
-	{
+	style = sci_get_style_at(sci, pos + lex_offset);
+
+	/* add ; after functions */
+	if (lexer_cpp_like(lexer, style) &&
+			chars_left[0] == '(' &&
+		 !has_sel &&
+			ac_info->close_functions &&
+			pos == get_end_pos(sci, line) &&
+			sci_get_line_indentation(sci, line) != 0 &&
+		 !check_define(sci, line))
 		chars_right[1] = ';';
-	}
 
 	style = sci_get_style_at(sci, pos);
 
 	/* suppress double completion symbols */
-	ch_next = sci_get_char_at(sci, pos);
-	if(ch == ch_next && !has_sel && ac_info->suppress_doubling)
+	ch_next = char_at(sci, pos);
+	if (ch == ch_next && !has_sel && ac_info->suppress_doubling &&
+	  !(chars_left[0] != chars_right[0] && ch == chars_left[0]))
 	{
-		/*if(sci_get_char_at(sci, pos - 1) != '\\') maybe...*/
-		/* puts("Suppress double completion"); */
-		if((!highlighting_is_code_style(lexer, style)) && ch != '"' && ch != '\'')
+		/* jump_on_data may be 2 (due to autoclosing ");"). Need to decrement if ")" is pressed */
+		if (data->jump_on_tab > 0)
+			data->jump_on_tab -= 1;
+		if ((!ac_info->comments_ac_enable && !highlighting_is_code_style(lexer, style)) &&
+		      ch != '"' && ch != '\'')
 			return AC_CONTINUE_ACTION;
 
 		/* suppress ; only at end of line */
-		if(ch == ';' && pos + 1 != line_end_pos)
+		if (ch == ';' && pos + 1 != get_end_pos(sci, line))
 			return AC_CONTINUE_ACTION;
-
-		sci_set_current_position(sci, pos + 1, TRUE);
-		return AC_STOP_ACTION;
+		SSM(sci, SCI_DELETERANGE, pos, 1);
+		return AC_CONTINUE_ACTION;
 	}
 
-	if(ch == ';')
+	if (ch == ';')
 		return AC_CONTINUE_ACTION;
 
 	/* If we have selected text */
-	if(has_sel && ac_info->enclose_selections)
-	{
-		selection_start = sci_get_selection_start(sci);
-		selection_end = sci_get_selection_end(sci);
-
-		/* case if selection covers mixed style */
-		if(highlighting_is_code_style(lexer, sci_get_style_at(sci, selection_start)) !=
-		   highlighting_is_code_style(lexer, sci_get_style_at(sci, selection_end)))
-			in_comment = FALSE;
-		else
-			in_comment = !highlighting_is_code_style(lexer, style);
-		if(!ac_info->comments_enclose && in_comment)
-			return AC_CONTINUE_ACTION;
-
-		sci_start_undo_action(sci);
-		/* Insert {} block - special case: make indents, move cursor to beginning */
-		if((ch == '{' || ch == '}') && lexer_has_braces(sci) &&
-		    ac_info->make_indent_for_cbracket && !in_comment)
-		{
-			start_line = sci_get_line_from_position(sci, selection_start);
-			start_pos = SSM(sci, SCI_GETLINEINDENTPOSITION, (uptr_t)start_line, 0);
-			SSM(sci, SCI_INSERTTEXT, start_pos, (sptr_t)"{\n");
-
-			end_line = sci_get_line_from_position(sci, selection_end);
-			start_indent = sci_get_line_indentation(sci, start_line);
-			indent_width = editor_get_indent_prefs(editor)->width;
-			sci_set_line_indentation(sci, start_line, start_indent);
-			sci_set_line_indentation(sci, start_line + 1, start_indent + indent_width);
-			for(i = start_line + 2; i <= end_line; i++)
-			{
-				current_indent = sci_get_line_indentation(sci, i);
-				sci_set_line_indentation(sci, i, current_indent + indent_width);
-			}
-			text_end_pos = sci_get_line_end_position(sci, i - 1);
-			sci_set_current_position(sci, text_end_pos, FALSE);
-			SSM(sci, SCI_ADDTEXT, 2, (sptr_t)"\n}");
-			sci_set_line_indentation(sci, i, start_indent);
-			if(ac_info->move_cursor_to_beginning)
-				sci_set_current_position(sci, start_pos, TRUE);
-		}
-		else
-		{
-			SSM(sci, SCI_INSERTTEXT, selection_start, (sptr_t) chars_left);
-			SSM(sci, SCI_INSERTTEXT, selection_end + 1, (sptr_t) chars_right);
-			sci_set_current_position(sci, selection_end + 1, TRUE);
-			if(ac_info->keep_selection)
-			{
-				sci_set_selection_start(sci, selection_start + 1);
-				sci_set_selection_end(sci, selection_end + 1);
-			}
-		}
-		sci_end_undo_action(sci);
-		return AC_STOP_ACTION;
-	}
+	if (has_sel && ac_info->enclose_selections)
+		return enclose_selection(data, sci, ch, lexer, style, chars_left, chars_right, editor);
 
 	/* disable autocompletion inside comments and strings */
-	if(!ac_info->comments_ac_enable && !highlighting_is_code_style(lexer, style))
+	if (!ac_info->comments_ac_enable && !highlighting_is_code_style(lexer, style))
 		return AC_CONTINUE_ACTION;
 
-	if(ch == '}' || ch == ']' || ch ==')')
+	if (ch == chars_right[0] && chars_left[0] != chars_right[0])
 		return AC_CONTINUE_ACTION;
 
+	/* add ; after struct */
+	struct_semicolon(sci, pos, chars_right, filetype);
+
 	/* just close char */
 	SSM(sci, SCI_INSERTTEXT, pos, (sptr_t)chars_right);
 	sci_set_current_position(sci, pos, TRUE);
+	data->jump_on_tab += strlen(chars_right);
+	data->last_caret = pos;
+	data->last_line = sci_get_current_line(sci);
 	return AC_CONTINUE_ACTION;
 }
 
 static gboolean
 on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
-	GeanyDocument *doc = user_data;
-	if(NULL == doc)
-		return AC_CONTINUE_ACTION;
-	return auto_close_chars(doc, event);
+	AutocloseUserData *data = user_data;
+	g_return_val_if_fail(NULL != data && NULL != data->doc, AC_CONTINUE_ACTION);
+	return auto_close_chars(data, event);
 }
 
 static void
-on_document_activate(GObject *obj, GeanyDocument *doc, gpointer user_data)
+on_editor_notify(GObject *obj, gint scn, SCNotification *nt, gpointer user_data)
 {
-	ScintillaObject *sci = NULL;
-	if(NULL == doc || NULL == doc->editor)
+	AutocloseUserData *data = user_data;
+
+	if (!ac_info->jump_on_tab)
 		return;
-	sci = doc->editor->sci;
-	if(NULL == sci)
+	if (!data || !data->doc || !data->doc->editor || !data->doc->editor->sci)
 		return;
+
+	ScintillaObject *sci = data->doc->editor->sci;
+	/* reset jump_on_tab state when user clicked away */
+	gboolean updated_sel  = nt->updated & SC_UPDATE_SELECTION;
+	gboolean updated_text = nt->updated & SC_UPDATE_CONTENT;
+	gint new_caret = sci_get_current_position(sci);
+	gint new_line  = sci_get_current_line(sci);
+	if (updated_sel && !updated_text)
+	{
+		gint delta = data->last_caret -  new_caret;
+		gint delta_l = data->last_line - new_line;
+		if (delta_l == 0 && data->jump_on_tab)
+			data->jump_on_tab += delta;
+		else
+			data->jump_on_tab = 0;
+	}
+	data->last_caret = new_caret;
+	data->last_line = new_line;
+}
+
+#define AC_GOBJECT_KEY "autoclose-userdata"
+
+static void
+on_document_activate(GObject *obj, GeanyDocument *doc, gpointer user_data)
+{
+	AutocloseUserData *data;
+	ScintillaObject   *sci = NULL;
+	g_return_if_fail(NULL != doc && NULL != doc->editor);
+	sci = doc->editor->sci;
+	g_return_if_fail(NULL != sci);
+
+	data = g_new0(AutocloseUserData, 1);
+	data->doc = doc;
+	plugin_signal_connect(geany_plugin, G_OBJECT(sci), "sci-notify",
+		FALSE, G_CALLBACK(on_editor_notify), data);
 	plugin_signal_connect(geany_plugin, G_OBJECT(sci), "key-press-event",
-			FALSE, G_CALLBACK(on_key_press), doc);
+			FALSE, G_CALLBACK(on_key_press), data);
+	/* save data pointer via GObject too for on_document_close() */
+	g_object_set_data(G_OBJECT(sci), AC_GOBJECT_KEY, data);
+}
+
+static void
+on_document_close(GObject *obj, GeanyDocument *doc, gpointer user_data)
+{
+	/* free the AutocloseUserData instance */
+	ScintillaObject   *sci = doc->editor->sci;
+	AutocloseUserData *data = g_object_steal_data(G_OBJECT(sci), AC_GOBJECT_KEY);
+	g_free(data);
 }
 
 PluginCallback plugin_callbacks[] =
 {
-	{ "document-open", (GCallback) &on_document_activate, FALSE, NULL },
-	{ "document-new", (GCallback) &on_document_activate, FALSE, NULL },
+	{ "document-open",  (GCallback) &on_document_activate, FALSE, NULL },
+	{ "document-new",   (GCallback) &on_document_activate, FALSE, NULL },
+	{ "document-close", (GCallback) &on_document_close,    FALSE, NULL },
 	{ NULL, NULL, FALSE, NULL }
 };
 
 static void
 configure_response_cb(GtkDialog *dialog, gint response, gpointer user_data)
 {
-	if(response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
+	if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
 		return;
 	GKeyFile *config = g_key_file_new();
-	gchar *data;
-	gchar *config_dir = g_path_get_dirname(ac_info->config_file);
+	gchar    *data;
+	gchar    *config_dir = g_path_get_dirname(ac_info->config_file);
 
 	g_key_file_load_from_file(config, ac_info->config_file, G_KEY_FILE_NONE, NULL);
 
-	/* just to improve readability */
-	#define SAVE_CONF_BOOL(name) do {\
-		ac_info->name = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(dialog), "check_" #name)));\
-		g_key_file_set_boolean(config, "autoclose", #name, ac_info->name);\
-	} while(0)
+#define SAVE_CONF_BOOL(name) do {                                              \
+    ac_info->name = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(            \
+    g_object_get_data(G_OBJECT(dialog), "check_" #name)));                     \
+    g_key_file_set_boolean(config, "autoclose", #name, ac_info->name);         \
+} while (0)
+
 	SAVE_CONF_BOOL(parenthesis);
 	SAVE_CONF_BOOL(abracket);
+	SAVE_CONF_BOOL(abracket_htmlonly);
 	SAVE_CONF_BOOL(cbracket);
 	SAVE_CONF_BOOL(sbracket);
 	SAVE_CONF_BOOL(dquote);
 	SAVE_CONF_BOOL(squote);
 	SAVE_CONF_BOOL(backquote);
+	SAVE_CONF_BOOL(backquote_bashonly);
 	SAVE_CONF_BOOL(comments_ac_enable);
 	SAVE_CONF_BOOL(delete_pairing_brace);
 	SAVE_CONF_BOOL(suppress_doubling);
@@ -437,9 +870,12 @@
 	SAVE_CONF_BOOL(move_cursor_to_beginning);
 	SAVE_CONF_BOOL(improved_cbracket_indent);
 	SAVE_CONF_BOOL(close_functions);
-	#undef SAVE_CONF_BOOL
+	SAVE_CONF_BOOL(bcksp_remove_pair);
+	SAVE_CONF_BOOL(jump_on_tab);
+
+#undef SAVE_CONF_BOOL
 
-	if(!g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0)
+	if (!g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0)
 	{
 		dialogs_show_msgbox(GTK_MESSAGE_ERROR,
 			_("Plugin configuration directory could not be created."));
@@ -473,16 +909,18 @@
 
 	g_key_file_load_from_file(config, ac_info->config_file, G_KEY_FILE_NONE, NULL);
 
-	/* just to improve readability */
-	#define GET_CONF_BOOL(name, def) ac_info->name = utils_get_setting_boolean(config, "autoclose", #name, def)
+#define GET_CONF_BOOL(name, def) ac_info->name = utils_get_setting_boolean(config, "autoclose", #name, def)
+
 	GET_CONF_BOOL(parenthesis, TRUE);
-	/* Angular bracket conflicts with conditional statements */
-	GET_CONF_BOOL(abracket, FALSE);
+	/* Angular bracket conflicts with conditional statements, enable only for HTML by default */
+	GET_CONF_BOOL(abracket, TRUE);
+	GET_CONF_BOOL(abracket_htmlonly, TRUE);
 	GET_CONF_BOOL(cbracket, TRUE);
 	GET_CONF_BOOL(sbracket, TRUE);
 	GET_CONF_BOOL(dquote, TRUE);
 	GET_CONF_BOOL(squote, TRUE);
 	GET_CONF_BOOL(backquote, TRUE);
+	GET_CONF_BOOL(backquote_bashonly, TRUE);
 	GET_CONF_BOOL(comments_ac_enable, FALSE);
 	GET_CONF_BOOL(delete_pairing_brace, TRUE);
 	GET_CONF_BOOL(suppress_doubling, TRUE);
@@ -492,68 +930,97 @@
 	GET_CONF_BOOL(make_indent_for_cbracket, TRUE);
 	GET_CONF_BOOL(move_cursor_to_beginning, TRUE);
 	GET_CONF_BOOL(improved_cbracket_indent, TRUE);
-	GET_CONF_BOOL(close_functions, FALSE);
-	#undef GET_CONF_BOOL
+	GET_CONF_BOOL(close_functions, TRUE);
+	GET_CONF_BOOL(bcksp_remove_pair, FALSE);
+	GET_CONF_BOOL(jump_on_tab, TRUE);
+
+#undef GET_CONF_BOOL
 
 	g_key_file_free(config);
 }
 
-/* for easy refactoring */
-#define GET_CHECKBOX_ACTIVE(name)  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(data), "check_" #name)))
-#define SET_SENS(name)             gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(data), "check_" #name), sens)
+#define GET_CHECKBOX_ACTIVE(name) gboolean sens = gtk_toggle_button_get_active(\
+           GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(data), "check_" #name)))
+
+#define SET_SENS(name) gtk_widget_set_sensitive(                               \
+                        g_object_get_data(G_OBJECT(data), "check_" #name), sens)
 
 static void
 ac_make_indent_for_cbracket_cb(GtkToggleButton *togglebutton, gpointer data)
 {
-	gboolean sens = GET_CHECKBOX_ACTIVE(make_indent_for_cbracket);
+	GET_CHECKBOX_ACTIVE(make_indent_for_cbracket);
 	SET_SENS(move_cursor_to_beginning);
 }
 
 static void
 ac_parenthesis_cb(GtkToggleButton *togglebutton, gpointer data)
 {
-	gboolean sens = GET_CHECKBOX_ACTIVE(parenthesis);
+	GET_CHECKBOX_ACTIVE(parenthesis);
 	SET_SENS(close_functions);
 }
 
 static void
 ac_cbracket_cb(GtkToggleButton *togglebutton, gpointer data)
 {
-	gboolean sens = GET_CHECKBOX_ACTIVE(cbracket);
+	GET_CHECKBOX_ACTIVE(cbracket);
 	SET_SENS(make_indent_for_cbracket);
 	SET_SENS(move_cursor_to_beginning);
 }
 
 static void
+ac_abracket_htmlonly_cb(GtkToggleButton *togglebutton, gpointer data)
+{
+	GET_CHECKBOX_ACTIVE(abracket);
+	SET_SENS(abracket_htmlonly);
+}
+
+static void
+ac_backquote_bashonly_cb(GtkToggleButton *togglebutton, gpointer data)
+{
+	GET_CHECKBOX_ACTIVE(backquote);
+	SET_SENS(backquote_bashonly);
+}
+
+static void
 ac_enclose_selections_cb(GtkToggleButton *togglebutton, gpointer data)
 {
-	gboolean sens = GET_CHECKBOX_ACTIVE(enclose_selections);
+	GET_CHECKBOX_ACTIVE(enclose_selections);
 	SET_SENS(keep_selection);
 	SET_SENS(comments_enclose);
 }
 
+static void
+ac_delete_pairing_brace_cb(GtkToggleButton *togglebutton, gpointer data)
+{
+	GET_CHECKBOX_ACTIVE(delete_pairing_brace);
+	SET_SENS(bcksp_remove_pair);
+}
+
 GtkWidget *
 plugin_configure(GtkDialog *dialog)
 {
-	GtkWidget *widget, *vbox, *frame, *container;
-
+	GtkWidget *widget, *vbox, *frame, *container, *scrollbox;
 	vbox = gtk_vbox_new(FALSE, 0);
-
-	#define WIDGET_FRAME(description) do{\
-		container = gtk_vbox_new(FALSE, 0);\
-		frame = gtk_frame_new(NULL);\
-		gtk_frame_set_label(GTK_FRAME(frame), _(description));\
-		gtk_container_add(GTK_CONTAINER(frame), container);\
-		gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 3);\
-	} while(0)
-
-	#define WIDGET_CONF_BOOL(name, description, tooltip) do { \
-		widget = gtk_check_button_new_with_label(_(description)); \
-		if(tooltip) gtk_widget_set_tooltip_text(widget, _(tooltip));\
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), ac_info->name); \
-		gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 3); \
-		g_object_set_data(G_OBJECT(dialog), "check_" #name, widget); \
-	} while(0)
+	scrollbox = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollbox), vbox);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+#define WIDGET_FRAME(description) do {                                         \
+    container = gtk_vbox_new(FALSE, 0);                                        \
+    frame = gtk_frame_new(NULL);                                               \
+    gtk_frame_set_label(GTK_FRAME(frame), _(description));                     \
+    gtk_container_add(GTK_CONTAINER(frame), container);                        \
+    gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 3);                 \
+} while (0)
+
+#define WIDGET_CONF_BOOL(name, description, tooltip) do {                      \
+    widget = gtk_check_button_new_with_label(_(description));                  \
+    if (tooltip) gtk_widget_set_tooltip_text(widget, _(tooltip));              \
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), ac_info->name);    \
+    gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 3);           \
+    g_object_set_data(G_OBJECT(dialog), "check_" #name, widget);               \
+} while (0)
 
 	WIDGET_FRAME("Auto-close quotes and brackets");
 	WIDGET_CONF_BOOL(parenthesis, "Parenthesis ( )",
@@ -566,12 +1033,18 @@
 		"Auto-close square brackets \"[\" -> \"[|]\"");
 	WIDGET_CONF_BOOL(abracket, "Angular brackets < >",
 		"Auto-close angular brackets \"<\" -> \"<|>\"");
+	g_signal_connect(widget, "toggled", G_CALLBACK(ac_abracket_htmlonly_cb), dialog);
+	WIDGET_CONF_BOOL(abracket_htmlonly, "\tOnly for HTML",
+		"Auto-close angular brackets only in HTML documents");
 	WIDGET_CONF_BOOL(dquote, "Double quotes \" \"",
 		"Auto-close double quotes \" -> \"|\"");
 	WIDGET_CONF_BOOL(squote, "Single quotes \' \'",
 		"Auto-close single quotes ' -> '|'");
 	WIDGET_CONF_BOOL(backquote, "Backquote ` `",
 		"Auto-close backquote ` -> `|`");
+	g_signal_connect(widget, "toggled", G_CALLBACK(ac_backquote_bashonly_cb), dialog);
+	WIDGET_CONF_BOOL(backquote_bashonly, "\tOnly for Bash",
+		"Auto-close backquote only in Bash");
 
 	WIDGET_FRAME("Improve curly brackets completion");
 	WIDGET_CONF_BOOL(make_indent_for_cbracket, "Indent when enclosing",
@@ -581,7 +1054,7 @@
 		"takes into account only lines.");
 	g_signal_connect(widget, "toggled", G_CALLBACK(ac_make_indent_for_cbracket_cb), dialog);
 	WIDGET_CONF_BOOL(move_cursor_to_beginning, "Move cursor to beginning",
-		"If you chacked \"Indent when enclosing\", moving cursor "
+		"If you checked \"Indent when enclosing\", moving cursor "
 		"to beginning may be useful: usually you make new block "
 		"and need to create new statement before this block.");
 	WIDGET_CONF_BOOL(improved_cbracket_indent, "Improved auto-indentation",
@@ -592,6 +1065,7 @@
 	container = vbox;
 	WIDGET_CONF_BOOL(delete_pairing_brace, "Delete pairing character while backspacing first",
 		"Check if you want to delete pairing bracket by pressing BackSpace.");
+	g_signal_connect(widget, "toggled", G_CALLBACK(ac_delete_pairing_brace_cb), dialog);
 	WIDGET_CONF_BOOL(suppress_doubling, "Suppress double-completion",
 		"Check if you want to allow editor automatically fix mistypes "
 		"with brackets: if you type \"{}\" you will get \"{}\", not \"{}}\".");
@@ -611,15 +1085,25 @@
 	WIDGET_CONF_BOOL(close_functions, "Auto-complete \";\" for functions",
 		"Full function auto-closing (works only for C/C++): type \"sin(\" "
 		"and you will get \"sin(|);\".");
-	#undef WIDGET_CONF_BOOL
+	WIDGET_CONF_BOOL(bcksp_remove_pair, "Shift+BackSpace removes pairing brace too",
+		"Remove left and right brace while pressing Shift+BackSpace.\nTip: "
+		"to completely remove indented block just Shift+BackSpace first \"{\" "
+		"or last \"}\".");
+	WIDGET_CONF_BOOL(jump_on_tab, "Jump on Tab to enclosed char",
+		"Jump behind autoclosed items on Tab press.");
+
+#undef WIDGET_CONF_BOOL
+#undef WIDGET_FRAME
 
 	ac_make_indent_for_cbracket_cb(NULL, dialog);
 	ac_cbracket_cb(NULL, dialog);
 	ac_enclose_selections_cb(NULL, dialog);
 	ac_parenthesis_cb(NULL, dialog);
+	ac_abracket_htmlonly_cb(NULL, dialog);
+	ac_delete_pairing_brace_cb(NULL, dialog);
 	g_signal_connect(dialog, "response", G_CALLBACK(configure_response_cb), NULL);
-	gtk_widget_show_all(vbox);
-	return vbox;
+	gtk_widget_show_all(scrollbox);
+	return scrollbox;
 }
 
 /* Called by Geany before unloading the plugin. */
@@ -629,3 +1113,9 @@
 	g_free(ac_info->config_file);
 	g_free(ac_info);
 }
+
+void
+plugin_help(void)
+{
+	utils_open_browser("http://plugins.geany.org/autoclose.html");
+}


Modified: build/autoclose.m4
3 files changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -1,7 +1,8 @@
 AC_DEFUN([GP_CHECK_AUTOCLOSE],
 [
     GP_ARG_DISABLE([Autoclose], [auto])
-    GP_CHECK_PLUGIN_GTK2_ONLY([Autoclose])
+    GP_CHECK_PLUGIN_DEPS([Autoclose], [AUTOCLOSE],
+                         [$GP_GTK_PACKAGE >= 2.8])
     GP_COMMIT_PLUGIN_STATUS([Autoclose])
     AC_CONFIG_FILES([
         autoclose/Makefile



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Plugins-Commits mailing list