1 /* shiftcolumn.c - a Geany plugin
2 *
3 * Copyright 2009 Andrew L Janke <a.janke@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <geanyplugin.h>
27
28 #ifdef HAVE_LOCALE_H
29 # include <locale.h>
30 #endif
31
32 #include <glib.h>
33 #include <glib/gprintf.h>
34 #include <gdk/gdkkeysyms.h>
35
36 GeanyPlugin *geany_plugin;
37 GeanyData *geany_data;
38
39 PLUGIN_VERSION_CHECK(224)
40 PLUGIN_SET_TRANSLATABLE_INFO(LOCALEDIR, GETTEXT_PACKAGE,
41 _("Shift Column"),
42 _("Shift a selection left and right."
43 "\nThis plugin currently has no maintainer. Would you like to help "
44 "by contributing to this plugin?"),
45 VERSION, "Andrew L Janke <a.janke@gmail.com>")
46
47
48 static GtkWidget *menu_item_shift_left = NULL;
49 static GtkWidget *menu_item_shift_right = NULL;
50
51 /* Keybinding(s) */
52 enum{
53 KB_SHIFT_LEFT,
54 KB_SHIFT_RIGHT,
55 KB_COUNT
56 };
57
58
shift_left_cb(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)59 static void shift_left_cb(G_GNUC_UNUSED GtkMenuItem *menuitem,
60 G_GNUC_UNUSED gpointer gdata){
61 gchar *txt;
62 gchar *txt_i;
63 gchar char_before;
64
65 gint startpos;
66 gint endpos;
67
68 gint startline;
69 gint endline;
70 gint line_iter;
71 gint linepos;
72 gint linelen;
73
74 gint startcol;
75 gint endcol;
76
77 gint i;
78
79 gint n_spaces;
80 gchar *spaces;
81
82 ScintillaObject *sci;
83
84 /* get a pointer to the scintilla object */
85 sci = document_get_current()->editor->sci;
86
87 if (sci_has_selection(sci)){
88
89 startpos = sci_get_selection_start(sci);
90 endpos = sci_get_selection_end(sci);
91
92 /* sanity check -- we dont care which way the block was selected */
93 if(startpos > endpos){
94 i = endpos;
95 endpos = startpos;
96 startpos = i;
97 }
98
99 startline = sci_get_line_from_position(sci, startpos);
100 /* Setting also start point for 1st line */
101 linepos = sci_get_position_from_line(sci, startline);
102 endline = sci_get_line_from_position(sci, endpos);
103
104 /* normal mode */
105 if(startline == endline){
106
107 /* get the text in question */
108 txt_i = sci_get_selection_contents(sci);
109
110 char_before = sci_get_char_at(sci, startpos - 1);
111
112 /* set up new text buf */
113 txt = g_strdup_printf("%s%c", txt_i, char_before);
114
115 /* start undo */
116 sci_start_undo_action(sci);
117
118 /* put the new text in */
119 sci_set_selection_start(sci, startpos - 1);
120 sci_set_selection_end(sci, endpos);
121 sci_replace_sel(sci, txt);
122
123 /* select the right bit again */
124 sci_set_selection_start(sci, startpos - 1);
125 sci_set_selection_end(sci, endpos - 1);
126
127 /* end undo */
128 sci_end_undo_action(sci);
129
130 g_free(txt);
131 g_free(txt_i);
132 }
133
134 /* rectangle mode (we hope!) */
135 else{
136 startcol = sci_get_col_from_position(sci, startpos);
137 endcol = sci_get_col_from_position(sci, endpos);
138
139 /* return early for the trivial case */
140 if(startcol == 0 || startcol == endcol){
141 return;
142 }
143
144 /* start undo */
145 sci_start_undo_action(sci);
146
147 for(line_iter = startline; line_iter <= endline; line_iter++){
148 linepos = sci_get_position_from_line(sci, line_iter);
149 linelen = sci_get_line_length(sci, line_iter);
150
151 /* do we need to do something */
152 if(linelen >= startcol - 1 ){
153
154 /* if between the two columns */
155 /* pad to the end first */
156 if(linelen <= endcol){
157
158 /* bung in some spaces -- sorry, I dont like tabs */
159 n_spaces = endcol - linelen + 1;
160 spaces = g_malloc(sizeof(gchar) * (n_spaces + 1));
161 for(i = 0; i < n_spaces; i++){
162 spaces[i] = ' ';
163 }
164 spaces[i] = '\0';
165
166 sci_insert_text(sci, linepos + linelen - 1, spaces);
167 g_free(spaces);
168 }
169
170 /* now move the text itself */
171 sci_set_selection_mode(sci, 0);
172 sci_set_selection_start(sci, linepos + startcol);
173 sci_set_selection_end(sci, linepos + endcol);
174
175 txt_i = sci_get_selection_contents(sci);
176 char_before = sci_get_char_at(sci, linepos + startcol - 1);
177
178 /* set up new text buf */
179 txt = g_strdup_printf("%s%c", txt_i, char_before);
180
181 /* put the new text in */
182 sci_set_selection_start(sci, linepos + startcol - 1);
183 sci_replace_sel(sci, txt);
184
185 g_free(txt);
186 g_free(txt_i);
187 }
188 }
189
190 /* put the selection box back */
191 /* here we rely upon the last result of linepos */
192 sci_set_selection_mode(sci, 1);
193 sci_set_selection_start(sci, startpos - 1);
194 sci_set_selection_end(sci, linepos + endcol - 1);
195
196 /* end undo action */
197 sci_end_undo_action(sci);
198 }
199
200 }
201 }
202
shift_right_cb(G_GNUC_UNUSED GtkMenuItem * menuitem,G_GNUC_UNUSED gpointer gdata)203 static void shift_right_cb(G_GNUC_UNUSED GtkMenuItem *menuitem,
204 G_GNUC_UNUSED gpointer gdata){
205 gchar *txt;
206 gchar *txt_i;
207 gchar char_after;
208
209 gint startpos;
210 gint endpos;
211
212 gint startline;
213 gint endline;
214 gint line_iter;
215 gint linepos;
216 gint linelen;
217
218 gint startcol;
219 gint endcol;
220
221 gint i;
222
223 ScintillaObject *sci;
224
225 /* get a pointer to the scintilla object */
226 sci = document_get_current()->editor->sci;
227
228 if (sci_has_selection(sci)){
229
230 startpos = sci_get_selection_start(sci);
231 endpos = sci_get_selection_end(sci);
232
233 /* sanity check -- we dont care which way the block was selected */
234 if(startpos > endpos){
235 i = endpos;
236 endpos = startpos;
237 startpos = i;
238 }
239
240 startline = sci_get_line_from_position(sci, startpos);
241 linepos = sci_get_position_from_line(sci, startline);
242 endline = sci_get_line_from_position(sci, endpos);
243
244 /* normal mode */
245 if(startline == endline){
246
247 /* get the text in question */
248 txt_i = sci_get_selection_contents(sci);
249
250 char_after = sci_get_char_at(sci, endpos);
251
252 /* set up new text buf */
253 txt = g_strdup_printf("%c%s", char_after, txt_i);
254
255 /* start undo */
256 sci_start_undo_action(sci);
257
258 /* put the new text in */
259 sci_set_selection_start(sci, startpos);
260 sci_set_selection_end(sci, endpos + 1);
261 sci_replace_sel(sci, txt);
262
263 /* select the right bit again */
264 sci_set_selection_start(sci, startpos + 1);
265 sci_set_selection_end(sci, endpos + 1);
266
267 /* end undo */
268 sci_end_undo_action(sci);
269
270 g_free(txt);
271 g_free(txt_i);
272 }
273
274 /* rectangle mode (we hope!) */
275 else{
276 startcol = sci_get_col_from_position(sci, startpos);
277 endcol = sci_get_col_from_position(sci, endpos);
278
279 /* start undo */
280 sci_start_undo_action(sci);
281
282 for(line_iter = startline; line_iter <= endline; line_iter++){
283 linepos = sci_get_position_from_line(sci, line_iter);
284 linelen = sci_get_line_length(sci, line_iter);
285
286 /* do we need to do something */
287 if(linelen >= startcol - 1 ){
288
289 /* if between the two columns or at the end */
290 /* add in a space */
291 if(linelen <= endcol || linelen - 1 == endcol){
292 txt = g_malloc(sizeof(gchar) * 2);
293 sprintf(txt, " ");
294
295 sci_insert_text(sci, linepos + startcol, txt);
296 g_free(txt);
297 }
298
299 else{
300 /* move the text itself */
301 sci_set_selection_mode(sci, 0);
302 sci_set_selection_start(sci, linepos + startcol);
303 sci_set_selection_end(sci, linepos + endcol);
304
305 txt_i = sci_get_selection_contents(sci);
306 char_after = sci_get_char_at(sci, linepos + endcol);
307
308 /* set up new text buf */
309 txt = g_strdup_printf("%c%s", char_after, txt_i);
310
311 /* put the new text in */
312 sci_set_selection_end(sci, linepos + endcol + 1);
313 sci_replace_sel(sci, txt);
314
315 g_free(txt);
316 g_free(txt_i);
317 }
318 }
319 }
320
321 /* put the selection box back */
322 /* here we rely upon the last result of linepos */
323 sci_set_selection_mode(sci, 1);
324 sci_set_selection_start(sci, startpos + 1);
325 sci_set_selection_end(sci, linepos + endcol + 1);
326
327 /* end undo action */
328 sci_end_undo_action(sci);
329 }
330 }
331 }
332
333
kb_shift_left(G_GNUC_UNUSED guint key_id)334 static void kb_shift_left(G_GNUC_UNUSED guint key_id){
335
336 /* sanity check */
337 if (document_get_current() == NULL){
338 return;
339 }
340
341 shift_left_cb(NULL, NULL);
342 }
343
kb_shift_right(G_GNUC_UNUSED guint key_id)344 static void kb_shift_right(G_GNUC_UNUSED guint key_id){
345
346 /* sanity check */
347 if (document_get_current() == NULL){
348 return;
349 }
350
351 shift_right_cb(NULL, NULL);
352 }
353
plugin_init(G_GNUC_UNUSED GeanyData * data)354 void plugin_init(G_GNUC_UNUSED GeanyData *data){
355 GeanyKeyGroup *key_group;
356
357 menu_item_shift_left = gtk_menu_item_new_with_mnemonic(_("Shift Left"));
358 gtk_widget_show(menu_item_shift_left);
359 gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu),
360 menu_item_shift_left);
361 g_signal_connect(menu_item_shift_left, "activate",
362 G_CALLBACK(shift_left_cb), NULL);
363
364 menu_item_shift_right = gtk_menu_item_new_with_mnemonic(_("Shift Right"));
365 gtk_widget_show(menu_item_shift_right);
366 gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu),
367 menu_item_shift_right);
368 g_signal_connect(menu_item_shift_right, "activate",
369 G_CALLBACK(shift_right_cb), NULL);
370
371 /* make sure our menu items aren't called when there is no doc open */
372 ui_add_document_sensitive(menu_item_shift_right);
373 ui_add_document_sensitive(menu_item_shift_left);
374
375 /* setup keybindings */
376 key_group = plugin_set_key_group(geany_plugin, "shiftcolumn", KB_COUNT, NULL);
377 keybindings_set_item(key_group, KB_SHIFT_LEFT, kb_shift_left,
378 0, GDK_CONTROL_MASK, "shift_left", _("Shift Left"), menu_item_shift_left);
379 keybindings_set_item(key_group, KB_SHIFT_RIGHT, kb_shift_right,
380 0, GDK_CONTROL_MASK, "shift_right", _("Shift Right"), menu_item_shift_right);
381 }
382
plugin_cleanup(void)383 void plugin_cleanup(void){
384 gtk_widget_destroy(menu_item_shift_left);
385 gtk_widget_destroy(menu_item_shift_right);
386 }
387