1 /* Bluefish HTML Editor
2 * doc_text_tools.c - text tools
3 *
4 * Copyright (C) 2008-2017 Olivier Sessink
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 3 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 /*#define DEBUG*/
20
21 #include "bluefish.h"
22 #include "bf_lib.h"
23 #include "gtk_easy.h"
24 #include "dialog_utils.h"
25 #include "document.h"
26 #include "undo_redo.h"
27 #include "stringlist.h"
28
29 /* special replace: strip trailing spaces */
30 /* use a very simple loop, one that knows whitespace, non-whitespace and a newline */
31 void
strip_trailing_spaces(Tdocument * doc)32 strip_trailing_spaces(Tdocument * doc)
33 {
34 gint i = 0, wstart = 0, coffset = 0;
35 gint start, end;
36 gchar *buf;
37
38 if (!doc_get_selection(doc, &start, &end)) {
39 start = 0;
40 end = -1;
41 }
42 buf = doc_get_chars(doc, start, end);
43 coffset = start;
44
45 doc_unre_new_group(doc);
46 while (buf[i] != '\0') {
47 switch (buf[i]) {
48 case ' ':
49 case '\t':
50 /* do nothing */
51 break;
52 case '\n':
53 if (wstart + 1 < i) {
54 gint cstart, cend;
55 cstart = utf8_byteoffset_to_charsoffset_cached(buf, wstart + 1);
56 cend = utf8_byteoffset_to_charsoffset_cached(buf, i);
57 doc_replace_text_backend(doc, "", cstart + coffset, cend + coffset);
58 coffset -= (cend - cstart);
59 }
60 /* no break, fall trough */
61 default:
62 wstart = i;
63 break;
64 }
65 i++;
66 }
67 g_free(buf);
68 doc_unre_new_group(doc);
69 }
70
71 static gint
join_lines_backend(Tdocument * doc,gint start,gint end)72 join_lines_backend(Tdocument * doc, gint start, gint end)
73 {
74 gint i = 0, cstart, cend, coffset;
75 gchar *buf;
76 gboolean in_split = FALSE;
77 gint so_line_split = 0, eo_line_split = 0;
78
79 coffset = start; /* the offset in 'buf' compared to the gtktextbuffer */
80 buf = doc_get_chars(doc, start, end);
81 utf8_offset_cache_reset();
82 DEBUG_MSG("join_lines_backend, from %d:%d\n",start,end);
83 while (buf[i] != '\0') {
84 if (in_split) {
85 if (buf[i] == '\n' || buf[i] == '\r') {
86 in_split = FALSE;
87 DEBUG_MSG("join_lines, don't join empty line at byte %d\n", i);
88 } else if (buf[i] != '\t' && buf[i] != ' ') {
89 eo_line_split = i;
90 in_split = FALSE;
91 cstart = utf8_byteoffset_to_charsoffset_cached(buf, so_line_split);
92 cend = utf8_byteoffset_to_charsoffset_cached(buf, eo_line_split);
93 DEBUG_MSG("join_lines, replace from %d to %d, coffset=%d\n", cstart + coffset, cend + coffset,
94 coffset);
95 doc_replace_text_backend(doc, " ", cstart + coffset, cend + coffset);
96 coffset += (1 - (cend - cstart));
97 }
98 } else {
99 if (buf[i] == '\n') {
100 so_line_split = i;
101 in_split = TRUE;
102 } else if (buf[i] == '\r') {
103 so_line_split = i;
104 in_split = TRUE;
105 if (buf[i + 1] == '\n')
106 i++;
107 }
108 }
109 i++;
110 }
111 g_free(buf);
112 DEBUG_MSG("join_lines_backend, return offset %d\n",coffset-start);
113 return coffset - start;
114 }
115
116 void
join_lines(Tdocument * doc)117 join_lines(Tdocument * doc)
118 {
119 gint start, end;
120 if (!doc_get_selection(doc, &start, &end)) {
121 start = 0;
122 end = -1;
123 }
124 doc_unre_new_group(doc);
125 join_lines_backend(doc, start, end);
126 doc_unre_new_group(doc);
127 }
128
129 #define WS_POS_UNDEFINED G_MAXINT
130 static void
split_lines_backend(Tdocument * doc,gint start,gint end)131 split_lines_backend(Tdocument * doc, gint start, gint end)
132 {
133 gint coffset = 0; /* the offset that we have introduced since the start of this function call */
134 gint count = 0, tabsize;
135 gint startws = 0, endws = 0, starti = start, endi = -1, requested_size;
136 /* ws= whitespace, i=indenting, these are character positions in the GtkTextBufferr !!!!!!!! */
137 gint charpos;
138 gchar *buf, *p;
139 gunichar c;
140
141 tabsize = doc_get_tabsize(doc);
142 p = buf = doc_get_chars(doc, start, end);
143 utf8_offset_cache_reset();
144 requested_size = main_v->props.right_margin_pos;
145 coffset = 0;
146 charpos = start;
147 DEBUG_MSG("split_lines_backend, from %d:%d on right margin %d\n",start,end, requested_size);
148 c = g_utf8_get_char(p);
149 while (c != '\0') {
150 #ifdef DEBUGSPLIT
151 g_print("%d '%c'\n",charpos,c<128?c:'Q');
152 #endif
153 if (count > requested_size && startws!=WS_POS_UNDEFINED) {
154 gchar *new_indenting, *tmp1, *tmp2;
155 if (startws >= endws)
156 endws = charpos;
157 DEBUG_MSG("split_lines, count=%d(>%d), startws=%d, endws=%d, coffset=%d c='%c'\n", count,requested_size, startws,
158 endws, coffset, c);
159 if (starti == endi || endi==-1) {
160 new_indenting = g_strdup("\n");
161 } else {
162 tmp1 = buf+utf8_byteoffset_to_charsoffset_cached(buf, starti-start);
163 tmp2 = buf+utf8_byteoffset_to_charsoffset_cached(buf, endi-start);
164 /*tmp1 = g_utf8_offset_to_pointer(buf, starti-start);
165 tmp2 = g_utf8_offset_to_pointer(buf, endi-start);*/
166 new_indenting = g_strndup(tmp1, (tmp2 - tmp1));
167 DEBUG_MSG("split_lines_backend, starti=%d,endi=%d, len=%d, bytes=%d, new_indenting='%s'\n", starti, endi, endi-starti, (gint) (tmp2 - tmp1),
168 new_indenting);
169 }
170 DEBUG_MSG("split_lines_backend, replace from startws=%d to endws=%d with offset %d with new indenting\n", startws, endws, coffset);
171 count = charpos - endws;
172 #ifdef DEBUGSPLIT
173 tmp1 = doc_get_chars(doc, startws + coffset, endws + coffset);
174 g_print("replace '%s' with newline + identing\n",tmp1);
175 g_free(tmp1);
176 #endif
177 doc_replace_text_backend(doc, new_indenting, startws + coffset, endws + coffset);
178 coffset += (g_utf8_strlen(new_indenting, -1) - (endws - startws));
179 DEBUG_MSG("split_lines_backend, new coffset=%d, new count=%d, set startws=%d and endws=%d\n", coffset, count, 0,charpos);
180 startws = WS_POS_UNDEFINED;
181 endws = WS_POS_UNDEFINED;
182 g_free(new_indenting);
183 }
184 if (c == '\t') {
185 count += tabsize;
186 if (startws < endws || startws==WS_POS_UNDEFINED) {
187 startws = charpos;
188 endws = charpos;
189 DEBUG_MSG("split_lines_backend, tab, set startws to %d\n", startws);
190 }
191 } else if (c == ' ') {
192 count++;
193 if (startws < endws || startws==WS_POS_UNDEFINED) {
194 startws = charpos;
195 endws = charpos;
196 DEBUG_MSG("split_lines_backend, space, set startws to %d\n", startws);
197 }
198 } else if (c == '\n') {
199 count = 0;
200 starti = charpos;
201 endws = startws = charpos + 1;
202 DEBUG_MSG("split_lines_backend, newline, set starti=%d, endws=startws=%d\n", starti, endws);
203 } else {
204 count++;
205 if (starti > endi) {
206 endi = charpos;
207 DEBUG_MSG("split_lines_backend, non-whitespace (%c) and no valid endi, set endi to %d, starti=%d\n", c<128?c:'Q',endi, starti);
208 } else if (startws >= endws && startws!=WS_POS_UNDEFINED) {
209 endws = charpos;
210 DEBUG_MSG("split_lines_backend, non-whitespace (%c) and no valid endws, set endws to %d\n", c<128?c:'Q', endws);
211 }
212 }
213 p = g_utf8_next_char(p);
214 charpos++;
215 c = g_utf8_get_char(p);
216 }
217 g_free(buf);
218 }
219
220 void
split_lines(Tdocument * doc)221 split_lines(Tdocument * doc)
222 {
223 gint start, end;
224 if (!doc_get_selection(doc, &start, &end)) {
225 start = 0;
226 end = -1;
227 }
228 doc_unre_new_group(doc);
229 split_lines_backend(doc, start, end);
230 doc_unre_new_group(doc);
231 }
232
233
234 void
rewrap_lines(Tdocument * doc)235 rewrap_lines(Tdocument * doc)
236 {
237 gint start, end, offset;
238 if (!doc_get_selection(doc, &start, &end)) {
239 start = 0;
240 end = -1;
241 }
242 doc_unre_new_group(doc);
243 offset = join_lines_backend(doc, start, end);
244 DEBUG_MSG("rewrap_lines, offset=%d\n",offset);
245 split_lines_backend(doc, start, end == -1 ? end : end+offset);
246 doc_unre_new_group(doc);
247 }
248
249 /* from spaces to tabs or from tabs to spaces */
250 void
convert_identing(Tdocument * doc,gboolean to_tabs)251 convert_identing(Tdocument * doc, gboolean to_tabs)
252 {
253 gint i = 0, wstart = 0, coffset = 0, indenting = 0, tabsize;
254 gchar *buf = doc_get_chars(doc, 0, -1);
255
256 utf8_offset_cache_reset();
257 tabsize = doc_get_tabsize(doc);
258 /*g_print("got tabsize %d\n",tabsize); */
259 doc_unre_new_group(doc);
260 while (buf[i] != '\0') {
261 switch (buf[i]) {
262 case '\n':
263 wstart = i;
264 indenting = 0;
265 break;
266 case '\t':
267 /* a tab increases to the next tab stop */
268 indenting = ((indenting / tabsize) + 1) * tabsize;
269 break;
270 case ' ':
271 indenting += 1;
272 break;
273 default:
274 if (wstart != -1 && indenting > 0 && (wstart + 1 != i)) {
275 gchar *newindent;
276 gint cstart, cend;
277 if (to_tabs) {
278 newindent = bf_str_repeat("\t", (indenting / tabsize));
279 } else {
280 newindent = bf_str_repeat(" ", indenting);
281 }
282 cstart = utf8_byteoffset_to_charsoffset_cached(buf, wstart + 1);
283 cend = utf8_byteoffset_to_charsoffset_cached(buf, i);
284 doc_replace_text_backend(doc, newindent, cstart + coffset, cend + coffset);
285 coffset += strlen(newindent) - (cend - cstart);
286 g_free(newindent);
287 }
288 wstart = -1;
289 break;
290 }
291 i++;
292 }
293 g_free(buf);
294 doc_unre_new_group(doc);
295 }
296
297 static void
convert_to_columns_backend(Tdocument * doc,gint so,gint eo,gint numcolumns,gboolean spread_horiz,const gchar * separator,const gchar * fillempty)298 convert_to_columns_backend(Tdocument * doc, gint so, gint eo, gint numcolumns, gboolean spread_horiz,
299 const gchar * separator, const gchar * fillempty)
300 {
301 gint numlines, numnewlines, i = 0, j = 0;
302 gchar *buf;
303 GList *buflist;
304 guint offset = 0, separatorlen;
305 /* get buffer */
306 buf = doc_get_chars(doc, so, eo);
307 utf8_offset_cache_reset();
308 /* buffer to list */
309 buflist = get_list_from_buffer(buf, NULL, FALSE);
310 g_free(buf);
311 /* get the number of lines */
312 numlines = g_list_length(buflist);
313 numnewlines = (0.99999999 + 1.0 * numlines / numcolumns);
314 /* g_print("float=%f, int=%d\n",0.9999+1.0*numlines/numcolumns, (int)(0.9999+1.0*numlines/numcolumns));*/
315 /*g_print("numlines=%d, numcolumns=%d, numnewlines=%d\n",numlines,numcolumns,numnewlines); */
316 separatorlen = g_utf8_strlen(separator, -1);
317 doc_unre_new_group(doc);
318 doc_replace_text_backend(doc, NULL, so, eo);
319 for (i = 0; i < numnewlines; i++) {
320 for (j = 0; j < numcolumns; j++) {
321 gchar *tmp;
322 if (spread_horiz) {
323 /*g_print("i=%d,j=%d,numcolumns=%d, insert string i*numcolumns+j %d\n",i,j,numcolumns,i*numcolumns+j); */
324 tmp = g_list_nth_data(buflist, i * numcolumns + j);
325 } else {
326 /*g_print("i=%d,j=%d,numnewlines=%d, insert string i+j*numnewlines %d\n",i,j,numnewlines,i+j*numnewlines); */
327 tmp = g_list_nth_data(buflist, i + j * numnewlines);
328 }
329 if (tmp) {
330 doc_replace_text_backend(doc, tmp, so + offset, so + offset);
331 offset += g_utf8_strlen(tmp, -1);
332 } else {
333 doc_replace_text_backend(doc, fillempty, so + offset, so + offset);
334 offset += g_utf8_strlen(fillempty, -1);
335 }
336 if (j + 1 == numcolumns) {
337 /*g_print("j=%d, numcolumns=%d, j+1==numcolumns, newline!\n",j,numcolumns); */
338 doc_replace_text_backend(doc, "\n", so + offset, so + offset);
339 offset += 1;
340 } else {
341 doc_replace_text_backend(doc, separator, so + offset, so + offset);
342 offset += separatorlen;
343 }
344 }
345
346 }
347 doc_unre_new_group(doc);
348 free_stringlist(buflist);
349 }
350
351 typedef struct {
352 Tdocument *doc;
353 GtkWidget *dialog;
354 GtkWidget *horizontally;
355 GtkWidget *separator;
356 GtkWidget *numcolumns;
357 GtkWidget *fillempty;
358 } Tconvertcolumn;
359
360 static void
convert_to_columns_lcb(GtkDialog * dialog,gint response,Tconvertcolumn * cc)361 convert_to_columns_lcb(GtkDialog * dialog, gint response, Tconvertcolumn * cc)
362 {
363 if (response == GTK_RESPONSE_ACCEPT) {
364 gint start, end;
365 const gchar *separator, *fillempty;
366
367 if (!doc_get_selection(cc->doc, &start, &end)) {
368 start = 0;
369 end = -1;
370 }
371
372 separator = gtk_entry_get_text(GTK_ENTRY(cc->separator));
373 fillempty = gtk_entry_get_text(GTK_ENTRY(cc->fillempty));
374 if (BFWIN(cc->doc->bfwin)->session->convertcolumn_separator)
375 g_free(BFWIN(cc->doc->bfwin)->session->convertcolumn_separator);
376 if (BFWIN(cc->doc->bfwin)->session->convertcolumn_fillempty)
377 g_free(BFWIN(cc->doc->bfwin)->session->convertcolumn_fillempty);
378 BFWIN(cc->doc->bfwin)->session->convertcolumn_separator = g_strdup(separator);
379 BFWIN(cc->doc->bfwin)->session->convertcolumn_fillempty = g_strdup(fillempty);
380 BFWIN(cc->doc->bfwin)->session->convertcolumn_horizontally =
381 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc->horizontally));
382
383 convert_to_columns_backend(cc->doc, start, end,
384 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cc->numcolumns)),
385 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cc->horizontally)),
386 separator, fillempty);
387 }
388 gtk_widget_destroy(cc->dialog);
389 g_free(cc);
390 }
391
392 void
convert_to_columns(Tdocument * doc)393 convert_to_columns(Tdocument * doc)
394 {
395 Tconvertcolumn *cc;
396 GtkWidget *content_area, *hbox, *table;
397
398 cc = g_new0(Tconvertcolumn, 1);
399 cc->doc = doc;
400 cc->dialog = gtk_dialog_new_with_buttons(_("Lines into columns"),
401 GTK_WINDOW(BFWIN(doc->bfwin)->main_window),
402 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL,
403 GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
404 g_signal_connect(G_OBJECT(cc->dialog), "response", G_CALLBACK(convert_to_columns_lcb), cc);
405 window_delete_on_escape(GTK_WINDOW(cc->dialog));
406 gtk_container_set_border_width(GTK_CONTAINER(cc->dialog), 10);
407 content_area = gtk_dialog_get_content_area(GTK_DIALOG(cc->dialog));
408 gtk_box_set_spacing(GTK_BOX(content_area), 10);
409
410 cc->numcolumns = spinbut_with_value("2", 2, 99, 1, 5);
411 hbox = gtk_hbox_new(FALSE, 5);
412 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Number of columns:")), FALSE, FALSE, 0);
413 gtk_box_pack_start(GTK_BOX(hbox), cc->numcolumns, FALSE, FALSE, 0);
414 gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0);
415 cc->horizontally =
416 boxed_checkbut_with_value(_("Spread lines horizontally"),
417 BFWIN(cc->doc->bfwin)->session->convertcolumn_horizontally, content_area);
418
419 table = dialog_table_in_vbox_defaults(2, 2, 0, content_area);
420
421 cc->separator =
422 dialog_entry_in_table(BFWIN(cc->doc->bfwin)->session->convertcolumn_separator, table, 1, 2, 0, 1);
423 dialog_mnemonic_label_in_table(_("Column separator:"), cc->separator, table, 0, 1, 0, 1);
424
425 cc->fillempty =
426 dialog_entry_in_table(BFWIN(cc->doc->bfwin)->session->convertcolumn_fillempty, table, 1, 2, 1, 2);
427 dialog_mnemonic_label_in_table(_("Fill empty entries:"), cc->separator, table, 0, 1, 1, 2);
428
429 gtk_widget_show_all(cc->dialog);
430 }
431
432 void
select_current_identifier(Tdocument * doc)433 select_current_identifier(Tdocument *doc)
434 {
435 GtkTextIter cursor, so, eo;
436 gtk_text_buffer_get_iter_at_mark(doc->buffer, &cursor, gtk_text_buffer_get_insert(doc->buffer));
437 if (bluefish_text_view_get_active_identifier(BLUEFISH_TEXT_VIEW(doc->view), &cursor, &so, &eo)) {
438 gtk_text_buffer_select_range(doc->buffer, &so, &eo);
439 }
440 }
441
442 void
select_between_matching_block_boundaries(Tdocument * doc)443 select_between_matching_block_boundaries(Tdocument *doc)
444 {
445 GtkTextIter so,eo;
446 static gboolean innerblock=FALSE;
447 GtkTextIter cursor;
448 guint offset;
449 /* if we do not have a selection we start with innerblock is true, in all other
450 cases we just revert innerblock */
451 if (!gtk_text_buffer_get_has_selection(doc->buffer)) {
452 innerblock = TRUE;
453 } else {
454 innerblock = !innerblock;
455 }
456
457 gtk_text_buffer_get_iter_at_mark(doc->buffer, &cursor, gtk_text_buffer_get_insert(doc->buffer));
458 DEBUG_MSG("select_between_matching_block_boundaries, innerblock=%d, location=%d\n", innerblock, gtk_text_iter_get_offset(&cursor));
459 offset = gtk_text_iter_get_offset(&cursor);
460 if (!bluefish_text_view_get_active_block_boundaries(BLUEFISH_TEXT_VIEW(doc->view),
461 offset, innerblock, &so, &eo)) {
462 DEBUG_MSG("select_between_matching_block_boundaries, no block, return\n");
463 return;
464 }
465 if (innerblock && gtk_text_iter_equal(&so, &eo)) {
466 DEBUG_MSG("select_between_matching_block_boundaries, iters are equal, request innerblock=FALSE\n");
467 innerblock = FALSE;
468 if (!bluefish_text_view_get_active_block_boundaries(BLUEFISH_TEXT_VIEW(doc->view),
469 offset, innerblock, &so, &eo)) {
470 DEBUG_MSG("select_between_matching_block_boundaries, innerblock=FALSE, no block, return\n");
471 return;
472 }
473 }
474 gtk_text_buffer_select_range(doc->buffer, &so, &eo);
475 }
476
477 void
duplicate_line(Tdocument * doc)478 duplicate_line(Tdocument *doc)
479 {
480 GtkTextIter it1, it2;
481 gchar *text;
482 gtk_text_buffer_get_iter_at_mark(doc->buffer, &it1, gtk_text_buffer_get_insert(doc->buffer));
483 gtk_text_iter_set_line_offset(&it1,0);
484 it2 = it1;
485 gtk_text_iter_forward_line(&it2);
486 text = gtk_text_buffer_get_text(doc->buffer,&it1,&it2,TRUE);
487 doc_unre_new_group(doc);
488 gtk_text_buffer_insert(doc->buffer,&it2,text,-1);
489 g_free(text);
490 doc_unre_new_group(doc);
491 }
492
493 void
delete_line(Tdocument * doc)494 delete_line(Tdocument *doc)
495 {
496 GtkTextIter it1, it2;
497 gtk_text_buffer_get_iter_at_mark(doc->buffer, &it1, gtk_text_buffer_get_insert(doc->buffer));
498 gtk_text_iter_set_line_offset(&it1,0);
499 it2 = it1;
500 gtk_text_iter_forward_line(&it2);
501 doc_unre_new_group(doc);
502 gtk_text_buffer_delete(doc->buffer, &it1,&it2);
503 doc_unre_new_group(doc);
504 }
505
506 void
doc_move_selection(Tdocument * doc,gboolean up,gboolean curline_if_no_selection)507 doc_move_selection(Tdocument *doc, gboolean up, gboolean curline_if_no_selection)
508 {
509 GtkTextIter so, eo;
510 gchar *text;
511 gint offset, size;
512 if (!gtk_text_buffer_get_selection_bounds(doc->buffer, &so, &eo)) {
513 DEBUG_MSG("doc_move_selection, no selection, select the current line!\n");
514 if (curline_if_no_selection) {
515 gtk_text_buffer_get_iter_at_mark(doc->buffer,&so,gtk_text_buffer_get_insert(doc->buffer));
516 eo = so;
517 } else {
518 return;
519 }
520 }
521 /* so and eo are guaranteed to be in ascending order */
522 if (gtk_text_iter_equal(&so, &eo)) {
523 gtk_text_iter_forward_char(&eo);
524 }
525 if (!gtk_text_iter_starts_line(&so))
526 gtk_text_iter_set_line_offset(&so, 0);
527 if (!gtk_text_iter_starts_line(&eo))
528 gtk_text_iter_forward_line(&eo);
529
530 doc_unre_new_group(doc);
531 doc_block_undo_reg(doc);
532
533 offset = gtk_text_iter_get_offset(&so);
534 DEBUG_MSG("start moving text from %d:%d\n",gtk_text_iter_get_offset(&so),gtk_text_iter_get_offset(&eo));
535 size = gtk_text_iter_get_offset(&eo)-offset;
536 text = gtk_text_buffer_get_text(doc->buffer,&so,&eo,TRUE);
537 /*g_print("doc_move_selection, got selection %d:%d\n",offset,offset+size);*/
538 gtk_text_buffer_delete(doc->buffer, &so, &eo);
539 doc_unre_add(doc, text, offset, offset+size, UndoDelete);
540
541 /* now we have to move the cursor up,
542 because we changed the text we invalidated all iters, so get them again */
543 gtk_text_buffer_get_iter_at_offset(doc->buffer, &so, offset);
544 if (up) {
545 gtk_text_iter_backward_line(&so);
546 DEBUG_MSG("UP -> new start location is at %d\n",gtk_text_iter_get_offset(&so));
547 } else {
548 gtk_text_iter_forward_line(&so);
549 DEBUG_MSG("DOWN -> new start location is at %d\n",gtk_text_iter_get_offset(&so));
550 }
551 offset = gtk_text_iter_get_offset(&so);
552 gtk_text_buffer_insert(doc->buffer,&so,text,-1);
553 doc_unre_add(doc, text, offset, offset+size, UndoInsert);
554 g_free(text);
555
556 doc_unblock_undo_reg(doc);
557 doc_set_modified(doc, 1);
558 doc_unre_new_group(doc);
559
560 /* and select the text again */
561 DEBUG_MSG("doc_move_selection, select %d:%d\n",offset,offset+size);
562 gtk_text_buffer_get_iter_at_offset(doc->buffer, &so, offset);
563 gtk_text_buffer_get_iter_at_offset(doc->buffer, &eo, offset+size);
564 DEBUG_MSG("select new location %d:%d\n",gtk_text_iter_get_offset(&so),gtk_text_iter_get_offset(&eo));
565 gtk_text_buffer_select_range(doc->buffer,&so,&eo);
566 }
567
568 void
doc_insert_filename(Tdocument * doc,gboolean relative)569 doc_insert_filename(Tdocument *doc, gboolean relative)
570 {
571 gchar *tmp, *relativeto=NULL;
572 if (relative && doc->uri) {
573 relativeto = g_file_get_uri(doc->uri);
574 }
575 tmp = run_file_select_dialog(GTK_WINDOW(BFWIN(doc->bfwin)->main_window)
576 , NULL, relativeto,GTK_FILE_CHOOSER_ACTION_OPEN);
577 if (tmp)
578 doc_insert_two_strings(doc, tmp, NULL);
579 g_free(relativeto);
580 g_free(tmp);
581 }
582