SF.net SVN: geany-plugins:[1760] trunk/geany-plugins/geanyextrasel

sheckley at users.sourceforge.net sheckley at xxxxx
Mon Nov 29 17:44:34 UTC 2010


Revision: 1760
          http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=1760&view=rev
Author:   sheckley
Date:     2010-11-29 17:44:34 +0000 (Mon, 29 Nov 2010)

Log Message:
-----------
see the ChangeLog from 2010-11-20 to 2010-11-28

Modified Paths:
--------------
    trunk/geany-plugins/geanyextrasel/ChangeLog
    trunk/geany-plugins/geanyextrasel/README
    trunk/geany-plugins/geanyextrasel/src/extrasel.c

Modified: trunk/geany-plugins/geanyextrasel/ChangeLog
===================================================================
--- trunk/geany-plugins/geanyextrasel/ChangeLog	2010-11-21 16:57:50 UTC (rev 1759)
+++ trunk/geany-plugins/geanyextrasel/ChangeLog	2010-11-29 17:44:34 UTC (rev 1760)
@@ -1,3 +1,27 @@
+2010-11-28  Dimitar Zhekov  <dimitar.zhekov at gmail.com>
+
+ * src/extrasel.c:
+   Added "Rectangle Select to Anchor".
+   Changed "Select to anchor" to select rectangle in column mode.
+
+2010-11-27  Dimitar Zhekov  <dimitar.zhekov at gmail.com>
+
+ * src/extrasel.c:
+   Added "Set Anchor" and "Select to Anchor".
+   Per-file column mode and anchor position.
+
+2010-11-21  Dimitar Zhekov  <dimitar.zhekov at gmail.com>
+
+ * src/extrasel.c:
+   Added virtual spaces support. Increased the required API version
+   to that of Geany 0.19 (the first that includes virtual spaces).
+
+2010-11-20  Dimitar Zhekov  <dimitar.zhekov at gmail.com>
+
+ * src/extrasel.c:
+   Fixed Scintilla Shift+movement key convertion of rectangle selection
+   to stream. In theory this is rarely used feature, not a bug.
+
 2010-11-11  Dimitar Zhekov  <dimitar.zhekov at gmail.com>
 
  * src/extrasel.c:

Modified: trunk/geany-plugins/geanyextrasel/README
===================================================================
--- trunk/geany-plugins/geanyextrasel/README	2010-11-21 16:57:50 UTC (rev 1759)
+++ trunk/geany-plugins/geanyextrasel/README	2010-11-29 17:44:34 UTC (rev 1760)
@@ -5,9 +5,9 @@
 -----
 The Extra Selection adds the following functions:
 
-Goto matching brace and select (Select to matching brace).
+Goto matching brace and select (Select to Matching Brace).
 
-Goto line and select (Select to line).
+Goto line and select (Select to Line).
 
 Ctrl-Shift-Alt-Left/Right/Home/End keys - same as Ctrl-Shift, but for
 rectangular selection.
@@ -15,6 +15,8 @@
 Column mode - while active, all (Ctrl)-Shift-movement keys do rectangle
 selection instead of stream.
 
+Selection with anchor instead of the Shift-movement keys.
+
 "Movement keys" refers to the arrows, Home, End, Page Up and Page Down.
 
 For more information, see the Usage section below.
@@ -22,7 +24,7 @@
 
 Requirements
 ------------
-Geany 0.18 or later and the respective headers and development libraries.
+Geany 0.19 or later and the respective headers and development libraries.
 
 
 Installation
@@ -42,17 +44,19 @@
 
 Usage
 -----
-Under Tools -> Extra Selection, there are 3 new items: "Column mode",
-"Select to line" and "Select to matching brace". Normally these should be
-bound to keys, for example Alt-c, Alt-Shift-l and Control-Shift-b. Now:
+Under Tools -> Extra Selection, there are 6 new items: "Column Mode",
+"Select to Line" and "Select to Matching Brace", "Set Anchor", "Select to
+Anchor" and "Rectangle Select to Anchor". Normally these should be bound
+to keys, for example Alt-C, Alt-Shift-L, Ctrl-Shift-B, F12, Shift-F12 and
+Alt-Shift-F12. Now:
 
-1. Position the cursor on an opening brace and invoke "Select to matching
-   brace". The cursor will move to the closing brace, and the braced area
+1. Position the cursor on an opening brace and invoke "Select to Matching
+   Brace". The cursor will move to the closing brace, and the braced area
    will be selected.
 
-2. Position the cursor on line 10, invoke "Select to line" and enter 15.
+2. Position the cursor on line 10, invoke "Select to Line" and enter 15.
    The cursor will move to line 15, and the area between the previous and
-   the new current cursor position will be selected.
+   the current cursor position will be selected.
 
 3. Select a small rectangular area and press Control-Alt-Shift-Right. The
    cursor will move to the next word, extending the rectangurar selection.
@@ -69,26 +73,34 @@
 
    Unfortunately, holding Alt for rectangular selection has some problems,
    which apply both to the standard Geany keys and these added by the
-   plugin. Under Windows, the Alt-keypad keys generates unicodes, even if
+   plugin. Under Windows, the Alt-keypad keys generate unicodes, even if
    used with Shift or Control. With X11, some Alt-(Ctrl)-(Shift)-movement
    keys may be used by the window manager for moving windows, switching to
    the previous/next desktop etc. So then:
 
-4. Turn "Column mode" on. While active, the (Control)-Shift-movement keys
+4. Turn "Column Mode" on. While active, the (Control)-Shift-movement keys
    will select a rectangle instead of stream, without the need to hold
    Alt (in fact, the (Control)-Alt-Shift-movement keys will be temporarily
    blocked). This way, you will avoid the Alt key problems mentioned
    above, and it's more convenient to select while holding Shift only.
 
+5. Finally, invoke "Set Anchor", navigate to another point in the document
+   and invoke "Select to Anchor" - the result is obvious. Note that the
+   anchor position is set exactly where the insertion cursor is, not on
+   the character right of the cursor (or on the overtype cursor). When the
+   column mode is active, "Rectangle Selection to Anchor" is disabled, and
+   "Select to Anchor" does rectangular selection.
 
+
 Known issues
 ------------
-The column mode is global, not per-document. However, (de)activating it
-will change the selection (if any) to stream/rectangle for the current
-document only.
+If the cursor is on a large line number, converting a stream selection to
+rectangular may cause a noticable delay. This is scintilla-related; with
+the newest scintilla versions (r3465+), the delay is much smaller.
 
-The column mode applies to the movement keys only - not to mouse
-selection, find functions etc.
+If you set the anchor beyond a line end (in the "virtual space"), and edit
+the text before it, the anchor will be moved to the line end. Not a big
+issue, and tracking a virtual position is impossible in scintilla.
 
 
 License

Modified: trunk/geany-plugins/geanyextrasel/src/extrasel.c
===================================================================
--- trunk/geany-plugins/geanyextrasel/src/extrasel.c	2010-11-21 16:57:50 UTC (rev 1759)
+++ trunk/geany-plugins/geanyextrasel/src/extrasel.c	2010-11-29 17:44:34 UTC (rev 1760)
@@ -25,10 +25,10 @@
 GeanyData	*geany_data;
 GeanyFunctions	*geany_functions;
 
-PLUGIN_VERSION_CHECK(150)
+PLUGIN_VERSION_CHECK(189)
 
-PLUGIN_SET_INFO(_("Extra Selection"), _("Column mode, select to line / matching brace."),
-		"0.2", "Dimitar Toshkov Zhekov <dimitar.zhekov at gmail.com>");
+PLUGIN_SET_INFO(_("Extra Selection"), _("Column mode, select to line / brace / anchor."),
+	"0.4", "Dimitar Toshkov Zhekov <dimitar.zhekov at gmail.com>")
 
 /* Keybinding(s) */
 enum
@@ -36,24 +36,97 @@
 	COLUMN_MODE_KB,
 	GOTO_LINE_EXTEND_KB,
 	BRACE_MATCH_EXTEND_KB,
+	SET_ANCHOR_KB,
+	ANCHOR_EXTEND_KB,
+	ANCHOR_RECTEXTEND_KB,
 	COUNT_KB
 };
 
 PLUGIN_KEY_GROUP(extra_select, COUNT_KB)
 
 static GtkWidget *main_menu_item = NULL;
-static GtkWidget *column_mode_item;
-static GtkWidget *goto_line_item;
-static GtkWidget *brace_match_item;
+static GtkCheckMenuItem *column_mode_item;
+static GtkWidget *anchor_rect_select_item;
 static gpointer *go_to_line1_item = NULL;
 
-static gboolean column_mode = FALSE;
+static gint column_mode = FALSE;
+static gboolean plugin_ignore_callback = FALSE;
+static gint select_anchor = 0, select_space = 0;
 
+/* Common functions / macros */
+
+ScintillaObject *scintilla_get_current(void)
+{
+	GeanyDocument *doc = document_get_current();
+	return doc ? doc->editor->sci : NULL;
+}
+
+#define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
+#define sci_get_anchor(sci) SSM(sci, SCI_GETANCHOR, 0, 0)
+#define sci_set_anchor(sci, anchor) SSM(sci, SCI_SETANCHOR, anchor, 0)
+#define sci_get_main_selection(sci) SSM(sci, SCI_GETMAINSELECTION, 0, 0)
+#define sci_rectangle_selection(sci) (sci_get_selection_mode(sci) == SC_SEL_RECTANGLE || \
+	sci_get_selection_mode(sci) == SC_SEL_THIN)
+#define sci_virtual_space(sci, ACTION, OBJECT, space) \
+	(sci_rectangle_selection(sci) ? \
+	SSM(sci, ACTION##RECTANGULARSELECTION##OBJECT##VIRTUALSPACE, space, 0) : \
+	SSM(sci, ACTION##SELECTIONN##OBJECT##VIRTUALSPACE, sci_get_main_selection(sci), space))
+#define sci_set_virtual_space(sci, OBJECT, space) \
+	do { if (space) sci_virtual_space(sci, SCI_SET, OBJECT, space); } while(0)
+#define sci_get_anchor_space(sci) sci_virtual_space(sci, SCI_GET, ANCHOR, 0)
+#define sci_set_anchor_space(sci, space) sci_set_virtual_space(sci, ANCHOR, space)
+#define sci_get_cursor_space(sci) sci_virtual_space(sci, SCI_GET, CARET, 0)
+#define sci_set_cursor_space(sci, space) sci_set_virtual_space(sci, CARET, space)
+
+static void create_selection(ScintillaObject *sci, int anchor, int anchor_space,
+	gboolean rectangle)
+{
+	int cursor = sci_get_current_position(sci);
+	int cursor_space = sci_get_cursor_space(sci);
+
+	if (rectangle)
+	{
+		sci_set_selection_mode(sci, SC_SEL_RECTANGLE);
+		sci_set_anchor(sci, anchor);
+		/* sci_set_current_position() sets anchor = cursor, bypass */
+		scintilla_send_message(sci, SCI_SETCURRENTPOS, cursor, 0);
+	}
+	else
+	{
+		sci_set_selection_mode(sci, SC_SEL_STREAM);
+		scintilla_send_message(sci, SCI_SETSEL, anchor, cursor);
+	}
+
+	sci_set_anchor_space(sci, anchor_space);
+	sci_set_cursor_space(sci, cursor_space);
+	sci_send_command(sci, SCI_CANCEL);
+}
+
+static void convert_selection(ScintillaObject *sci, gboolean rectangle)
+{
+	if (sci_has_selection(sci))
+		create_selection(sci, sci_get_anchor(sci), sci_get_anchor_space(sci), rectangle);
+}
+
+static void on_extra_select_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
+	G_GNUC_UNUSED gpointer gdata)
+{
+	if (column_mode != gtk_check_menu_item_get_active(column_mode_item))
+	{
+		plugin_ignore_callback = TRUE;
+		gtk_check_menu_item_set_active(column_mode_item, column_mode);
+		plugin_ignore_callback = FALSE;
+		gtk_widget_set_sensitive(anchor_rect_select_item, !column_mode);
+	}
+}
+
+/* New rectangle selection keys */
+
 typedef struct _command_key
 {
 	guint key;
 	guint keypad;
-	gint command;
+	int command;
 } command_key;
 
 static const command_key command_keys[] =
@@ -64,53 +137,73 @@
 	{ GDK_Right,  GDK_KP_Right,  SCI_WORDRIGHTEND },
 	{ GDK_Home,   GDK_KP_Home,   SCI_DOCUMENTSTART },
 	{ GDK_End,    GDK_KP_End,    SCI_DOCUMENTEND },
+	{ GDK_Prior,  GDK_KP_Prior,  0 },
+	{ GDK_Next,   GDK_KP_Next,   0 },
 	{ 0, 0, 0 }
 };
 
-/* not #defined in 0.18 */
-#define sci_get_anchor(sci) scintilla_send_message((sci), SCI_GETANCHOR, 0, 0)
-#define sci_set_anchor(sci, pos) scintilla_send_message((sci), SCI_SETANCHOR, (pos), 0)
-
 static void column_mode_command(ScintillaObject *sci, int command)
 {
-	gboolean set_anchor = sci_get_selection_mode(sci) != SC_SEL_RECTANGLE;
+	gboolean convert = !sci_rectangle_selection(sci);
 	int anchor;
+	int anchor_space;
 
-	if (set_anchor)
+	if (convert)
+	{
 		anchor = sci_get_anchor(sci);
+		anchor_space = sci_get_anchor_space(sci);
+	}
 	sci_set_selection_mode(sci, SC_SEL_RECTANGLE);
 	sci_send_command(sci, command);
-	if (set_anchor)
+	if (convert)
+	{
 		sci_set_anchor(sci, anchor);
+		sci_set_anchor_space(sci, anchor_space);
+	}
 	sci_send_command(sci, SCI_CANCEL);
 }
 
 static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *event, G_GNUC_UNUSED
 	gpointer user_data)
 {
-	guint state = GDK_CONTROL_MASK | GDK_SHIFT_MASK | (column_mode ? 0 : GDK_MOD1_MASK);
+	guint mask = GDK_CONTROL_MASK | GDK_SHIFT_MASK | (column_mode ? 0 : GDK_MOD1_MASK);
+	guint state = event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK);
 
-	if ((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK)) == state)
+	if (state == mask)
 	{
 		const command_key *ck;
 
+		for (ck = command_keys; ck->command; ck++)
+		{
+			if (event->keyval == ck->key || event->keyval == ck->keypad)
+			{
+				ScintillaObject *sci = scintilla_get_current();
+
+				if (sci && gtk_window_get_focus(GTK_WINDOW(widget)) == GTK_WIDGET(sci))
+				{
+					column_mode_command(sci, ck->command);
+					return TRUE;
+				}
+				break;
+			}
+		}
+	}
+	else if (!column_mode && state == GDK_SHIFT_MASK)
+	{
+		const command_key *ck;
+
 		for (ck = command_keys; ck->key; ck++)
 		{
 			if (event->keyval == ck->key || event->keyval == ck->keypad)
 			{
-				GeanyDocument *doc = document_get_current();
+				ScintillaObject *sci = scintilla_get_current();
 
-				if (doc)
+				if (sci && sci_has_selection(sci) && sci_rectangle_selection(sci) &&
+					gtk_window_get_focus(GTK_WINDOW(widget)) == GTK_WIDGET(sci))
 				{
-					ScintillaObject *sci = doc->editor->sci;
-
-					if (gtk_window_get_focus(GTK_WINDOW(widget)) == GTK_WIDGET(sci))
-					{
-						column_mode_command(sci, ck->command);
-						return TRUE;
-					}
+					/* not exactly a bug, yet... */
+					convert_selection(sci, FALSE);
 				}
-
 				break;
 			}
 		}
@@ -119,32 +212,19 @@
 	return FALSE;
 }
 
+/* Column mode */
+
 typedef struct _select_key
 {
-	gint key;
-	gint stream;
-	gint rectangle;
+	int key;
+	int stream;
+	int rectangle;
 } select_key;
 
-/* not #defined in 0.18 */
 #define sci_clear_cmdkey(sci, key) scintilla_send_message((sci), SCI_CLEARCMDKEY, (key), 0)
 #define sci_assign_cmdkey(sci, key, command) \
 	scintilla_send_message((sci), SCI_ASSIGNCMDKEY, (key), (command))
 
-static void assign_select_key(ScintillaObject *sci, const select_key *sk)
-{
-	if (column_mode)
-	{
-		sci_clear_cmdkey(sci, sk->key | (SCMOD_ALT << 16));
-		sci_assign_cmdkey(sci, sk->key, sk->rectangle);
-	}
-	else
-	{
-		sci_assign_cmdkey(sci, sk->key, sk->stream);
-		sci_assign_cmdkey(sci, sk->key | (SCMOD_ALT << 16), sk->rectangle);
-	}
-}
-
 static select_key select_keys[] =
 {
 	{ SCK_HOME  | (SCMOD_SHIFT << 16),  SCI_NULL,             SCI_NULL },
@@ -163,15 +243,58 @@
 	const select_key *sk;
 
 	for (sk = select_keys; sk->key; sk++)
-		assign_select_key(sci, sk);
+	{
+		if (column_mode)
+		{
+			sci_clear_cmdkey(sci, sk->key | (SCMOD_ALT << 16));
+			sci_assign_cmdkey(sci, sk->key, sk->rectangle);
+		}
+		else
+		{
+			sci_assign_cmdkey(sci, sk->key, sk->stream);
+			sci_assign_cmdkey(sci, sk->key | (SCMOD_ALT << 16), sk->rectangle);
+		}
+	}
 }
 
-static void on_document_switch(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
+static void on_column_mode_toggled(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED
+	gpointer gdata)
+{
+	ScintillaObject *sci = scintilla_get_current();
+
+	if (sci && !plugin_ignore_callback)
+	{
+		column_mode = gtk_check_menu_item_get_active(column_mode_item);
+		assign_select_keys(sci);
+		g_object_set_data(G_OBJECT(sci), "column_mode", GINT_TO_POINTER(column_mode));
+		if (sci_has_selection(sci) && sci_rectangle_selection(sci) != column_mode)
+			convert_selection(sci, column_mode);
+		gtk_widget_set_sensitive(anchor_rect_select_item, !column_mode);
+	}
+}
+
+static void on_column_mode_key(G_GNUC_UNUSED guint key_id)
+{
+	gtk_check_menu_item_set_active(column_mode_item, !column_mode);
+}
+
+static void on_document_create(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GeanyDocument *doc,
 	G_GNUC_UNUSED gpointer user_data)
 {
-	assign_select_keys(doc->editor->sci);
+	column_mode = FALSE;
+	select_anchor = select_space = 0;
 }
 
+static void on_document_activate(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
+	G_GNUC_UNUSED gpointer user_data)
+{
+	ScintillaObject *sci = doc->editor->sci;
+
+	column_mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sci), "column_mode"));
+	select_anchor = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sci), "select_anchor"));
+	select_space = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sci), "select_space"));
+}
+
 static void update_home_key(void)
 {
 	if (geany_data->editor_prefs->smart_home_key)
@@ -192,71 +315,21 @@
 
 	if (column_mode)
 	{
-		GeanyDocument *doc = document_get_current();
+		ScintillaObject *sci = scintilla_get_current();
 
-		if (doc)
-			assign_select_key(doc->editor->sci, select_keys);
+		if (sci)
+			assign_select_keys(sci);
 	}
 }
 
-PluginCallback plugin_callbacks[] =
-{
-	{ "document-new", (GCallback) &on_document_switch, FALSE, NULL },
-	{ "document-open", (GCallback) &on_document_switch, FALSE, NULL },
-	{ "document-activate", (GCallback) &on_document_switch, FALSE, NULL },
-	{ "save-settings", (GCallback) &on_settings_change, FALSE, NULL },
-	{ NULL, NULL, FALSE, NULL }
-};
+/* Select to line / matching brace */
 
-static void on_extra_select_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
-	G_GNUC_UNUSED gpointer gdata)
-{
-	gtk_widget_set_sensitive(goto_line_item, document_get_current() != NULL);
-	gtk_widget_set_sensitive(brace_match_item, document_get_current() != NULL);
-}
-
-static void on_column_mode_toggled(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED
-	gpointer gdata)
-{
-	GeanyDocument *doc = document_get_current();
-
-	column_mode = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(column_mode_item));
-	if (doc)
-	{
-		ScintillaObject *sci = doc->editor->sci;
-		int select_mode = sci_get_selection_mode(sci);
-		int anchor = sci_get_anchor(sci);
-		int cursor = sci_get_current_position(sci);
-
-		assign_select_keys(sci);
-		if (column_mode && select_mode == SC_SEL_STREAM)
-		{
-			sci_set_selection_mode(sci, SC_SEL_RECTANGLE);
-			sci_set_anchor(sci, anchor);
-			/* sci_set_current_pos() clears the selection, bypass */
-			scintilla_send_message(sci, SCI_SETCURRENTPOS, cursor, 0);
-		}
-		else if (!column_mode && select_mode == SC_SEL_RECTANGLE)
-		{
-			sci_set_selection_mode(sci, SC_SEL_STREAM);
-			scintilla_send_message(sci, SCI_SETSEL, anchor, cursor);
-		}
-		sci_send_command(sci, SCI_CANCEL);
-	}
-}
-
-static void on_column_mode_key(G_GNUC_UNUSED guint key_id)
-{
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(column_mode_item), !column_mode);
-}
-
 static void doit_and_select(guint group_id, guint key_id)
 {
-	GeanyDocument *doc = document_get_current();
+	ScintillaObject *sci = scintilla_get_current();
 
-	if (doc)
+	if (sci)
 	{
-		ScintillaObject *sci = doc->editor->sci;
 		int before = sci_get_current_position(sci), after;
 
 		if (key_id != GEANY_KEYS_GOTO_LINE || !geany_data->toolbar_prefs->visible)
@@ -298,59 +371,185 @@
 	on_brace_match_activate(NULL, NULL);
 }
 
+/* Set anchor / select to anchor */
+
+static void save_selection(ScintillaObject *sci)
+{
+	g_object_set_data(G_OBJECT(sci), "select_anchor", GINT_TO_POINTER(select_anchor));
+	g_object_set_data(G_OBJECT(sci), "select_space", GINT_TO_POINTER(select_space));
+}
+
+static gboolean on_editor_notify(G_GNUC_UNUSED GObject *obj, GeanyEditor *editor,
+	SCNotification *nt, G_GNUC_UNUSED gpointer user_data)
+{
+	if (nt->nmhdr.code == SCN_MODIFIED)
+	{
+		if (nt->modificationType & SC_MOD_INSERTTEXT)
+		{
+			if (nt->position < select_anchor)
+			{
+				select_anchor += nt->length;
+				select_space = 0;
+				save_selection(editor->sci);
+			}
+		}
+		else if (nt->modificationType & SC_MOD_DELETETEXT)
+		{
+			if (nt->position < select_anchor)
+			{
+				if (nt->position + nt->length < select_anchor)
+					select_anchor -= nt->length;
+				else
+					select_anchor = nt->position;
+				select_space = 0;
+				save_selection(editor->sci);
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+static void on_set_anchor_activate(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED
+	gpointer gdata)
+{
+	ScintillaObject *sci = scintilla_get_current();
+
+	if (sci)
+	{
+		select_anchor = sci_get_current_position(sci);
+		select_space = sci_get_cursor_space(sci);
+		save_selection(sci);
+	}
+}
+
+static void on_set_anchor_key(G_GNUC_UNUSED guint key_id)
+{
+	on_set_anchor_activate(NULL, NULL);
+}
+
+static void select_to_anchor(gboolean rectangle)
+{
+	ScintillaObject *sci = scintilla_get_current();
+
+	if (sci)
+		create_selection(sci, select_anchor, select_space, rectangle);
+}
+
+static void on_select_to_anchor_activate(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED
+	gpointer gdata)
+{
+	select_to_anchor(column_mode);
+}
+
+static void on_select_to_anchor_key(G_GNUC_UNUSED guint key_id)
+{
+	on_select_to_anchor_activate(NULL, NULL);
+}
+
+static void on_select_rectangle_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
+	G_GNUC_UNUSED gpointer gdata)
+{
+	if (!column_mode)
+		select_to_anchor(TRUE);
+}
+
+static void on_select_rectangle_key(G_GNUC_UNUSED guint key_id)
+{
+	on_select_rectangle_activate(NULL, NULL);
+}
+
+/* Plugin globals */
+
+PluginCallback plugin_callbacks[] =
+{
+	{ "document-new", (GCallback) &on_document_create, FALSE, NULL },
+	{ "document-open", (GCallback) &on_document_create, FALSE, NULL },
+	{ "document-activate", (GCallback) &on_document_activate, FALSE, NULL },
+	{ "save-settings", (GCallback) &on_settings_change, FALSE, NULL },
+	{ "editor-notify", (GCallback) &on_editor_notify, FALSE, NULL },
+	{ NULL, NULL, FALSE, NULL }
+};
+
 void plugin_init(G_GNUC_UNUSED GeanyData *data)
 {
-	GtkWidget *extra_select_menu;
+	GtkContainer *menu;
+	GtkWidget *item;
 
 	main_locale_init(LOCALEDIR, GETTEXT_PACKAGE);
 
-	main_menu_item = gtk_menu_item_new_with_mnemonic(_("E_xtra Selection"));
-	gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), main_menu_item);
-	g_signal_connect(main_menu_item, "activate", G_CALLBACK(on_extra_select_activate), NULL);
-	extra_select_menu = gtk_menu_new();
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(main_menu_item), extra_select_menu);
+	item = gtk_menu_item_new_with_mnemonic(_("E_xtra Selection"));
+	main_menu_item = item;
+	gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), item);
+	g_signal_connect(item, "activate", G_CALLBACK(on_extra_select_activate), NULL);
+	ui_add_document_sensitive(item);
+	menu = GTK_CONTAINER(gtk_menu_new());
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), GTK_WIDGET(menu));
 
-	column_mode_item = gtk_check_menu_item_new_with_mnemonic(_("_Column Mode"));
-	gtk_container_add(GTK_CONTAINER(extra_select_menu), column_mode_item);
-	g_signal_connect(column_mode_item, "toggled", G_CALLBACK(on_column_mode_toggled), NULL);
+	item = gtk_check_menu_item_new_with_mnemonic(_("_Column Mode"));
+	column_mode_item = GTK_CHECK_MENU_ITEM(item);
+	gtk_container_add(menu, item);
+	g_signal_connect(item, "toggled", G_CALLBACK(on_column_mode_toggled), NULL);
 	keybindings_set_item(plugin_key_group, COLUMN_MODE_KB, on_column_mode_key, 0, 0,
-		"column_mode", _("Column mode"), column_mode_item);
+		"column_mode", _("Column mode"), item);
 
-	goto_line_item = gtk_menu_item_new_with_mnemonic(_("Select to _Line"));
-	gtk_container_add(GTK_CONTAINER(extra_select_menu), goto_line_item);
-	g_signal_connect(goto_line_item, "activate", G_CALLBACK(on_goto_line_activate), NULL);
+	item = gtk_menu_item_new_with_mnemonic(_("Select to _Line"));
+	gtk_container_add(menu, item);
+	g_signal_connect(item, "activate", G_CALLBACK(on_goto_line_activate), NULL);
 	keybindings_set_item(plugin_key_group, GOTO_LINE_EXTEND_KB, on_goto_line_key, 0, 0,
-		"goto_line_extend", _("Select to line"), goto_line_item);
+		"goto_line_extend", _("Select to line"), item);
 
-	brace_match_item = gtk_menu_item_new_with_mnemonic(_("Select to Matching _Brace"));
-	gtk_container_add(GTK_CONTAINER(extra_select_menu), brace_match_item);
-	g_signal_connect(brace_match_item, "activate", G_CALLBACK(on_brace_match_activate),
-		NULL);
+	item = gtk_menu_item_new_with_mnemonic(_("Select to Matching _Brace"));
+	gtk_container_add(menu, item);
+	g_signal_connect(item, "activate", G_CALLBACK(on_brace_match_activate), NULL);
 	keybindings_set_item(plugin_key_group, BRACE_MATCH_EXTEND_KB, on_brace_match_key, 0, 0,
-		"brace_match_extend", _("Select to matching brace"), brace_match_item);
+		"brace_match_extend", _("Select to matching brace"), item);
 
+	gtk_container_add(menu, gtk_separator_menu_item_new());
+
+	item = gtk_menu_item_new_with_mnemonic(_("_Set Anchor"));
+	gtk_container_add(menu, item);
+	g_signal_connect(item, "activate", G_CALLBACK(on_set_anchor_activate), NULL);
+	keybindings_set_item(plugin_key_group, SET_ANCHOR_KB, on_set_anchor_key, 0, 0,
+		"set_anchor", _("Set anchor"), item);
+
+	item = gtk_menu_item_new_with_mnemonic(_("Select to _Anchor"));
+	gtk_container_add(menu, item);
+	g_signal_connect(item, "activate", G_CALLBACK(on_select_to_anchor_activate), NULL);
+	keybindings_set_item(plugin_key_group, ANCHOR_EXTEND_KB, on_select_to_anchor_key, 0, 0,
+		"select_to_anchor", _("Select to anchor"), item);
+
+	item = gtk_menu_item_new_with_mnemonic(_("_Rectangle Select to Anchor"));
+	anchor_rect_select_item = item;
+	gtk_container_add(menu, item);
+	g_signal_connect(item, "activate", G_CALLBACK(on_select_rectangle_activate), NULL);
+	keybindings_set_item(plugin_key_group, ANCHOR_RECTEXTEND_KB, on_select_rectangle_key, 0,
+		0, "rect_select_to_anchor", _("Rectangle select to anchor"), item);
+
 	gtk_widget_show_all(main_menu_item);
 
 	go_to_line1_item = g_object_get_data((gpointer) geany->main_widgets->window,
 		"go_to_line1");
 
 	update_home_key();
-
 	plugin_signal_connect(geany_plugin, G_OBJECT(geany->main_widgets->window),
 		"key-press-event", FALSE, G_CALLBACK(on_key_press_event), NULL);
 }
 
-/* for 0.18 compatibility */
-#ifndef foreach_document
-#define foreach_document documents_foreach
-#endif
-
 void plugin_cleanup(void)
 {
 	guint i;
 
+	gtk_widget_destroy(main_menu_item);
 	column_mode = FALSE;
-	foreach_document (i)
-		assign_select_keys(documents[i]->editor->sci);
-	gtk_widget_destroy(main_menu_item);
+
+	foreach_document(i)
+	{
+		ScintillaObject *sci = documents[i]->editor->sci;
+
+		assign_select_keys(sci);
+		g_object_steal_data(G_OBJECT(sci), "column_mode");
+		g_object_steal_data(G_OBJECT(sci), "select_anchor");
+		g_object_steal_data(G_OBJECT(sci), "select_space");
+	}
 }


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Plugins-Commits mailing list