1 /*
2 * extrasel.c
3 *
4 * Copyright 2010 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <gdk/gdkkeysyms.h>
25
26 #include <geanyplugin.h>
27
28 GeanyPlugin *geany_plugin;
29 GeanyData *geany_data;
30
31 PLUGIN_VERSION_CHECK(224)
32
33 PLUGIN_SET_TRANSLATABLE_INFO(LOCALEDIR, GETTEXT_PACKAGE,
34 _("Extra Selection"), _("Column mode, select to line / brace / anchor."
35 "\nThis plugin currently has no maintainer. Would you like to help by "
36 "contributing to this plugin?"),
37 "0.52", "Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>")
38
39 /* Keybinding(s) */
40 enum
41 {
42 COLUMN_MODE_KB,
43 GOTO_LINE_EXTEND_KB,
44 BRACE_MATCH_EXTEND_KB,
45 CONVERT_SELECTION_KB,
46 SET_ANCHOR_KB,
47 ANCHOR_EXTEND_KB,
48 ANCHOR_RECTEXTEND_KB,
49 COUNT_KB
50 };
51
52 static GtkWidget *main_menu_item = NULL;
53 static GtkCheckMenuItem *column_mode_item;
54 static GtkWidget *anchor_rect_select_item;
55 static gpointer *go_to_line1_item = NULL;
56
57 static gint column_mode = FALSE;
58 static gint plugin_internal_callback = FALSE;
59 static gint select_anchor = 0, select_space = 0;
60
61 /* Common functions / macros */
62
scintilla_get_current(void)63 static ScintillaObject *scintilla_get_current(void)
64 {
65 GeanyDocument *doc = document_get_current();
66 return doc ? doc->editor->sci : NULL;
67 }
68
69 #define SSM(s, m, w, l) scintilla_send_message(s, m, w, l)
70 #define sci_get_anchor(sci) SSM(sci, SCI_GETANCHOR, 0, 0)
71 #define sci_set_anchor(sci, anchor) SSM(sci, SCI_SETANCHOR, anchor, 0)
72 #define sci_get_main_selection(sci) SSM(sci, SCI_GETMAINSELECTION, 0, 0)
73 #define sci_rectangle_selection(sci) (sci_get_selection_mode(sci) == SC_SEL_RECTANGLE || \
74 sci_get_selection_mode(sci) == SC_SEL_THIN)
75 #define sci_virtual_space(sci, ACTION, OBJECT, space) \
76 (sci_rectangle_selection(sci) ? \
77 SSM(sci, ACTION##RECTANGULARSELECTION##OBJECT##VIRTUALSPACE, space, 0) : \
78 SSM(sci, ACTION##SELECTIONN##OBJECT##VIRTUALSPACE, sci_get_main_selection(sci), space))
79 #define sci_set_virtual_space(sci, OBJECT, space) \
80 do { if (space) sci_virtual_space(sci, SCI_SET, OBJECT, space); } while(0)
81 #define sci_get_anchor_space(sci) sci_virtual_space(sci, SCI_GET, ANCHOR, 0)
82 #define sci_set_anchor_space(sci, space) sci_set_virtual_space(sci, ANCHOR, space)
83 #define sci_get_cursor_space(sci) sci_virtual_space(sci, SCI_GET, CARET, 0)
84 #define sci_set_cursor_space(sci, space) sci_set_virtual_space(sci, CARET, space)
85
create_selection(ScintillaObject * sci,int anchor,int anchor_space,gboolean rectangle)86 static void create_selection(ScintillaObject *sci, int anchor, int anchor_space,
87 gboolean rectangle)
88 {
89 int cursor = sci_get_current_position(sci);
90 int cursor_space = sci_get_cursor_space(sci);
91
92 if (rectangle)
93 {
94 sci_set_selection_mode(sci, SC_SEL_RECTANGLE);
95 sci_set_anchor(sci, anchor);
96 /* sci_set_current_position() sets anchor = cursor, bypass */
97 scintilla_send_message(sci, SCI_SETCURRENTPOS, cursor, 0);
98 }
99 else
100 {
101 sci_set_selection_mode(sci, SC_SEL_STREAM);
102 scintilla_send_message(sci, SCI_SETSEL, anchor, cursor);
103 }
104
105 sci_set_anchor_space(sci, anchor_space);
106 sci_set_cursor_space(sci, cursor_space);
107 sci_send_command(sci, SCI_CANCEL);
108 }
109
convert_selection(ScintillaObject * sci,gboolean rectangle)110 static void convert_selection(ScintillaObject *sci, gboolean rectangle)
111 {
112 if (sci_has_selection(sci))
113 create_selection(sci, sci_get_anchor(sci), sci_get_anchor_space(sci), rectangle);
114 }
115
116 /* New rectangle selection keys */
117
118 typedef struct _command_key
119 {
120 guint key;
121 guint keypad;
122 int command;
123 } command_key;
124
125 static const command_key command_keys[] =
126 {
127 { GDK_Up, GDK_KP_Up, SCI_PARAUP },
128 { GDK_Down, GDK_KP_Down, SCI_PARADOWN },
129 { GDK_Left, GDK_KP_Left, SCI_WORDLEFT },
130 { GDK_Right, GDK_KP_Right, SCI_WORDRIGHTEND },
131 { GDK_Home, GDK_KP_Home, SCI_DOCUMENTSTART },
132 { GDK_End, GDK_KP_End, SCI_DOCUMENTEND },
133 { GDK_Prior, GDK_KP_Prior, 0 },
134 { GDK_Next, GDK_KP_Next, 0 },
135 { 0, 0, 0 }
136 };
137
column_mode_command(ScintillaObject * sci,int command)138 static void column_mode_command(ScintillaObject *sci, int command)
139 {
140 /* In the current SCI versions, using the command_keys->command for
141 rectangular selection creates various problems. So we select a
142 stream instead, and convert it to rectangle. It's slower, but all
143 command-s move the cursor at least a word. */
144 int anchor = sci_get_anchor(sci);
145 int anchor_space = sci_get_anchor_space(sci);
146
147 sci_set_selection_mode(sci, SC_SEL_STREAM);
148 sci_send_command(sci, command);
149 create_selection(sci, anchor, anchor_space, TRUE);
150 }
151
on_key_press_event(GtkWidget * widget,GdkEventKey * event,G_GNUC_UNUSED gpointer gdata)152 static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *event,
153 G_GNUC_UNUSED gpointer gdata)
154 {
155 guint mask = GDK_CONTROL_MASK | GDK_SHIFT_MASK | (column_mode ? 0 : GDK_MOD1_MASK);
156 guint state = event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK);
157
158 if (state == mask)
159 {
160 const command_key *ck;
161
162 for (ck = command_keys; ck->command; ck++)
163 {
164 if (event->keyval == ck->key || event->keyval == ck->keypad)
165 {
166 ScintillaObject *sci = scintilla_get_current();
167
168 if (sci && gtk_window_get_focus(GTK_WINDOW(widget)) == GTK_WIDGET(sci))
169 {
170 column_mode_command(sci, ck->command);
171 return TRUE;
172 }
173 break;
174 }
175 }
176 }
177 else if (!column_mode && state == GDK_SHIFT_MASK)
178 {
179 const command_key *ck;
180
181 for (ck = command_keys; ck->key; ck++)
182 {
183 if (event->keyval == ck->key || event->keyval == ck->keypad)
184 {
185 ScintillaObject *sci = scintilla_get_current();
186
187 if (sci && sci_has_selection(sci) && sci_rectangle_selection(sci) &&
188 gtk_window_get_focus(GTK_WINDOW(widget)) == GTK_WIDGET(sci))
189 {
190 /* not exactly a bug, but... */
191 convert_selection(sci, FALSE);
192 }
193 break;
194 }
195 }
196 }
197
198 return FALSE;
199 }
200
201 /* Column mode */
202
203 typedef struct _select_key
204 {
205 int key;
206 int stream;
207 int rectangle;
208 } select_key;
209
210 #define sci_clear_cmdkey(sci, key) scintilla_send_message((sci), SCI_CLEARCMDKEY, (key), 0)
211 #define sci_assign_cmdkey(sci, key, command) \
212 scintilla_send_message((sci), SCI_ASSIGNCMDKEY, (key), (command))
213
214 static select_key select_keys[] =
215 {
216 { SCK_HOME | (SCMOD_SHIFT << 16), SCI_NULL, SCI_NULL },
217 { SCK_UP | (SCMOD_SHIFT << 16), SCI_LINEUPEXTEND, SCI_LINEUPRECTEXTEND },
218 { SCK_DOWN | (SCMOD_SHIFT << 16), SCI_LINEDOWNEXTEND, SCI_LINEDOWNRECTEXTEND },
219 { SCK_LEFT | (SCMOD_SHIFT << 16), SCI_CHARLEFTEXTEND, SCI_CHARLEFTRECTEXTEND },
220 { SCK_RIGHT | (SCMOD_SHIFT << 16), SCI_CHARRIGHTEXTEND, SCI_CHARRIGHTRECTEXTEND },
221 { SCK_END | (SCMOD_SHIFT << 16), SCI_LINEENDEXTEND, SCI_LINEENDRECTEXTEND },
222 { SCK_PRIOR | (SCMOD_SHIFT << 16), SCI_PAGEUPEXTEND, SCI_PAGEUPRECTEXTEND },
223 { SCK_NEXT | (SCMOD_SHIFT << 16), SCI_PAGEDOWNEXTEND, SCI_PAGEDOWNRECTEXTEND },
224 { 0, 0, 0 }
225 };
226
assign_select_keys(ScintillaObject * sci)227 static void assign_select_keys(ScintillaObject *sci)
228 {
229 const select_key *sk;
230
231 for (sk = select_keys; sk->key; sk++)
232 {
233 if (column_mode)
234 {
235 sci_clear_cmdkey(sci, sk->key | (SCMOD_ALT << 16));
236 sci_assign_cmdkey(sci, sk->key, sk->rectangle);
237 }
238 else
239 {
240 sci_assign_cmdkey(sci, sk->key, sk->stream);
241 sci_assign_cmdkey(sci, sk->key | (SCMOD_ALT << 16), sk->rectangle);
242 }
243 }
244 }
245
on_column_mode_toggled(G_GNUC_UNUSED GtkMenuItem * menuitem)246 static void on_column_mode_toggled(G_GNUC_UNUSED GtkMenuItem *menuitem)
247 {
248 ScintillaObject *sci = scintilla_get_current();
249
250 if (sci)
251 {
252 column_mode = gtk_check_menu_item_get_active(column_mode_item);
253 gtk_widget_set_sensitive(anchor_rect_select_item, !column_mode);
254
255 if (!plugin_internal_callback)
256 {
257 assign_select_keys(sci);
258 g_object_set_data(G_OBJECT(sci), "column_mode", GINT_TO_POINTER(column_mode));
259 if (sci_has_selection(sci) && sci_rectangle_selection(sci) != column_mode)
260 convert_selection(sci, column_mode);
261 }
262 }
263 }
264
on_column_mode_key(G_GNUC_UNUSED guint key_id)265 static void on_column_mode_key(G_GNUC_UNUSED guint key_id)
266 {
267 gtk_check_menu_item_set_active(column_mode_item, !column_mode);
268 }
269
on_document_create(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GeanyDocument * doc,G_GNUC_UNUSED gpointer gdata)270 static void on_document_create(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GeanyDocument *doc,
271 G_GNUC_UNUSED gpointer gdata)
272 {
273 select_anchor = select_space = 0;
274 plugin_internal_callback = TRUE;
275 gtk_check_menu_item_set_active(column_mode_item, FALSE);
276 plugin_internal_callback = FALSE;
277 }
278
on_document_activate(G_GNUC_UNUSED GObject * obj,GeanyDocument * doc,G_GNUC_UNUSED gpointer gdata)279 static void on_document_activate(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
280 G_GNUC_UNUSED gpointer gdata)
281 {
282 ScintillaObject *sci = doc->editor->sci;
283
284 plugin_internal_callback = TRUE;
285 column_mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sci), "column_mode"));
286 gtk_check_menu_item_set_active(column_mode_item, column_mode);
287 plugin_internal_callback = FALSE;
288 select_anchor = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sci), "select_anchor"));
289 select_space = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sci), "select_space"));
290 }
291
update_home_key(void)292 static void update_home_key(void)
293 {
294 if (geany_data->editor_prefs->smart_home_key)
295 {
296 select_keys->stream = SCI_VCHOMEEXTEND;
297 select_keys->rectangle = SCI_VCHOMERECTEXTEND;
298 }
299 else
300 {
301 select_keys->stream = SCI_HOMEEXTEND;
302 select_keys->rectangle = SCI_HOMERECTEXTEND;
303 }
304 }
305
on_settings_change(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GKeyFile * keyfile,G_GNUC_UNUSED gpointer gdata)306 static void on_settings_change(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GKeyFile *keyfile,
307 G_GNUC_UNUSED gpointer gdata)
308 {
309 update_home_key();
310
311 if (column_mode)
312 {
313 guint i;
314
315 foreach_document(i)
316 assign_select_keys(documents[i]->editor->sci);
317 }
318 }
319
320 /* Select to line / matching brace */
321
doit_and_select(guint group_id,guint key_id)322 static void doit_and_select(guint group_id, guint key_id)
323 {
324 ScintillaObject *sci = scintilla_get_current();
325
326 if (sci)
327 {
328 int before = sci_get_current_position(sci), after;
329
330 if (key_id != GEANY_KEYS_GOTO_LINE || !geany_data->toolbar_prefs->visible)
331 keybindings_send_command(group_id, key_id);
332 else if (go_to_line1_item)
333 g_signal_emit_by_name(go_to_line1_item, "activate");
334 else
335 {
336 if (geany_data->prefs->beep_on_errors)
337 #if GTK_CHECK_VERSION(2, 2, 0)
338 gdk_display_beep(gdk_display_get_default());
339 #else
340 gdk_beep();
341 #endif
342 return;
343 }
344
345 after = sci_get_current_position(sci);
346 if (before != after)
347 sci_set_anchor(sci, before);
348 }
349 }
350
on_goto_line_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)351 static void on_goto_line_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
352 G_GNUC_UNUSED gpointer gdata)
353 {
354 doit_and_select(GEANY_KEY_GROUP_GOTO, GEANY_KEYS_GOTO_LINE);
355 }
356
on_goto_line_key(G_GNUC_UNUSED guint key_id)357 static void on_goto_line_key(G_GNUC_UNUSED guint key_id)
358 {
359 on_goto_line_activate(NULL, NULL);
360 }
361
on_brace_match_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)362 static void on_brace_match_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
363 G_GNUC_UNUSED gpointer gdata)
364 {
365 doit_and_select(GEANY_KEY_GROUP_GOTO, GEANY_KEYS_GOTO_MATCHINGBRACE);
366 }
367
on_brace_match_key(G_GNUC_UNUSED guint key_id)368 static void on_brace_match_key(G_GNUC_UNUSED guint key_id)
369 {
370 on_brace_match_activate(NULL, NULL);
371 }
372
on_convert_selection_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)373 static void on_convert_selection_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
374 G_GNUC_UNUSED gpointer gdata)
375 {
376 ScintillaObject *sci = scintilla_get_current();
377
378 if (sci)
379 convert_selection(sci, !sci_rectangle_selection(sci));
380 }
381
on_convert_selection_key(G_GNUC_UNUSED guint key_id)382 static void on_convert_selection_key(G_GNUC_UNUSED guint key_id)
383 {
384 on_convert_selection_activate(NULL, NULL);
385 }
386
387 /* Set anchor / select to anchor */
388
save_selection(ScintillaObject * sci)389 static void save_selection(ScintillaObject *sci)
390 {
391 g_object_set_data(G_OBJECT(sci), "select_anchor", GINT_TO_POINTER(select_anchor));
392 g_object_set_data(G_OBJECT(sci), "select_space", GINT_TO_POINTER(select_space));
393 }
394
on_editor_notify(G_GNUC_UNUSED GObject * obj,GeanyEditor * editor,SCNotification * nt,G_GNUC_UNUSED gpointer gdata)395 static gboolean on_editor_notify(G_GNUC_UNUSED GObject *obj, GeanyEditor *editor,
396 SCNotification *nt, G_GNUC_UNUSED gpointer gdata)
397 {
398 if (nt->nmhdr.code == SCN_MODIFIED)
399 {
400 if (nt->modificationType & SC_MOD_INSERTTEXT)
401 {
402 if (nt->position < select_anchor)
403 {
404 select_anchor += nt->length;
405 select_space = 0;
406 save_selection(editor->sci);
407 }
408 }
409 else if (nt->modificationType & SC_MOD_DELETETEXT)
410 {
411 if (nt->position < select_anchor)
412 {
413 if (nt->position + nt->length < select_anchor)
414 select_anchor -= nt->length;
415 else
416 select_anchor = nt->position;
417 select_space = 0;
418 save_selection(editor->sci);
419 }
420 }
421 }
422
423 return FALSE;
424 }
425
on_set_anchor_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)426 static void on_set_anchor_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
427 G_GNUC_UNUSED gpointer gdata)
428 {
429 ScintillaObject *sci = scintilla_get_current();
430
431 if (sci)
432 {
433 select_anchor = sci_get_current_position(sci);
434 select_space = sci_get_cursor_space(sci);
435 save_selection(sci);
436 }
437 }
438
on_set_anchor_key(G_GNUC_UNUSED guint key_id)439 static void on_set_anchor_key(G_GNUC_UNUSED guint key_id)
440 {
441 on_set_anchor_activate(NULL, NULL);
442 }
443
select_to_anchor(gboolean rectangle)444 static void select_to_anchor(gboolean rectangle)
445 {
446 ScintillaObject *sci = scintilla_get_current();
447
448 if (sci)
449 create_selection(sci, select_anchor, select_space, rectangle);
450 }
451
on_select_to_anchor_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)452 static void on_select_to_anchor_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
453 G_GNUC_UNUSED gpointer gdata)
454 {
455 select_to_anchor(column_mode);
456 }
457
on_select_to_anchor_key(G_GNUC_UNUSED guint key_id)458 static void on_select_to_anchor_key(G_GNUC_UNUSED guint key_id)
459 {
460 on_select_to_anchor_activate(NULL, NULL);
461 }
462
on_select_rectangle_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)463 static void on_select_rectangle_activate(G_GNUC_UNUSED GtkMenuItem *menuitem,
464 G_GNUC_UNUSED gpointer gdata)
465 {
466 if (!column_mode)
467 select_to_anchor(TRUE);
468 }
469
on_select_rectangle_key(G_GNUC_UNUSED guint key_id)470 static void on_select_rectangle_key(G_GNUC_UNUSED guint key_id)
471 {
472 on_select_rectangle_activate(NULL, NULL);
473 }
474
475 /* Plugin globals */
476
477 PluginCallback plugin_callbacks[] =
478 {
479 { "document-new", G_CALLBACK(on_document_create), FALSE, NULL },
480 { "document-open", G_CALLBACK(on_document_create), FALSE, NULL },
481 { "document-activate", G_CALLBACK(on_document_activate), FALSE, NULL },
482 { "save-settings", G_CALLBACK(on_settings_change), FALSE, NULL },
483 { "editor-notify", G_CALLBACK(on_editor_notify), FALSE, NULL },
484 { NULL, NULL, FALSE, NULL }
485 };
486
on_extra_select_activate(G_GNUC_UNUSED GtkMenuItem * menuitem,gpointer gdata)487 static void on_extra_select_activate(G_GNUC_UNUSED GtkMenuItem *menuitem, gpointer gdata)
488 {
489 gtk_widget_set_sensitive(GTK_WIDGET(gdata), sci_has_selection(scintilla_get_current()));
490 }
491
plugin_init(G_GNUC_UNUSED GeanyData * data)492 void plugin_init(G_GNUC_UNUSED GeanyData *data)
493 {
494 GtkContainer *menu;
495 GtkWidget *item;
496 GeanyKeyGroup *plugin_key_group;
497
498 plugin_key_group = plugin_set_key_group(geany_plugin, "extra_select", COUNT_KB, NULL);
499
500 item = gtk_menu_item_new_with_mnemonic(_("E_xtra Selection"));
501 main_menu_item = item;
502 gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), item);
503 ui_add_document_sensitive(item);
504 menu = GTK_CONTAINER(gtk_menu_new());
505 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), GTK_WIDGET(menu));
506
507 item = gtk_check_menu_item_new_with_mnemonic(_("_Column Mode"));
508 column_mode_item = GTK_CHECK_MENU_ITEM(item);
509 gtk_container_add(menu, item);
510 g_signal_connect(item, "toggled", G_CALLBACK(on_column_mode_toggled), NULL);
511 keybindings_set_item(plugin_key_group, COLUMN_MODE_KB, on_column_mode_key, 0, 0,
512 "column_mode", _("Column mode"), item);
513
514 item = gtk_menu_item_new_with_mnemonic(_("Select to _Line"));
515 gtk_container_add(menu, item);
516 g_signal_connect(item, "activate", G_CALLBACK(on_goto_line_activate), NULL);
517 keybindings_set_item(plugin_key_group, GOTO_LINE_EXTEND_KB, on_goto_line_key, 0, 0,
518 "goto_line_extend", _("Select to line"), item);
519
520 item = gtk_menu_item_new_with_mnemonic(_("Select to Matching _Brace"));
521 gtk_container_add(menu, item);
522 g_signal_connect(item, "activate", G_CALLBACK(on_brace_match_activate), NULL);
523 keybindings_set_item(plugin_key_group, BRACE_MATCH_EXTEND_KB, on_brace_match_key, 0, 0,
524 "brace_match_extend", _("Select to matching brace"), item);
525
526 item = gtk_menu_item_new_with_mnemonic(_("_Toggle Stream/Rectangular"));
527 gtk_container_add(menu, item);
528 g_signal_connect(item, "activate", G_CALLBACK(on_convert_selection_activate), NULL);
529 keybindings_set_item(plugin_key_group, CONVERT_SELECTION_KB, on_convert_selection_key,
530 0, 0, "convert_selection", _("Convert selection"), item);
531 g_signal_connect(main_menu_item, "activate", G_CALLBACK(on_extra_select_activate), item);
532
533 gtk_container_add(menu, gtk_separator_menu_item_new());
534
535 item = gtk_menu_item_new_with_mnemonic(_("_Set Anchor"));
536 gtk_container_add(menu, item);
537 g_signal_connect(item, "activate", G_CALLBACK(on_set_anchor_activate), NULL);
538 keybindings_set_item(plugin_key_group, SET_ANCHOR_KB, on_set_anchor_key, 0, 0,
539 "set_anchor", _("Set anchor"), item);
540
541 item = gtk_menu_item_new_with_mnemonic(_("Select to _Anchor"));
542 gtk_container_add(menu, item);
543 g_signal_connect(item, "activate", G_CALLBACK(on_select_to_anchor_activate), NULL);
544 keybindings_set_item(plugin_key_group, ANCHOR_EXTEND_KB, on_select_to_anchor_key, 0, 0,
545 "select_to_anchor", _("Select to anchor"), item);
546
547 item = gtk_menu_item_new_with_mnemonic(_("_Rectangle Select to Anchor"));
548 anchor_rect_select_item = item;
549 gtk_container_add(menu, item);
550 g_signal_connect(item, "activate", G_CALLBACK(on_select_rectangle_activate), NULL);
551 keybindings_set_item(plugin_key_group, ANCHOR_RECTEXTEND_KB, on_select_rectangle_key, 0,
552 0, "rect_select_to_anchor", _("Rectangle select to anchor"), item);
553
554 gtk_widget_show_all(main_menu_item);
555
556 go_to_line1_item = g_object_get_data((gpointer) geany->main_widgets->window,
557 "go_to_line1");
558
559 update_home_key();
560 plugin_signal_connect(geany_plugin, G_OBJECT(geany->main_widgets->window),
561 "key-press-event", FALSE, G_CALLBACK(on_key_press_event), NULL);
562 }
563
plugin_cleanup(void)564 void plugin_cleanup(void)
565 {
566 guint i = 0;
567
568 gtk_widget_destroy(main_menu_item);
569 column_mode = FALSE;
570
571 foreach_document(i)
572 {
573 ScintillaObject *sci = documents[i]->editor->sci;
574
575 assign_select_keys(sci);
576 g_object_steal_data(G_OBJECT(sci), "column_mode");
577 g_object_steal_data(G_OBJECT(sci), "select_anchor");
578 g_object_steal_data(G_OBJECT(sci), "select_space");
579 }
580 }
581