User:Pathosbot/TemplateEditor.cs: Difference between revisions

From Wikisource
Jump to navigation Jump to search
Content deleted Content added
+ correctly parse redundant parameter assignments
+ stop editing on error
Line 13: Line 13:
namespace HeaderConversion {
namespace HeaderConversion {
public class HeaderConversion : WikiFunctions.Plugin.IAWBPlugin {
public class HeaderConversion : WikiFunctions.Plugin.IAWBPlugin {
/********************
* Pause and display error
*******************/
void StopForError(string message, string text) {
if (text != "")
message += "\n\n" + text;

MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
AWB.BotModeCheckbox.Checked = false;
}

/********************
/********************
* Explicitly delimit templates in text:
* Explicitly delimit templates in text:
Line 28: Line 39:
count++;
count++;
if (count == 10)
if (count == 10)
MessageBox.Show("Warning: Exceeded loop limit for template escaping:\n" + text);
StopForError("exceeded loop limit for template escaping.", text);
};
};


Line 136: Line 147:
// exit if no header
// exit if no header
if (!Regex.IsMatch(header, "<start header2?>", RegexOptions.IgnoreCase)) {
if (!Regex.IsMatch(header, "<start header2?>", RegexOptions.IgnoreCase)) {
MessageBox.Show("Header not detected!");
StopForError("header not detected.", text);
return header;
return header;
}
}

Revision as of 22:51, 4 May 2008

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

using WikiFunctions;
using WikiFunctions.AWBSettings;
using WikiFunctions.Parse;

namespace HeaderConversion {
    public class HeaderConversion : WikiFunctions.Plugin.IAWBPlugin {
        /********************
         * Pause and display error
         *******************/
        void StopForError(string message, string text) {
            if (text != "")
                message += "\n\n" + text;

            MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            AWB.BotModeCheckbox.Checked = false;
        }

        /********************
         * Explicitly delimit templates in text:
         * {{foo|bar}} -> <start foo>foo<pipe>bar</end foo>
         *******************/
        string DelimitTemplates(string text) {
            /* delimit parameters */
            text = Regex.Replace(text, "\\|", "<pipe>");
            text = Regex.Replace(text, "\\[\\[([^\\]]+)<pipe>", "[[$1|"); // fix wikilinks

            /* delimit templates */
            int count = 0;
            while (Regex.IsMatch(text, "{{") && count < 10) {
                text = Regex.Replace(text, "{{([\\s\\n\\r]*([^<{}]+?)[\\s\\n\\r]*(?:<pipe>[^{}]*)?)}}", "<start $2>$1<end $2>", RegexOptions.Singleline);
                count++;
                if (count == 10)
                    StopForError("exceeded loop limit for template escaping.", text);
            };

            /* exit */
            return text;
        }

        /********************
         * Reverse explicit template delimiting:
         * <start foo>foo<pipe>bar</end foo> -> {{foo|bar}}
         *******************/
        string UndelimitTemplates(string text) {
            text = Regex.Replace(text, "<start[^>]+>", "{{");
            text = Regex.Replace(text, "<end[^>]+>", "}}");
            text = Regex.Replace(text, "<pipe>", "|");

            return text;
        }
        string UndelimitTemplates(string text, string regexSearch) {
            MatchCollection matches = Regex.Matches(text, regexSearch);

            foreach (Match match in matches) {
                text = text.Replace(match.Value, UndelimitTemplates(match.Value));
            }

            return text;
        }

        /********************
         * Given a delimited template, returns a hash table of its parameters
         *******************/
        Hashtable GetParameters(string text) {
            Hashtable parameters = new Hashtable();

            // normalize
            text = Regex.Replace(text, "^[\\r\\n\\s]]*<(?:start|end)[^>]+>[\\r\\n\\s]]*", ""); // remove template delimiters
            text = Regex.Replace(text, "[\\r\\n\\s]*<pipe>[\\r\\n\\s]*", "<pipe>"); // remove pipe whitespace
            text = Regex.Replace(text, "<pipe>([a-z_]+?)[\\r\\n\\s]*=[\\r\\n\\s]*", "<pipe>$1=", RegexOptions.IgnoreCase); // remove parameter whitespace

            // unescape nested templates
            text = UndelimitTemplates(text, "<start[^>]+>.+?<end[^>]+>");

            // no parameters
            if (!Regex.IsMatch(text, "(?<=<pipe>)[a-z_]+=.*?(?=<pipe>|$)")) {
                MessageBox.Show("No parameters detected:\n" + text);
                return parameters;
            }

            // process each parameters
            int unnamed = 0;
            MatchCollection matches = Regex.Matches(text, "(?<=<pipe>)[a-z_]+=.*?(?=<pipe>|$)", RegexOptions.Singleline);
            foreach(Match match in matches) {
                // parse key/value
                string name, value;
                if (Regex.IsMatch(match.Value, "^[a-z_]+=")) {
                    name  = Regex.Replace(match.Value, "=.*$", "", RegexOptions.Singleline);
                    value = Regex.Replace(match.Value, "^[a-z_]+=", "", RegexOptions.Singleline);
                }
                else {
                    unnamed++;
                    name  = "" + unnamed;
                    value = match.Value;
                }

                // add to hash
                if(parameters.Contains(name))
                    parameters[name] = value;
                else
                    parameters.Add(name, value);
            }

            // exit
            return parameters;
        }

        #region IAWBPlugin Members
        internal WikiFunctions.Plugin.IAutoWikiBrowser AWB;
        /********************
         * initialize plugin
         *******************/
        public void Initialise(WikiFunctions.Plugin.IAutoWikiBrowser sender) {
            if (sender == null)
                throw new ArgumentNullException("sender");
            else
                AWB = sender;
        }

        /********************
         * return plugin name
        *******************/
        string WikiFunctions.Plugin.IAWBPlugin.Name {
            get { return "HeaderConversion"; }
        }

        string WikiFunctions.Plugin.IAWBPlugin.WikiName {
            get { return "HeaderConversion"; }
        }

        /********************
        * Process article text
        *******************/
        public string ProcessArticle(WikiFunctions.Plugin.IAutoWikiBrowser sender, WikiFunctions.Plugin.ProcessArticleEventArgs eventargs) {
            // get text            
            string text = DelimitTemplates(eventargs.ArticleText);
            string header = text;
            
            // exit if no header
            if (!Regex.IsMatch(header, "<start header2?>", RegexOptions.IgnoreCase)) {
                StopForError("header not detected.", text);
                return header;
            }

            // get header parameters
            header = Regex.Replace(header, "<start header2?>|<end header2?>.+", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Hashtable parameters = GetParameters(header);

            // cleanup header parameters
            if(parameters.Contains("notes"))
                parameters["notes"] = Regex.Replace(parameters["notes"].ToString(), "[\\r\\n\\s]*$", "");
            if (parameters.Contains("previous"))
                parameters["previous"] = Regex.Replace(parameters["previous"].ToString(), "^(?:←|&larr;)+\\s*|^<(?!=.+>)", "");
            if (parameters.Contains("next"))
                parameters["next"] = Regex.Replace(parameters["next"].ToString(), "\\s*(?:→|&rarr;)+\\s*|(?!<<.+)>[\\r\\n\\s]*$", "");


            // generate header2 format
            string newHeader = "{{header2"
                + "\r\n | title    = " + ((parameters.Contains("title")) ? parameters["title"] : "")
                + "\r\n | author   = " + ((parameters.Contains("override_author") && parameters["override_author"].ToString() != "") ? "|override_author=" + parameters["override_author"] : (parameters.Contains("author")) ? parameters["author"] : "");
            if (parameters.Contains("translator")) {
                newHeader += "\r\n | translator = " + parameters["translator"];
            }
            newHeader += "\r\n | section  = " + ((parameters.Contains("section")) ? parameters["section"] : "")
                + "\r\n | previous = " + ((parameters.Contains("previous")) ? parameters["previous"] : "")
                + "\r\n | next     = " + ((parameters.Contains("next")) ? parameters["next"] : "")
                + "\r\n | notes    = " + ((parameters.Contains("notes")) ? parameters["notes"] : "")
                + "\r\n}}";

            // insert into text
            text = Regex.Replace(text, "<start header2?>.+?<end header2?>", newHeader, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            text = UndelimitTemplates(text);
            return text;
        }

        /********************
         * Not implemented
         *******************/
        public void LoadSettings(object[] prefs) {
            return;
        }
        public object[] SaveSettings() {
            return null;
        }
        public void Nudge(out bool Cancel) {
            Cancel = false;
        }
        public void Nudged(int Nudges) {}
        public void Reset() {}

        #endregion
    }
}