Updated Spanish translation
[anjuta-git-plugin.git] / plugins / tools / execute.c
blob086e2318968d7e1683f7ac4f9ea0d1251a066ec3
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 execute.c
4 Copyright (C) 2005 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Execute an external tool
24 *---------------------------------------------------------------------------*/
26 #include <config.h>
28 #include "execute.h"
30 #include "variable.h"
32 #include <libanjuta/anjuta-utils.h>
33 #include <libanjuta/interfaces/ianjuta-document-manager.h>
34 #include <libanjuta/interfaces/ianjuta-editor.h>
35 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
36 #include <libanjuta/interfaces/ianjuta-file-savable.h>
37 #include <libanjuta/interfaces/ianjuta-file-loader.h>
39 #include <glib.h>
41 #include <ctype.h>
43 /*---------------------------------------------------------------------------*/
45 #define ICON_FILE "anjuta-tools-plugin.png"
46 #define MAX_TOOL_PANES 4
48 /* Widget and signal name found in glade file
49 *---------------------------------------------------------------------------*/
51 #define TOOL_PARAMS "param_dialog"
52 #define TOOL_PARAMS_EN "tool.params"
53 #define TOOL_PARAMS_EN_COMBO "tool.params.combo"
55 /*---------------------------------------------------------------------------*/
57 /* Output information
58 * Allow to have common code for handling stderr and stdout but it includes
59 * some part checking if this is used to implement stderr or stdout. So, It
60 * is strongly linked to ATPExecutionContext.
62 typedef struct
64 ATPOutputType type;
65 struct _ATPExecutionContext* execution;
66 IAnjutaMessageView* view;
67 gboolean created;
68 GString* buffer;
69 IAnjutaEditor* editor;
70 guint position;
71 } ATPOutputContext;
73 /* Execute information
74 * This is filled at the beginning with all necessary tool information,
75 * so it becomes independent from the tool after creation. It includes
76 * two OutputContext (one for stderr and one for stdout). The context
77 * is not destroyed when the tool execution terminate, so it can be
78 * reuse later for another tool. It useful mainly for keeping pointer
79 * on created message panes. All the tool context are kept in a list. */
80 typedef struct _ATPExecutionContext
82 gchar* name;
83 gchar* directory; // used for opening file from message pane
84 ATPOutputContext output;
85 ATPOutputContext error;
86 AnjutaPlugin *plugin;
87 AnjutaLauncher *launcher;
88 gboolean busy;
89 } ATPExecutionContext;
91 /* Helper function
92 *---------------------------------------------------------------------------*/
94 /* Save all current anjuta files */
95 static void
96 save_all_files (AnjutaPlugin *plugin)
98 IAnjutaDocumentManager *docman;
99 IAnjutaFileSavable* save;
101 docman = anjuta_shell_get_interface (plugin->shell, IAnjutaDocumentManager, NULL);
102 /* No document manager, so no file to save */
103 if (docman != NULL)
105 save = IANJUTA_FILE_SAVABLE (docman);
106 if (save) ianjuta_file_savable_save (save, NULL);
110 /* Replace variable in source and add prefix separated with a space */
111 static gchar*
112 replace_variable (const gchar* prefix, const gchar* source,
113 ATPVariable* variable)
115 guint len;
116 gchar *val;
117 GString* str;
119 /* Create string and add prefix */
120 str = g_string_new (prefix);
121 if (prefix != NULL)
123 g_string_append_c (str, ' ');
126 /* Add source and replace variable */
127 if (source != NULL)
129 for (; *source != '\0'; source += len)
131 if (source[0] != '$')
133 /* Just append anything that doesn't looks like a variable */
134 for (len = 0; (source[len] != '\0') &&
135 (source[len] != '$'); len++);
136 g_string_append_len (str, source, len);
138 else if (source[1] != '(')
140 g_string_append_c (str, '$');
141 len = 1;
143 else
145 /* Check if there is a variable */
146 for (len = 2; g_ascii_isalnum(source[len])
147 || (source[len] == '_') ; len++);
148 if (source[len] == ')')
150 len++;
151 val = atp_variable_get_value_from_name_part (variable, source + 2, len - 3);
152 if (val)
154 /* This is really a variable, replace */
155 g_string_append (str, val);
156 continue;
160 /* It's not a variable */
161 g_string_append_len (str, source, len);
166 /* Remove leading space, trailing space and empty string */
167 val = g_string_free (str, FALSE);
168 if (val != NULL)
170 g_strstrip (val);
171 if ((val != NULL) && (*val == '\0'))
173 g_free (val);
174 val = NULL;
178 return val;
181 static gboolean
182 parse_error_line (const gchar * line, gchar ** filename, int *lineno)
184 gint i = 0;
185 gint j = 0;
186 gint k = 0;
187 gchar *dummy;
189 while (line[i++] != ':')
191 if (i >= strlen (line) || i >= 512 || line[i - 1] == ' ')
193 goto down;
196 if (isdigit (line[i]))
198 j = i;
199 while (isdigit (line[i++])) ;
200 dummy = g_strndup (&line[j], i - j - 1);
201 *lineno = atoi (dummy);
202 if (dummy)
203 g_free (dummy);
204 dummy = g_strndup (line, j - 1);
205 *filename = g_strdup (g_strstrip (dummy));
206 if (dummy)
207 g_free (dummy);
208 return TRUE;
211 down:
212 i = strlen (line) - 1;
213 while (isspace (line[i]) == FALSE)
215 i--;
216 if (i < 0)
218 *filename = NULL;
219 *lineno = 0;
220 return FALSE;
223 k = i++;
224 while (line[i++] != ':')
226 if (i >= strlen (line) || i >= 512 || line[i - 1] == ' ')
228 *filename = NULL;
229 *lineno = 0;
230 return FALSE;
233 if (isdigit (line[i]))
235 j = i;
236 while (isdigit (line[i++])) ;
237 dummy = g_strndup (&line[j], i - j - 1);
238 *lineno = atoi (dummy);
239 if (dummy)
240 g_free (dummy);
241 dummy = g_strndup (&line[k], j - k - 1);
242 *filename = g_strdup (g_strstrip (dummy));
243 if (dummy)
244 g_free (dummy);
245 return TRUE;
247 *lineno = 0;
248 *filename = NULL;
249 return FALSE;
252 /* Output context functions
253 *---------------------------------------------------------------------------*/
255 static void
256 on_message_buffer_click (IAnjutaMessageView *view, const gchar *line,
257 ATPOutputContext *this)
259 gchar *filename;
260 gint lineno;
262 if (parse_error_line (line, &filename, &lineno))
264 gchar *uri;
265 IAnjutaFileLoader *loader;
267 /* Go to file and line number */
268 loader = anjuta_shell_get_interface (this->execution->plugin->shell,
269 IAnjutaFileLoader,
270 NULL);
272 /* Append current directory */
273 if ((this->execution->directory != NULL) &&
274 (*filename != G_DIR_SEPARATOR))
276 if (*filename == '.')
278 uri = g_strdup_printf ("file://%s/%s#%d",
279 this->execution->directory,
280 filename + 1, lineno);
282 else
284 uri = g_strdup_printf ("file://%s/%s#%d",
285 this->execution->directory,
286 filename, lineno);
289 else
291 uri = g_strdup_printf ("file:///%s#%d", filename, lineno);
293 g_free (filename);
294 ianjuta_file_loader_load (loader, uri, FALSE, NULL);
295 g_free (uri);
299 static void
300 on_message_buffer_flush (IAnjutaMessageView *view, const gchar *msg_line,
301 ATPOutputContext *this)
303 gchar *dummy_fn;
304 gint dummy_int;
305 gchar *line;
306 IAnjutaMessageViewType type;
308 /* If there is a gdb style annotation to open a file, open it */
309 if (strlen(msg_line) > 2 && msg_line[0] == '\032' &&
310 msg_line[1] == '\032')
312 line = g_strdup_printf (_("Opening %s"), &msg_line[2]);
313 on_message_buffer_click (view, &msg_line[2], this);
315 else
317 line = g_strdup (msg_line);
320 if (this->view)
322 gchar *desc = "";
324 type = IANJUTA_MESSAGE_VIEW_TYPE_NORMAL;
325 if (parse_error_line(line, &dummy_fn, &dummy_int))
327 g_free (dummy_fn);
328 if ((strstr (line, _("warning:")) != NULL) ||
329 (strstr (line, "warning:") != NULL))
331 type = IANJUTA_MESSAGE_VIEW_TYPE_WARNING;
333 else if ((strstr (line, _("error:")) != NULL) ||
334 (strstr (line, "error:") != NULL))
336 type = IANJUTA_MESSAGE_VIEW_TYPE_ERROR;
338 desc = line;
340 else if (strstr (line, ":") != NULL)
342 type = IANJUTA_MESSAGE_VIEW_TYPE_INFO;
344 ianjuta_message_view_append (this->view, type, line, desc, NULL);
346 g_free (line);
349 /* Handle output for stdout and stderr */
350 static gboolean
351 atp_output_context_print (ATPOutputContext *this, const gchar* text)
353 const gchar* str;
355 if (this->type == ATP_TOUT_SAME)
357 /* Valid for error output only, get output type
358 * from standard output */
359 this = &this->execution->output;
362 switch (this->type)
364 case ATP_TOUT_SAME:
365 /* output should not use this */
366 g_return_val_if_reached (TRUE);
367 break;
368 case ATP_TOUT_NULL:
369 break;
370 case ATP_TOUT_COMMON_PANE:
371 case ATP_TOUT_NEW_PANE:
372 /* Check if the view has already been created */
373 if (this->created == FALSE)
375 IAnjutaMessageManager *man;
376 gchar* title = this->execution->name;
378 man = anjuta_shell_get_interface (this->execution->plugin->shell,
379 IAnjutaMessageManager, NULL);
380 if (this->view == NULL)
382 this->view = ianjuta_message_manager_add_view (man, title,
383 ICON_FILE,
384 NULL);
385 g_signal_connect (G_OBJECT (this->view), "buffer_flushed",
386 G_CALLBACK (on_message_buffer_flush), this);
387 g_signal_connect (G_OBJECT (this->view), "message_clicked",
388 G_CALLBACK (on_message_buffer_click), this);
389 g_object_add_weak_pointer (G_OBJECT (this->view),
390 (gpointer *)(gpointer)&this->view);
392 else
394 ianjuta_message_view_clear (this->view, NULL);
396 if (this->execution->error.type == ATP_TOUT_SAME)
398 /* Same message used for all outputs */
399 str = "";
401 else if (this == &this->execution->output)
403 /* Only for output data */
404 str = _("(output)");
406 else
408 /* Only for error data */
409 str = _("(error)");
411 title = g_strdup_printf ("%s %s", this->execution->name, str);
413 ianjuta_message_manager_set_view_title (man, this->view,
414 title, NULL);
415 g_free (title);
416 this->created = TRUE;
418 /* Display message */
419 if (this->view)
421 ianjuta_message_view_buffer_append (this->view, text, NULL);
423 break;
424 case ATP_TOUT_NEW_BUFFER:
425 case ATP_TOUT_REPLACE_BUFFER:
426 if (this->editor)
428 ianjuta_editor_append (this->editor, text, strlen(text), NULL);
430 break;
431 case ATP_TOUT_INSERT_BUFFER:
432 case ATP_TOUT_APPEND_BUFFER:
433 case ATP_TOUT_REPLACE_SELECTION:
434 case ATP_TOUT_POPUP_DIALOG:
435 g_string_append (this->buffer, text);
436 break;
437 case ATP_TOUT_UNKNOWN:
438 case ATP_OUTPUT_TYPE_COUNT:
439 g_return_val_if_reached (TRUE);
442 return TRUE;
445 /* Write a small message at the beginning use only on stdout */
446 static gboolean
447 atp_output_context_print_command (ATPOutputContext *this, const gchar* command)
449 gboolean ok;
451 ok = TRUE;
452 switch (this->type)
454 case ATP_TOUT_NULL:
455 case ATP_TOUT_SAME:
456 break;
457 case ATP_TOUT_COMMON_PANE:
458 case ATP_TOUT_NEW_PANE:
460 ok = atp_output_context_print (this, _("Running command: "));
461 ok &= atp_output_context_print (this, command);
462 ok &= atp_output_context_print (this, "...\n");
463 break;
464 case ATP_TOUT_NEW_BUFFER:
465 case ATP_TOUT_REPLACE_BUFFER:
466 case ATP_TOUT_INSERT_BUFFER:
467 case ATP_TOUT_APPEND_BUFFER:
468 case ATP_TOUT_REPLACE_SELECTION:
469 case ATP_TOUT_POPUP_DIALOG:
470 /* Do nothing for all these cases */
471 break;
472 case ATP_TOUT_UNKNOWN:
473 case ATP_OUTPUT_TYPE_COUNT:
474 g_return_val_if_reached (TRUE);
477 return ok;
480 /* Call at the end for stdout and stderr */
481 static gboolean
482 atp_output_context_print_result (ATPOutputContext *this, gint error)
484 gboolean ok;
485 char buffer[33];
486 IAnjutaMessageManager *man;
488 ok = TRUE;
489 switch (this->type)
491 case ATP_TOUT_NULL:
492 case ATP_TOUT_SAME:
493 break;
494 case ATP_TOUT_COMMON_PANE:
495 case ATP_TOUT_NEW_PANE:
496 if (this == &this->execution->output)
498 if (error)
500 ok = atp_output_context_print (this, _("Completed... unsuccessful with "));
501 sprintf (buffer, "%d", error);
502 ok &= atp_output_context_print (this, buffer);
504 else
506 ok = atp_output_context_print (this, _("Completed... successful"));
508 ok &= atp_output_context_print (this, "\n");
509 if (this->view)
511 man = anjuta_shell_get_interface (this->execution->plugin->shell,
512 IAnjutaMessageManager, NULL);
513 ianjuta_message_manager_set_current_view (man, this->view, NULL);
517 break;
518 case ATP_TOUT_NEW_BUFFER:
519 case ATP_TOUT_REPLACE_BUFFER:
520 /* Do nothing */
521 break;
522 case ATP_TOUT_INSERT_BUFFER:
523 if (this->editor)
525 ianjuta_editor_insert (this->editor, this->position, this->buffer->str,
526 this->buffer->len, NULL);
528 g_string_free (this->buffer, TRUE);
529 this->buffer = NULL;
530 break;
531 case ATP_TOUT_APPEND_BUFFER:
532 if (this->editor)
534 ianjuta_editor_append (this->editor, this->buffer->str,
535 this->buffer->len, NULL);
537 g_string_free (this->buffer, TRUE);
538 this->buffer = NULL;
539 break;
540 case ATP_TOUT_REPLACE_SELECTION:
541 if (this->editor)
543 ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (this->editor),
544 this->buffer->str,
545 this->buffer->len, NULL);
547 g_string_free (this->buffer, TRUE);
548 this->buffer = NULL;
549 break;
550 case ATP_TOUT_POPUP_DIALOG:
551 if (this->buffer->len)
553 if (this == &this->execution->output)
555 anjuta_util_dialog_info (GTK_WINDOW (this->execution->plugin->shell),
556 this->buffer->str);
558 else
560 anjuta_util_dialog_error (GTK_WINDOW (this->execution->plugin->shell),
561 this->buffer->str);
563 g_string_free (this->buffer, TRUE);
564 this->buffer = NULL;
566 break;
567 case ATP_TOUT_UNKNOWN:
568 case ATP_OUTPUT_TYPE_COUNT:
569 g_return_val_if_reached (TRUE);
572 return ok;
575 static IAnjutaEditor*
576 get_current_editor(IAnjutaDocumentManager* docman)
578 if (docman == NULL)
579 return NULL;
580 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(docman, NULL);
581 if (doc && IANJUTA_IS_EDITOR(doc))
582 return IANJUTA_EDITOR(doc);
583 else
584 return NULL;
587 static ATPOutputContext*
588 atp_output_context_initialize (ATPOutputContext *this,
589 ATPExecutionContext *execution,
590 ATPOutputType type)
592 IAnjutaDocumentManager *docman;
594 this->type = type;
595 switch (this->type)
597 case ATP_TOUT_NULL:
598 case ATP_TOUT_SAME:
599 break;
600 case ATP_TOUT_COMMON_PANE:
601 case ATP_TOUT_NEW_PANE:
602 this->created = FALSE;
603 break;
604 case ATP_TOUT_REPLACE_BUFFER:
605 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->execution->plugin)->shell, IAnjutaDocumentManager, NULL);
606 this->editor = get_current_editor(docman);
607 if (this->editor != NULL)
609 g_object_add_weak_pointer (G_OBJECT (this->editor), (gpointer *)(gpointer)&this->editor);
610 ianjuta_editor_erase_all (this->editor, NULL);
611 break;
613 /* Go through, try to create a new buffer */
614 case ATP_TOUT_NEW_BUFFER:
615 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->execution->plugin)->shell, IAnjutaDocumentManager, NULL);
616 this->editor = get_current_editor(docman);
617 if (this->editor == NULL)
619 anjuta_util_dialog_warning (GTK_WINDOW (this->execution->plugin->shell), _("Unable to create a buffer, command aborted"));
620 return NULL;
622 g_object_add_weak_pointer (G_OBJECT (this->editor), (gpointer *)(gpointer)&this->editor);
623 break;
624 case ATP_TOUT_INSERT_BUFFER:
625 case ATP_TOUT_APPEND_BUFFER:
626 case ATP_TOUT_REPLACE_SELECTION:
627 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->execution->plugin)->shell, IAnjutaDocumentManager, NULL);
628 this->editor = docman == NULL ? NULL : IANJUTA_EDITOR( ianjuta_document_manager_get_current_document (docman, NULL));
629 if (this->editor == NULL)
631 anjuta_util_dialog_warning (GTK_WINDOW (this->execution->plugin->shell), _("No document currently open, command aborted"));
632 return NULL;
634 g_object_add_weak_pointer (G_OBJECT (this->editor), (gpointer *)(gpointer)&this->editor);
635 this->position = ianjuta_editor_get_position (this->editor, NULL);
636 /* No break, need a buffer too */
637 case ATP_TOUT_POPUP_DIALOG:
638 if (this->buffer == NULL)
640 this->buffer = g_string_new ("");
642 else
644 g_string_erase (this->buffer, 0, -1);
646 break;
647 case ATP_TOUT_UNKNOWN:
648 case ATP_OUTPUT_TYPE_COUNT:
649 g_return_val_if_reached (this);
652 return this;
656 static ATPOutputContext*
657 atp_output_context_construct (ATPOutputContext *this,
658 ATPExecutionContext *execution,
659 ATPOutputType type)
662 this->execution = execution;
663 this->view = NULL;
664 this->buffer = NULL;
666 return atp_output_context_initialize (this, execution, type);
669 static void
670 atp_output_context_destroy (ATPOutputContext *this)
672 if (this->view)
674 IAnjutaMessageManager *man;
676 man = anjuta_shell_get_interface (this->execution->plugin->shell,
677 IAnjutaMessageManager, NULL);
678 ianjuta_message_manager_remove_view (man, this->view, NULL);
679 this->view = NULL;
681 if (this->buffer)
683 g_string_free (this->buffer, TRUE);
687 /* Execution context
688 *---------------------------------------------------------------------------*/
690 static void
691 on_run_terminated (AnjutaLauncher* launcher, gint pid, gint status,
692 gulong time, gpointer user_data)
694 ATPExecutionContext *this = (ATPExecutionContext *)user_data;
696 atp_output_context_print_result (&this->output, status);
697 atp_output_context_print_result (&this->error, status);
698 this->busy = FALSE;
701 static void
702 on_run_output (AnjutaLauncher* launcher, AnjutaLauncherOutputType type,
703 const gchar* output, gpointer user_data)
705 ATPExecutionContext* this = (ATPExecutionContext*)user_data;
707 switch (type)
709 case ANJUTA_LAUNCHER_OUTPUT_STDOUT:
710 atp_output_context_print (&this->output, output);
711 break;
712 case ANJUTA_LAUNCHER_OUTPUT_STDERR:
713 atp_output_context_print (&this->error, output);
714 break;
715 case ANJUTA_LAUNCHER_OUTPUT_PTY:
716 break;
720 static ATPExecutionContext*
721 atp_execution_context_reuse (ATPExecutionContext* this, const gchar *name,
722 ATPOutputType output, ATPOutputType error)
724 if (this->name) g_free (this->name);
725 this->name = atp_remove_mnemonic (name);
727 if (atp_output_context_initialize (&this->output, this, output) == NULL)
729 return NULL;
731 if (atp_output_context_initialize (&this->error, this, error) == NULL)
733 return NULL;
736 return this;
739 static ATPExecutionContext*
740 atp_execution_context_new (AnjutaPlugin *plugin, const gchar *name,
741 guint id, ATPOutputType output, ATPOutputType error)
743 ATPExecutionContext *this;
745 this = g_new0 (ATPExecutionContext, 1);
747 this->plugin = plugin;
748 this->launcher = anjuta_launcher_new ();
749 g_signal_connect (G_OBJECT (this->launcher), "child-exited",
750 G_CALLBACK (on_run_terminated), this);
751 this->name = atp_remove_mnemonic (name);
753 if (atp_output_context_construct (&this->output, this, output) == NULL)
755 g_free (this);
756 return NULL;
758 if (atp_output_context_construct (&this->error, this, error) == NULL)
760 g_free (this);
761 return NULL;
764 return this;
767 static void
768 atp_execution_context_free (ATPExecutionContext* this)
770 atp_output_context_destroy (&this->output);
771 atp_output_context_destroy (&this->error);
773 if (this->launcher)
775 g_object_unref (this->launcher);
777 if (this->name) g_free (this->name);
778 if (this->directory) g_free (this->directory);
780 g_free (this);
783 static void
784 atp_execution_context_set_directory (ATPExecutionContext* this,
785 const gchar* directory)
787 if (this->directory != NULL) g_free (this->directory);
788 this->directory = directory == NULL ? NULL : g_strdup (directory);
791 static void
792 atp_execution_context_execute (ATPExecutionContext* this,
793 const gchar* command, const gchar* input)
795 gchar* prev_dir = NULL;
797 atp_output_context_print_command (&this->output, command);
799 /* Change working directory */
800 if (this->directory != NULL)
802 prev_dir = g_get_current_dir();
803 chdir (this->directory);
805 /* Execute */
806 anjuta_launcher_execute (this->launcher, command, on_run_output, this);
807 /* Restore previous current directory */
808 if (this->directory != NULL)
810 chdir (prev_dir);
811 g_free (prev_dir);
813 anjuta_launcher_set_encoding (this->launcher, NULL);
814 this->busy = TRUE;
816 /* Send stdin data if needed */
817 if (input != NULL)
819 anjuta_launcher_send_stdin (this->launcher, input);
820 /* Send end marker */
821 anjuta_launcher_send_stdin (this->launcher, "\x04");
825 /* Execute context list
826 *---------------------------------------------------------------------------*/
828 ATPContextList *
829 atp_context_list_construct (ATPContextList *this)
831 this->list = NULL;
832 return this;
835 void
836 atp_context_list_destroy (ATPContextList *this)
838 GList *item;
840 for (item = this->list; item != NULL; item = this->list)
842 this->list = g_list_remove_link (this->list, item);
843 atp_execution_context_free ((ATPExecutionContext *)item->data);
844 g_list_free (item);
848 static ATPExecutionContext*
849 atp_context_list_find_context (ATPContextList *this, AnjutaPlugin *plugin,
850 const gchar* name, ATPOutputType output,
851 ATPOutputType error)
853 ATPExecutionContext* context;
854 GList* reuse = NULL;
855 guint best;
856 guint pane;
857 GList* node;
858 gboolean new_pane;
859 gboolean output_pane;
860 gboolean error_pane;
862 pane = 0;
863 best = 0;
864 context = NULL;
865 new_pane = (output == ATP_TOUT_NEW_PANE) || (error == ATP_TOUT_NEW_PANE);
866 output_pane = (output == ATP_TOUT_NEW_PANE) || (output == ATP_TOUT_COMMON_PANE);
867 error_pane = (error == ATP_TOUT_NEW_PANE) || (error == ATP_TOUT_COMMON_PANE);
868 for (node = this->list; node != NULL; node = g_list_next (node))
870 ATPExecutionContext* current;
871 guint score;
873 current = (ATPExecutionContext *)node->data;
875 /* Count number of used message panes */
876 if (current->output.view != NULL) pane++;
877 if (current->error.view != NULL) pane++;
879 score = 1;
880 if ((current->output.view != NULL) == output_pane) score++;
881 if ((current->error.view != NULL) == error_pane) score++;
883 if (!current->busy)
885 if ((score > best) || ((score == best) && (new_pane)))
887 /* Reuse this context */
888 context = current;
889 reuse = node;
890 best = score;
895 if ((new_pane) && (pane < MAX_TOOL_PANES))
897 /* Not too many message pane, we can create a new one */
898 context = NULL;
901 if (context == NULL)
903 /* Create a new node */
904 context = atp_execution_context_new (plugin, name, 0, output, error);
905 if (context != NULL)
907 this->list = g_list_prepend (this->list, context);
910 else
912 this->list = g_list_remove_link (this->list, reuse);
913 context = atp_execution_context_reuse (context, name, output, error);
914 if (context != NULL)
916 this->list = g_list_concat (reuse, this->list);
920 return context;
923 /* Execute tools
924 *---------------------------------------------------------------------------*/
926 /* Menu activate handler which executes the tool. It should do command
927 ** substitution, input, output and error redirection, setting the
928 ** working directory, etc.
930 void
931 atp_user_tool_execute (GtkMenuItem *item, ATPUserTool* this)
933 ATPPlugin* plugin;
934 ATPVariable* variable;
935 ATPContextList* list;
936 ATPExecutionContext* context;
937 IAnjutaDocumentManager *docman;
938 IAnjutaEditor *ed;
939 gchar* dir;
940 gchar* cmd;
941 gchar* input;
942 gchar* val = NULL;
944 plugin = atp_user_tool_get_plugin (this);
945 variable = atp_plugin_get_variable (plugin);
947 /* Save files if requested */
948 if (atp_user_tool_get_flag (this, ATP_TOOL_AUTOSAVE))
950 save_all_files (ANJUTA_PLUGIN (plugin));
953 /* Make command line */
954 cmd = replace_variable (atp_user_tool_get_command (this),
955 atp_user_tool_get_param (this), variable);
957 /* Get working directory and replace variable */
958 dir = replace_variable (NULL, atp_user_tool_get_working_dir (this),
959 variable);
961 if (atp_user_tool_get_flag (this, ATP_TOOL_TERMINAL))
963 /* Run in a terminal */
964 /* don't need a execution context, launch and forget */
966 gnome_execute_terminal_shell (dir, cmd);
968 else
970 /* Get stdin if necessary */
971 input = NULL;
972 switch (atp_user_tool_get_input (this))
974 case ATP_TIN_BUFFER:
975 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
976 IAnjutaDocumentManager, NULL);
977 ed = get_current_editor(docman);
978 if (ed != NULL)
980 input = ianjuta_editor_get_text (ed, 0, -1, NULL);
982 break;
983 case ATP_TIN_SELECTION:
984 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
985 IAnjutaDocumentManager, NULL);
986 ed = get_current_editor(docman);
987 if (ed != NULL)
989 input = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (ed),
990 NULL);
992 break;
993 case ATP_TIN_STRING:
994 input = replace_variable (NULL,
995 atp_user_tool_get_input_string (this),
996 variable);
997 break;
998 case ATP_TIN_FILE:
999 val = replace_variable (NULL, atp_user_tool_get_input_string (this),
1000 variable);
1001 if ((val == NULL) || (!g_file_get_contents (val, &input, NULL, NULL)))
1003 anjuta_util_dialog_error (atp_plugin_get_app_window (plugin),
1004 _("Unable to open input file %s, Command aborted"), val == NULL ? "(null)" : val);
1005 if (val != NULL) g_free (val);
1006 if (dir != NULL) g_free (dir);
1007 if (cmd != NULL) g_free (cmd);
1009 return;
1011 g_free (val);
1012 break;
1013 default:
1014 break;
1017 list = atp_plugin_get_context_list (plugin);
1019 context = atp_context_list_find_context (list, ANJUTA_PLUGIN(plugin),
1020 atp_user_tool_get_name (this),
1021 atp_user_tool_get_output (this),
1022 atp_user_tool_get_error (this));
1024 if (context)
1026 /* Set working directory */
1027 atp_execution_context_set_directory (context, dir);
1029 /* Run command */
1030 atp_execution_context_execute (context, cmd, input);
1033 if (input != NULL) g_free(input);
1036 if (dir != NULL) g_free (dir);
1037 if (cmd != NULL) g_free (cmd);