debug-manager: removed size_request
[anjuta.git] / plugins / tools / execute.c
blob0b53c5d5c84089e98a797292b81eddabb53d21e8
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>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <ctype.h>
44 /*---------------------------------------------------------------------------*/
46 #define ICON_FILE "anjuta-tools-plugin-48.png"
47 #define MAX_TOOL_PANES 4
49 /* Widget and signal name found in glade file
50 *---------------------------------------------------------------------------*/
52 #define TOOL_PARAMS "param_dialog"
53 #define TOOL_PARAMS_EN "tool.params"
54 #define TOOL_PARAMS_EN_COMBO "tool.params.combo"
56 /*---------------------------------------------------------------------------*/
58 /* Output information
59 * Allow to have common code for handling stderr and stdout but it includes
60 * some part checking if this is used to implement stderr or stdout. So, It
61 * is strongly linked to ATPExecutionContext.
63 typedef struct
65 ATPOutputType type;
66 struct _ATPExecutionContext* execution;
67 IAnjutaMessageView* view;
68 gboolean created;
69 GString* buffer;
70 IAnjutaEditor* editor;
71 IAnjutaIterable *position;
72 } ATPOutputContext;
74 /* Execute information
75 * This is filled at the beginning with all necessary tool information,
76 * so it becomes independent from the tool after creation. It includes
77 * two OutputContext (one for stderr and one for stdout). The context
78 * is not destroyed when the tool execution terminate, so it can be
79 * reuse later for another tool. It useful mainly for keeping pointer
80 * on created message panes. All the tool context are kept in a list. */
81 typedef struct _ATPExecutionContext
83 gchar* name;
84 gchar* directory; // used for opening file from message pane
85 ATPOutputContext output;
86 ATPOutputContext error;
87 AnjutaPlugin *plugin;
88 AnjutaLauncher *launcher;
89 gboolean busy;
90 } ATPExecutionContext;
92 /* Helper function
93 *---------------------------------------------------------------------------*/
95 /* Save all current anjuta files */
96 static void
97 save_all_files (AnjutaPlugin *plugin)
99 IAnjutaDocumentManager *docman;
100 IAnjutaFileSavable* save;
102 docman = anjuta_shell_get_interface (plugin->shell, IAnjutaDocumentManager, NULL);
103 /* No document manager, so no file to save */
104 if (docman != NULL)
106 save = IANJUTA_FILE_SAVABLE (docman);
107 if (save) ianjuta_file_savable_save (save, NULL);
111 /* Replace variable in source and add prefix separated with a space */
112 static gchar*
113 replace_variable (const gchar* prefix, const gchar* source,
114 ATPVariable* variable)
116 guint len;
117 gchar *val;
118 GString* str;
120 /* Create string and add prefix */
121 str = g_string_new (prefix);
122 if (prefix != NULL)
124 g_string_append_c (str, ' ');
127 /* Add source and replace variable */
128 if (source != NULL)
130 for (; *source != '\0'; source += len)
132 if (source[0] != '$')
134 /* Just append anything that doesn't looks like a variable */
135 for (len = 0; (source[len] != '\0') &&
136 (source[len] != '$'); len++);
137 g_string_append_len (str, source, len);
139 else if (source[1] != '(')
141 g_string_append_c (str, '$');
142 len = 1;
144 else
146 /* Check if there is a variable */
147 for (len = 2; g_ascii_isalnum(source[len])
148 || (source[len] == '_') ; len++);
149 if (source[len] == ')')
151 len++;
152 val = atp_variable_get_value_from_name_part (variable, source + 2, len - 3);
153 if (val)
155 /* This is really a variable, replace */
156 g_string_append (str, val);
157 continue;
161 /* It's not a variable */
162 g_string_append_len (str, source, len);
167 /* Remove leading space, trailing space and empty string */
168 val = g_string_free (str, FALSE);
169 if (val != NULL)
171 g_strstrip (val);
172 if ((val != NULL) && (*val == '\0'))
174 g_free (val);
175 val = NULL;
179 return val;
182 static gboolean
183 parse_error_line (const gchar * line, gchar ** filename, int *lineno)
185 gint i = 0;
186 gint j = 0;
187 gint k = 0;
188 gchar *dummy;
190 while (line[i++] != ':')
192 if (i >= strlen (line) || i >= 512 || line[i - 1] == ' ')
194 goto down;
197 if (isdigit (line[i]))
199 j = i;
200 while (isdigit (line[i++])) ;
201 dummy = g_strndup (&line[j], i - j - 1);
202 *lineno = atoi (dummy);
203 if (dummy)
204 g_free (dummy);
205 dummy = g_strndup (line, j - 1);
206 *filename = g_strdup (g_strstrip (dummy));
207 if (dummy)
208 g_free (dummy);
209 return TRUE;
212 down:
213 i = strlen (line) - 1;
214 while (isspace (line[i]) == FALSE)
216 i--;
217 if (i < 0)
219 *filename = NULL;
220 *lineno = 0;
221 return FALSE;
224 k = i++;
225 while (line[i++] != ':')
227 if (i >= strlen (line) || i >= 512 || line[i - 1] == ' ')
229 *filename = NULL;
230 *lineno = 0;
231 return FALSE;
234 if (isdigit (line[i]))
236 j = i;
237 while (isdigit (line[i++])) ;
238 dummy = g_strndup (&line[j], i - j - 1);
239 *lineno = atoi (dummy);
240 if (dummy)
241 g_free (dummy);
242 dummy = g_strndup (&line[k], j - k - 1);
243 *filename = g_strdup (g_strstrip (dummy));
244 if (dummy)
245 g_free (dummy);
246 return TRUE;
248 *lineno = 0;
249 *filename = NULL;
250 return FALSE;
253 /* Output context functions
254 *---------------------------------------------------------------------------*/
256 static void
257 on_message_buffer_click (IAnjutaMessageView *view, const gchar *line,
258 ATPOutputContext *this)
260 gchar *filename;
261 gint lineno;
263 if (parse_error_line (line, &filename, &lineno))
265 gchar *path;
266 GFile* file;
267 IAnjutaDocumentManager* docman;
269 /* Go to file and line number */
270 docman = anjuta_shell_get_interface (this->execution->plugin->shell,
271 IAnjutaDocumentManager,
272 NULL);
274 /* Append current directory */
275 if ((this->execution->directory != NULL) &&
276 (*filename != G_DIR_SEPARATOR))
278 if (*filename == '.')
280 path = g_build_filename (this->execution->directory,
281 filename + 1, NULL);
283 else
285 path = g_build_filename (this->execution->directory,
286 filename, NULL);
289 else
291 path = g_strdup(filename);
293 g_free (filename);
294 file = g_file_new_for_path (path);
295 ianjuta_document_manager_goto_file_line (docman, file, lineno, NULL);
296 g_free (path);
297 g_object_unref (file);
301 static void
302 on_message_buffer_flush (IAnjutaMessageView *view, const gchar *msg_line,
303 ATPOutputContext *this)
305 gchar *dummy_fn;
306 gint dummy_int;
307 gchar *line;
308 IAnjutaMessageViewType type;
310 /* If there is a gdb style annotation to open a file, open it */
311 if (strlen(msg_line) > 2 && msg_line[0] == '\032' &&
312 msg_line[1] == '\032')
314 line = g_strdup_printf (_("Opening %s"), &msg_line[2]);
315 on_message_buffer_click (view, &msg_line[2], this);
317 else
319 line = g_strdup (msg_line);
322 if (this->view)
324 gchar *desc = "";
326 type = IANJUTA_MESSAGE_VIEW_TYPE_NORMAL;
327 if (parse_error_line(line, &dummy_fn, &dummy_int))
329 g_free (dummy_fn);
330 if ((strstr (line, _("warning:")) != NULL) ||
331 (strstr (line, "warning:") != NULL))
333 type = IANJUTA_MESSAGE_VIEW_TYPE_WARNING;
335 else if ((strstr (line, _("error:")) != NULL) ||
336 (strstr (line, "error:") != NULL))
338 type = IANJUTA_MESSAGE_VIEW_TYPE_ERROR;
340 desc = line;
342 else if (strstr (line, ":") != NULL)
344 type = IANJUTA_MESSAGE_VIEW_TYPE_INFO;
346 ianjuta_message_view_append (this->view, type, line, desc, NULL);
348 g_free (line);
351 /* Handle output for stdout and stderr */
352 static gboolean
353 atp_output_context_print (ATPOutputContext *this, const gchar* text)
355 const gchar* str;
357 if (this->type == ATP_TOUT_SAME)
359 /* Valid for error output only, get output type
360 * from standard output */
361 this = &this->execution->output;
364 switch (this->type)
366 case ATP_TOUT_SAME:
367 /* output should not use this */
368 g_return_val_if_reached (TRUE);
369 break;
370 case ATP_TOUT_NULL:
371 break;
372 case ATP_TOUT_COMMON_PANE:
373 case ATP_TOUT_NEW_PANE:
374 /* Check if the view has already been created */
375 if (this->created == FALSE)
377 IAnjutaMessageManager *man;
378 gchar* title = this->execution->name;
380 man = anjuta_shell_get_interface (this->execution->plugin->shell,
381 IAnjutaMessageManager, NULL);
382 if (this->view == NULL)
384 this->view = ianjuta_message_manager_add_view (man, title,
385 ICON_FILE,
386 NULL);
387 g_signal_connect (G_OBJECT (this->view), "buffer_flushed",
388 G_CALLBACK (on_message_buffer_flush), this);
389 g_signal_connect (G_OBJECT (this->view), "message_clicked",
390 G_CALLBACK (on_message_buffer_click), this);
391 g_object_add_weak_pointer (G_OBJECT (this->view),
392 (gpointer *)(gpointer)&this->view);
394 else
396 ianjuta_message_view_clear (this->view, NULL);
398 if (this->execution->error.type == ATP_TOUT_SAME)
400 /* Same message used for all outputs */
401 str = "";
403 else if (this == &this->execution->output)
405 /* This is append to the tool name to give something
406 * like "My tools (output)". It's used to name the message
407 * pane where the output of the tool is send to
409 str = _("(output)");
411 else
413 /* This is append to the tool name to give something
414 * like "My tools (error)". It's used to name the message
415 * pane where the errors of the tool is send to
417 str = _("(error)");
419 title = g_strdup_printf ("%s %s", this->execution->name, str);
421 ianjuta_message_manager_set_view_title (man, this->view,
422 title, NULL);
423 g_free (title);
424 this->created = TRUE;
426 /* Display message */
427 if (this->view)
429 ianjuta_message_view_buffer_append (this->view, text, NULL);
431 break;
432 case ATP_TOUT_NEW_BUFFER:
433 case ATP_TOUT_REPLACE_BUFFER:
434 if (this->editor)
436 ianjuta_editor_append (this->editor, text, strlen(text), NULL);
438 break;
439 case ATP_TOUT_INSERT_BUFFER:
440 case ATP_TOUT_APPEND_BUFFER:
441 case ATP_TOUT_REPLACE_SELECTION:
442 case ATP_TOUT_POPUP_DIALOG:
443 g_string_append (this->buffer, text);
444 break;
445 case ATP_TOUT_UNKNOWN:
446 case ATP_OUTPUT_TYPE_COUNT:
447 g_return_val_if_reached (TRUE);
450 return TRUE;
453 /* Write a small message at the beginning use only on stdout */
454 static gboolean
455 atp_output_context_print_command (ATPOutputContext *this, const gchar* command)
457 gboolean ok;
458 gchar *msg;
460 ok = TRUE;
461 switch (this->type)
463 case ATP_TOUT_NULL:
464 case ATP_TOUT_SAME:
465 break;
466 case ATP_TOUT_COMMON_PANE:
467 case ATP_TOUT_NEW_PANE:
468 /* Display the name of the command */
469 msg = g_strdup_printf(_("Running command: %s…\n"), command);
470 ok = atp_output_context_print (this, msg);
471 g_free (msg);
472 break;
473 case ATP_TOUT_NEW_BUFFER:
474 case ATP_TOUT_REPLACE_BUFFER:
475 case ATP_TOUT_INSERT_BUFFER:
476 case ATP_TOUT_APPEND_BUFFER:
477 case ATP_TOUT_REPLACE_SELECTION:
478 case ATP_TOUT_POPUP_DIALOG:
479 /* Do nothing for all these cases */
480 break;
481 case ATP_TOUT_UNKNOWN:
482 case ATP_OUTPUT_TYPE_COUNT:
483 g_return_val_if_reached (TRUE);
486 return ok;
489 /* Call at the end for stdout and stderr */
490 static gboolean
491 atp_output_context_print_result (ATPOutputContext *this, gint error)
493 gboolean ok;
494 gchar* buffer;
495 IAnjutaMessageManager *man;
497 ok = TRUE;
498 switch (this->type)
500 case ATP_TOUT_NULL:
501 case ATP_TOUT_SAME:
502 break;
503 case ATP_TOUT_COMMON_PANE:
504 case ATP_TOUT_NEW_PANE:
505 if (this == &this->execution->output)
507 if (error)
509 buffer = g_strdup_printf (_("Completed unsuccessfully with status code %d\n"),
510 error);
511 ok = atp_output_context_print (this, buffer);
512 g_free (buffer);
514 else
516 ok = atp_output_context_print (this, _("Completed successfully\n"));
518 ok &= atp_output_context_print (this, "\n");
519 if (this->view)
521 man = anjuta_shell_get_interface (this->execution->plugin->shell,
522 IAnjutaMessageManager, NULL);
523 ianjuta_message_manager_set_current_view (man, this->view, NULL);
527 break;
528 case ATP_TOUT_NEW_BUFFER:
529 case ATP_TOUT_REPLACE_BUFFER:
530 /* Do nothing */
531 break;
532 case ATP_TOUT_INSERT_BUFFER:
533 if (this->editor)
535 ianjuta_editor_insert (this->editor, this->position, this->buffer->str,
536 this->buffer->len, NULL);
538 g_string_free (this->buffer, TRUE);
539 this->buffer = NULL;
540 break;
541 case ATP_TOUT_APPEND_BUFFER:
542 if (this->editor)
544 ianjuta_editor_append (this->editor, 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_REPLACE_SELECTION:
551 if (this->editor)
553 ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (this->editor),
554 this->buffer->str,
555 this->buffer->len, NULL);
557 g_string_free (this->buffer, TRUE);
558 this->buffer = NULL;
559 break;
560 case ATP_TOUT_POPUP_DIALOG:
561 if (this->buffer->len)
563 if (this == &this->execution->output)
565 anjuta_util_dialog_info (GTK_WINDOW (this->execution->plugin->shell),
566 this->buffer->str);
568 else
570 anjuta_util_dialog_error (GTK_WINDOW (this->execution->plugin->shell),
571 this->buffer->str);
573 g_string_free (this->buffer, TRUE);
574 this->buffer = NULL;
576 break;
577 case ATP_TOUT_UNKNOWN:
578 case ATP_OUTPUT_TYPE_COUNT:
579 g_return_val_if_reached (TRUE);
582 return ok;
585 static IAnjutaEditor*
586 get_current_editor(IAnjutaDocumentManager* docman)
588 if (docman == NULL)
589 return NULL;
590 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(docman, NULL);
591 if (doc && IANJUTA_IS_EDITOR(doc))
592 return IANJUTA_EDITOR(doc);
593 else
594 return NULL;
597 static ATPOutputContext*
598 atp_output_context_initialize (ATPOutputContext *this,
599 ATPExecutionContext *execution,
600 ATPOutputType type)
602 IAnjutaDocumentManager *docman;
604 this->type = type;
605 switch (this->type)
607 case ATP_TOUT_NULL:
608 case ATP_TOUT_SAME:
609 break;
610 case ATP_TOUT_COMMON_PANE:
611 case ATP_TOUT_NEW_PANE:
612 this->created = FALSE;
613 break;
614 case ATP_TOUT_REPLACE_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 g_object_add_weak_pointer (G_OBJECT (this->editor), (gpointer *)(gpointer)&this->editor);
620 ianjuta_editor_erase_all (this->editor, NULL);
621 break;
623 /* Go through, try to create a new buffer */
624 case ATP_TOUT_NEW_BUFFER:
625 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->execution->plugin)->shell, IAnjutaDocumentManager, NULL);
626 this->editor = get_current_editor(docman);
627 if (this->editor == NULL)
629 anjuta_util_dialog_warning (GTK_WINDOW (this->execution->plugin->shell), _("Unable to create a buffer: command aborted"));
630 return NULL;
632 g_object_add_weak_pointer (G_OBJECT (this->editor), (gpointer *)(gpointer)&this->editor);
633 break;
634 case ATP_TOUT_INSERT_BUFFER:
635 case ATP_TOUT_APPEND_BUFFER:
636 case ATP_TOUT_REPLACE_SELECTION:
637 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->execution->plugin)->shell, IAnjutaDocumentManager, NULL);
638 this->editor = docman == NULL ? NULL : IANJUTA_EDITOR( ianjuta_document_manager_get_current_document (docman, NULL));
639 if (this->editor == NULL)
641 anjuta_util_dialog_warning (GTK_WINDOW (this->execution->plugin->shell), _("No document currently open: command aborted"));
642 return NULL;
644 g_object_add_weak_pointer (G_OBJECT (this->editor), (gpointer *)(gpointer)&this->editor);
645 this->position = ianjuta_editor_get_position (this->editor, NULL);
646 /* No break, need a buffer too */
647 case ATP_TOUT_POPUP_DIALOG:
648 if (this->buffer == NULL)
650 this->buffer = g_string_new ("");
652 else
654 g_string_erase (this->buffer, 0, -1);
656 break;
657 case ATP_TOUT_UNKNOWN:
658 case ATP_OUTPUT_TYPE_COUNT:
659 g_return_val_if_reached (this);
662 return this;
666 static ATPOutputContext*
667 atp_output_context_construct (ATPOutputContext *this,
668 ATPExecutionContext *execution,
669 ATPOutputType type)
672 this->execution = execution;
673 this->view = NULL;
674 this->buffer = NULL;
675 this->position = NULL;
677 return atp_output_context_initialize (this, execution, type);
680 static void
681 atp_output_context_destroy (ATPOutputContext *this)
683 if (this->view)
685 IAnjutaMessageManager *man;
687 man = anjuta_shell_get_interface (this->execution->plugin->shell,
688 IAnjutaMessageManager, NULL);
689 ianjuta_message_manager_remove_view (man, this->view, NULL);
690 this->view = NULL;
692 if (this->buffer)
694 g_string_free (this->buffer, TRUE);
696 if (this->position)
698 g_object_unref (this->position);
702 /* Execution context
703 *---------------------------------------------------------------------------*/
705 static void
706 on_run_terminated (AnjutaLauncher* launcher, gint pid, gint status,
707 gulong time, gpointer user_data)
709 ATPExecutionContext *this = (ATPExecutionContext *)user_data;
711 atp_output_context_print_result (&this->output, status);
712 atp_output_context_print_result (&this->error, status);
713 this->busy = FALSE;
716 static void
717 on_run_output (AnjutaLauncher* launcher, AnjutaLauncherOutputType type,
718 const gchar* output, gpointer user_data)
720 ATPExecutionContext* this = (ATPExecutionContext*)user_data;
722 switch (type)
724 case ANJUTA_LAUNCHER_OUTPUT_STDOUT:
725 atp_output_context_print (&this->output, output);
726 break;
727 case ANJUTA_LAUNCHER_OUTPUT_STDERR:
728 atp_output_context_print (&this->error, output);
729 break;
730 case ANJUTA_LAUNCHER_OUTPUT_PTY:
731 break;
735 static ATPExecutionContext*
736 atp_execution_context_reuse (ATPExecutionContext* this, const gchar *name,
737 ATPOutputType output, ATPOutputType error)
739 if (this->name) g_free (this->name);
740 this->name = atp_remove_mnemonic (name);
742 if (atp_output_context_initialize (&this->output, this, output) == NULL)
744 return NULL;
746 if (atp_output_context_initialize (&this->error, this, error) == NULL)
748 return NULL;
751 return this;
754 static ATPExecutionContext*
755 atp_execution_context_new (AnjutaPlugin *plugin, const gchar *name,
756 guint id, ATPOutputType output, ATPOutputType error)
758 ATPExecutionContext *this;
760 this = g_new0 (ATPExecutionContext, 1);
762 this->plugin = plugin;
763 this->launcher = anjuta_launcher_new ();
764 g_signal_connect (G_OBJECT (this->launcher), "child-exited",
765 G_CALLBACK (on_run_terminated), this);
766 this->name = atp_remove_mnemonic (name);
768 if (atp_output_context_construct (&this->output, this, output) == NULL)
770 g_free (this);
771 return NULL;
773 if (atp_output_context_construct (&this->error, this, error) == NULL)
775 g_free (this);
776 return NULL;
779 return this;
782 static void
783 atp_execution_context_free (ATPExecutionContext* this)
785 atp_output_context_destroy (&this->output);
786 atp_output_context_destroy (&this->error);
788 if (this->launcher)
790 g_object_unref (this->launcher);
792 if (this->name) g_free (this->name);
793 if (this->directory) g_free (this->directory);
795 g_free (this);
798 static void
799 atp_execution_context_set_directory (ATPExecutionContext* this,
800 const gchar* directory)
802 if (this->directory != NULL) g_free (this->directory);
803 this->directory = directory == NULL ? NULL : g_strdup (directory);
806 static void
807 atp_execution_context_execute (ATPExecutionContext* this,
808 const gchar* command, const gchar* input)
810 gchar* prev_dir = NULL;
812 atp_output_context_print_command (&this->output, command);
814 /* Change working directory */
815 if (this->directory != NULL)
817 prev_dir = anjuta_util_get_current_dir();
818 chdir (this->directory);
820 /* Execute */
821 anjuta_launcher_execute (this->launcher, command, on_run_output, this);
822 /* Restore previous current directory */
823 if (this->directory != NULL)
825 chdir (prev_dir);
826 g_free (prev_dir);
828 anjuta_launcher_set_encoding (this->launcher, NULL);
829 this->busy = TRUE;
831 /* Send stdin data if needed */
832 if (input != NULL)
834 anjuta_launcher_send_stdin (this->launcher, input);
835 /* Send end marker */
836 anjuta_launcher_send_stdin (this->launcher, "\x04");
840 /* Execute context list
841 *---------------------------------------------------------------------------*/
843 ATPContextList *
844 atp_context_list_construct (ATPContextList *this)
846 this->list = NULL;
847 return this;
850 void
851 atp_context_list_destroy (ATPContextList *this)
853 GList *item;
855 for (item = this->list; item != NULL; item = this->list)
857 this->list = g_list_remove_link (this->list, item);
858 atp_execution_context_free ((ATPExecutionContext *)item->data);
859 g_list_free (item);
863 static ATPExecutionContext*
864 atp_context_list_find_context (ATPContextList *this, AnjutaPlugin *plugin,
865 const gchar* name, ATPOutputType output,
866 ATPOutputType error)
868 ATPExecutionContext* context;
869 GList* reuse = NULL;
870 guint best;
871 guint pane;
872 GList* node;
873 gboolean new_pane;
874 gboolean output_pane;
875 gboolean error_pane;
877 pane = 0;
878 best = 0;
879 context = NULL;
880 new_pane = (output == ATP_TOUT_NEW_PANE) || (error == ATP_TOUT_NEW_PANE);
881 output_pane = (output == ATP_TOUT_NEW_PANE) || (output == ATP_TOUT_COMMON_PANE);
882 error_pane = (error == ATP_TOUT_NEW_PANE) || (error == ATP_TOUT_COMMON_PANE);
883 for (node = this->list; node != NULL; node = g_list_next (node))
885 ATPExecutionContext* current;
886 guint score;
888 current = (ATPExecutionContext *)node->data;
890 /* Count number of used message panes */
891 if (current->output.view != NULL) pane++;
892 if (current->error.view != NULL) pane++;
894 score = 1;
895 if ((current->output.view != NULL) == output_pane) score++;
896 if ((current->error.view != NULL) == error_pane) score++;
898 if (!current->busy)
900 if ((score > best) || ((score == best) && (new_pane)))
902 /* Reuse this context */
903 context = current;
904 reuse = node;
905 best = score;
910 if ((new_pane) && (pane < MAX_TOOL_PANES))
912 /* Not too many message pane, we can create a new one */
913 context = NULL;
916 if (context == NULL)
918 /* Create a new node */
919 context = atp_execution_context_new (plugin, name, 0, output, error);
920 if (context != NULL)
922 this->list = g_list_prepend (this->list, context);
925 else
927 this->list = g_list_remove_link (this->list, reuse);
928 context = atp_execution_context_reuse (context, name, output, error);
929 if (context != NULL)
931 this->list = g_list_concat (reuse, this->list);
935 return context;
938 /* Execute tools
939 *---------------------------------------------------------------------------*/
941 /* Menu activate handler which executes the tool. It should do command
942 ** substitution, input, output and error redirection, setting the
943 ** working directory, etc.
945 void
946 atp_user_tool_execute (GtkMenuItem *item, ATPUserTool* this)
948 ATPPlugin* plugin;
949 ATPVariable* variable;
950 ATPContextList* list;
951 ATPExecutionContext* context;
952 IAnjutaDocumentManager *docman;
953 IAnjutaEditor *ed;
954 gchar* dir;
955 gchar* cmd;
956 gchar* input;
957 gchar* val = NULL;
959 plugin = atp_user_tool_get_plugin (this);
960 variable = atp_plugin_get_variable (plugin);
962 /* Save files if requested */
963 if (atp_user_tool_get_flag (this, ATP_TOOL_AUTOSAVE))
965 save_all_files (ANJUTA_PLUGIN (plugin));
968 /* Make command line */
969 cmd = replace_variable (atp_user_tool_get_command (this),
970 atp_user_tool_get_param (this), variable);
972 /* Get working directory and replace variable */
973 dir = replace_variable (NULL, atp_user_tool_get_working_dir (this),
974 variable);
976 if (atp_user_tool_get_flag (this, ATP_TOOL_TERMINAL))
978 /* Run in a terminal */
979 /* don't need a execution context, launch and forget */
981 anjuta_util_execute_terminal_shell (dir, cmd);
983 else
985 /* Get stdin if necessary */
986 input = NULL;
987 switch (atp_user_tool_get_input (this))
989 case ATP_TIN_BUFFER:
990 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
991 IAnjutaDocumentManager, NULL);
992 ed = get_current_editor(docman);
993 if (ed != NULL)
995 input = ianjuta_editor_get_text_all (ed, NULL);
997 break;
998 case ATP_TIN_SELECTION:
999 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
1000 IAnjutaDocumentManager, NULL);
1001 ed = get_current_editor(docman);
1002 if (ed != NULL)
1004 input = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (ed),
1005 NULL);
1007 break;
1008 case ATP_TIN_STRING:
1009 input = replace_variable (NULL,
1010 atp_user_tool_get_input_string (this),
1011 variable);
1012 break;
1013 case ATP_TIN_FILE:
1014 val = replace_variable (NULL, atp_user_tool_get_input_string (this),
1015 variable);
1016 if ((val == NULL) || (!g_file_get_contents (val, &input, NULL, NULL)))
1018 anjuta_util_dialog_error (atp_plugin_get_app_window (plugin),
1019 _("Unable to open input file %s, command aborted"), val == NULL ? "(null)" : val);
1020 if (val != NULL) g_free (val);
1021 if (dir != NULL) g_free (dir);
1022 if (cmd != NULL) g_free (cmd);
1024 return;
1026 g_free (val);
1027 break;
1028 default:
1029 break;
1032 list = atp_plugin_get_context_list (plugin);
1034 context = atp_context_list_find_context (list, ANJUTA_PLUGIN(plugin),
1035 atp_user_tool_get_name (this),
1036 atp_user_tool_get_output (this),
1037 atp_user_tool_get_error (this));
1039 if (context)
1041 /* Set working directory */
1042 atp_execution_context_set_directory (context, dir);
1044 /* Run command */
1045 atp_execution_context_execute (context, cmd, input);
1048 if (input != NULL) g_free(input);
1051 if (dir != NULL) g_free (dir);
1052 if (cmd != NULL) g_free (cmd);