1 /* Bluefish HTML Editor
2 * doc_comments.c - toggle comments
3 *
4 * Copyright (C) 2010-2012 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 "bftextview2.h"
24 #include "doc_comments.h"
25 #include "undo_redo.h"
26
27
28 static gint
add_line_comment(Tdocument * doc,const gchar * commentstring,gint start,gint end)29 add_line_comment(Tdocument *doc, const gchar *commentstring, gint start, gint end) {
30 gint i=0,coffset=0,commentstring_len;
31 gchar *buf;
32
33 if (start!=0)
34 start--; /* include a possible newline character if
35 the selection started at te first character of a line */
36
37 commentstring_len = g_utf8_strlen(commentstring,-1);
38
39 buf = doc_get_chars(doc,start,end);
40 utf8_offset_cache_reset();
41
42 doc_unre_new_group(doc);
43 while (buf[i] != '\0') {
44 if (i==0 || (buf[i]=='\n' && buf[i+1]!='\0')) {
45 gint cstart;
46 cstart = utf8_byteoffset_to_charsoffset_cached(buf, i+1);
47 doc_replace_text_backend(doc, commentstring, coffset+start+cstart, coffset+start+cstart);
48 coffset += commentstring_len;
49 }
50 i++;
51 }
52 g_free(buf);
53 doc_unre_new_group(doc);
54 return coffset;
55 }
56
remove_line_comment(Tdocument * doc,const gchar * buf,const gchar * commentstring,gint start,gint end)57 static void remove_line_comment(Tdocument *doc, const gchar *buf, const gchar *commentstring, gint start, gint end) {
58 gint commentstring_len,i=0,coffset;
59 gboolean newline;
60
61 commentstring_len=strlen(commentstring);
62 doc_unre_new_group(doc);
63 coffset=start;
64 newline=TRUE;
65 while (buf[i] != '\0') {
66 if (buf[i]=='\n') {
67 newline=TRUE;
68 } else if (newline) {
69 if (strncmp(&buf[i], commentstring, commentstring_len)==0) {
70 gint cstart = utf8_byteoffset_to_charsoffset_cached(buf, i);
71 doc_replace_text_backend(doc, NULL, coffset+cstart, coffset+cstart+commentstring_len);
72 coffset -= commentstring_len;
73 }
74 newline=FALSE;
75 }
76 i++;
77 }
78 doc_unre_new_group(doc);
79 }
80
add_block_comment(Tdocument * doc,const gchar * so_commentstring,const gchar * eo_commentstring,gint start,gint end)81 static void add_block_comment(Tdocument *doc, const gchar *so_commentstring, const gchar *eo_commentstring, gint start, gint end) {
82 gint offset;
83
84 doc_unre_new_group(doc);
85
86 doc_replace_text_backend(doc, so_commentstring, start, start);
87 offset = g_utf8_strlen(so_commentstring,-1);
88 doc_replace_text_backend(doc, eo_commentstring, end+offset, end+offset);
89
90 doc_unre_new_group(doc);
91 }
92
remove_block_comment(Tdocument * doc,const gchar * buf,const gchar * so_commentstring,const gchar * eo_commentstring,gint start,gint end)93 static void remove_block_comment(Tdocument *doc, const gchar *buf, const gchar *so_commentstring, const gchar *eo_commentstring, gint start, gint end) {
94 gint i=0,n=0,coffset,eo_commentstring_len;
95 gint so=0;
96 gint cstart,cend;
97
98 /* first see if there is an start-of-block */
99 coffset=start;
100
101 while (buf[i] != '\0') {
102 if (n==0 && (buf[i]==' '||buf[i]=='\n'||buf[i]=='\t')) {
103 /* do nothing */
104 } else if (buf[i]==so_commentstring[n]) {
105 if (n==0)
106 so=i;
107 n++;
108 if (so_commentstring[n]=='\0') {
109 /* we found the end of the start-of-comment string */
110 break;
111 }
112 } else {
113 n=0;
114 break;
115 }
116 i++;
117 }
118 if (n != strlen(so_commentstring)) {
119 return;
120 }
121
122 doc_unre_new_group(doc);
123 cstart = utf8_byteoffset_to_charsoffset_cached(buf, so);
124 cend = cstart+strlen(so_commentstring);
125 DEBUG_MSG("remove_block_comment, remove start-of-comment %d:%d\n",coffset+cstart, coffset+cend);
126 doc_replace_text_backend(doc, NULL, coffset+cstart, coffset+cend);
127 coffset -= (cend-cstart);
128
129 /* now find the end-of-block */
130 i=strlen(buf)-1;
131 eo_commentstring_len = strlen(eo_commentstring)-1;
132 n=eo_commentstring_len;
133 while (i>=0) {
134 if (n==eo_commentstring_len && (buf[i]==' '||buf[i]=='\n'||buf[i]=='\t')) {
135 /* do nothing */
136 } else if (buf[i]==eo_commentstring[n]) {
137 if (n==eo_commentstring_len) {
138 /*eo=n+1;*/
139 /* we found the end of the end-of-comment string */
140 }
141 if (n==0) {
142 so = i;
143 break;
144 }
145 n--;
146 } else {
147 break;
148 }
149 i--;
150 }
151 if (n==0) {
152 cstart = utf8_byteoffset_to_charsoffset_cached(buf, so);
153 cend = cstart+strlen(eo_commentstring);
154 DEBUG_MSG("remove_block_comment, remove end-of-comment %d:%d\n",coffset+cstart, coffset+cend);
155 doc_replace_text_backend(doc, NULL, coffset+cstart, coffset+cend);
156 }
157
158 doc_unre_new_group(doc);
159 }
160
toggle_comment(Tdocument * doc)161 void toggle_comment(Tdocument *doc) {
162 GtkTextIter its,ite;
163 gboolean ret;
164
165 ret = bluefish_text_view_in_comment(BLUEFISH_TEXT_VIEW(doc->view), &its, &ite);
166 if (ret) { /* remove comment */
167 gchar *buf;
168 gint i=0;
169 buf = gtk_text_buffer_get_text(doc->buffer, &its, &ite, FALSE);
170 DEBUG_MSG("toggle_comment, remove comment\n");
171 while (g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).so) {
172 if (strncmp(g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).so
173 , buf
174 , strlen(g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).so)
175 )==0) {
176 if (g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).type == comment_type_block)
177 remove_block_comment(doc, buf, g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).so
178 , g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).eo
179 , gtk_text_iter_get_offset(&its),gtk_text_iter_get_offset(&ite));
180 else
181 remove_line_comment(doc, buf, g_array_index(BLUEFISH_TEXT_VIEW(doc->view)->bflang->st->comments, Tcomment, i).so
182 , gtk_text_iter_get_offset(&its),gtk_text_iter_get_offset(&ite));
183 break;
184 }
185 i++;
186 }
187 g_free(buf);
188 } else { /* add comment */
189 gboolean sameline, selection=FALSE;
190 gint offsets,offsete,extraoffset=0;
191 Tcomment *comment;
192 DEBUG_MSG("toggle_comment, add comment\n");
193 if (gtk_text_buffer_get_has_selection(doc->buffer)) {
194 sameline = gtk_text_iter_get_line(&its)==gtk_text_iter_get_line(&ite);
195 selection=TRUE;
196 } else {
197 gtk_text_iter_set_line_offset(&its,0);
198 if (!gtk_text_iter_ends_line(&ite)) {
199 gtk_text_iter_forward_to_line_end(&ite);
200 }
201 sameline = TRUE;
202 }
203 comment = bluefish_text_view_get_comment(BLUEFISH_TEXT_VIEW(doc->view), &its, sameline?comment_type_line:comment_type_block);
204 DEBUG_MSG("toggle_comment, comment=%p\n",comment);
205 if (!comment)
206 return;
207 offsets = gtk_text_iter_get_offset(&its);
208 offsete = gtk_text_iter_get_offset(&ite);
209 DEBUG_MSG("got comment with type %d, so=%s\n",comment->type, comment->so);
210 if (comment->type == comment_type_line) {
211 extraoffset = add_line_comment(doc, comment->so, offsets,offsete);
212 /*extraoffset = strlen(comment->so);*/
213 } else {
214 add_block_comment(doc, comment->so, comment->eo, gtk_text_iter_get_offset(&its), gtk_text_iter_get_offset(&ite));
215 extraoffset = strlen(comment->so) + strlen(comment->eo);
216 }
217 if (selection) {
218 /* the buffer has changes, so we have to re-set the iters from the offsets */
219 gtk_text_buffer_get_iter_at_offset(doc->buffer, &its, offsets);
220 gtk_text_buffer_get_iter_at_offset(doc->buffer, &ite, offsete+extraoffset);
221 DEBUG_MSG("toggle_comment, reset selection to %d:%d\n", gtk_text_iter_get_offset(&its), gtk_text_iter_get_offset(&ite));
222 gtk_text_buffer_select_range(doc->buffer,&its,&ite);
223 }
224 }
225 }
226