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