girara
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
config.c
Go to the documentation of this file.
1 /* See LICENSE file for license and copyright information */
2 
3 #include <stdlib.h>
4 #include <string.h>
5 #include <glib/gi18n-lib.h>
6 
7 #include "config.h"
8 #include "commands.h"
9 #include "datastructures.h"
10 #include "internal.h"
11 #include "session.h"
12 #include "settings.h"
13 #include "shortcuts.h"
14 #include "utils.h"
15 
16 #define COMMENT_PREFIX "\"#"
17 
18 static void
19 cb_window_icon(girara_session_t* session, const char* UNUSED(name),
20  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
21 {
22  g_return_if_fail(session != NULL && value != NULL);
23 
24  if (session->gtk.window != NULL) {
25  char* path = girara_fix_path(value); // value != NULL
26 
27  GError* error = NULL;
28  gtk_window_set_icon_from_file(GTK_WINDOW(session->gtk.window), path, &error);
29  if (error != NULL) {
30  girara_error("failed to load window icon: %s", error->message);
31  g_error_free(error);
32  }
33 
34  free(path);
35  }
36 }
37 
38 static void
39 cb_font(girara_session_t* session, const char* UNUSED(name),
40  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
41 {
42  g_return_if_fail(session != NULL && value != NULL);
43 
44  pango_font_description_free(session->style.font);
45 
46  /* parse font */
47  PangoFontDescription* font = pango_font_description_from_string(value);
48  session->style.font = font;
49 
50  /* inputbar */
51  if (session->gtk.inputbar_entry != NULL) {
52  gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_entry), font);
53  }
54 
55  if (session->gtk.inputbar_dialog != NULL) {
56  gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_dialog), font);
57  }
58 
59  /* notification area */
60  if (session->gtk.notification_text != NULL) {
61  gtk_widget_override_font(GTK_WIDGET(session->gtk.notification_text), font);
62  }
63 
64  GIRARA_LIST_FOREACH(session->elements.statusbar_items, girara_statusbar_item_t *, iter, item)
65  if (item != NULL){
66  gtk_widget_override_font(GTK_WIDGET(item->text), font);
67  }
68  GIRARA_LIST_FOREACH_END(session->elements.statusbar_items, girara_statusbar_item_t *, iter, item);
69 }
70 
71 static void
72 cb_guioptions(girara_session_t* session, const char* UNUSED(name),
73  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
74 {
75  g_return_if_fail(session != NULL && value != NULL);
76 
77  /* set default values */
78  bool show_commandline = false;
79  bool show_statusbar = false;
80  bool show_hscrollbar = false;
81  bool show_vscrollbar = false;
82 
83  /* evaluate input */
84  char* input = (char*) value;
85  const size_t input_length = strlen(input);
86 
87  for (size_t i = 0; i < input_length; i++) {
88  switch (input[i]) {
89  /* command line */
90  case 'c':
91  show_commandline = true;
92  break;
93  /* statusbar */
94  case 's':
95  show_statusbar = true;
96  break;
97  case 'h':
98  show_hscrollbar = true;
99  break;
100  case 'v':
101  show_vscrollbar = true;
102  break;
103  }
104  }
105 
106  /* apply settings */
107  if (show_commandline == true) {
108  session->global.autohide_inputbar = false;
109  gtk_widget_show(session->gtk.inputbar);
110  } else {
111  session->global.autohide_inputbar = true;
112  gtk_widget_hide(session->gtk.inputbar);
113  }
114 
115  if (show_statusbar == true) {
116  session->global.hide_statusbar = false;
117  gtk_widget_show(session->gtk.statusbar);
118  } else {
119  session->global.hide_statusbar = true;
120  gtk_widget_hide(session->gtk.statusbar);
121  }
122 
123  GtkWidget* vscrollbar = gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
124  GtkWidget* hscrollbar = gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
125 
126  if (vscrollbar != NULL) {
127  gtk_widget_set_visible(vscrollbar, show_vscrollbar);
128  }
129 
130  if (hscrollbar != NULL) {
131  gtk_widget_set_visible(hscrollbar, show_hscrollbar);
132  }
133 }
134 
135 static void
136 cb_scrollbars(girara_session_t* session, const char* name,
137  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
138 {
139  g_return_if_fail(session != NULL && value != NULL);
140 
141  const bool val = *(bool*) value;
142 
143  char* guioptions = NULL;
144  girara_setting_get(session, "guioptions", &guioptions);
145  g_return_if_fail(guioptions != NULL);
146 
147  bool show_hscrollbar = strchr(guioptions, 'h') != NULL;
148  bool show_vscrollbar = strchr(guioptions, 'v') != NULL;
149 
150  if (strcmp(name, "show-scrollbars") == 0) {
151  show_hscrollbar = show_vscrollbar = val;
152  } else if (strcmp(name, "show-h-scrollbar") == 0) {
153  show_hscrollbar = val;
154  } else if (strcmp(name, "show-v-scrollbar") == 0) {
155  show_vscrollbar = val;
156  }
157 
158  const size_t guioptions_len = strlen(guioptions);
159  char* new_guioptions = g_try_malloc0(sizeof(char) * (guioptions_len + 3));
160  char* iterator = new_guioptions;
161  if (new_guioptions == NULL) {
162  g_free(guioptions);
163  return;
164  }
165 
166  /* copy everything apart from h and v */
167  for (size_t i = 0; i != guioptions_len; ++i) {
168  if (guioptions[i] != 'h' && guioptions[i] != 'v') {
169  *iterator = guioptions[i];
170  ++iterator;
171  }
172  }
173  g_free(guioptions);
174 
175  if (show_hscrollbar == true) {
176  *iterator = 'h';
177  ++iterator;
178  }
179  if (show_vscrollbar == true) {
180  *iterator = 'v';
181  ++iterator;
182  }
183 
184  girara_setting_set(session, "guioptions", new_guioptions);
185  g_free(new_guioptions);
186 }
187 
188 void
189 girara_config_load_default(girara_session_t* session)
190 {
191  if (session == NULL) {
192  return;
193  }
194 
195  /* values */
196  int statusbar_h_padding = 8;
197  int statusbar_v_padding = 2;
198  int window_width = 800;
199  int window_height = 600;
200  int n_completion_items = 15;
201  bool show_scrollbars = false;
202  girara_mode_t normal_mode = session->modes.normal;
203 
204  /* other values */
205  session->global.autohide_inputbar = true;
206 
207  /* settings */
208  girara_setting_add(session, "font", "monospace normal 9", STRING, FALSE, _("Font"), cb_font, NULL);
209  girara_setting_add(session, "default-fg", "#DDDDDD", STRING, TRUE, _("Default foreground color"), NULL, NULL);
210  girara_setting_add(session, "default-bg", "#000000", STRING, TRUE, _("Default background color"), NULL, NULL);
211  girara_setting_add(session, "inputbar-fg", "#9FBC00", STRING, TRUE, _("Inputbar foreground color"), NULL, NULL);
212  girara_setting_add(session, "inputbar-bg", "#131313", STRING, TRUE, _("Inputbar background color"), NULL, NULL);
213  girara_setting_add(session, "statusbar-fg", "#FFFFFF", STRING, TRUE, _("Statusbar foreground color"), NULL, NULL);
214  girara_setting_add(session, "statusbar-bg", "#000000", STRING, TRUE, _("Statsubar background color"), NULL, NULL);
215  girara_setting_add(session, "completion-fg", "#DDDDDD", STRING, TRUE, _("Completion foreground color"), NULL, NULL);
216  girara_setting_add(session, "completion-bg", "#232323", STRING, TRUE, _("Completion background color"), NULL, NULL);
217  girara_setting_add(session, "completion-group-fg", "#DEDEDE", STRING, TRUE, _("Completion group foreground color"), NULL, NULL);
218  girara_setting_add(session, "completion-group-bg", "#000000", STRING, TRUE, _("Completion group background color"), NULL, NULL);
219  girara_setting_add(session, "completion-highlight-fg", "#232323", STRING, TRUE, _("Completion highlight foreground color"), NULL, NULL);
220  girara_setting_add(session, "completion-highlight-bg", "#9FBC00", STRING, TRUE, _("Completion highlight background color"), NULL, NULL);
221  girara_setting_add(session, "notification-error-fg", "#FFFFFF", STRING, TRUE, _("Error notification foreground color"), NULL, NULL);
222  girara_setting_add(session, "notification-error-bg", "#FF1212", STRING, TRUE, _("Error notification background color"), NULL, NULL);
223  girara_setting_add(session, "notification-warning-fg", "#000000", STRING, TRUE, _("Warning notification foreground color"), NULL, NULL);
224  girara_setting_add(session, "notification-warning-bg", "#F3F000", STRING, TRUE, _("Warning notifaction background color"), NULL, NULL);
225  girara_setting_add(session, "notification-fg", "#000000", STRING, TRUE, _("Notification foreground color"), NULL, NULL);
226  girara_setting_add(session, "notification-bg", "#FFFFFF", STRING, TRUE, _("Notification background color"), NULL, NULL);
227  girara_setting_add(session, "tabbar-fg", "#939393", STRING, TRUE, _("Tab bar foreground color"), NULL, NULL);
228  girara_setting_add(session, "tabbar-bg", "#000000", STRING, TRUE, _("Tab bar background color"), NULL, NULL);
229  girara_setting_add(session, "tabbar-focus-fg", "#9FBC00", STRING, TRUE, _("Tab bar foreground color (active)"), NULL, NULL);
230  girara_setting_add(session, "tabbar-focus-bg", "#000000", STRING, TRUE, _("Tab bar background color (active)"), NULL, NULL);
231  girara_setting_add(session, "word-separator", " /.-=&#?", STRING, TRUE, NULL, NULL, NULL);
232  girara_setting_add(session, "window-width", &window_width, INT, TRUE, _("Initial window width"), NULL, NULL);
233  girara_setting_add(session, "window-height", &window_height, INT, TRUE, _("Initial window height"), NULL, NULL);
234  girara_setting_add(session, "statusbar-h-padding", &statusbar_h_padding, INT, TRUE, _("Horizontal padding for the status input and notification bars"), NULL, NULL);
235  girara_setting_add(session, "statusbar-v-padding", &statusbar_v_padding, INT, TRUE, _("Vertical padding for the status input and notification bars"), NULL, NULL);
236  girara_setting_add(session, "n-completion-items", &n_completion_items, INT, TRUE, _("Number of completion items"), NULL, NULL);
237  girara_setting_add(session, "show-scrollbars", &show_scrollbars, BOOLEAN, FALSE, _("Show both the horizontal and vertical scrollbars"), cb_scrollbars, NULL);
238  girara_setting_add(session, "show-h-scrollbar", &show_scrollbars, BOOLEAN, FALSE, _("Show the horizontal scrollbar"), cb_scrollbars, NULL);
239  girara_setting_add(session, "show-v-scrollbar", &show_scrollbars, BOOLEAN, FALSE, _("Show the vertical scrollbar"), cb_scrollbars, NULL);
240  girara_setting_add(session, "window-icon", "", STRING, FALSE, _("Window icon"), cb_window_icon, NULL);
241  girara_setting_add(session, "exec-command", "", STRING, FALSE, _("Command to execute in :exec"), NULL, NULL);
242  girara_setting_add(session, "guioptions", "s", STRING, FALSE, _("Show or hide certain GUI elements"), cb_guioptions, NULL);
243 
244  /* shortcuts */
245  girara_shortcut_add(session, 0, GDK_KEY_Escape, NULL, girara_sc_abort, normal_mode, 0, NULL);
246  girara_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_c, NULL, girara_sc_abort, normal_mode, 0, NULL);
247  girara_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_q, NULL, girara_sc_quit, normal_mode, 0, NULL);
248  girara_shortcut_add(session, 0, GDK_KEY_colon, NULL, girara_sc_focus_inputbar, normal_mode, 0, ":");
249  girara_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_w, NULL, girara_sc_tab_close, normal_mode, 0, NULL);
250  girara_shortcut_add(session, 0, 0, "gt", girara_sc_tab_navigate, normal_mode, GIRARA_NEXT, NULL);
251  girara_shortcut_add(session, 0, 0, "gT", girara_sc_tab_navigate, normal_mode, GIRARA_PREVIOUS, NULL);
252 
253  /* inputbar shortcuts */
254  girara_inputbar_shortcut_add(session, 0, GDK_KEY_Escape, girara_isc_abort, 0, NULL);
255  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_c, girara_isc_abort, 0, NULL);
256  girara_inputbar_shortcut_add(session, 0, GDK_KEY_Tab, girara_isc_completion, GIRARA_NEXT, NULL);
257  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_Tab, girara_isc_completion, GIRARA_NEXT_GROUP, NULL);
258  girara_inputbar_shortcut_add(session, 0, GDK_KEY_ISO_Left_Tab, girara_isc_completion, GIRARA_PREVIOUS, NULL);
259  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_ISO_Left_Tab, girara_isc_completion, GIRARA_PREVIOUS_GROUP, NULL);
261  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_h, girara_isc_string_manipulation, GIRARA_DELETE_LAST_CHAR, NULL);
263  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_k, girara_isc_string_manipulation, GIRARA_DELETE_TO_LINE_END, NULL);
264  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_d, girara_isc_string_manipulation, GIRARA_DELETE_CURR_CHAR, NULL);
265  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_w, girara_isc_string_manipulation, GIRARA_DELETE_LAST_WORD, NULL);
266  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_f, girara_isc_string_manipulation, GIRARA_NEXT_CHAR, NULL);
267  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_b, girara_isc_string_manipulation, GIRARA_PREVIOUS_CHAR, NULL);
270  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_a, girara_isc_string_manipulation, GIRARA_GOTO_START, NULL);
271  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_e, girara_isc_string_manipulation, GIRARA_GOTO_END, NULL);
273  girara_inputbar_shortcut_add(session, 0, GDK_KEY_Down, girara_isc_command_history, GIRARA_NEXT, NULL);
274  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_p, girara_isc_command_history, GIRARA_PREVIOUS, NULL);
275  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_n, girara_isc_command_history, GIRARA_NEXT, NULL);
276 
277  /* commands */
278  girara_inputbar_command_add(session, "exec", NULL, girara_cmd_exec, NULL, _("Execute a command"));
279  girara_inputbar_command_add(session, "map", "m", girara_cmd_map, NULL, _("Map a key sequence"));
280  girara_inputbar_command_add(session, "quit", "q", girara_cmd_quit, NULL, _("Quit the program"));
281  girara_inputbar_command_add(session, "set", "s", girara_cmd_set, girara_cc_set, _("Set an option"));
282  girara_inputbar_command_add(session, "unmap", NULL, girara_cmd_unmap, NULL, _("Unmap a key sequence"));
283 
284  /* config handle */
285  girara_config_handle_add(session, "map", girara_cmd_map);
286  girara_config_handle_add(session, "set", girara_cmd_set);
287  girara_config_handle_add(session, "unmap", girara_cmd_unmap);
288 
289  /* shortcut mappings */
290  girara_shortcut_mapping_add(session, "focus_inputbar", girara_sc_focus_inputbar);
293  girara_shortcut_mapping_add(session, "feedkeys", girara_sc_feedkeys);
296 }
297 
298 bool
299 girara_config_handle_add(girara_session_t* session, const char* identifier, girara_command_function_t handle)
300 {
301  g_return_val_if_fail(session != NULL, false);
302  g_return_val_if_fail(identifier != NULL, false);
303 
304  /* search for existing config handle */
305  GIRARA_LIST_FOREACH(session->config.handles, girara_config_handle_t*, iter, data)
306  if (strcmp(data->identifier, identifier) == 0) {
307  data->handle = handle;
309  return true;
310  }
311  GIRARA_LIST_FOREACH_END(session->config.handles, girara_config_handle_t*, iter, data);
312 
313  /* add new config handle */
314  girara_config_handle_t* config_handle = g_slice_new(girara_config_handle_t);
315 
316  config_handle->identifier = g_strdup(identifier);
317  config_handle->handle = handle;
318  girara_list_append(session->config.handles, config_handle);
319 
320  return true;
321 }
322 
323 void
324 girara_config_handle_free(girara_config_handle_t* handle)
325 {
326  if (handle == NULL) {
327  return;
328  }
329 
330  g_free(handle->identifier);
331  g_slice_free(girara_config_handle_t, handle);
332 }
333 
334 static bool
335 config_parse(girara_session_t* session, const char* path)
336 {
337  /* open file */
338  FILE* file = girara_file_open(path, "r");
339 
340  if (file == NULL) {
341  return false;
342  }
343 
344  /* read lines */
345  char* line = NULL;
346  unsigned int line_number = 1;
347  while ((line = girara_file_read_line(file)) != NULL) {
348  /* skip empty lines and comments */
349  if (strlen(line) == 0 || strchr(COMMENT_PREFIX, line[0]) != NULL) {
350  free(line);
351  continue;
352  }
353 
354  gchar** argv = NULL;
355  gint argc = 0;
356 
357  girara_list_t* argument_list = girara_list_new();
358  if (argument_list == NULL) {
359  free(line);
360  fclose(file);
361  return false;
362  }
363 
364  girara_list_set_free_function(argument_list, g_free);
365  if (g_shell_parse_argv(line, &argc, &argv, NULL) != FALSE) {
366  for(int i = 1; i < argc; i++) {
367  char* argument = g_strdup(argv[i]);
368  girara_list_append(argument_list, (void*) argument);
369  }
370  } else {
371  girara_list_free(argument_list);
372  fclose(file);
373  free(line);
374  return false;
375  }
376 
377  /* include gets a special treatment */
378  if (strcmp(argv[0], "include") == 0) {
379  if (argc != 2) {
380  girara_warning("Could not process line %d in '%s': usage: include path.", line_number, path);
381  } else {
382  char* newpath = NULL;
383  if (g_path_is_absolute(argv[1]) == TRUE) {
384  newpath = g_strdup(argv[1]);
385  } else {
386  char* basename = g_path_get_dirname(path);
387  char* tmp = g_build_filename(basename, argv[1], NULL);
388  newpath = girara_fix_path(tmp);
389  g_free(tmp);
390  g_free(basename);
391  }
392 
393  if (strcmp(newpath, path) == 0) {
394  girara_warning("Could not process line %d in '%s': trying to include itself.", line_number, path);
395  } else {
396  girara_debug("Loading config file '%s'.", newpath);
397  if (config_parse(session, newpath) == FALSE) {
398  girara_warning("Could not process line %d in '%s': failed to load '%s'.", line_number, path, newpath);
399  }
400  }
401  g_free(newpath);
402  }
403  } else {
404  /* search for config handle */
405  girara_config_handle_t* handle = NULL;
406  GIRARA_LIST_FOREACH(session->config.handles, girara_config_handle_t*, iter, tmp)
407  handle = tmp;
408  if (strcmp(handle->identifier, argv[0]) == 0) {
409  handle->handle(session, argument_list);
410  break;
411  } else {
412  handle = NULL;
413  }
414  GIRARA_LIST_FOREACH_END(session->config.handles, girara_config_handle_t*, iter, tmp);
415 
416  if (handle == NULL) {
417  girara_warning("Could not process line %d in '%s': Unknown handle '%s'", line_number, path, argv[0]);
418  }
419  }
420 
421  line_number++;
422  girara_list_free(argument_list);
423  g_strfreev(argv);
424  free(line);
425  }
426 
427  fclose(file);
428  return true;
429 }
430 
431 void
432 girara_config_parse(girara_session_t* session, const char* path)
433 {
434  config_parse(session, path);
435 }