1 /*
2 * marker-source-view.c
3 *
4 * Copyright (C) 2017 - 2018 Fabio Colacio
5 *
6 * Marker is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * Marker 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 GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with Marker; see the file LICENSE.md. If not,
18 * see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "marker-source-view.h"
26 #include "marker-prefs.h"
27 #include "marker-utils.h"
28
29 #include <glib.h>
30 #include <gtkspell/gtkspell.h>
31
32 struct _MarkerSourceView
33 {
34 GtkSourceView parent_instance;
35 GSettings *settings;
36 GtkSpellChecker *spell;
37 GtkSourceSearchContext *search_context;
38 };
39
G_DEFINE_TYPE(MarkerSourceView,marker_source_view,GTK_SOURCE_TYPE_VIEW)40 G_DEFINE_TYPE(MarkerSourceView, marker_source_view, GTK_SOURCE_TYPE_VIEW)
41
42 void
43 marker_source_view_surround_selection_with (MarkerSourceView *source_view,
44 const char *insertion)
45 {
46 GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
47 GtkTextIter start, end;
48 gint start_index, end_index, selection_len;
49 gboolean selected;
50 size_t len = strlen (insertion);
51
52 selected = gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
53
54 start_index = gtk_text_iter_get_line_offset (&start);
55 end_index = gtk_text_iter_get_line_offset (&end);
56 selection_len = end_index - start_index;
57
58 gtk_text_buffer_insert (buffer, &start, insertion, len);
59 gtk_text_iter_forward_chars (&start, selection_len);
60 gtk_text_buffer_insert (buffer, &start, insertion, len);
61
62 if (!selected)
63 {
64 gtk_text_iter_backward_chars (&start, len);
65 gtk_text_buffer_place_cursor (buffer, &start);
66 }
67 }
68
69 void
marker_source_view_insert_link(MarkerSourceView * source_view)70 marker_source_view_insert_link (MarkerSourceView *source_view)
71 {
72 GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
73 GtkTextIter start, end;
74 gint start_index, end_index, selection_len;
75 gboolean selected;
76
77 selected = gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
78 if (selected) {
79 start_index = gtk_text_iter_get_line_offset (&start);
80 end_index = gtk_text_iter_get_line_offset (&end);
81 selection_len = end_index - start_index;
82
83 gchar * selected = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
84 if (!marker_utils_is_url(selected)) {
85 gtk_text_buffer_insert (buffer, &start, "[", 1);
86 gtk_text_iter_forward_chars (&start, selection_len);
87 gtk_text_buffer_insert (buffer, &start, "]()", 3);
88 gtk_text_iter_backward_chars(&start, 1);
89 gtk_text_buffer_place_cursor(buffer, &start);
90
91 } else {
92 gtk_text_buffer_insert (buffer, &start, "[](", 3);
93 gtk_text_iter_forward_chars (&start, selection_len);
94 gtk_text_buffer_insert (buffer, &start, ")", 1);
95 gtk_text_iter_backward_chars(&start, selection_len + 3);
96 gtk_text_buffer_place_cursor(buffer, &start);
97 }
98 } else {
99 gchar * link = g_strdup("[]()");
100 GtkTextMark * mark = gtk_text_buffer_get_insert(buffer);
101 gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);
102 size_t len = strlen(link);
103
104 gtk_text_buffer_insert(buffer, &start, link, len);
105 gtk_text_iter_backward_chars(&start, 3);
106 gtk_text_buffer_place_cursor(buffer, &start);
107 g_free(link);
108 }
109 }
110
111 void
marker_source_view_insert_image(MarkerSourceView * source_view,const char * image_path)112 marker_source_view_insert_image (MarkerSourceView *source_view,
113 const char *image_path)
114 {
115 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
116 GtkTextIter start ;
117
118 gtk_text_buffer_get_iter_at_mark(buffer, &start, gtk_text_buffer_get_insert(buffer));
119
120 gchar * img = g_strdup_printf("![](%s)", image_path);
121
122 size_t len = strlen(img);
123
124 gtk_text_buffer_insert(buffer, &start, img, len);
125 g_free(img);
126 }
127
128 void
marker_source_view_set_spell_check(MarkerSourceView * source_view,gboolean state)129 marker_source_view_set_spell_check(MarkerSourceView *source_view,
130 gboolean state)
131 {
132 g_assert (MARKER_IS_SOURCE_VIEW (source_view));
133
134 gboolean is_attached =
135 source_view->spell == gtk_spell_checker_get_from_text_view (GTK_TEXT_VIEW (source_view));
136
137 if (state && !is_attached)
138 {
139 gtk_spell_checker_attach((GtkSpellChecker*)source_view->spell, GTK_TEXT_VIEW(source_view));
140 }
141 else if (!state && is_attached)
142 {
143 g_object_ref (source_view->spell);
144 gtk_spell_checker_detach((GtkSpellChecker*)source_view->spell);
145 }
146 }
147
148 void
marker_source_view_set_spell_check_lang(MarkerSourceView * source_view,const gchar * lang)149 marker_source_view_set_spell_check_lang (MarkerSourceView *source_view,
150 const gchar *lang)
151 {
152 g_assert (MARKER_IS_SOURCE_VIEW (source_view));
153 gtk_spell_checker_set_language (source_view->spell, lang, NULL);
154 }
155
156 void
marker_source_view_set_syntax_theme(MarkerSourceView * source_view,const char * theme)157 marker_source_view_set_syntax_theme(MarkerSourceView* source_view,
158 const char* theme)
159 {
160 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
161 GtkSourceStyleSchemeManager* style_manager =
162 gtk_source_style_scheme_manager_get_default();
163 GtkSourceStyleScheme* scheme =
164 gtk_source_style_scheme_manager_get_scheme(style_manager, theme);
165 gtk_source_buffer_set_style_scheme(GTK_SOURCE_BUFFER(buffer), scheme);
166 }
167
168 gboolean
marker_source_view_get_modified(MarkerSourceView * source_view)169 marker_source_view_get_modified(MarkerSourceView* source_view)
170 {
171 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
172 return gtk_text_buffer_get_modified(buffer);
173 }
174
175 void
marker_source_view_set_modified(MarkerSourceView * source_view,gboolean modified)176 marker_source_view_set_modified(MarkerSourceView* source_view,
177 gboolean modified)
178 {
179 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
180 gtk_text_buffer_set_modified(buffer, modified);
181 }
182
183 gchar*
marker_source_view_get_text(MarkerSourceView * source_view,gboolean include_position)184 marker_source_view_get_text(MarkerSourceView* source_view,
185 gboolean include_position)
186 {
187 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
188 GtkTextIter start, end;
189 gtk_text_buffer_get_start_iter(buffer, &start);
190 gtk_text_buffer_get_end_iter(buffer, &end);
191 if (include_position && !gtk_text_iter_equal(&start, &end)) {
192 gchar * identifier = g_strdup("<span id=\"cursor_pos\"></span>");
193 GtkTextIter pos;
194 gtk_text_buffer_get_selection_bounds (buffer, &pos, NULL);
195 gchar * beginning = gtk_text_buffer_get_text(buffer, &start, &pos, FALSE);
196 gchar * ending = gtk_text_buffer_get_text(buffer, &pos, &end, FALSE);
197 return g_strconcat(beginning, identifier, ending, NULL);
198 }
199 return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
200 }
201
202 int
marker_source_view_get_cursor_position(MarkerSourceView * source_view)203 marker_source_view_get_cursor_position (MarkerSourceView *source_view)
204 {
205 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
206 GtkTextIter pos;
207 gtk_text_buffer_get_selection_bounds (buffer, &pos, NULL);
208 return gtk_text_iter_get_offset(&pos);
209 }
210
211
212 void
marker_source_view_set_text(MarkerSourceView * source_view,const char * text,size_t size)213 marker_source_view_set_text(MarkerSourceView* source_view,
214 const char* text,
215 size_t size)
216 {
217 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view));
218 gtk_text_buffer_set_text(buffer, text, size);
219 }
220
221 void
marker_source_view_set_language(MarkerSourceView * source_view,const gchar * language_name)222 marker_source_view_set_language(MarkerSourceView* source_view,
223 const gchar* language_name)
224 {
225 if (GTK_SOURCE_IS_VIEW(source_view))
226 {
227 GtkSourceLanguageManager* manager =
228 gtk_source_language_manager_get_default();
229
230 GtkSourceLanguage* language =
231 gtk_source_language_manager_get_language(manager, language_name);
232
233 GtkSourceBuffer* buffer =
234 GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view)));
235
236 gtk_source_buffer_set_language(buffer, language);
237
238 g_object_unref(manager);
239 }
240 }
241
242 static void
default_font_changed(GSettings * settings,const gchar * key,gpointer user_data)243 default_font_changed(GSettings* settings,
244 const gchar* key,
245 gpointer user_data)
246 {
247 MarkerSourceView* source_view = (MarkerSourceView*) user_data;
248 gchar* fontname = g_settings_get_string(settings, key);
249 PangoFontDescription* font = pango_font_description_from_string(fontname);
250 gtk_widget_modify_font(GTK_WIDGET(source_view), font);
251 pango_font_description_free(font);
252 g_free(fontname);
253 }
254
255 static void
marker_source_view_init(MarkerSourceView * source_view)256 marker_source_view_init (MarkerSourceView *source_view)
257 {
258 GtkSourceSearchContext * search_context = gtk_source_search_context_new(GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(source_view))),
259 NULL);
260 source_view->search_context = search_context;
261 marker_source_view_set_language (source_view, "markdown");
262 source_view->settings = g_settings_new ("org.gnome.desktop.interface");
263 g_signal_connect (source_view->settings, "changed::monospace-font-name", G_CALLBACK (default_font_changed), source_view);
264 gchar *fontname = g_settings_get_string (source_view->settings, "monospace-font-name");
265 PangoFontDescription* font = pango_font_description_from_string (fontname);
266 gtk_widget_modify_font (GTK_WIDGET (source_view), font);
267 pango_font_description_free (font);
268 g_free (fontname);
269
270 gtk_source_view_set_insert_spaces_instead_of_tabs (GTK_SOURCE_VIEW (source_view), marker_prefs_get_replace_tabs ());
271 gtk_source_view_set_tab_width (GTK_SOURCE_VIEW (source_view), marker_prefs_get_tab_width ());
272 gtk_source_view_set_auto_indent (GTK_SOURCE_VIEW (source_view), marker_prefs_get_auto_indent ());
273
274 source_view->spell = gtk_spell_checker_new ();
275 gchar* lang = marker_prefs_get_spell_check_language();
276 gtk_spell_checker_set_language (source_view->spell, lang, NULL);
277 if (marker_prefs_get_spell_check ()){
278 gtk_spell_checker_attach (source_view->spell, GTK_TEXT_VIEW (source_view));
279 }
280 }
281
282 static void
marker_source_view_class_init(MarkerSourceViewClass * class)283 marker_source_view_class_init(MarkerSourceViewClass* class)
284 {
285
286 }
287
288 MarkerSourceView*
marker_source_view_new(void)289 marker_source_view_new(void)
290 {
291 return g_object_new(MARKER_TYPE_SOURCE_VIEW, NULL);
292 }
293
294 GtkSourceSearchContext*
marker_source_get_search_context(MarkerSourceView * source_view)295 marker_source_get_search_context (MarkerSourceView *source_view)
296 {
297 return source_view->search_context;
298 }
299