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