1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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
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>
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
;
52 on_value_added_current_editor (AnjutaPlugin
*plugin
, const gchar
*name
,
53 const GValue
*value
, gpointer data
);
55 on_value_removed_current_editor (AnjutaPlugin
*plugin
, const gchar
*name
,
58 /*Export for GtkBuilder*/
60 on_jsdirs_rm_button_clicked (GtkButton
*button
, gpointer user_data
);
62 on_jsdirs_add_button_clicked (GtkButton
*button
, gpointer user_data
);
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
,
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
);
92 js_support_plugin_finalize (GObject
*obj
)
94 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
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
);
110 js_support_plugin_instance_init (GObject
*obj
)
112 JSLang
*plugin
= (JSLang
*)obj
;
113 plugin
->prefs
= NULL
;
114 plugin
->symbol
= NULL
;
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
;
131 install_support (JSLang
*plugin
)
134 IAnjutaLanguage
* lang_manager
;
138 if (!IANJUTA_IS_EDITOR (plugin
->current_editor
))
140 lang_manager
= anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin
)->shell
,
141 IAnjutaLanguage
, NULL
);
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"))
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
),
154 DEBUG_PRINT ("%s", "JSLang: Install support");
156 ianjuta_editor_assist_add (IANJUTA_EDITOR_ASSIST(plugin
->current_editor
),
157 IANJUTA_PROVIDER(plugin
), NULL
);
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
);
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
);
190 js_support_plugin
->current_editor
= NULL
;
193 install_support (js_support_plugin
);
197 on_value_removed_current_editor (AnjutaPlugin
*plugin
, const gchar
*name
,
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
;
211 jsdirs_save (GtkTreeModel
*list_store
)
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
);
224 if (!gtk_tree_model_iter_children (list_store
, &iter
, NULL
))
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
);
240 on_jsdirs_rm_button_clicked (GtkButton
*button
, gpointer user_data
)
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
))
249 gtk_list_store_remove (GTK_LIST_STORE (list_store
), &iter
);
250 jsdirs_save (list_store
);
254 on_jsdirs_add_button_clicked (GtkButton
*button
, gpointer user_data
)
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",
267 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
,
268 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
269 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
271 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
)
274 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
278 gtk_list_store_append (list_store
, &iter
);
279 gtk_list_store_set (list_store
, &iter
, 0, filename
, -1);
282 jsdirs_save (GTK_TREE_MODEL (list_store
));
284 gtk_widget_destroy (dialog
);
288 jsdirs_init_treeview (JSLang
* plugin
)
290 const gchar
*project_root
= NULL
;
292 GtkListStore
*list_store
= GTK_LIST_STORE (gtk_builder_get_object (
293 plugin
->bxml
, JSDIRS_LISTSTORE
));
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");
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);
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"
326 on_autocompletion_toggled (GtkToggleButton
* button
,
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
);
341 ipreferences_merge (IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
,
344 /* Add preferences */
345 GError
* error
= NULL
;
346 JSLang
* plugin
= (JSLang
*) ipref
;
347 plugin
->bxml
= gtk_builder_new ();
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
,
364 "preferences", _("JavaScript"),
366 toggle
= GTK_WIDGET (gtk_builder_get_object (plugin
->bxml
, PREF_WIDGET_AUTO
));
367 g_signal_connect (toggle
, "toggled", G_CALLBACK (on_autocompletion_toggled
),
369 on_autocompletion_toggled (GTK_TOGGLE_BUTTON (toggle
), plugin
);
373 ipreferences_unmerge (IAnjutaPreferences
* ipref
, AnjutaPreferences
* prefs
,
376 JSLang
* plugin
= (JSLang
*) ipref
;
377 anjuta_preferences_remove_page(prefs
, _("JavaScript"));
378 g_object_unref (plugin
->bxml
);
382 ipreferences_iface_init (IAnjutaPreferencesIface
* iface
)
384 iface
->merge
= ipreferences_merge
;
385 iface
->unmerge
= ipreferences_unmerge
;
389 iprovider_activate (IAnjutaProvider
* self
,
390 IAnjutaIterable
* iter
,
394 JSLang
*plugin
= (JSLang
*) self
;
395 anjuta_language_provider_activate (plugin
->lang_prov
, self
, iter
, data
);
399 iprovider_populate (IAnjutaProvider
* self
,
400 IAnjutaIterable
* cursor
,
403 JSLang
*plugin
= (JSLang
*) self
;
404 anjuta_language_provider_populate (plugin
->lang_prov
, self
, cursor
);
408 iprovider_get_name (IAnjutaProvider
* self
,
411 return _("JavaScript");
414 static IAnjutaIterable
*
415 iprovider_get_start_iter (IAnjutaProvider
* self
,
418 JSLang
*plugin
= (JSLang
*) self
;
419 return anjuta_language_provider_get_start_iter (plugin
->lang_prov
);
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
;
432 ilanguage_provider_get_calltip_cache (IAnjutaLanguageProvider
*obj
,
436 /* TODO: Not implemented yet */
441 ilanguage_provider_get_calltip_context (IAnjutaLanguageProvider
*obj
,
442 IAnjutaIterable
*iter
,
445 /* TODO: Not implemented yet
447 gchar *args = code_completion_get_func_tooltip (plugin, sym);
448 t = g_list_append (t, args);
451 ianjuta_editor_tip_show (IANJUTA_EDITOR_TIP(plugin->current_editor), t,
460 ilanguage_provider_new_calltip (IAnjutaLanguageProvider
* obj
,
462 IAnjutaIterable
* cursor
,
465 /* TODO: Not implemented yet */
469 static IAnjutaIterable
*
470 ilanguage_provider_populate (IAnjutaLanguageProvider
* obj
,
471 IAnjutaIterable
* iter
,
474 JSLang
*plugin
= (JSLang
*)obj
;
475 IAnjutaIterable
* start_iter
;
478 start_iter
= ianjuta_iterable_clone (iter
, NULL
);
480 if (!plugin
->current_editor
)
483 gchar
*str
= code_completion_get_str (IANJUTA_EDITOR (plugin
->current_editor
), FALSE
);
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
),
496 /* Highlight missed semicolon */
497 code_completion_get_list (plugin
, file
, NULL
, depth
);
502 DEBUG_PRINT ("JSLang: Auto complete for %s (TMFILE=%s)", str
, file
);
503 for (i
= strlen (str
) - 1; i
; i
--)
508 /* TODO: Use anjuta_language_provider_get_pre_word in the future */
510 suggestions
= code_completion_get_list (plugin
, file
, g_strndup (str
, i
), depth
);
512 suggestions
= code_completion_get_list (plugin
, file
, NULL
, depth
);
515 GList
*nsuggest
= NULL
;
519 suggestions
= filter_list (suggestions
, str
+ i
+ 1);
520 k
= strlen (str
+ i
+ 1);
523 suggestions
= filter_list (suggestions
, str
);
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);
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
);
553 anjuta_language_provider_proposals (plugin
->lang_prov
, IANJUTA_PROVIDER(obj
),
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
)
574 ANJUTA_SIMPLE_PLUGIN (JSLang
, js_support_plugin
);