message-view: bgo #727634 - Cannot copy build output
[anjuta.git] / libanjuta / anjuta-modeline.c
blob45eb51490b57da341b6e75294357d7be00c94803
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-modeline.c
4 * Copyright (C) Sébastien Granjoux 2013 <seb.sfo@free.fr>
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 /**
21 * SECTION:anjuta-modeline
22 * @short_description: Parse editor mode line
23 * @see_also:
24 * @stability: Unstable
25 * @include: libanjuta/anjuta-modeline.h
29 #include "anjuta-modeline.h"
31 #include "anjuta-debug.h"
33 #include <glib-object.h>
35 #include <stdlib.h>
36 #include <string.h>
38 /* Types declarations
39 *---------------------------------------------------------------------------*/
41 enum {
42 SET_USE_SPACES = 1 << 0,
43 SET_STATEMENT_INDENTATION = 1 << 1,
44 SET_TAB_SIZE = 1 << 2,
45 CHECK_NEXT = 1 << 4
48 typedef struct {
49 gint settings;
51 gint use_spaces;
52 gint statement_indentation;
53 gint tab_size;
54 } IndentationParams;
57 /* Helpers functions
58 *---------------------------------------------------------------------------*/
60 /* Private functions
61 *---------------------------------------------------------------------------*/
63 static gchar *
64 get_editor_line (IAnjutaEditor *editor, gint line)
66 IAnjutaIterable *start;
67 IAnjutaIterable *end;
68 gchar *content = NULL;
70 if (line < 0)
72 gint last;
74 end = ianjuta_editor_get_end_position(editor, NULL);
75 last = ianjuta_editor_get_line_from_position (editor, end, NULL);
76 line = last + line;
77 g_object_unref (end);
79 if (line > 0)
81 start = ianjuta_editor_get_line_begin_position (editor, line, NULL);
82 end = ianjuta_editor_get_line_end_position (editor, line, NULL);
83 content = ianjuta_editor_get_text (editor, start, end, NULL);
84 g_object_unref (start);
85 g_object_unref (end);
88 return content;
91 static void
92 set_vim_params (IndentationParams *params, const gchar *key, const gchar *value)
94 //DEBUG_PRINT ("Setting indent param: %s = %s", key, value);
95 if ((strcmp (key, "expandtab") == 0) ||
96 (strcmp (key, "et") == 0))
98 params->use_spaces = 1;
99 params->settings |= SET_USE_SPACES;
101 else if ((strcmp (key, "noexpandtab") == 0) ||
102 (strcmp (key, "noet") == 0))
104 params->use_spaces = 0;
105 params->settings |= SET_USE_SPACES;
107 else if ((strcmp (key, "shiftwidth") == 0) ||
108 (strcmp (key, "sw") == 0))
110 params->statement_indentation = atoi (value);
111 params->settings |= SET_STATEMENT_INDENTATION;
113 else if ((strcmp (key, "softtabstop") == 0) ||
114 (strcmp (key, "sts") == 0) ||
115 (strcmp (key, "tabstop") == 0) ||
116 (strcmp (key, "ts") == 0))
118 params->tab_size = atoi (value);
119 params->settings |= SET_TAB_SIZE;
123 static gboolean
124 parse_vim_modeline (IndentationParams *params, const gchar *line, gint linenum)
126 gchar *ptr;
127 gchar *end;
128 gchar *key;
129 gchar *value;
131 /* Check the first 5 and last 5 lines */
132 if ((linenum < -5) || (linenum == 0) || (linenum > 5))
134 return FALSE;
137 ptr = strstr (line, "vim:");
138 if (ptr == NULL)
140 if ((linenum != -5) && (linenum != 5)) params->settings = CHECK_NEXT;
141 return FALSE;
143 ptr += 4;
144 while (g_ascii_isspace (*ptr)) ptr++;
145 if (strncmp (ptr, "set", 3) != 0)
147 if ((linenum != -5) && (linenum != 5)) params->settings = CHECK_NEXT;
148 return FALSE;
150 ptr += 3;
152 for (end = ptr;; end++)
154 if ((*end == ':') && (*(end-1) != '\\')) break;
156 *end = '\0';
158 while (*ptr != '\0')
160 gchar sep;
162 while (g_ascii_isspace (*ptr)) ptr++;
163 if (*ptr == '\0') break;
165 /* Get key */
166 key = ptr++;
167 value = NULL;
168 while ((*ptr != '\0') && (*ptr != '=') && !g_ascii_isspace(*ptr)) ptr++;
169 sep = *ptr;
170 *ptr = '\0';
172 if (sep == '=')
174 /* Get value */
175 value = ++ptr;
176 while ((*ptr != '\0') && !g_ascii_isspace(*ptr)) ptr++;
177 sep = *ptr;
178 *ptr = '\0';
180 if (sep != '\0') ptr++;
183 set_vim_params (params, key, value);
186 return TRUE;
189 static void
190 set_emacs_params (IndentationParams *params, const gchar *key, const gchar *value)
192 //DEBUG_PRINT ("Setting indent param: %s = %s", key, value);
193 if (strcmp (key, "indent-tabs-mode") == 0)
195 if (strcmp (value, "t") == 0)
197 params->use_spaces = 0;
198 params->settings |= SET_USE_SPACES;
200 else if (strcmp (value, "nil") == 0)
202 params->use_spaces = 1;
203 params->settings |= SET_USE_SPACES;
206 else if ((strcmp (key, "c-basic-offset") == 0) ||
207 (strcmp (key, "indent-offset") == 0))
209 params->statement_indentation = atoi (value);
210 params->settings |= SET_STATEMENT_INDENTATION;
212 else if (strcasecmp (key, "tab-width") == 0)
214 params->tab_size = atoi (value);
215 params->settings |= SET_TAB_SIZE;
219 static gboolean
220 parse_emacs_modeline (IndentationParams *params, gchar *line, gint linenum)
222 gchar *ptr;
223 gchar *end;
224 gchar *key;
225 gchar *value;
227 if (linenum == 1)
229 /* If first line is a shebang, check second line */
230 if ((line[0] == '#') && (line[1] =='!'))
232 params->settings |= CHECK_NEXT;
233 return FALSE;
236 else if (linenum != 2)
238 /* Check only the 2 first lines */
239 return FALSE;
242 ptr = strstr (line, "-*-");
243 if (ptr == NULL) return FALSE;
244 ptr += 3;
245 end = strstr (ptr, "-*-");
246 if (end == NULL) return FALSE;
247 *end = '\0';
249 while (*ptr != '\0')
251 gchar sep;
253 while (g_ascii_isspace (*ptr)) ptr++;
254 if (*ptr == '\0') break;
256 /* Get key */
257 key = ptr++;
258 value = NULL;
259 while ((*ptr != '\0') && (*ptr != ':') && (*ptr != ';')) ptr++;
260 sep = *ptr;
262 end = ptr - 1;
263 while (g_ascii_isspace (*end)) end--;
264 *(end + 1) = '\0';
266 if (sep == ':')
268 /* Get value */
269 ptr++;
270 while (g_ascii_isspace (*ptr)) ptr++;
271 if (*ptr != '\0')
273 value = ptr;
274 while ((*ptr != '\0') && (*ptr != ';')) ptr++;
275 sep = *ptr;
277 end = ptr - 1;
278 while (g_ascii_isspace (*end)) end--;
279 *(end + 1) = '\0';
281 if (sep == ';') ptr++;
285 set_emacs_params (params, key, value);
288 return TRUE;
292 static gboolean
293 set_indentation (IAnjutaEditor *editor, IndentationParams *params)
295 if (params->settings == 0) return FALSE;
297 if (params->settings & SET_USE_SPACES)
298 ianjuta_editor_set_use_spaces (editor, params->use_spaces, NULL);
300 if (params->settings & SET_STATEMENT_INDENTATION)
301 ianjuta_editor_set_indentsize (editor, params->statement_indentation, NULL);
303 if (params->settings & SET_TAB_SIZE)
304 ianjuta_editor_set_tabsize (editor, params->tab_size, NULL);
306 return TRUE;
310 /* Public functions
311 *---------------------------------------------------------------------------*/
315 * anjuta_apply_modeline:
316 * @editor: #IAnjutaEditor object
318 * Check the editor buffer to find a mode line and update the indentation
319 * settings if found.
321 * The mode line is special line used by the text editor to define settings for
322 * the current file, typically indentation. Anjuta currently recognize two kinds
323 * of mode line:
325 * Emacs mode line, on the first or the second line if the first one is a
326 * shebang (#!) with the following format:
327 * -*- key1: value1; key2: value2 -*-
329 * Vim mode line, one the first 5 or the last 5 lines with the following format:
330 * vim:set key1=value1 key2=value2
332 * Returns: %TRUE if a mode line has been found and applied.
334 gboolean
335 anjuta_apply_modeline (IAnjutaEditor *editor)
337 IndentationParams params = {CHECK_NEXT,0,0,0};
338 gint line;
339 gchar *content = NULL;
341 g_return_val_if_fail (IANJUTA_IS_EDITOR (editor), FALSE);
343 /* Check the first lines */
344 for (line = 1; params.settings == CHECK_NEXT; line++)
346 g_free (content);
347 content = get_editor_line (editor, line);
348 if (content == NULL) return FALSE;
350 params.settings = 0;
351 if (parse_vim_modeline (&params, content, line)) break;
352 if (parse_emacs_modeline (&params, content, line)) break;
355 /* Check the last lines */
356 if (params.settings == 0) params.settings = CHECK_NEXT;
357 for (line = -1;params.settings == CHECK_NEXT; line--)
359 g_free (content);
360 content = get_editor_line (editor, line);
361 if (content == NULL) return FALSE;
363 params.settings = 0;
364 if (parse_vim_modeline (&params, content, line)) break;
365 if (parse_emacs_modeline (&params, content, line)) break;
367 g_free (content);
369 /* Set indentation settings */
370 return set_indentation (editor, &params);