1 /*
2  * gms.c: miniscript plugin for geany editor
3  *            Geany, a fast and lightweight IDE
4  *
5  * Copyright 2008 Pascal BURLOT <prublot(at)users(dot)sourceforge(dot)net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301, USA.
21  *
22  */
23 
24 /**
25  * gms is a tool to apply a script filter on a text selection, or on
26  * the whole document, or all opened documents.
27  *
28  * note: the script filter could be : Unix shell, perl , python , sed ,awk ...
29  */
30 
31 #include    "config.h"
32 
33 #include    <geanyplugin.h>
34 
35 /* headers */
36 #include    <stdlib.h>
37 #include    <glib.h>
38 #include    <glib/gstdio.h>
39 
40 /* user header */
41 #include    "gms.h"
42 #include    "gms_gui.h"
43 #include    "gms_debug.h"
44 
45 
46 GeanyPlugin     *geany_plugin;
47 GeanyData       *geany_data;
48 
49 
50 /* Check that the running Geany supports the plugin API used below, and check
51  * for binary compatibility. */
52 PLUGIN_VERSION_CHECK(224)
53 
54 /* All plugins must set name, description, version and author. */
55 PLUGIN_SET_TRANSLATABLE_INFO(
56     LOCALEDIR, GETTEXT_PACKAGE,
57     _("Mini Script"),
58     _("A tool to apply a script filter on a text selection or current document(s)"),
59     "0.1" , _("Pascal BURLOT, a Geany user"))
60 
61 static GtkWidget     *gms_item   = NULL ;
62 static gms_handle_t gms_hnd     = NULL ;
63 static gchar        *gms_command = NULL ;
64 
65 
66 /**
67  * \brief the function creates from the current selection to the input file
68  */
create_selection_2_input_file(ScintillaObject * sci)69 static void create_selection_2_input_file( ScintillaObject *sci )
70 {
71     gchar *contents = sci_get_selection_contents(sci);
72 
73     GMS_PNULL(contents) ;
74 
75     g_file_set_contents(gms_get_in_filename(gms_hnd), contents, -1 , NULL );
76     GMS_G_FREE(contents);
77 }
78 
79 /**
80  * \brief the function reads the result file
81  */
read_result_file(gchar * filename)82 static gchar *read_result_file( gchar *filename )
83 {
84     gchar *utf8     = NULL;
85     gchar *contents = NULL;
86     GError *error   = NULL ;
87     if (g_file_get_contents(filename, &contents, NULL, &error ))
88     {
89         if ( contents )
90         {
91             utf8 = g_locale_to_utf8 (contents, -1, NULL, NULL, NULL);
92             GMS_G_FREE(contents);
93         }
94     }
95     return utf8 ;
96 }
97 /**
98  * \brief the function select entirely the document
99  */
select_entirely_doc(ScintillaObject * sci)100 static void select_entirely_doc( ScintillaObject *sci  )
101 {
102     gint            size_buf = sci_get_length(sci);
103 
104     sci_set_selection_start( sci , 0 ) ;
105     sci_set_selection_end( sci , size_buf ) ;
106 }
107 
108 /**
109  * \brief the function updates the current document
110  */
update_doc(ScintillaObject * sci,gchar * contents)111 static void update_doc( ScintillaObject *sci, gchar * contents )
112 {
113     if (contents==NULL) return ;
114     sci_replace_sel( sci, contents );
115 }
116 /**
117  * \brief the function deletes the tempory files
118  */
delete_tmp_files(void)119 static void delete_tmp_files(void)
120 {
121     if( g_file_test( gms_get_in_filename(gms_hnd),G_FILE_TEST_EXISTS) == TRUE )
122         g_unlink( gms_get_in_filename(gms_hnd) ) ;
123     if( g_file_test( gms_get_out_filename(gms_hnd),G_FILE_TEST_EXISTS) == TRUE )
124         g_unlink( gms_get_out_filename(gms_hnd) ) ;
125     if( g_file_test( gms_get_filter_filename(gms_hnd),G_FILE_TEST_EXISTS) == TRUE )
126         g_unlink( gms_get_filter_filename(gms_hnd) ) ;
127 }
128 
129 /**
130  * \brief the function updates the current document
131  */
run_filter(ScintillaObject * sci)132 static gint run_filter( ScintillaObject *sci )
133 {
134     int r , ret = 0 ;
135     gchar *result = NULL ;
136 
137     gms_command = gms_get_str_command(gms_hnd);
138     r = system( gms_command ) ;
139     if ( r != 0 )
140     {
141         GtkWidget *dlg ;
142         result = read_result_file( gms_get_error_filename(gms_hnd) ) ;
143 
144         dlg = gtk_message_dialog_new( GTK_WINDOW(geany->main_widgets->window),
145                         GTK_DIALOG_DESTROY_WITH_PARENT,
146                         GTK_MESSAGE_ERROR,
147                         GTK_BUTTONS_CLOSE,
148                         "%s", result);
149 
150         gtk_dialog_run(GTK_DIALOG(dlg));
151         gtk_widget_destroy(GTK_WIDGET(dlg)) ;
152 		ret = -1 ;
153     }
154     else
155     {
156         result = read_result_file( gms_get_out_filename(gms_hnd) ) ;
157 
158         if ( gms_get_output_mode( gms_hnd) == OUT_CURRENT_DOC )
159         {
160             if ( gms_get_input_mode( gms_hnd) != IN_SELECTION )
161                 select_entirely_doc(  sci  ) ;
162 
163             update_doc( sci, result ) ;
164         }
165         else
166         {
167             document_new_file( NULL, NULL, result ) ;
168         }
169     }
170     GMS_G_FREE( result ) ;
171 
172 	return ret ;
173 }
174 
175 /**
176  * \brief Callback when the menu item is clicked.
177  */
item_activate(GtkMenuItem * menuitem,gpointer gdata)178 static void item_activate(GtkMenuItem *menuitem, gpointer gdata)
179 {
180     GeanyDocument   *doc = document_get_current();
181     ScintillaObject *sci = doc->editor->sci ;
182     if ( gms_hnd  == NULL )
183         return ;
184 
185     if ( gms_dlg( gms_hnd ) == 0 )
186         return ;
187 
188     gms_create_filter_file( gms_hnd ) ;
189 
190     switch ( gms_get_input_mode(gms_hnd) )
191     {
192         case IN_CURRENT_DOC :
193             select_entirely_doc(  sci  ) ;
194             create_selection_2_input_file(sci) ;
195             run_filter( sci ) ;
196             delete_tmp_files() ;
197             break;
198         case IN_SELECTION :
199             create_selection_2_input_file(sci) ;
200             run_filter( sci ) ;
201             delete_tmp_files() ;
202             break;
203         case IN_DOCS_SESSION :
204             {
205                 guint nb_doc = 0  , i=0;
206 
207 				/* find the opened document in the geany session */
208                 while ( (doc = document_get_from_page(nb_doc))!=NULL ) nb_doc++;
209 
210                 /* For each document */
211                 for( i=0; i<nb_doc;i++)
212                 {
213                     doc = document_get_from_page(i) ;
214                     sci = doc->editor->sci ;
215                     select_entirely_doc(  sci  ) ;
216                     create_selection_2_input_file(sci) ;
217                     if ( run_filter( sci ) )
218 						break ; /* if error then stop the loop */
219                 }
220             }
221             delete_tmp_files() ;
222             break;
223         default:
224             delete_tmp_files() ;
225             return ;
226     }
227 
228 }
229 
230 
231 /**
232  * \brief Called by Geany to initialize the plugin.
233  * \note data is the same as geany_data.
234  */
plugin_init(GeanyData * data)235 void plugin_init(GeanyData *data)
236 {
237     const GeanyIndentPrefs *iprefs = editor_get_indent_prefs(NULL);
238 
239     gms_hnd = gms_new(geany->main_widgets->window,
240                     data->interface_prefs->editor_font ,
241                     iprefs->width,
242 					geany->app->configdir
243                     ) ;
244 
245     /* Add an item to the Tools menu */
246     gms_item = gtk_menu_item_new_with_mnemonic(_("_Mini-Script"));
247     gtk_widget_show(gms_item);
248     gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), gms_item);
249     g_signal_connect(gms_item, "activate", G_CALLBACK(item_activate), NULL);
250 
251     /* make the menu item sensitive only when documents are open */
252     ui_add_document_sensitive(gms_item);
253 
254 }
255 
256 
257 /* Called by Geany to show the plugin's configure dialog. This function is always called after
258  * plugin_init() was called.
259  * You can omit this function if the plugin doesn't need to be configured.
260  * Note: parent is the parent window which can be used as the transient window for the created
261  *  dialog. */
262 #if 1
plugin_configure(GtkDialog * dialog)263 GtkWidget *plugin_configure(GtkDialog *dialog)
264 {
265     g_signal_connect(dialog, "response", G_CALLBACK(on_gms_configure_response), gms_hnd );
266     return gms_configure_gui( gms_hnd ) ;
267 }
268 #endif
269 
270 /**
271  * \brief Called by Geany before unloading the plugin.
272  */
plugin_cleanup(void)273 void plugin_cleanup(void)
274 {
275     if ( gms_hnd != NULL )
276        gms_delete( &gms_hnd ) ;
277 
278     /* remove the menu item added in plugin_init() */
279     gtk_widget_destroy(gms_item);
280 }
281