[latexila] Build Tools: big code clean-up



commit 0f0a2568d120c065659e0e43ae97c6cd7503ff67
Author: SÃbastien Wilmet <swilmet src gnome org>
Date:   Sun Jul 31 00:46:21 2011 +0200

    Build Tools: big code clean-up
    
    Rename BuildIssue -> BuildMsg, since the build view contains other types
    of messages than issues.
    
    The post processors messages are stored in a GNode. It's more flexible
    than previously, and it's cleaner.

 src/build_tool_runner.vala    |   55 +++-----
 src/build_view.vala           |  183 ++++++++++++++------------
 src/latex_post_processor.vala |   90 ++++++-------
 src/post_processors.vala      |  292 ++++++++++++++++++++---------------------
 4 files changed, 308 insertions(+), 312 deletions(-)
---
diff --git a/src/build_tool_runner.vala b/src/build_tool_runner.vala
index a059bbc..5b20732 100644
--- a/src/build_tool_runner.vala
+++ b/src/build_tool_runner.vala
@@ -51,6 +51,7 @@ public class BuildToolRunner : GLib.Object
     public BuildToolRunner (File file, BuildTool? tool, BuildView view,
         Gtk.Action action_stop_exec)
     {
+        // FIXME really useful?
         return_if_fail (tool != null);
 
         this.file = file;
@@ -68,7 +69,7 @@ public class BuildToolRunner : GLib.Object
 
         // verify if file extension is allowed for the build tool
         string[] extensions = tool.extensions.split (" ");
-        if (tool.extensions.length > 0
+        if (0 < tool.extensions.length
             && ! (Utils.get_extension (filename) in extensions))
         {
             stderr.printf ("Warning: bad file extension\n");
@@ -252,20 +253,10 @@ public class BuildToolRunner : GLib.Object
                 break;
         }
 
-        post_processor.process (file, output, status);
+        post_processor.set_status (status);
+        post_processor.process (file, output);
 
-        PostProcessorIssues[] all_issues = post_processor.get_issues ();
-        foreach (PostProcessorIssues issues in all_issues)
-        {
-            if (issues.partition_msg != null)
-            {
-                TreeIter iter = view.add_partition (issues.partition_msg,
-                    issues.partition_state, job_partitions[job_num]);
-                view.append_issues (iter, issues.issues);
-            }
-            else
-                view.append_issues (job_partitions[job_num], issues.issues);
-        }
+        view.append_messages (job_partitions[job_num], post_processor.get_messages ());
 
         if (post_processor.successful)
         {
@@ -307,15 +298,14 @@ public class BuildToolRunner : GLib.Object
         if (current_job.post_processor == PostProcessorType.RUBBER
             && filename.contains (" "))
         {
-            Gee.ArrayList<BuildIssue?> issues = new Gee.ArrayList<BuildIssue?> ();
-            BuildIssue issue = BuildIssue ();
-            issue.message =
+            BuildMsg message = BuildMsg ();
+            message.text =
                 _("Rubber may not support filenames with spaces (even in a directory)");
-            issue.message_type = BuildMessageType.WARNING;
-            issue.filename = filename;
-            issues.add (issue);
+            message.type = BuildMsgType.WARNING;
+            message.filename = filename;
+            message.lines_set = false;
 
-            view.append_issues (job_partitions[job_num], issues);
+            view.append_single_message (job_partitions[job_num], message);
         }
 
         try
@@ -329,27 +319,24 @@ public class BuildToolRunner : GLib.Object
         {
             view.set_partition_state (job_partitions[job_num], PartitionState.FAILED);
 
-            Gee.ArrayList<BuildIssue?> issues = new Gee.ArrayList<BuildIssue?> ();
-            BuildIssue error_issue = BuildIssue ();
-            error_issue.message = e.message;
-            error_issue.message_type = BuildMessageType.ERROR;
-            error_issue.start_line = -1;
-            issues.add (error_issue);
+            BuildMsg error_msg = BuildMsg ();
+            error_msg.text = e.message;
+            error_msg.type = BuildMsgType.ERROR;
+            error_msg.lines_set = false;
+            view.append_single_message (job_partitions[job_num], error_msg);
 
             // If the command doesn't seem to be installed, display a more understandable
             // message.
             if (e is SpawnError.NOENT)
             {
-                BuildIssue info_issue = BuildIssue ();
-                info_issue.message =
+                BuildMsg info_msg = BuildMsg ();
+                info_msg.text =
                     _("%s doesn't seem to be installed.").printf (command[0]);
-                info_issue.message_type = BuildMessageType.OTHER;
-                info_issue.start_line = -1;
-                issues.add (info_issue);
+                info_msg.type = BuildMsgType.OTHER;
+                info_msg.lines_set = false;
+                view.append_single_message (job_partitions[job_num], info_msg);
             }
 
-            view.append_issues (job_partitions[job_num], issues);
-
             if (current_job.must_succeed)
                 failed ();
             else
diff --git a/src/build_view.vala b/src/build_view.vala
index 1ff2f6b..6d4d981 100644
--- a/src/build_view.vala
+++ b/src/build_view.vala
@@ -27,7 +27,7 @@ public enum PartitionState
     ABORTED
 }
 
-public enum BuildMessageType
+public enum BuildMsgType
 {
     ERROR,
     WARNING,
@@ -35,21 +35,22 @@ public enum BuildMessageType
     OTHER
 }
 
-public struct BuildIssue
+public struct BuildMsg
 {
-    public string message;
-    public BuildMessageType message_type;
+    public string text;
+    public BuildMsgType type;
     public string? filename;
 
-    // no line: -1
-    // if end_line is -1, end_line takes the same value as start_line
+    public bool lines_set;
     public int start_line;
+
+    // if -1, takes the same value as start_line
     public int end_line;
 }
 
 public class BuildView : HBox
 {
-    enum BuildInfo
+    private enum BuildInfo
     {
         ICON,
         MESSAGE,
@@ -68,22 +69,22 @@ public class BuildView : HBox
     public bool show_warnings { get; set; }
     public bool show_badboxes { get; set; }
 
-    private unowned MainWindow main_window;
-    private TreeStore store;
-    private TreeModelFilter filtered_model;
-    private TreeView view;
-    private unowned ToggleAction action_view_bottom_panel;
+    private unowned MainWindow _main_window;
+    private TreeStore _store;
+    private TreeModelFilter _filtered_model;
+    private TreeView _view;
+    private unowned ToggleAction _action_view_bottom_panel;
 
     public BuildView (MainWindow main_window, Toolbar toolbar,
         ToggleAction view_bottom_panel)
     {
-        this.main_window = main_window;
-        this.action_view_bottom_panel = view_bottom_panel;
+        _main_window = main_window;
+        _action_view_bottom_panel = view_bottom_panel;
 
-        store = new TreeStore (BuildInfo.N_COLUMNS,
+        _store = new TreeStore (BuildInfo.N_COLUMNS,
             typeof (string),    // icon (stock-id)
             typeof (string),    // message
-            typeof (BuildMessageType),
+            typeof (BuildMsgType),
             typeof (int),       // weight (normal or bold)
             typeof (string),    // basename
             typeof (string),    // path
@@ -94,31 +95,31 @@ public class BuildView : HBox
         );
 
         /* filter errors/warnings/badboxes */
-        filtered_model = new TreeModelFilter (store, null);
-        filtered_model.set_visible_func ((model, iter) =>
+        _filtered_model = new TreeModelFilter (_store, null);
+        _filtered_model.set_visible_func ((model, iter) =>
         {
-            BuildMessageType msg_type;
+            BuildMsgType msg_type;
             model.get (iter, BuildInfo.MESSAGE_TYPE, out msg_type, -1);
 
             switch (msg_type)
             {
-                case BuildMessageType.ERROR:
+                case BuildMsgType.ERROR:
                     return show_errors;
-                case BuildMessageType.WARNING:
+                case BuildMsgType.WARNING:
                     return show_warnings;
-                case BuildMessageType.BADBOX:
+                case BuildMsgType.BADBOX:
                     return show_badboxes;
                 default:
                     return true;
             }
         });
 
-        this.notify["show-errors"].connect (() => filtered_model.refilter ());
-        this.notify["show-warnings"].connect (() => filtered_model.refilter ());
-        this.notify["show-badboxes"].connect (() => filtered_model.refilter ());
+        this.notify["show-errors"].connect (() => _filtered_model.refilter ());
+        this.notify["show-warnings"].connect (() => _filtered_model.refilter ());
+        this.notify["show-badboxes"].connect (() => _filtered_model.refilter ());
 
         /* create tree view */
-        view = new TreeView.with_model (filtered_model);
+        _view = new TreeView.with_model (_filtered_model);
 
         TreeViewColumn column_job = new TreeViewColumn ();
         column_job.title = _("Job");
@@ -135,17 +136,17 @@ public class BuildView : HBox
         column_job.add_attribute (renderer_text, "text", BuildInfo.MESSAGE);
         column_job.add_attribute (renderer_text, "weight", BuildInfo.WEIGHT);
 
-        view.append_column (column_job);
+        _view.append_column (column_job);
 
-        view.insert_column_with_attributes (-1, _("File"), new CellRendererText (),
+        _view.insert_column_with_attributes (-1, _("File"), new CellRendererText (),
             "text", BuildInfo.BASENAME);
-        view.insert_column_with_attributes (-1, _("Line"), new CellRendererText (),
+        _view.insert_column_with_attributes (-1, _("Line"), new CellRendererText (),
             "text", BuildInfo.LINE);
 
-        view.set_tooltip_column (BuildInfo.PATH);
+        _view.set_tooltip_column (BuildInfo.PATH);
 
         // selection
-        TreeSelection select = view.get_selection ();
+        TreeSelection select = _view.get_selection ();
         select.set_mode (SelectionMode.SINGLE);
         select.set_select_function ((select, model, path, path_currently_selected) =>
         {
@@ -157,7 +158,7 @@ public class BuildView : HBox
         });
 
         // double-click
-        view.row_activated.connect ((path) => select_row (filtered_model, path));
+        _view.row_activated.connect ((path) => select_row (_filtered_model, path));
 
         // close button
         Button close_button = new Button ();
@@ -168,11 +169,11 @@ public class BuildView : HBox
         close_button.clicked.connect (() =>
         {
             this.hide ();
-            action_view_bottom_panel.active = false;
+            _action_view_bottom_panel.active = false;
         });
 
         // with a scrollbar
-        Widget sw = Utils.add_scrollbar (view);
+        Widget sw = Utils.add_scrollbar (_view);
         pack_start (sw);
 
         VBox vbox = new VBox (false, 0);
@@ -188,7 +189,7 @@ public class BuildView : HBox
             // the row is not selected
             return false;
 
-        BuildMessageType msg_type;
+        BuildMsgType msg_type;
         File file;
         int start_line, end_line;
 
@@ -199,7 +200,7 @@ public class BuildView : HBox
             BuildInfo.END_LINE, out end_line,
             -1);
 
-        if (msg_type != BuildMessageType.OTHER && file != null)
+        if (msg_type != BuildMsgType.OTHER && file != null)
         {
             jump_to_file (file, start_line, end_line);
 
@@ -208,14 +209,14 @@ public class BuildView : HBox
         }
 
         // maybe it's a parent, so we can show or hide its children
-        else if (msg_type == BuildMessageType.OTHER)
+        else if (msg_type == BuildMsgType.OTHER)
         {
             if (model.iter_has_child (iter))
             {
-                if (view.is_row_expanded (path))
-                    view.collapse_row (path);
+                if (_view.is_row_expanded (path))
+                    _view.collapse_row (path);
                 else
-                    view.expand_to_path (path);
+                    _view.expand_to_path (path);
 
                 // the row is not selected
                 return false;
@@ -228,7 +229,7 @@ public class BuildView : HBox
 
     private void jump_to_file (File file, int start_line, int end_line)
     {
-        DocumentTab tab = main_window.open_document (file);
+        DocumentTab tab = _main_window.open_document (file);
 
         // If the file was not yet opened, it takes some time. If we try to select the
         // lines when the file is not fully charged, the lines are simply not selected.
@@ -244,67 +245,85 @@ public class BuildView : HBox
 
     public void clear ()
     {
-        store.clear ();
-        view.columns_autosize ();
+        _store.clear ();
+        _view.columns_autosize ();
     }
 
     public TreeIter add_partition (string msg, PartitionState state, TreeIter? parent,
         bool bold = false)
     {
         TreeIter iter;
-        store.append (out iter, parent);
-        store.set (iter,
+        _store.append (out iter, parent);
+        _store.set (iter,
             BuildInfo.ICON,         get_icon_from_state (state),
             BuildInfo.MESSAGE,      msg,
-            BuildInfo.MESSAGE_TYPE, BuildMessageType.OTHER,
+            BuildInfo.MESSAGE_TYPE, BuildMsgType.OTHER,
             BuildInfo.WEIGHT,       bold ? 800 : 400,
             -1);
 
-        view.expand_all ();
+        _view.expand_all ();
 
         return iter;
     }
 
     public void set_partition_state (TreeIter partition_id, PartitionState state)
     {
-        store.set (partition_id, BuildInfo.ICON, get_icon_from_state (state), -1);
+        _store.set (partition_id, BuildInfo.ICON, get_icon_from_state (state), -1);
     }
 
-    public void append_issues (TreeIter partition_id, Gee.ArrayList<BuildIssue?> issues)
+    public void append_messages (TreeIter partition_id, Node<BuildMsg?> messages)
     {
-        foreach (BuildIssue issue in issues)
+        unowned Node<BuildMsg?> cur_node = messages.first_child ();
+        while (cur_node != null)
         {
-            File file = null;
-            string path = null;
+            TreeIter iter = append_single_message (partition_id, cur_node.data);
+            append_messages (iter, cur_node);
+            cur_node = cur_node.next_sibling ();
+        }
 
-            if (issue.filename != null)
-            {
-                file = File.new_for_path (issue.filename);
-                path = Utils.replace_home_dir_with_tilde (issue.filename);
+        _view.expand_all ();
+    }
 
-                // the path is displayed in a tooltip
-                path = Markup.escape_text (path);
-            }
+    public TreeIter append_single_message (TreeIter partition_id, BuildMsg message)
+    {
+        File file = null;
+        string path = null;
+
+        if (message.filename != null)
+        {
+            file = File.new_for_path (message.filename);
+            path = Utils.replace_home_dir_with_tilde (message.filename);
 
-            TreeIter iter;
-            store.append (out iter, partition_id);
-            store.set (iter,
-                BuildInfo.ICON,         get_icon_from_msg_type (issue.message_type),
-                BuildInfo.MESSAGE,      issue.message,
-                BuildInfo.MESSAGE_TYPE, issue.message_type,
-                BuildInfo.WEIGHT,       400,
-                BuildInfo.BASENAME,     issue.filename != null ?
-                                        Path.get_basename (issue.filename) : null,
-                BuildInfo.FILE,         file,
-                BuildInfo.PATH,         path,
-                BuildInfo.START_LINE,   issue.start_line,
-                BuildInfo.END_LINE,     issue.end_line,
-                BuildInfo.LINE,         issue.start_line != -1 ?
-                                        issue.start_line.to_string () : null,
-                -1);
+            // the path is displayed in a tooltip
+            path = Markup.escape_text (path);
         }
 
-        view.expand_all ();
+        int start_line = -1;
+        int end_line = -1;
+        string line_str = null;
+        if (message.lines_set)
+        {
+            start_line = message.start_line;
+            end_line = message.end_line;
+            line_str = start_line.to_string ();
+        }
+
+        TreeIter iter;
+        _store.append (out iter, partition_id);
+        _store.set (iter,
+            BuildInfo.ICON,         get_icon_from_msg_type (message.type),
+            BuildInfo.MESSAGE,      message.text,
+            BuildInfo.MESSAGE_TYPE, message.type,
+            BuildInfo.WEIGHT,       400,
+            BuildInfo.BASENAME,     file != null ? file.get_basename () : null,
+            BuildInfo.FILE,         file,
+            BuildInfo.PATH,         path,
+            BuildInfo.START_LINE,   start_line,
+            BuildInfo.END_LINE,     end_line,
+            BuildInfo.LINE,         line_str,
+            -1);
+
+        return iter;
     }
 
     private string? get_icon_from_state (PartitionState state)
@@ -324,17 +343,17 @@ public class BuildView : HBox
         }
     }
 
-    private string? get_icon_from_msg_type (BuildMessageType type)
+    private string? get_icon_from_msg_type (BuildMsgType type)
     {
         switch (type)
         {
-            case BuildMessageType.ERROR:
+            case BuildMsgType.ERROR:
                 return Stock.DIALOG_ERROR;
-            case BuildMessageType.WARNING:
+            case BuildMsgType.WARNING:
                 return Stock.DIALOG_WARNING;
-            case BuildMessageType.BADBOX:
+            case BuildMsgType.BADBOX:
                 return "badbox";
-            case BuildMessageType.OTHER:
+            case BuildMsgType.OTHER:
                 return null;
             default:
                 return_val_if_reached (null);
@@ -344,6 +363,6 @@ public class BuildView : HBox
     public new void show ()
     {
         base.show ();
-        action_view_bottom_panel.active = true;
+        _action_view_bottom_panel.active = true;
     }
 }
diff --git a/src/latex_post_processor.vala b/src/latex_post_processor.vala
index 210f0d8..6814e4d 100644
--- a/src/latex_post_processor.vala
+++ b/src/latex_post_processor.vala
@@ -17,11 +17,8 @@
  * along with LaTeXila.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-private class LatexPostProcessor : GLib.Object, PostProcessor
+private class LatexPostProcessor : PostProcessor
 {
-    public bool successful { get; protected set; }
-    private Gee.ArrayList<BuildIssue?> issues = new Gee.ArrayList<BuildIssue?> ();
-
     private enum FilterStatus
     {
         START,
@@ -47,7 +44,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
     private const int NO_LINE = -1;
 
     // the current message
-    private BuildIssue msg;
+    private BuildMsg msg;
 
     // if a message is splitted, we enter in a different status, so we fetch the end
     // of the message
@@ -132,9 +129,8 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         }
     }
 
-    public void process (File file, string output, int status)
+    public override void process (File file, string output)
     {
-        successful = status == 0;
         directory_path = file.get_parent ().get_parse_name ();
 
         string[] lines = output.split ("\n");
@@ -145,22 +141,14 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         // Stats.
         // Since all the messages printed by the 'latex' or 'pdflatex' command are in
         // English, it would be strange to have only this one translated.
-        msg.message = "%d %s, %d %s, %d %s".printf (
+        msg.text = "%d %s, %d %s, %d %s".printf (
             nb_errors,   nb_errors   == 1 ? "error"   : "errors",
             nb_warnings, nb_warnings == 1 ? "warning" : "warnings",
             nb_badboxes, nb_badboxes == 1 ? "badbox"  : "badboxes");
-        msg.message_type = BuildMessageType.OTHER;
+        msg.type = BuildMsgType.OTHER;
         add_msg (false);
     }
 
-    public PostProcessorIssues[] get_issues ()
-    {
-        PostProcessorIssues[] pp_issues = new PostProcessorIssues[1];
-        pp_issues[0].partition_msg = null;
-        pp_issues[0].issues = issues;
-        return pp_issues;
-    }
-
     private void latex_output_filter (string line)
     {
         switch (status)
@@ -210,7 +198,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
                 if (! reg_badbox.match (line))
                     return false;
 
-                msg.message_type = BuildMessageType.BADBOX;
+                msg.type = BuildMsgType.BADBOX;
 
                 if (detect_badbox_line (line, false))
                     add_msg ();
@@ -245,7 +233,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         {
             status = FilterStatus.START;
             string[] strings = reg_badbox_lines.split (badbox);
-            msg.message = strings[1];
+            msg.text = strings[1];
             int n1 = int.parse (strings[2]);
             int n2 = int.parse (strings[3]);
 
@@ -267,7 +255,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         {
             status = FilterStatus.START;
             string[] strings = reg_badbox_line.split (badbox);
-            msg.message = strings[1];
+            msg.text = strings[1];
             msg.start_line = int.parse (strings[2]);
             return true;
         }
@@ -276,7 +264,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         {
             status = FilterStatus.START;
             string[] strings = reg_badbox_output.split (badbox);
-            msg.message = strings[1];
+            msg.text = strings[1];
             msg.start_line = NO_LINE;
             return true;
         }
@@ -284,7 +272,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         else if (nb_lines > 4 || current_line_is_empty)
         {
             status = FilterStatus.START;
-            msg.message = badbox;
+            msg.text = badbox;
             msg.start_line = NO_LINE;
             return true;
         }
@@ -301,7 +289,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
                 MatchInfo match_info;
                 if (reg_warning.match (line, 0, out match_info))
                 {
-                    msg.message_type = BuildMessageType.WARNING;
+                    msg.type = BuildMsgType.WARNING;
 
                     string contents = match_info.fetch_named ("contents");
 
@@ -322,9 +310,9 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
 
                 else if (reg_warning_no_file.match (line))
                 {
-                    msg.message_type = BuildMessageType.WARNING;
+                    msg.type = BuildMsgType.WARNING;
                     string[] strings = reg_warning_no_file.split (line);
-                    msg.message = strings[1];
+                    msg.text = strings[1];
                     msg.start_line = NO_LINE;
                     add_msg ();
                     return true;
@@ -355,7 +343,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         {
             status = FilterStatus.START;
             string[] strings = reg_warning_line.split (warning);
-            msg.message = strings[1];
+            msg.text = strings[1];
             msg.start_line = int.parse (strings[2]);
             return true;
         }
@@ -364,7 +352,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         {
             status = FilterStatus.START;
             string[] strings = reg_warning_international_line.split (warning);
-            msg.message = strings[1];
+            msg.text = strings[1];
             msg.start_line = int.parse (strings[2]);
             return true;
         }
@@ -372,7 +360,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         else if (warning[warning.length - 1] == '.')
         {
             status = FilterStatus.START;
-            msg.message = warning;
+            msg.text = warning;
             msg.start_line = NO_LINE;
             return true;
         }
@@ -380,7 +368,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         else if (nb_lines > 5 || current_line_is_empty)
         {
             status = FilterStatus.START;
-            msg.message = warning;
+            msg.text = warning;
             msg.start_line = NO_LINE;
             return true;
         }
@@ -420,12 +408,12 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
                 if (found)
                 {
                     nb_lines++;
-                    msg.message_type = BuildMessageType.ERROR;
+                    msg.type = BuildMsgType.ERROR;
 
                     // the message is complete
                     if (line[line.length - 1] == '.')
                     {
-                        msg.message = tmp;
+                        msg.text = tmp;
                         status = FilterStatus.ERROR_SEARCH_LINE;
                     }
                     // the message is splitted
@@ -445,12 +433,12 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
 
                 if (line[line.length - 1] == '.')
                 {
-                    msg.message = line_buf;
+                    msg.text = line_buf;
                     status = FilterStatus.ERROR_SEARCH_LINE;
                 }
                 else if (nb_lines > 4)
                 {
-                    msg.message = line_buf;
+                    msg.text = line_buf;
                     msg.start_line = NO_LINE;
                     add_msg ();
                     nb_lines = 0;
@@ -494,11 +482,11 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
             return false;
 
         msg.start_line = NO_LINE;
-        msg.message_type = BuildMessageType.OTHER;
+        msg.type = BuildMsgType.OTHER;
 
         if (! reg_other_bytes.match (line))
         {
-            msg.message = line;
+            msg.text = line;
             add_msg (false);
             return true;
         }
@@ -512,7 +500,7 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
 
         // do nothing
         if (nb_bytes < 1024)
-            msg.message = line;
+            msg.text = line;
 
         // size in KB (less than 1 MB)
         else if (nb_bytes < 1024 * 1024)
@@ -536,13 +524,13 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
             {
                 string new_line =
                     reg_other_bytes.replace_literal (line, -1, 0, human_size);
-                msg.message = new_line;
+                msg.text = new_line;
             }
 
             // nice try!
             catch (RegexError e)
             {
-                msg.message = line;
+                msg.text = line;
             }
         }
 
@@ -822,8 +810,8 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
     private void add_msg (bool set_filename = true)
     {
         // exclude some useless messages here
-        if (msg.message_type == BuildMessageType.WARNING
-            && msg.message == "There were undefined references.")
+        if (msg.type == BuildMsgType.WARNING
+            && msg.text == "There were undefined references.")
         {
             reset_msg ();
             return;
@@ -836,39 +824,43 @@ private class LatexPostProcessor : GLib.Object, PostProcessor
         {
             // A message on several lines are sometimes indented, so when the lines are
             // catenated there are a lot of spaces. We replace these spaces by one space.
-            msg.message = reg_spaces.replace (msg.message, -1, 0, " ");
+            msg.text = reg_spaces.replace (msg.text, -1, 0, " ");
         }
         catch (RegexError e)
         {
             stderr.printf ("Latex post processor warning: %s\n", e.message);
         }
 
-        switch (msg.message_type)
+        switch (msg.type)
         {
-            case BuildMessageType.BADBOX:
+            case BuildMsgType.BADBOX:
                 nb_badboxes++;
                 break;
 
-            case BuildMessageType.WARNING:
+            case BuildMsgType.WARNING:
                 nb_warnings++;
                 break;
 
-            case BuildMessageType.ERROR:
+            case BuildMsgType.ERROR:
                 nb_errors++;
                 break;
         }
 
-        issues.add (msg);
+        if (msg.start_line != NO_LINE)
+            msg.lines_set = true;
+
+        append_message (msg);
         reset_msg ();
     }
 
     private void reset_msg ()
     {
-        msg = BuildIssue ();
-        msg.message = null;
-        msg.message_type = BuildMessageType.OTHER;
+        msg = BuildMsg ();
+        msg.text = null;
+        msg.type = BuildMsgType.OTHER;
         msg.filename = null;
         msg.start_line = NO_LINE;
         msg.end_line = NO_LINE;
+        msg.lines_set = false;
     }
 }
diff --git a/src/post_processors.vala b/src/post_processors.vala
index 7ee6701..4fc487b 100644
--- a/src/post_processors.vala
+++ b/src/post_processors.vala
@@ -17,94 +17,96 @@
  * along with LaTeXila.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-public struct PostProcessorIssues
+private abstract class PostProcessor : GLib.Object
 {
-    public string? partition_msg;
-    public PartitionState partition_state;
-    public Gee.ArrayList<BuildIssue?> issues;
-}
-
-private interface PostProcessor : GLib.Object
-{
-    public abstract bool successful { get; protected set; }
-    public abstract void process (File file, string output, int status);
-    public abstract PostProcessorIssues[] get_issues ();
-}
+    protected Node<BuildMsg?> _all_messages = new Node<BuildMsg?> (BuildMsg ());
+    private unowned Node<BuildMsg?> _prev_message = null;
 
-private class NoOutputPostProcessor : GLib.Object, PostProcessor
-{
     public bool successful { get; protected set; }
 
-    public void process (File file, string output, int status)
+    public Node<BuildMsg?> get_messages ()
     {
-        successful = status == 0;
+        return (owned) _all_messages;
+    }
+
+    protected unowned Node<BuildMsg?> append_message (BuildMsg message)
+    {
+        unowned Node<BuildMsg?> new_message;
+
+        bool prev_msg_is_invalid = _prev_message != null && _prev_message.next != null;
+
+        // If _prev_message is not the last node, do a normal 'append'.
+        if (_prev_message == null || prev_msg_is_invalid)
+            new_message = _all_messages.append_data (message);
+
+        else
+        {
+            // 'insert_after' is O(1), whereas 'append' is O(N).
+            // That's why we keep the previous node.
+            new_message = _all_messages.insert_after (_prev_message,
+                new Node<BuildMsg?> (message));
+        }
+
+        _prev_message = new_message;
+        return new_message;
     }
 
-    public PostProcessorIssues[] get_issues ()
+    public void set_status (int status)
     {
-        // empty
-        PostProcessorIssues[] issues = {};
-        return issues;
+        successful = status == 0;
     }
+
+    public abstract void process (File file, string output);
 }
 
-private class AllOutputPostProcessor : GLib.Object, PostProcessor
+private class NoOutputPostProcessor : PostProcessor
 {
-    public bool successful { get; protected set; }
-    private Gee.ArrayList<BuildIssue?> issues = new Gee.ArrayList<BuildIssue?> ();
-
-    public void process (File file, string output, int status)
+    public override void process (File file, string output)
     {
-        successful = status == 0;
+    }
+}
 
+private class AllOutputPostProcessor : PostProcessor
+{
+    public override void process (File file, string output)
+    {
         if (output.length == 0)
             return;
 
         string[] lines = output.split ("\n");
-        int l = lines.length;
-        return_if_fail (l > 0);
+        int nb_lines = lines.length;
+        return_if_fail (nb_lines > 0);
 
         // Generally there is a \n at the end of the output so an empty line is added,
         // but we don't want to display it.
-        if (lines[l-1].length == 0)
-            l--;
+        if (lines[nb_lines - 1].length == 0)
+            nb_lines--;
 
-        BuildIssue issue = BuildIssue ();
-        issue.message_type = BuildMessageType.OTHER;
-        issue.filename = null;
-        issue.start_line = -1;
-        issue.end_line = -1;
+        BuildMsg message = BuildMsg ();
+        message.type = BuildMsgType.OTHER;
+        message.filename = null;
+        message.lines_set = false;
 
-        for (int i = 0 ; i < l ; i++)
+        for (int line_num = 0 ; line_num < nb_lines ; line_num++)
         {
-            issue.message = lines[i];
-            issues.add (issue);
+            message.text = lines[line_num];
+            append_message (message);
         }
     }
-
-    public PostProcessorIssues[] get_issues ()
-    {
-        PostProcessorIssues[] pp_issues = new PostProcessorIssues[1];
-        pp_issues[0].partition_msg = null;
-        pp_issues[0].issues = issues;
-        return pp_issues;
-    }
 }
 
-private class RubberPostProcessor : GLib.Object, PostProcessor
+private class RubberPostProcessor : PostProcessor
 {
-    public bool successful { get; protected set; }
-    private static Regex? pattern = null;
-    private Gee.ArrayList<BuildIssue?> issues = new Gee.ArrayList<BuildIssue?> ();
+    private static Regex? _pattern = null;
 
     public RubberPostProcessor ()
     {
-        if (pattern != null)
+        if (_pattern != null)
             return;
 
         try
         {
-            pattern = new Regex (
+            _pattern = new Regex (
                 "(?P<file>[^:\n]+)(:(?P<line>[\\d\\-]+))?:(?P<text>.+)$",
                 RegexCompileFlags.MULTILINE | RegexCompileFlags.OPTIMIZE);
         }
@@ -114,43 +116,44 @@ private class RubberPostProcessor : GLib.Object, PostProcessor
         }
     }
 
-    public void process (File file, string output, int status)
+    public override void process (File file, string output)
     {
-        successful = status == 0;
-        if (pattern == null)
-            return;
+        return_if_fail (_pattern != null);
 
         string parent_path = file.get_parent ().get_parse_name ();
 
         MatchInfo match_info;
-        pattern.match (output, 0, out match_info);
+        _pattern.match (output, 0, out match_info);
         while (match_info.matches ())
         {
-            BuildIssue issue = BuildIssue ();
-            string text = issue.message = match_info.fetch_named ("text");
+            BuildMsg message = BuildMsg ();
+            message.text = match_info.fetch_named ("text");
 
             // message type
-            issue.message_type = BuildMessageType.ERROR;
-            if (text.contains ("Underfull") || text.contains ("Overfull"))
-                issue.message_type = BuildMessageType.BADBOX;
+            message.type = BuildMsgType.ERROR;
+            if (message.text.contains ("Underfull") || message.text.contains ("Overfull"))
+                message.type = BuildMsgType.BADBOX;
 
             // line
-            issue.start_line = issue.end_line = -1;
-            string line = match_info.fetch_named ("line");
-            if (line != null && line.length > 0)
+            message.lines_set = false;
+            string? line = match_info.fetch_named ("line");
+            if (line != null && 0 < line.length)
             {
+                message.lines_set = true;
                 string[] parts = line.split ("-");
-                issue.start_line = int.parse (parts[0]);
-                if (parts.length > 1 && parts[1] != null && parts[1].length > 0)
-                    issue.end_line = int.parse (parts[1]);
+                message.start_line = int.parse (parts[0]);
+                if (1 < parts.length && parts[1] != null && 0 < parts[1].length)
+                    message.end_line = int.parse (parts[1]);
+                else
+                    message.end_line = -1;
             }
 
             // filename
-            issue.filename = match_info.fetch_named ("file");
-            if (issue.filename[0] != '/')
-                issue.filename = "%s/%s".printf (parent_path, issue.filename);
+            message.filename = match_info.fetch_named ("file");
+            if (message.filename[0] != '/')
+                message.filename = "%s/%s".printf (parent_path, message.filename);
 
-            issues.add (issue);
+            append_message (message);
 
             try
             {
@@ -163,30 +166,19 @@ private class RubberPostProcessor : GLib.Object, PostProcessor
             }
         }
     }
-
-    public PostProcessorIssues[] get_issues ()
-    {
-        PostProcessorIssues[] pp_issues = new PostProcessorIssues[1];
-        pp_issues[0].partition_msg = null;
-        pp_issues[0].issues = issues;
-        return pp_issues;
-    }
 }
 
-private class LatexmkPostProcessor : GLib.Object, PostProcessor
+private class LatexmkPostProcessor : PostProcessor
 {
-    public bool successful { get; protected set; }
-    private PostProcessorIssues[] all_issues = {};
+    private static Regex? _reg_rule = null;
+    private static Regex? _reg_no_rule = null;
+    private bool _force_show_all;
 
-    private static Regex? reg_rule = null;
-    private static Regex? reg_no_rule = null;
-    private bool show_all;
-
-    public LatexmkPostProcessor (bool show_all = false)
+    public LatexmkPostProcessor (bool force_show_all)
     {
-        this.show_all = show_all;
+        _force_show_all = force_show_all;
 
-        if (reg_rule != null)
+        if (_reg_rule != null)
             return;
 
         try
@@ -194,7 +186,7 @@ private class LatexmkPostProcessor : GLib.Object, PostProcessor
             string ungreedy_lines = "((?U)(.*\\R)*)";
 
             string reg_rule_str = "-{12}\\R";
-            reg_rule_str += "(?P<line>Run number \\d+ of rule '(?P<rule>.*)')\\R";
+            reg_rule_str += "(?P<title>Run number \\d+ of rule '(?P<rule>.*)')\\R";
             reg_rule_str += "(-{12}\\R){2}";
             reg_rule_str += "Running '(?P<cmd>.*)'\\R";
             reg_rule_str += "-{12}\\R";
@@ -204,13 +196,13 @@ private class LatexmkPostProcessor : GLib.Object, PostProcessor
             reg_rule_str += "(?P<output>" + ungreedy_lines + ")";
             reg_rule_str += "(Latexmk:|Rule '.*':)";
 
-            reg_rule = new Regex (reg_rule_str, RegexCompileFlags.OPTIMIZE);
+            _reg_rule = new Regex (reg_rule_str, RegexCompileFlags.OPTIMIZE);
 
             string reg_no_rule_str = "(Latexmk: This is Latexmk.*\\R)?";
             reg_no_rule_str += "(\\*{4} Report bugs.*\\R)?";
             reg_no_rule_str += "(?P<output>(.*\\R)*)";
 
-            reg_no_rule = new Regex (reg_no_rule_str);
+            _reg_no_rule = new Regex (reg_no_rule_str);
         }
         catch (RegexError e)
         {
@@ -218,40 +210,28 @@ private class LatexmkPostProcessor : GLib.Object, PostProcessor
         }
     }
 
-    public void process (File file, string output, int status)
+    public override void process (File file, string output)
     {
-        successful = status == 0;
+        return_if_fail (_reg_rule != null && _reg_no_rule != null);
 
-        return_if_fail (reg_rule != null && reg_no_rule != null);
-
-        string latex_output = null;
-        int last_latex_cmd_index = 0;
+        string last_latex_output = null;
+        unowned Node<BuildMsg?> last_latex_node = null;
 
         MatchInfo match_info;
-        reg_rule.match (output, 0, out match_info);
-
-        int i;
-        for (i = 0 ; match_info.matches () ; i++)
+        _reg_rule.match (output, 0, out match_info);
+        while (match_info.matches ())
         {
-            PostProcessorIssues pp_issues = PostProcessorIssues ();
-            pp_issues.partition_msg = match_info.fetch_named ("line");
-            pp_issues.partition_state = PartitionState.SUCCEEDED;
-
-            Gee.ArrayList<BuildIssue?> issues = new Gee.ArrayList<BuildIssue?> ();
-
-            BuildIssue issue = BuildIssue ();
-            issue.message_type = BuildMessageType.OTHER;
-            issue.start_line = -1;
-            issue.message = "$ " + match_info.fetch_named ("cmd");
-            issues.add (issue);
+            Node<BuildMsg?> cmd_messages = null;
 
+            /* command output */
             string rule = match_info.fetch_named ("rule");
 
             // if the rule is latex or pdflatex, we store the output
-            if (rule.has_suffix ("latex"))
+            bool is_latex_cmd = rule == "latex" || rule == "pdflatex";
+            if (is_latex_cmd)
             {
-                latex_output = match_info.fetch_named ("output");
-                last_latex_cmd_index = i;
+                last_latex_output = match_info.fetch_named ("output");
+                cmd_messages = new Node<BuildMsg?> (BuildMsg ());
             }
 
             // if it's another rule (bibtex, makeindex, etc), we show all output
@@ -259,18 +239,30 @@ private class LatexmkPostProcessor : GLib.Object, PostProcessor
             {
                 string cmd_output = match_info.fetch_named ("output");
                 PostProcessor all_output_pp = new AllOutputPostProcessor ();
-                all_output_pp.process (file, cmd_output, 0);
-                PostProcessorIssues[] all_output_issues = all_output_pp.get_issues ();
+                all_output_pp.process (file, cmd_output);
+                cmd_messages = all_output_pp.get_messages ();
+            }
 
-                // normally there is no partition in the output
-                return_if_fail (all_output_issues.length == 1
-                    && all_output_issues[0].partition_msg == null);
+            /* title */
+            BuildMsg title_msg = BuildMsg ();
+            title_msg.type = BuildMsgType.OTHER;
+            title_msg.lines_set = false;
+            title_msg.text = match_info.fetch_named ("title");
 
-                issues.add_all (all_output_issues[0].issues);
-            }
+            cmd_messages.data = title_msg;
 
-            pp_issues.issues = issues;
-            all_issues += pp_issues;
+            /* command line */
+            BuildMsg cmd_line_msg = BuildMsg ();
+            cmd_line_msg.type = BuildMsgType.OTHER;
+            cmd_line_msg.lines_set = false;
+            cmd_line_msg.text = "$ " + match_info.fetch_named ("cmd");
+
+            cmd_messages.insert_data (0, cmd_line_msg);
+
+            if (is_latex_cmd)
+                last_latex_node = _all_messages.append ((owned) cmd_messages);
+            else
+                _all_messages.append ((owned) cmd_messages);
 
             try
             {
@@ -283,47 +275,53 @@ private class LatexmkPostProcessor : GLib.Object, PostProcessor
             }
         }
 
-        // Run latex post processor on the last latex or pdflatex output
-        if (latex_output != null)
+        /* Run the latex post processor on the last latex or pdflatex output */
+        if (last_latex_output != null)
         {
             PostProcessor latex_pp = new LatexPostProcessor ();
-            latex_pp.process (file, latex_output, 0);
-            PostProcessorIssues[] latex_issues = latex_pp.get_issues ();
+            latex_pp.process (file, last_latex_output);
+            Node<BuildMsg?> latex_messages = latex_pp.get_messages ();
 
-            // normally there is no partition in the latex output
-            return_if_fail (latex_issues.length == 1
-                && latex_issues[0].partition_msg == null);
+            bool last_cmd_is_latex_cmd = _all_messages.last_child () == last_latex_node;
 
             // Almost all the time, the user wants to see only the latex output.
             // If an error has occured, we verify if the last command was a latex command.
             // If it is the case, there is no need to show all output.
-            if (! show_all && (successful || last_latex_cmd_index == i - 1))
-                all_issues = latex_issues;
+            if (! _force_show_all && (successful || last_cmd_is_latex_cmd))
+                _all_messages = (owned) latex_messages;
+
+            // Replace 'last_latex_node' by 'latex_messages'
             else
-                all_issues[last_latex_cmd_index].issues.add_all (latex_issues[0].issues);
+            {
+                // take the title
+                latex_messages.data = last_latex_node.data;
+
+                // take the command line
+                latex_messages.insert (0, last_latex_node.first_child ().unlink ());
+
+                // replace
+                int pos = _all_messages.child_position (last_latex_node);
+                last_latex_node.unlink ();
+                _all_messages.insert (pos, (owned) latex_messages);
+            }
         }
 
-        if (i > 0)
+        if (_all_messages.children != null)
             return;
 
-        // show all output since there were no rule executed
+        /* show all output since there were no rule executed */
 
         PostProcessor all_output_pp = new AllOutputPostProcessor ();
 
-        if (reg_no_rule.match (output, 0, out match_info))
+        if (_reg_no_rule.match (output, 0, out match_info))
         {
             // almost all output
             string all_output = match_info.fetch_named ("output");
-            all_output_pp.process (file, all_output, 0);
+            all_output_pp.process (file, all_output);
         }
         else
-            all_output_pp.process (file, output, 0);
+            all_output_pp.process (file, output);
 
-        all_issues = all_output_pp.get_issues ();
-    }
-
-    public PostProcessorIssues[] get_issues ()
-    {
-        return all_issues;
+        _all_messages = all_output_pp.get_messages ();
     }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]