Updated Spanish translation
[anjuta.git] / plugins / language-support-js / plugin.c
blob1009abd9906fe1e52c04abe148533df42340b0fc
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 Copyright (C) 2009 Maxim Ermilov <zaspire@rambler.ru>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
21 #include <libanjuta/anjuta-shell.h>
22 #include <libanjuta/anjuta-session.h>
23 #include <libanjuta/anjuta-debug.h>
24 #include <libanjuta/anjuta-language-provider.h>
25 #include <libanjuta/interfaces/ianjuta-document-manager.h>
26 #include <libanjuta/interfaces/ianjuta-project-manager.h>
27 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
28 #include <libanjuta/interfaces/ianjuta-editor-tip.h>
29 #include <libanjuta/interfaces/ianjuta-language.h>
30 #include <libanjuta/interfaces/ianjuta-language-provider.h>
31 #include <libanjuta/interfaces/ianjuta-preferences.h>
32 #include <ctype.h>
34 #include <glib.h>
35 #include "util.h"
36 #include "plugin.h"
37 #include "prefs.h"
38 #include "code-completion.h"
40 #include "gi-symbol.h"
42 #define PREFS_BUILDER ANJUTA_GLADE_DIR"/anjuta-language-javascript.ui"
43 #define ICON_FILE "anjuta-language-cpp-java-plugin.png"
44 #define UI_FILE ANJUTA_UI_DIR"/anjuta-language-javascript.xml"
46 #define JSDIRS_LISTSTORE "jsdirs_liststore"
47 #define JSDIRS_TREEVIEW "jsdirs_treeview"
49 static gpointer parent_class;
51 static void
52 on_value_added_current_editor (AnjutaPlugin *plugin, const gchar *name,
53 const GValue *value, gpointer data);
54 static void
55 on_value_removed_current_editor (AnjutaPlugin *plugin, const gchar *name,
56 gpointer data);
58 /*Export for GtkBuilder*/
59 G_MODULE_EXPORT void
60 on_jsdirs_rm_button_clicked (GtkButton *button, gpointer user_data);
61 G_MODULE_EXPORT void
62 on_jsdirs_add_button_clicked (GtkButton *button, gpointer user_data);
64 static gboolean
65 js_support_plugin_activate (AnjutaPlugin *plugin)
67 JSLang *js_support_plugin;
69 DEBUG_PRINT ("%s", "JSLang: Activating JSLang plugin ...");
70 js_support_plugin = (JSLang*) plugin;
71 js_support_plugin->prefs = g_settings_new (JS_SUPPORT_SCHEMA);
72 js_support_plugin->editor_watch_id =
73 anjuta_plugin_add_watch (plugin, IANJUTA_DOCUMENT_MANAGER_CURRENT_DOCUMENT,
74 on_value_added_current_editor,
75 on_value_removed_current_editor,
76 plugin);
77 return TRUE;
80 static gboolean
81 js_support_plugin_deactivate (AnjutaPlugin *plugin)
83 JSLang *js_support_plugin;
85 DEBUG_PRINT ("%s", "JSLang: Dectivating JSLang plugin ...");
86 js_support_plugin = (JSLang*) plugin;
87 anjuta_plugin_remove_watch (plugin, js_support_plugin->editor_watch_id, TRUE);
88 return TRUE;
91 static void
92 js_support_plugin_finalize (GObject *obj)
94 G_OBJECT_CLASS (parent_class)->finalize (obj);
97 static void
98 js_support_plugin_dispose (GObject *obj)
100 JSLang *self = (JSLang*)obj;
102 g_assert (self != NULL);
104 g_clear_object (&self->symbol);
106 G_OBJECT_CLASS (parent_class)->dispose (obj);
109 static void
110 js_support_plugin_instance_init (GObject *obj)
112 JSLang *plugin = (JSLang*)obj;
113 plugin->prefs = NULL;
114 plugin->symbol = NULL;
117 static void
118 js_support_plugin_class_init (GObjectClass *klass)
120 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
122 parent_class = g_type_class_peek_parent (klass);
124 plugin_class->activate = js_support_plugin_activate;
125 plugin_class->deactivate = js_support_plugin_deactivate;
126 klass->finalize = js_support_plugin_finalize;
127 klass->dispose = js_support_plugin_dispose;
130 static void
131 install_support (JSLang *plugin)
133 const gchar *lang;
134 IAnjutaLanguage* lang_manager;
136 setPlugin (plugin);
138 if (!IANJUTA_IS_EDITOR (plugin->current_editor))
139 return;
140 lang_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
141 IAnjutaLanguage, NULL);
142 if (!lang_manager)
143 return;
144 lang = ianjuta_language_get_name_from_editor (lang_manager,
145 IANJUTA_EDITOR_LANGUAGE (plugin->current_editor), NULL);
146 if (!lang || !g_str_equal (lang, "JavaScript"))
147 return;
149 plugin->lang_prov = g_object_new (ANJUTA_TYPE_LANGUAGE_PROVIDER, NULL);
150 anjuta_language_provider_install (plugin->lang_prov,
151 IANJUTA_EDITOR (plugin->current_editor),
152 plugin->prefs);
154 DEBUG_PRINT ("%s", "JSLang: Install support");
156 ianjuta_editor_assist_add (IANJUTA_EDITOR_ASSIST(plugin->current_editor),
157 IANJUTA_PROVIDER(plugin), NULL);
160 static void
161 uninstall_support (JSLang *plugin)
163 if (plugin->lang_prov)
165 g_object_unref (plugin->lang_prov);
166 plugin->lang_prov = NULL;
169 DEBUG_PRINT ("%s", "JSLang: Uninstall support");
171 ianjuta_editor_assist_remove (IANJUTA_EDITOR_ASSIST(plugin->current_editor),
172 IANJUTA_PROVIDER(plugin), NULL);
176 static void
177 on_value_added_current_editor (AnjutaPlugin *plugin, const gchar *name,
178 const GValue *value, gpointer data)
180 JSLang *js_support_plugin;
181 IAnjutaDocument* doc = IANJUTA_DOCUMENT(g_value_get_object (value));
183 DEBUG_PRINT ("%s", "JSLang: Add editor");
185 js_support_plugin = (JSLang*) plugin;
186 if (IANJUTA_IS_EDITOR(doc))
187 js_support_plugin->current_editor = G_OBJECT(doc);
188 else
190 js_support_plugin->current_editor = NULL;
191 return;
193 install_support (js_support_plugin);
196 static void
197 on_value_removed_current_editor (AnjutaPlugin *plugin, const gchar *name,
198 gpointer data)
200 JSLang *js_support_plugin;
202 DEBUG_PRINT ("%s", "JSLang: Remove editor");
204 js_support_plugin = (JSLang*) plugin;
205 if (IANJUTA_IS_EDITOR(js_support_plugin->current_editor))
206 uninstall_support (js_support_plugin);
207 js_support_plugin->current_editor = NULL;
210 static void
211 jsdirs_save (GtkTreeModel *list_store)
213 GtkTreeIter iter;
214 const gchar *project_root = NULL;
215 anjuta_shell_get (ANJUTA_PLUGIN (getPlugin ())->shell,
216 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
217 G_TYPE_STRING, &project_root, NULL);
219 GFile *tmp = g_file_new_for_uri (project_root);
220 AnjutaSession *session = anjuta_session_new (g_file_get_path (tmp));
221 g_object_unref (tmp);
223 GList *dirs = NULL;
224 if (!gtk_tree_model_iter_children (list_store, &iter, NULL))
225 return;
228 gchar *dir;
229 gtk_tree_model_get (list_store, &iter, 0, &dir, -1);
231 g_assert (dir != NULL);
233 dirs = g_list_append (dirs, dir);
234 } while (gtk_tree_model_iter_next (list_store, &iter));
235 anjuta_session_set_string_list (session, "options", "js_dirs", dirs);
236 anjuta_session_sync (session);
239 G_MODULE_EXPORT void
240 on_jsdirs_rm_button_clicked (GtkButton *button, gpointer user_data)
242 GtkTreeIter iter;
243 GtkTreeView *tree = GTK_TREE_VIEW (user_data);
244 GtkTreeModel *list_store = gtk_tree_view_get_model (tree);
245 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree);
247 if (!gtk_tree_selection_get_selected (selection, &list_store, &iter))
248 return;
249 gtk_list_store_remove (GTK_LIST_STORE (list_store), &iter);
250 jsdirs_save (list_store);
253 G_MODULE_EXPORT void
254 on_jsdirs_add_button_clicked (GtkButton *button, gpointer user_data)
256 GtkWidget *dialog;
258 g_assert (user_data != NULL);
260 GtkTreeView *tree = GTK_TREE_VIEW (user_data);
261 GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (tree));
263 g_assert (list_store != NULL);
265 dialog = gtk_file_chooser_dialog_new ("Choose directory",
266 NULL,
267 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
268 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
269 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
270 NULL);
271 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
273 char *filename;
274 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
275 if (filename)
277 GtkTreeIter iter;
278 gtk_list_store_append (list_store, &iter);
279 gtk_list_store_set (list_store, &iter, 0, filename, -1);
280 g_free (filename);
282 jsdirs_save (GTK_TREE_MODEL (list_store));
284 gtk_widget_destroy (dialog);
287 static void
288 jsdirs_init_treeview (JSLang* plugin)
290 const gchar *project_root = NULL;
291 GtkTreeIter iter;
292 GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (
293 plugin->bxml, JSDIRS_LISTSTORE));
294 if (!list_store)
295 return;
297 anjuta_shell_get (ANJUTA_PLUGIN (plugin)->shell,
298 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
299 G_TYPE_STRING, &project_root, NULL);
301 GFile *tmp = g_file_new_for_uri (project_root);
302 AnjutaSession *session = anjuta_session_new (g_file_get_path (tmp));
303 g_object_unref (tmp);
304 GList* dir_list = anjuta_session_get_string_list (session, "options", "js_dirs");
305 GList *i;
306 gtk_list_store_clear (list_store);
308 for (i = dir_list; i; i = g_list_next (i))
310 gtk_list_store_append (list_store, &iter);
311 gtk_list_store_set (list_store, &iter, 0, i->data, -1);
313 if (!dir_list)
315 gtk_list_store_append (list_store, &iter);
316 gtk_list_store_set (list_store, &iter, 0, ".", -1);
320 #define PREF_WIDGET_SPACE "preferences:completion-space-after-func"
321 #define PREF_WIDGET_BRACE "preferences:completion-brace-after-func"
322 #define PREF_WIDGET_CLOSEBRACE "preferences:completion-closebrace-after-func"
323 #define PREF_WIDGET_AUTO "preferences:completion-enable"
325 static void
326 on_autocompletion_toggled (GtkToggleButton* button,
327 JSLang* plugin)
329 GtkWidget* widget;
330 gboolean sensitive = gtk_toggle_button_get_active (button);
332 widget = GTK_WIDGET (gtk_builder_get_object (plugin->bxml, PREF_WIDGET_SPACE));
333 gtk_widget_set_sensitive (widget, sensitive);
334 widget = GTK_WIDGET (gtk_builder_get_object (plugin->bxml, PREF_WIDGET_BRACE));
335 gtk_widget_set_sensitive (widget, sensitive);
336 widget = GTK_WIDGET (gtk_builder_get_object (plugin->bxml, PREF_WIDGET_CLOSEBRACE));
337 gtk_widget_set_sensitive (widget, sensitive);
340 static void
341 ipreferences_merge (IAnjutaPreferences* ipref, AnjutaPreferences* prefs,
342 GError** e)
344 /* Add preferences */
345 GError* error = NULL;
346 JSLang* plugin = (JSLang*) ipref;
347 plugin->bxml = gtk_builder_new ();
348 GtkWidget* toggle;
350 if (!gtk_builder_add_from_file (plugin->bxml, PREFS_BUILDER, &error))
352 g_warning ("Couldn't load builder file: %s", error->message);
353 g_error_free (error);
356 GtkTreeView *tree = GTK_TREE_VIEW (gtk_builder_get_object (plugin->bxml, JSDIRS_TREEVIEW));
358 gtk_builder_connect_signals (plugin->bxml, tree);
359 jsdirs_init_treeview (plugin);
361 anjuta_preferences_add_from_builder (prefs,
362 plugin->bxml,
363 plugin->prefs,
364 "preferences", _("JavaScript"),
365 ICON_FILE);
366 toggle = GTK_WIDGET (gtk_builder_get_object (plugin->bxml, PREF_WIDGET_AUTO));
367 g_signal_connect (toggle, "toggled", G_CALLBACK (on_autocompletion_toggled),
368 plugin);
369 on_autocompletion_toggled (GTK_TOGGLE_BUTTON (toggle), plugin);
372 static void
373 ipreferences_unmerge (IAnjutaPreferences* ipref, AnjutaPreferences* prefs,
374 GError** e)
376 JSLang* plugin = (JSLang*) ipref;
377 anjuta_preferences_remove_page(prefs, _("JavaScript"));
378 g_object_unref (plugin->bxml);
381 static void
382 ipreferences_iface_init (IAnjutaPreferencesIface* iface)
384 iface->merge = ipreferences_merge;
385 iface->unmerge = ipreferences_unmerge;
388 static void
389 iprovider_activate (IAnjutaProvider* self,
390 IAnjutaIterable* iter,
391 gpointer data,
392 GError** e)
394 JSLang *plugin = (JSLang*) self;
395 anjuta_language_provider_activate (plugin->lang_prov, self, iter, data);
398 static void
399 iprovider_populate (IAnjutaProvider* self,
400 IAnjutaIterable* cursor,
401 GError** e)
403 JSLang *plugin = (JSLang*) self;
404 anjuta_language_provider_populate (plugin->lang_prov, self, cursor);
407 static const gchar*
408 iprovider_get_name (IAnjutaProvider* self,
409 GError** e)
411 return _("JavaScript");
414 static IAnjutaIterable*
415 iprovider_get_start_iter (IAnjutaProvider* self,
416 GError** e)
418 JSLang *plugin = (JSLang*) self;
419 return anjuta_language_provider_get_start_iter (plugin->lang_prov);
422 static void
423 iprovider_iface_init (IAnjutaProviderIface* iface)
425 iface->activate = iprovider_activate;
426 iface->populate = iprovider_populate;
427 iface->get_name = iprovider_get_name;
428 iface->get_start_iter = iprovider_get_start_iter;
431 static GList*
432 ilanguage_provider_get_calltip_cache (IAnjutaLanguageProvider *obj,
433 gchar* call_context,
434 GError** err)
436 /* TODO: Not implemented yet */
437 return NULL;
440 static gchar*
441 ilanguage_provider_get_calltip_context (IAnjutaLanguageProvider *obj,
442 IAnjutaIterable *iter,
443 GError** err)
445 /* TODO: Not implemented yet
446 GList *t = NULL;
447 gchar *args = code_completion_get_func_tooltip (plugin, sym);
448 t = g_list_append (t, args);
449 if (args)
451 ianjuta_editor_tip_show (IANJUTA_EDITOR_TIP(plugin->current_editor), t,
452 position, NULL);
453 g_free (args);
456 return NULL;
459 static void
460 ilanguage_provider_new_calltip (IAnjutaLanguageProvider* obj,
461 gchar* call_context,
462 IAnjutaIterable* cursor,
463 GError** err)
465 /* TODO: Not implemented yet */
466 return;
469 static IAnjutaIterable*
470 ilanguage_provider_populate (IAnjutaLanguageProvider* obj,
471 IAnjutaIterable* iter,
472 GError **err)
474 JSLang *plugin = (JSLang*)obj;
475 IAnjutaIterable* start_iter;
476 GList *suggestions;
478 start_iter = ianjuta_iterable_clone (iter, NULL);
480 if (!plugin->current_editor)
481 return start_iter;
482 gint depth;
483 gchar *str = code_completion_get_str (IANJUTA_EDITOR (plugin->current_editor), FALSE);
485 if (!str)
486 return start_iter;
488 g_assert (plugin->prefs);
489 gchar *file = file_completion (IANJUTA_EDITOR (plugin->current_editor), &depth);
491 if (strlen (str) < g_settings_get_int (plugin->prefs, MIN_CODECOMPLETE))
493 anjuta_language_provider_proposals (plugin->lang_prov, IANJUTA_PROVIDER(obj),
494 NULL, NULL, TRUE);
496 /* Highlight missed semicolon */
497 code_completion_get_list (plugin, file, NULL, depth);
498 return start_iter;
501 gint i;
502 DEBUG_PRINT ("JSLang: Auto complete for %s (TMFILE=%s)", str, file);
503 for (i = strlen (str) - 1; i; i--)
505 if (str[i] == '.')
506 break;
508 /* TODO: Use anjuta_language_provider_get_pre_word in the future */
509 if (i > 0)
510 suggestions = code_completion_get_list (plugin, file, g_strndup (str, i), depth);
511 else
512 suggestions = code_completion_get_list (plugin, file, NULL, depth);
513 if (suggestions)
515 GList *nsuggest = NULL;
516 gint k;
517 if (i > 0)
519 suggestions = filter_list (suggestions, str + i + 1);
520 k = strlen (str + i + 1);
521 } else
523 suggestions = filter_list (suggestions, str);
524 k = strlen (str);
526 GList *i;
527 for (; k > 0; k--)
528 ianjuta_iterable_previous (start_iter, NULL);
530 for (i = suggestions; i; i = g_list_next(i)) {
531 IAnjutaEditorAssistProposal* proposal;
532 AnjutaLanguageProposalData* prop_data;
534 proposal = g_new0(IAnjutaEditorAssistProposal, 1);
536 if (!i->data)
537 continue;
539 proposal->label = i->data;
540 prop_data = anjuta_language_proposal_data_new (i->data);
541 prop_data->is_func = code_completion_is_symbol_func (plugin, str);
542 /* TODO: Not implemented yet */
543 prop_data->has_para = TRUE;
544 prop_data->info = i->data;
545 proposal->data = prop_data;
546 nsuggest = g_list_prepend (nsuggest, proposal);
548 anjuta_language_provider_proposals (plugin->lang_prov, IANJUTA_PROVIDER(obj),
549 nsuggest, NULL, TRUE);
550 g_list_free (nsuggest);
551 return start_iter;
553 anjuta_language_provider_proposals (plugin->lang_prov, IANJUTA_PROVIDER(obj),
554 NULL, NULL, TRUE);
556 return start_iter;
559 static void
560 ilanguage_provider_iface_init (IAnjutaLanguageProviderIface* iface)
562 iface->get_calltip_cache = ilanguage_provider_get_calltip_cache;
563 iface->get_calltip_context = ilanguage_provider_get_calltip_context;
564 iface->new_calltip = ilanguage_provider_new_calltip;
565 iface->populate_completions = ilanguage_provider_populate;
568 ANJUTA_PLUGIN_BEGIN (JSLang, js_support_plugin);
569 ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES);
570 ANJUTA_PLUGIN_ADD_INTERFACE(iprovider, IANJUTA_TYPE_PROVIDER);
571 ANJUTA_PLUGIN_ADD_INTERFACE(ilanguage_provider, IANJUTA_TYPE_LANGUAGE_PROVIDER)
572 ANJUTA_PLUGIN_END;
574 ANJUTA_SIMPLE_PLUGIN (JSLang, js_support_plugin);