Beispiel #1
0
        /// <summary>
        /// Locates the parent tag of the tag provided
        /// </summary>
        public static XMLContextTag GetParentTag(ScintillaNet.ScintillaControl sci, XMLContextTag tag)
        {
            int pos = tag.Position + 1;

            if (pos <= 0)
            {
                pos = sci.CurrentPos;
            }
            XMLContextTag  parent;
            Stack <string> stack = new Stack <string>();

            do
            {
                parent = XMLComplete.GetXMLContextTag(sci, pos);
                pos    = parent.Position;
                if (parent.Name != null && parent.Tag != null)
                {
                    if (parent.Closing)
                    {
                        stack.Push(parent.Name);
                    }
                    else if (!parent.Closed && (stack.Count == 0 || stack.Pop() != parent.Name))
                    {
                        break;
                    }
                }
            }while (pos > 0);
            return(parent);
        }
Beispiel #2
0
        static private XMLContextTag GetXMLContextTag(ScintillaControl sci, int position)
        {
            XMLContextTag xtag = new XMLContextTag();

            if ((position == 0) || (sci == null))
            {
                return(xtag);
            }
            StringBuilder tag = new StringBuilder();
            char          c   = (char)sci.CharAt(position - 1);

            position -= 2;
            tag.Append(c);
            while (position >= 0)
            {
                c = (char)sci.CharAt(position);
                tag.Insert(0, c);
                if (c == '>')
                {
                    return(xtag);
                }
                if (c == '<')
                {
                    break;
                }
                position--;
            }
            //
            xtag.Position = position;
            xtag.Tag      = tag.ToString();
            Match mTag = re_TagName.Match(xtag.Tag + " ");

            if (mTag.Success)
            {
                xtag.Name = mTag.Groups["name"].Value;
                if (xtag.Name.IndexOf(':') > 0)
                {
                    xtag.NameSpace = xtag.Name.Substring(0, xtag.Name.IndexOf(':'));
                }
            }
            return(xtag);
        }
Beispiel #3
0
        /// <summary>
        /// Gets the xml context tag
        /// </summary>
        public static XMLContextTag GetXMLContextTag(ScintillaControl sci, Int32 position)
        {
            XMLContextTag xtag = new XMLContextTag();

            if ((position == 0) || (sci == null))
            {
                return(xtag);
            }
            string tag = "";

            //Char c = (Char)sci.CharAt(position);
            //tag += c;
            position--;
            Char c = (Char)sci.CharAt(position);

            tag = c + tag;
            bool inComment = false;
            bool inCDATA   = false;

            while (position > 0)
            {
                position--;
                c   = (Char)sci.CharAt(position);
                tag = c + tag;

                if (tag == "]]>")
                {
                    inCDATA = true;
                }
                else if (tag == "-->")
                {
                    inComment = true;
                }

                if (c == '<')
                {
                    if ((inComment && !tag.StartsWith("<!--")) ||
                        (inCDATA && !tag.StartsWith("<![CDATA[")))
                    {
                        continue;
                    }
                    break;
                }

                if (inCDATA || inComment)
                {
                    continue;
                }
                if (c == '>')
                {
                    xtag.Position = position + 1;
                    return(xtag);
                }
                else if (c == '{' && sci.BaseStyleAt(position) != 6 /*XML attribute value*/)
                {
                    // code probably not inside a tag: most likely style or script tag without CDATA or comment
                    return(xtag);
                }
            }
            xtag.Position = position;
            xtag.Tag      = tag;
            Match mTag = tagName.Match(tag + " ");

            if (mTag.Success)
            {
                xtag.Name    = mTag.Groups["name"].Value;
                xtag.Closing = tag[1] == '/';
                xtag.Closed  = tag.EndsWith("/>") || tag.EndsWith("-->");
                if (xtag.Name.IndexOf(':') > 0)
                {
                    xtag.NameSpace = xtag.Name.Substring(0, xtag.Name.IndexOf(':'));
                }
            }
            else if (tag.StartsWith("<!--"))
            {
                xtag.Name   = "!--";
                xtag.Closed = tag.EndsWith("-->");
            }
            else if (tag.StartsWith("<![CDATA["))
            {
                xtag.Name   = "![CDATA[";
                xtag.Closed = tag.EndsWith("]]>");
            }
            return(xtag);
        }
Beispiel #4
0
        /// <summary>
        /// Handles the incoming keys object
        /// </summary>
        public static Boolean OnShortCut(Keys keys)
        {
            if (cType == XMLType.Invalid)
            {
                return(false);
            }
            if (keys == (Keys.Control | Keys.Space))
            {
                ITabbedDocument document = PluginBase.MainForm.CurrentDocument;
                if (!document.IsEditable)
                {
                    return(false);
                }
                ScintillaControl sci  = document.SciControl;
                XMLContextTag    ctag = GetXMLContextTag(sci, sci.CurrentPos);
                // Starting tag
                if (ctag.Tag == null && (sci.CurrentPos > 0))
                {
                    if ((Char)sci.CharAt(sci.CurrentPos - 1) == '<')
                    {
                        ctag.Tag  = "<";
                        ctag.Name = "";
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (ctag.Tag.EndsWith(">"))
                {
                    return(false);
                }
                // Closing tag
                else if (ctag.Tag.StartsWith("</") && (ctag.Tag.IndexOf(' ') < 0))
                {
                    ctag.Name    = ctag.Tag.Substring(2);
                    ctag.Tag     = "<" + ctag.Name;
                    ctag.Closing = true;
                }
                // Element completion
                if (ctag.Name != null && (ctag.Tag.Length == ctag.Name.Length + 1))
                {
                    // Allow another plugin to handle this
                    DataEvent de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled)
                    {
                        return(true);
                    }

                    if (cType == XMLType.Known)
                    {
                        List <ICompletionListItem> items = new List <ICompletionListItem>();
                        String previous = null;
                        foreach (HTMLTag tag in knownTags)
                        {
                            if (tag.Name != previous)
                            {
                                items.Add(new HtmlTagItem(tag.Name, tag.Tag));
                                previous = tag.Name;
                            }
                        }
                        CompletionList.Show(items, false, ctag.Name);
                    }
                }
                // Attribute completion
                else
                {
                    Int32     position;
                    String    word;
                    Object[]  obj;
                    DataEvent de;

                    if (InQuotes(ctag.Tag))
                    {
                        position = sci.CurrentPos - 1;
                        word     = GetWordLeft(sci, ref position);

                        obj = new Object[] { ctag, word };
                        de  = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", obj);
                        EventManager.DispatchEvent(PluginBase.MainForm, de);

                        return(true);
                    }
                    if (ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('='))
                    {
                        return(true);
                    }
                    position = sci.CurrentPos - 1;
                    word     = GetWordLeft(sci, ref position);

                    // Allow another plugin to handle this
                    obj = new Object[] { ctag, word };
                    de  = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled)
                    {
                        return(true);
                    }

                    if (cType == XMLType.Known)
                    {
                        foreach (HTMLTag tag in knownTags)
                        {
                            if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                            {
                                List <ICompletionListItem> items = new List <ICompletionListItem>();
                                String previous = null;
                                foreach (String attr in tag.Attributes)
                                {
                                    if (attr != previous)
                                    {
                                        items.Add(new HtmlAttributeItem(attr));
                                        previous = attr;
                                    }
                                }
                                CompletionList.Show(items, true, word.Trim());
                                return(true);
                            }
                        }
                    }
                }
                return(true);
            }
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Handles the incoming character
        /// </summary>
        public static void OnChar(ScintillaControl sci, Int32 value)
        {
            if (cType == XMLType.Invalid || (sci.ConfigurationLanguage != "xml" && sci.ConfigurationLanguage != "html"))
            {
                return;
            }
            XMLContextTag ctag;
            Int32         position = sci.CurrentPos;

            if (sci.BaseStyleAt(position) == 6 && value != '"')
            {
                return; // in XML attribute
            }
            Char      c = ' ';
            DataEvent de;

            switch (value)
            {
            case 10:
                // Shift+Enter to insert <BR/>
                Int32 line = sci.LineFromPosition(position);
                if (Control.ModifierKeys == Keys.Shift)
                {
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
                    {
                        int start = sci.PositionFromLine(line) - ((sci.EOLMode == 0)? 2:1);
                        sci.SetSel(start, position);
                        sci.ReplaceSel((PluginSettings.UpperCaseHtmlTags) ? "<BR/>" : "<br/>");
                        sci.SetSel(start + 5, start + 5);
                        return;
                    }
                }
                if (PluginSettings.SmartIndenter)
                {
                    // Get last non-empty line
                    String text  = "";
                    Int32  line2 = line - 1;
                    while (line2 >= 0 && text.Length == 0)
                    {
                        text = sci.GetLine(line2).TrimEnd();
                        line2--;
                    }
                    if ((text.EndsWith(">") && !text.EndsWith("?>") && !text.EndsWith("%>") && !closingTag.IsMatch(text)) || text.EndsWith("<!--") || text.EndsWith("<![CDATA["))
                    {
                        // Get the previous tag
                        do
                        {
                            position--;
                            c = (Char)sci.CharAt(position);
                        }while (position > 0 && c != '>');
                        ctag = GetXMLContextTag(sci, c == '>' ? position + 1 : position);
                        if ((Char)sci.CharAt(position - 1) == '/')
                        {
                            return;
                        }
                        // Insert blank line if we pressed Enter between a tag & it's closing tag
                        Int32  indent     = sci.GetLineIndentation(line2 + 1);
                        String checkStart = null;
                        bool   subIndent  = true;
                        if (text.EndsWith("<!--"))
                        {
                            checkStart = "-->"; subIndent = false;
                        }
                        else if (text.EndsWith("<![CDATA["))
                        {
                            checkStart = "]]>"; subIndent = false;
                        }
                        else if (ctag.Closed)
                        {
                            subIndent = false;
                        }
                        else if (ctag.Name != null)
                        {
                            checkStart = "</" + ctag.Name;
                            if (ctag.Name.ToLower() == "script" || ctag.Name.ToLower() == "style")
                            {
                                subIndent = false;
                            }
                            if (ctag.Tag.IndexOf('\r') > 0 || ctag.Tag.IndexOf('\n') > 0)
                            {
                                subIndent = false;
                            }
                        }
                        if (checkStart != null)
                        {
                            text = sci.GetLine(line).TrimStart();
                            if (text.StartsWith(checkStart))
                            {
                                sci.SetLineIndentation(line, indent);
                                sci.InsertText(sci.PositionFromLine(line), LineEndDetector.GetNewLineMarker(sci.EOLMode));
                            }
                        }
                        // Indent the code
                        if (subIndent)
                        {
                            indent += sci.Indent;
                        }
                        sci.SetLineIndentation(line, indent);
                        position = sci.LineIndentPosition(line);
                        sci.SetSel(position, position);
                        return;
                    }
                }
                break;

            case '<':
            case '/':
                if (value == '/')
                {
                    if ((position < 2) || ((Char)sci.CharAt(position - 2) != '<'))
                    {
                        return;
                    }
                    ctag         = new XMLContextTag();
                    ctag.Closing = true;
                }
                else
                {
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Tag != null)
                    {
                        return;
                    }
                }
                // Allow another plugin to handle this
                de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag);
                EventManager.DispatchEvent(PluginBase.MainForm, de);
                if (de.Handled)
                {
                    return;
                }

                // New tag
                if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                {
                    List <ICompletionListItem> items = new List <ICompletionListItem>();
                    String previous = null;
                    foreach (string ns in namespaces)
                    {
                        items.Add(new NamespaceItem(ns));
                    }
                    foreach (HTMLTag tag in knownTags)
                    {
                        if (tag.Name != previous && (tag.NS == "" || tag.NS == defaultNS))
                        {
                            items.Add(new HtmlTagItem(tag.Name, tag.Tag));
                            previous = tag.Name;
                        }
                    }
                    items.Sort(new ListItemComparer());
                    CompletionList.Show(items, true);
                }
                return;

            case ':':
                ctag = GetXMLContextTag(sci, position);
                if (ctag.NameSpace == null || position - ctag.Position > ctag.Name.Length + 2)
                {
                    return;
                }
                // Allow another plugin to handle this
                de = new DataEvent(EventType.Command, "XMLCompletion.Namespace", ctag);
                EventManager.DispatchEvent(PluginBase.MainForm, de);
                if (de.Handled)
                {
                    return;
                }

                // Show namespace's tags
                if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                {
                    List <ICompletionListItem> items = new List <ICompletionListItem>();
                    String previous = null;
                    foreach (HTMLTag tag in knownTags)
                    {
                        if (tag.Name != previous && tag.NS == ctag.NameSpace)
                        {
                            items.Add(new HtmlTagItem(tag.Name, tag.Name));
                            previous = tag.Name;
                        }
                    }
                    CompletionList.Show(items, true);
                }
                return;

            case '>':
                if (PluginSettings.CloseTags)
                {
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Name != null && !ctag.Closed)
                    {
                        // Allow another plugin to handle this
                        de = new DataEvent(EventType.Command, "XMLCompletion.CloseElement", ctag);
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                        if (de.Handled)
                        {
                            return;
                        }

                        if (ctag.Closing)
                        {
                            return;
                        }

                        Boolean isLeaf = false;
                        if (cType == XMLType.Known)
                        {
                            foreach (HTMLTag tag in knownTags)
                            {
                                if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                                {
                                    isLeaf = tag.IsLeaf;
                                    break;
                                }
                            }
                        }
                        if (isLeaf)
                        {
                            sci.SetSel(position - 1, position);
                            sci.ReplaceSel("/>");
                            sci.SetSel(position + 1, position + 1);
                        }
                        else
                        {
                            String closeTag = "</" + ctag.Name + ">";
                            sci.ReplaceSel(closeTag);
                            sci.SetSel(position, position);
                        }
                    }
                }
                return;

            case ' ':
                c = (char)sci.CharAt(position);
                if (c > 32 && c != '/' && c != '>' && c != '<')
                {
                    return;
                }
                ctag = GetXMLContextTag(sci, position);
                if (ctag.Tag != null)
                {
                    if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('='))
                    {
                        return;
                    }
                    // Allow another plugin to handle this
                    Object[] obj = new Object[] { ctag, "" };
                    de = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled)
                    {
                        return;
                    }

                    if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                    {
                        foreach (HTMLTag tag in knownTags)
                        {
                            if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                            {
                                List <ICompletionListItem> items = new List <ICompletionListItem>();
                                String previous = null;
                                foreach (String attr in tag.Attributes)
                                {
                                    if (attr != previous)
                                    {
                                        items.Add(new HtmlAttributeItem(attr));
                                        previous = attr;
                                    }
                                }
                                CompletionList.Show(items, true);
                                return;
                            }
                        }
                    }
                }

                /*else
                 * {
                 *  if (Control.ModifierKeys == Keys.Shift)
                 *  {
                 *      sci.SetSel(position - 1, position);
                 *      sci.ReplaceSel("&nbsp;");
                 *  }
                 * }*/
                return;

            case '=':
                if (PluginSettings.InsertQuotes)
                {
                    ctag     = GetXMLContextTag(sci, position);
                    position = sci.CurrentPos - 2;
                    if (ctag.Tag != null && !String.IsNullOrEmpty(ctag.Name) && Char.IsLetter(ctag.Name[0]) &&
                        !InQuotes(ctag.Tag) && (GetWordLeft(sci, ref position).Length > 0))
                    {
                        position = sci.CurrentPos;
                        c        = (Char)sci.CharAt(position);
                        if (c > 32 && c != '>')
                        {
                            sci.ReplaceSel("\"\" ");
                        }
                        else
                        {
                            sci.ReplaceSel("\"\"");
                        }
                        sci.SetSel(position + 1, position + 1);
                        justInsertedQuotesAt = position + 1;
                        // Allow another plugin to handle this
                        de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] { ctag, string.Empty });
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                    }
                }
                return;

            case '"':
                ctag = GetXMLContextTag(sci, position);
                if (position > 1 && ctag.Tag != null && !ctag.Tag.StartsWith("<!"))
                {
                    // TODO  Colorize text change to highlight what's been done
                    if (justInsertedQuotesAt == position - 1)
                    {
                        justInsertedQuotesAt = -1;
                        c = (Char)sci.CharAt(position - 2);
                        if (c == '"' && (Char)sci.CharAt(position - 2) == '"')
                        {
                            sci.SetSel(position - 2, position);
                            sci.ReplaceSel("\"");
                        }
                        // Allow another plugin to handle this
                        de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] { ctag, string.Empty });
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                    }
                    else
                    {
                        c = (Char)sci.CharAt(position - 1);
                        if (c == '"' && (Char)sci.CharAt(position) == '"')
                        {
                            sci.SetSel(position - 1, position + 1);
                            sci.ReplaceSel("\"");
                        }
                    }
                }
                break;

            case '?':
            case '%':
                if (PluginSettings.CloseTags && position > 1)
                {
                    ctag = GetXMLContextTag(sci, position - 2);
                    if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
                    {
                        if ((Char)sci.CharAt(position - 2) == '<')
                        {
                            sci.ReplaceSel((Char)value + ">");
                            sci.SetSel(position, position);
                        }
                    }
                }
                break;

            case '!':
                if (PluginSettings.CloseTags && position > 1)
                {
                    ctag = GetXMLContextTag(sci, position - 2);
                    if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
                    {
                        if ((Char)sci.CharAt(position - 2) == '<')
                        {
                            CompletionList.Show(xmlBlocks, true);
                        }
                    }
                }
                break;
            }
        }
 /// <summary>
 /// Locates the parent tag of the tag provided
 /// </summary>
 public static XMLContextTag GetParentTag(ScintillaControl sci, XMLContextTag tag)
 {
     int pos = tag.Position + 1;
     if (pos <= 0) pos = sci.CurrentPos;
     XMLContextTag parent;
     Stack<string> stack = new Stack<string>();
     do
     {
         parent = GetXMLContextTag(sci, pos);
         pos = parent.Position;
         if (parent.Name != null && parent.Tag != null)
         {
             if (parent.Closing) stack.Push(parent.Name);
             else if (!parent.Closed && (stack.Count == 0 || stack.Pop() != parent.Name))
                 break;
         }
     }
     while (pos > 0);
     return parent;
 }
        /// <summary>
        /// Gets the xml context tag
        /// </summary> 
        public static XMLContextTag GetXMLContextTag(ScintillaControl sci, Int32 position)
        {
            XMLContextTag xtag = new XMLContextTag();
            if ((position == 0) || (sci == null)) return xtag;
            string tag = "";
            //Char c = (Char)sci.CharAt(position);
            //tag += c;
            position--;
            Char c = (Char)sci.CharAt(position);
            tag = c + tag;
            bool inComment = false;
            bool inCDATA = false;
            while (position > 0)
            {
                position--;
                c = (Char)sci.CharAt(position);
                tag = c + tag;

                if (tag == "]]>") inCDATA = true;
                else if (tag == "-->") inComment = true;
                
                if (c == '<')
                {
                    if ((inComment && !tag.StartsWith("<!--"))
                        || (inCDATA && !tag.StartsWith("<![CDATA[")))
                        continue;
                    break;
                }

                if (inCDATA || inComment) continue;
                if (c == '>')
                {
                    xtag.Position = position + 1;
                    return xtag;
                }
                else if (c == '{' && sci.BaseStyleAt(position) != 6 /*XML attribute value*/)
                {
                    // code probably not inside a tag: most likely style or script tag without CDATA or comment
                    return xtag;
                }
            }
            xtag.Position = position;
            xtag.Tag = tag;
            Match mTag = tagName.Match(tag + " ");
            if (mTag.Success)
            {
                xtag.Name = mTag.Groups["name"].Value;
                xtag.Closing = tag[1] == '/';
                xtag.Closed = tag.EndsWith("/>") || tag.EndsWith("-->");
                if (xtag.Name.IndexOf(':') > 0)
                {
                    xtag.NameSpace = xtag.Name.Substring(0, xtag.Name.IndexOf(':'));
                }
            }
            else if (tag.StartsWith("<!--"))
            {
                xtag.Name = "!--";
                xtag.Closed = tag.EndsWith("-->");
            }
            else if (tag.StartsWith("<![CDATA["))
            {
                xtag.Name = "![CDATA[";
                xtag.Closed = tag.EndsWith("]]>");
            }
            return xtag;
        }
        /// <summary>
        /// Handles the incoming character
        /// </summary> 
        public static void OnChar(ScintillaControl sci, Int32 value)
        {
            if (cType == XMLType.Invalid || (sci.ConfigurationLanguage != "xml" && sci.ConfigurationLanguage != "html")) 
                return;
            XMLContextTag ctag;
            Int32 position = sci.CurrentPos;
            if (sci.BaseStyleAt(position) == 6 && value != '"')
                return; // in XML attribute

            Char c = ' ';
            DataEvent de;
            switch (value)
            {
                case 10:
                    // Shift+Enter to insert <BR/>
                    Int32 line = sci.LineFromPosition(position);
                    if (Control.ModifierKeys == Keys.Shift)
                    {
                        ctag = GetXMLContextTag(sci, position);
                        if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
                        {
                            int start = sci.PositionFromLine(line)-((sci.EOLMode == 0)? 2:1);
                            sci.SetSel(start, position);
                            sci.ReplaceSel((PluginSettings.UpperCaseHtmlTags) ? "<BR/>" : "<br/>");
                            sci.SetSel(start+5, start+5);
                            return;
                        }
                    }
                    if (PluginSettings.SmartIndenter)
                    {
                        // There is no standard for XML formatting, although most IDEs have similarities. We are mostly going with Visual Studio style with slight differences.
                        // Get last non-empty line.
                        String text = "";
                        Int32 line2 = line - 1;
                        while (line2 >= 0 && text.Length == 0)
                        {
                            text = sci.GetLine(line2).TrimEnd();
                            line2--;
                        }
                        if ((text.EndsWith(">") && !text.EndsWith("?>") && !text.EndsWith("%>")) || text.EndsWith("<!--") || text.EndsWith("<![CDATA["))
                        {
                            // Get the previous tag.
                            do
                            {
                                position--;
                                c = (Char)sci.CharAt(position);
                            }
                            while (position > 0 && c != '>');
                            ctag = GetXMLContextTag(sci, c == '>' ? position + 1 : position);
                            // Line indentation.
                            Int32 indent = sci.GetLineIndentation(line2 + 1);

                            String checkStart = null;
                            bool subIndent = true;
                            if (text.EndsWith("<!--")) { checkStart = "-->"; subIndent = false; }
                            else if (text.EndsWith("<![CDATA[")) { checkStart = "]]>"; subIndent = false; }
                            else if (ctag.Closed || ctag.Closing)
                            {
                                //Closed tag. Look for the nearest open and not closed tag for proper indentation
                                subIndent = false;
                                if (ctag.Name != null)
                                {
                                    var tmpTags = new Stack<XMLContextTag>();
                                    var tmpTag = ctag;

                                    if (!tmpTag.Closed) tmpTags.Push(tmpTag);
                                    while (tmpTag.Position != 0)
                                    {
                                        tmpTag = GetXMLContextTag(sci, tmpTag.Position);
                                        if (tmpTag.Tag != null && tmpTag.Name != null)
                                        {
                                            if (tmpTag.Closed) 
                                                continue;
                                            else if (tmpTag.Closing)
                                            {
                                                tmpTags.Push(tmpTag);
                                            }
                                            else
                                            {
                                                if (tmpTags.Count > 0 && tmpTags.Peek().Name == tmpTag.Name)
                                                    tmpTags.Pop();
                                                else
                                                    break;
                                            }
                                        }
                                    }
                                    if (tmpTags.Count > 0)
                                        indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTags.Pop().Position));
                                    else if (tmpTag.Name != null)
                                    {
                                        subIndent = true;
                                        checkStart = "</" + tmpTag.Name;
                                        indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTag.Position));
                                    }
                                    else
                                    {
                                        indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTag.Position));
                                    }
                                }
                            }
                            else if (ctag.Name != null)
                            {
                                // Indentation. Some IDEs use the tag position, VS uses the tag start line indentation. 
                                indent = sci.GetLineIndentation(sci.LineFromPosition(ctag.Position));
                                checkStart = "</" + ctag.Name;
                                if (ctag.Name.ToLower() == "script" || ctag.Name.ToLower() == "style") 
                                    subIndent = false;
                            }
                            try
                            {
                                sci.BeginUndoAction();
                                if (checkStart != null)
                                {
                                    text = sci.GetLine(line).TrimStart();
                                    if (text.StartsWith(checkStart))
                                    {
                                        sci.SetLineIndentation(line, indent);
                                        sci.InsertText(sci.PositionFromLine(line), LineEndDetector.GetNewLineMarker(sci.EOLMode));
                                    }
                                }
                                // Indent the code
                                if (subIndent) indent += sci.Indent;
                                sci.SetLineIndentation(line, indent);
                                position = sci.LineIndentPosition(line);
                                sci.SetSel(position, position);
                            }
                            finally { sci.EndUndoAction(); }
                            return;
                        }
                        else if (!text.EndsWith(">"))
                        {
                            ctag = GetXMLContextTag(sci, sci.CurrentPos);
                            if (ctag.Tag == null || ctag.Name == null) return;
                            // We're inside a tag. Visual Studio indents with regards to the first line, other IDEs indent using the indentation of the last line with text.
                            int indent;
                            string tag = (ctag.Tag.IndexOf('\r') > 0 || ctag.Tag.IndexOf('\n') > 0) ? ctag.Tag.Substring(0, ctag.Tag.IndexOfAny(new[] {'\r', '\n'})).TrimEnd() : ctag.Tag.TrimEnd();
                            if (tag.EndsWith("\""))
                            {
                                int i;
                                int l = tag.Length;
                                for (i = ctag.Name.Length + 1; i < l; i++)
                                {
                                    if (!char.IsWhiteSpace(tag[i]))
                                        break;
                                }
                                indent = sci.Column(ctag.Position) + sci.MBSafePosition(i);
                            }
                            else
                            {
                                indent = sci.GetLineIndentation(sci.LineFromPosition(ctag.Position)) + sci.Indent;
                            }

                            sci.SetLineIndentation(line, indent);
                            position = sci.LineIndentPosition(line);
                            sci.SetSel(position, position);
                            return;
                        }
                    }
                    break;
                    
                case '<':
                case '/':
                    if (value == '/')
                    {
                        if ((position < 2) || ((Char)sci.CharAt(position-2) != '<')) return;
                        ctag = new XMLContextTag();
                        ctag.Position = position - 2;
                        ctag.Closing = true;
                    }
                    else 
                    {
                        ctag = GetXMLContextTag(sci, position);
                        if (ctag.Tag != null) return;
                    }
                    // Allow another plugin to handle this
                    de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled) return;

                    // New tag
                    if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                    {
                        List<ICompletionListItem> items = new List<ICompletionListItem>();
                        String previous = null;
                        foreach (string ns in namespaces)
                        {
                            items.Add(new NamespaceItem(ns));
                        }
                        foreach (HTMLTag tag in knownTags) 
                            if (tag.Name != previous && (tag.NS == "" || tag.NS == defaultNS)) 
                            {
                                items.Add( new HtmlTagItem(tag.Name, tag.Tag));
                                previous = tag.Name;
                            }
                        items.Sort(new ListItemComparer());
                        CompletionList.Show(items, true);
                    }
                    return;

                case ':':
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.NameSpace == null || position - ctag.Position > ctag.Name.Length + 2) return;
                    // Allow another plugin to handle this
                    de = new DataEvent(EventType.Command, "XMLCompletion.Namespace", ctag);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled) return;

                    // Show namespace's tags
                    if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                    {
                        List<ICompletionListItem> items = new List<ICompletionListItem>();
                        String previous = null;
                        foreach (HTMLTag tag in knownTags)
                            if (tag.Name != previous && tag.NS == ctag.NameSpace)
                            {
                                items.Add(new HtmlTagItem(tag.Name, tag.Name));
                                previous = tag.Name;
                            }
                        CompletionList.Show(items, true);
                    }
                    return;

                case '>':
                    if (PluginSettings.CloseTags)
                    {
                        ctag = GetXMLContextTag(sci, position);
                        if (ctag.Name != null && !ctag.Closed)
                        {
                            // Allow another plugin to handle this
                            de = new DataEvent(EventType.Command, "XMLCompletion.CloseElement", ctag);
                            EventManager.DispatchEvent(PluginBase.MainForm, de);
                            if (de.Handled) return;

                            if (ctag.Closing) return;

                            Boolean isLeaf = false;
                            if (cType == XMLType.Known)
                            foreach(HTMLTag tag in knownTags)
                            {
                                if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                                {
                                    isLeaf = tag.IsLeaf;
                                    break;
                                }
                            }
                            if (isLeaf)
                            {
                                sci.SetSel(position-1,position);
                                sci.ReplaceSel("/>");
                                sci.SetSel(position+1, position+1);
                            }
                            else
                            {
                                String closeTag = "</"+ctag.Name+">";
                                sci.ReplaceSel(closeTag);
                                sci.SetSel(position, position);
                            }
                        }
                    }
                    return;
                    
                case ' ':
                    c = (char)sci.CharAt(position);
                    if (c > 32 && c != '/' && c != '>' && c != '<') return;
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Tag != null)
                    {
                        if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('=')) return;
                        // Allow another plugin to handle this
                        Object[] obj = new Object[] { ctag, "" };
                        de = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj);
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                        if (de.Handled) return;
                        
                        if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                        {
                            foreach (HTMLTag tag in knownTags)
                                if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                                {
                                    List<ICompletionListItem> items = new List<ICompletionListItem>();
                                    String previous = null;
                                    foreach (String attr in tag.Attributes)
                                        if (attr != previous)
                                        {
                                            items.Add(new HtmlAttributeItem(attr));
                                            previous = attr;
                                        }
                                    CompletionList.Show(items, true);
                                    return;
                                }
                        }
                    }
                    /*else
                    {
                        if (Control.ModifierKeys == Keys.Shift)
                        {
                            sci.SetSel(position - 1, position);
                            sci.ReplaceSel("&nbsp;");
                        }
                    }*/
                    return;
                
                case '=':
                    if (PluginSettings.InsertQuotes)
                    {
                        ctag = GetXMLContextTag(sci, position);
                        position = sci.CurrentPos-2;
                        if (ctag.Tag != null && !String.IsNullOrEmpty(ctag.Name) && Char.IsLetter(ctag.Name[0]) 
                            && !InQuotes(ctag.Tag) && (GetWordLeft(sci, ref position).Length > 0))
                        {
                            position = sci.CurrentPos;
                            c = (Char)sci.CharAt(position);
                            if (c > 32 && c != '>') sci.ReplaceSel("\"\" ");
                            else sci.ReplaceSel("\"\"");
                            sci.SetSel(position+1, position+1);
                            justInsertedQuotesAt = position+1;
                            // Allow another plugin to handle this
                            de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] { ctag, string.Empty });
                            EventManager.DispatchEvent(PluginBase.MainForm, de);
                        }
                    }
                    return;

                case '"':
                    ctag = GetXMLContextTag(sci, position);
                    if (position > 1 && ctag.Tag != null && !ctag.Tag.StartsWith("<!"))
                    {
                        // TODO  Colorize text change to highlight what's been done
                        if (justInsertedQuotesAt == position - 1)
                        {
                            justInsertedQuotesAt = -1;
                            c = (Char)sci.CharAt(position - 2);
                            if (c == '"' && (Char)sci.CharAt(position-2) == '"')
                            {
                                sci.SetSel(position - 2, position);
                                sci.ReplaceSel("\"");
                            }
                            // Allow another plugin to handle this
                            de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] {ctag, string.Empty});
                            EventManager.DispatchEvent(PluginBase.MainForm, de);
                        }
                        else
                        {
                            c = (Char)sci.CharAt(position - 1);
                            if (c == '"' && (Char)sci.CharAt(position) == '"')
                            {
                                sci.SetSel(position - 1, position + 1);
                                sci.ReplaceSel("\"");
                            }
                        }
                    }
                    break;
                    
                case '?':
                case '%':
                    if (PluginSettings.CloseTags && position > 1)
                    {
                        ctag = GetXMLContextTag(sci, position-2);
                        if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
                        {
                            if ((Char)sci.CharAt(position-2) == '<')
                            {
                                sci.ReplaceSel((Char)value + ">");
                                sci.SetSel(position, position);
                            }
                        }
                    }
                    break;
                
                case '!':
                    if (PluginSettings.CloseTags && position > 1)
                    {
                        ctag = GetXMLContextTag(sci, position-2);
                        if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
                        {
                            if ((Char)sci.CharAt(position-2) == '<')
                            {
                                CompletionList.Show(xmlBlocks, true);
                            }
                        }                       
                    }
                    break;
            }
        }
Beispiel #9
0
        /// <summary>
        /// Handles the incoming character
        /// </summary>
        public static void OnChar(ScintillaControl sci, Int32 value)
        {
            if (cType == XMLType.Invalid || (sci.ConfigurationLanguage != "xml" && sci.ConfigurationLanguage != "html"))
            {
                return;
            }
            XMLContextTag ctag;
            Int32         position = sci.CurrentPos;

            if (sci.BaseStyleAt(position) == 6 && value != '"')
            {
                return; // in XML attribute
            }
            Char      c = ' ';
            DataEvent de;

            switch (value)
            {
            case 10:
                // Shift+Enter to insert <BR/>
                Int32 line = sci.LineFromPosition(position);
                if (Control.ModifierKeys == Keys.Shift)
                {
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Tag == null || ctag.Tag.EndsWith('>'))
                    {
                        int start = sci.PositionFromLine(line) - ((sci.EOLMode == 0)? 2:1);
                        sci.SetSel(start, position);
                        sci.ReplaceSel((PluginSettings.UpperCaseHtmlTags) ? "<BR/>" : "<br/>");
                        sci.SetSel(start + 5, start + 5);
                        return;
                    }
                }
                if (PluginSettings.SmartIndenter)
                {
                    // There is no standard for XML formatting, although most IDEs have similarities. We are mostly going with Visual Studio style with slight differences.
                    // Get last non-empty line.
                    String text  = "";
                    Int32  line2 = line - 1;
                    while (line2 >= 0 && text.Length == 0)
                    {
                        text = sci.GetLine(line2).TrimEnd();
                        line2--;
                    }
                    if ((text.EndsWith('>') && !text.EndsWithOrdinal("?>") && !text.EndsWithOrdinal("%>")) || text.EndsWithOrdinal("<!--") || text.EndsWithOrdinal("<![CDATA["))
                    {
                        // Get the previous tag.
                        do
                        {
                            position--;
                            c = (Char)sci.CharAt(position);
                        }while (position > 0 && c != '>');
                        ctag = GetXMLContextTag(sci, c == '>' ? position + 1 : position);
                        // Line indentation.
                        Int32 indent = sci.GetLineIndentation(line2 + 1);

                        String checkStart = null;
                        bool   subIndent  = true;
                        if (text.EndsWithOrdinal("<!--"))
                        {
                            checkStart = "-->"; subIndent = false;
                        }
                        else if (text.EndsWithOrdinal("<![CDATA["))
                        {
                            checkStart = "]]>"; subIndent = false;
                        }
                        else if (ctag.Closed || ctag.Closing)
                        {
                            //Closed tag. Look for the nearest open and not closed tag for proper indentation
                            subIndent = false;
                            if (ctag.Name != null)
                            {
                                var tmpTags = new Stack <XMLContextTag>();
                                var tmpTag  = ctag;

                                if (!tmpTag.Closed)
                                {
                                    tmpTags.Push(tmpTag);
                                }
                                while (tmpTag.Position != 0)
                                {
                                    tmpTag = GetXMLContextTag(sci, tmpTag.Position);
                                    if (tmpTag.Tag != null && tmpTag.Name != null)
                                    {
                                        if (tmpTag.Closed)
                                        {
                                            continue;
                                        }
                                        else if (tmpTag.Closing)
                                        {
                                            tmpTags.Push(tmpTag);
                                        }
                                        else
                                        {
                                            if (tmpTags.Count > 0 && tmpTags.Peek().Name == tmpTag.Name)
                                            {
                                                tmpTags.Pop();
                                            }
                                            else
                                            {
                                                break;
                                            }
                                        }
                                    }
                                }
                                if (tmpTags.Count > 0)
                                {
                                    indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTags.Pop().Position));
                                }
                                else if (tmpTag.Name != null)
                                {
                                    subIndent  = true;
                                    checkStart = "</" + tmpTag.Name;
                                    indent     = sci.GetLineIndentation(sci.LineFromPosition(tmpTag.Position));
                                }
                                else
                                {
                                    indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTag.Position));
                                }
                            }
                        }
                        else if (ctag.Name != null)
                        {
                            // Indentation. Some IDEs use the tag position, VS uses the tag start line indentation.
                            indent     = sci.GetLineIndentation(sci.LineFromPosition(ctag.Position));
                            checkStart = "</" + ctag.Name;
                            if (ctag.Name.ToLower() == "script" || ctag.Name.ToLower() == "style")
                            {
                                subIndent = false;
                            }
                        }
                        try
                        {
                            sci.BeginUndoAction();
                            if (checkStart != null)
                            {
                                text = sci.GetLine(line).TrimStart();
                                if (text.StartsWithOrdinal(checkStart))
                                {
                                    sci.SetLineIndentation(line, indent);
                                    sci.InsertText(sci.PositionFromLine(line), LineEndDetector.GetNewLineMarker(sci.EOLMode));
                                }
                            }
                            // Indent the code
                            if (subIndent)
                            {
                                indent += sci.Indent;
                            }
                            sci.SetLineIndentation(line, indent);
                            position = sci.LineIndentPosition(line);
                            sci.SetSel(position, position);
                        }
                        finally { sci.EndUndoAction(); }
                        return;
                    }
                    else if (!text.EndsWith('>'))
                    {
                        ctag = GetXMLContextTag(sci, sci.CurrentPos);
                        if (ctag.Tag == null || ctag.Name == null)
                        {
                            return;
                        }
                        // We're inside a tag. Visual Studio indents with regards to the first line, other IDEs indent using the indentation of the last line with text.
                        int    indent;
                        string tag = (ctag.Tag.IndexOf('\r') > 0 || ctag.Tag.IndexOf('\n') > 0) ? ctag.Tag.Substring(0, ctag.Tag.IndexOfAny(new[] { '\r', '\n' })).TrimEnd() : ctag.Tag.TrimEnd();
                        if (tag.EndsWith('\"'))
                        {
                            int i;
                            int l = tag.Length;
                            for (i = ctag.Name.Length + 1; i < l; i++)
                            {
                                if (!char.IsWhiteSpace(tag[i]))
                                {
                                    break;
                                }
                            }
                            indent = sci.Column(ctag.Position) + sci.MBSafePosition(i);
                        }
                        else
                        {
                            indent = sci.GetLineIndentation(sci.LineFromPosition(ctag.Position)) + sci.Indent;
                        }

                        sci.SetLineIndentation(line, indent);
                        position = sci.LineIndentPosition(line);
                        sci.SetSel(position, position);
                        return;
                    }
                }
                break;

            case '<':
            case '/':
                if (value == '/')
                {
                    if ((position < 2) || ((Char)sci.CharAt(position - 2) != '<'))
                    {
                        return;
                    }
                    ctag          = new XMLContextTag();
                    ctag.Position = position - 2;
                    ctag.Closing  = true;
                }
                else
                {
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Tag != null)
                    {
                        return;
                    }
                }
                // Allow another plugin to handle this
                de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag);
                EventManager.DispatchEvent(PluginBase.MainForm, de);
                if (de.Handled)
                {
                    return;
                }

                // New tag
                if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                {
                    List <ICompletionListItem> items = new List <ICompletionListItem>();
                    String previous = null;
                    foreach (string ns in namespaces)
                    {
                        items.Add(new NamespaceItem(ns));
                    }
                    foreach (HTMLTag tag in knownTags)
                    {
                        if (tag.Name != previous && (tag.NS == "" || tag.NS == defaultNS))
                        {
                            items.Add(new HtmlTagItem(tag.Name, tag.Tag));
                            previous = tag.Name;
                        }
                    }
                    items.Sort(new ListItemComparer());
                    CompletionList.Show(items, true);
                }
                return;

            case ':':
                ctag = GetXMLContextTag(sci, position);
                if (ctag.NameSpace == null || position - ctag.Position > ctag.Name.Length + 2)
                {
                    return;
                }
                // Allow another plugin to handle this
                de = new DataEvent(EventType.Command, "XMLCompletion.Namespace", ctag);
                EventManager.DispatchEvent(PluginBase.MainForm, de);
                if (de.Handled)
                {
                    return;
                }

                // Show namespace's tags
                if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                {
                    List <ICompletionListItem> items = new List <ICompletionListItem>();
                    String previous = null;
                    foreach (HTMLTag tag in knownTags)
                    {
                        if (tag.Name != previous && tag.NS == ctag.NameSpace)
                        {
                            items.Add(new HtmlTagItem(tag.Name, tag.Name));
                            previous = tag.Name;
                        }
                    }
                    CompletionList.Show(items, true);
                }
                return;

            case '>':
                if (PluginSettings.CloseTags)
                {
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.Name != null && !ctag.Closed)
                    {
                        // Allow another plugin to handle this
                        de = new DataEvent(EventType.Command, "XMLCompletion.CloseElement", ctag);
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                        if (de.Handled)
                        {
                            return;
                        }

                        if (ctag.Closing)
                        {
                            return;
                        }

                        Boolean isLeaf = false;
                        if (cType == XMLType.Known)
                        {
                            foreach (HTMLTag tag in knownTags)
                            {
                                if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                                {
                                    isLeaf = tag.IsLeaf;
                                    break;
                                }
                            }
                        }
                        if (isLeaf)
                        {
                            sci.SetSel(position - 1, position);
                            sci.ReplaceSel("/>");
                            sci.SetSel(position + 1, position + 1);
                        }
                        else
                        {
                            String closeTag = "</" + ctag.Name + ">";
                            sci.ReplaceSel(closeTag);
                            sci.SetSel(position, position);
                        }
                    }
                }
                return;

            case ' ':
                c = (char)sci.CharAt(position);
                if (c > 32 && c != '/' && c != '>' && c != '<')
                {
                    return;
                }
                ctag = GetXMLContextTag(sci, position);
                if (ctag.Tag != null)
                {
                    if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('='))
                    {
                        return;
                    }
                    // Allow another plugin to handle this
                    Object[] obj = new Object[] { ctag, "" };
                    de = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled)
                    {
                        return;
                    }

                    if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                    {
                        foreach (HTMLTag tag in knownTags)
                        {
                            if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                            {
                                List <ICompletionListItem> items = new List <ICompletionListItem>();
                                String previous = null;
                                foreach (String attr in tag.Attributes)
                                {
                                    if (attr != previous)
                                    {
                                        items.Add(new HtmlAttributeItem(attr));
                                        previous = attr;
                                    }
                                }
                                CompletionList.Show(items, true);
                                return;
                            }
                        }
                    }
                }

                /*else
                 * {
                 *  if (Control.ModifierKeys == Keys.Shift)
                 *  {
                 *      sci.SetSel(position - 1, position);
                 *      sci.ReplaceSel("&nbsp;");
                 *  }
                 * }*/
                return;

            case '=':
                if (PluginSettings.InsertQuotes)
                {
                    ctag     = GetXMLContextTag(sci, position);
                    position = sci.CurrentPos - 2;
                    if (ctag.Tag != null && !String.IsNullOrEmpty(ctag.Name) && Char.IsLetter(ctag.Name[0]) &&
                        !InQuotes(ctag.Tag) && (GetWordLeft(sci, ref position).Length > 0))
                    {
                        position = sci.CurrentPos;
                        c        = (Char)sci.CharAt(position);
                        if (c > 32 && c != '>')
                        {
                            sci.ReplaceSel("\"\" ");
                        }
                        else
                        {
                            sci.ReplaceSel("\"\"");
                        }
                        sci.SetSel(position + 1, position + 1);
                        justInsertedQuotesAt = position + 1;
                        // Allow another plugin to handle this
                        de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] { ctag, string.Empty });
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                    }
                }
                return;

            case '"':
                ctag = GetXMLContextTag(sci, position);
                if (position > 1 && ctag.Tag != null && !ctag.Tag.StartsWithOrdinal("<!"))
                {
                    // TODO  Colorize text change to highlight what's been done
                    if (justInsertedQuotesAt == position - 1)
                    {
                        justInsertedQuotesAt = -1;
                        c = (Char)sci.CharAt(position - 2);
                        if (c == '"' && (Char)sci.CharAt(position - 2) == '"')
                        {
                            sci.SetSel(position - 2, position);
                            sci.ReplaceSel("\"");
                        }
                        // Allow another plugin to handle this
                        de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] { ctag, string.Empty });
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                    }
                    else
                    {
                        c = (Char)sci.CharAt(position - 1);
                        if (c == '"' && (Char)sci.CharAt(position) == '"')
                        {
                            sci.SetSel(position - 1, position + 1);
                            sci.ReplaceSel("\"");
                        }
                    }
                }
                break;

            case '?':
            case '%':
                if (PluginSettings.CloseTags && position > 1)
                {
                    ctag = GetXMLContextTag(sci, position - 2);
                    if (ctag.Tag == null || ctag.Tag.EndsWith('>'))
                    {
                        if ((Char)sci.CharAt(position - 2) == '<')
                        {
                            sci.ReplaceSel((Char)value + ">");
                            sci.SetSel(position, position);
                        }
                    }
                }
                break;

            case '!':
                if (PluginSettings.CloseTags && position > 1)
                {
                    ctag = GetXMLContextTag(sci, position - 2);
                    if (ctag.Tag == null || ctag.Tag.EndsWith('>'))
                    {
                        if ((Char)sci.CharAt(position - 2) == '<')
                        {
                            CompletionList.Show(xmlBlocks, true);
                        }
                    }
                }
                break;
            }
        }
Beispiel #10
0
        /// <summary>
        /// Handles the incoming character
        /// </summary> 
		public static void OnChar(ScintillaControl sci, Int32 value)
		{
            if (cType == XMLType.Invalid || (sci.ConfigurationLanguage != "xml" && sci.ConfigurationLanguage != "html")) 
                return;
			XMLContextTag ctag;
			Int32 position = sci.CurrentPos;
            if (sci.BaseStyleAt(position) == 6 && value != '"')
                return; // in XML attribute

			Char c = ' ';
            DataEvent de;
			switch (value)
			{
				case 10:
                    // Shift+Enter to insert <BR/>
                    Int32 line = sci.LineFromPosition(position);
					if (Control.ModifierKeys == Keys.Shift)
					{
						ctag = GetXMLContextTag(sci, position);
						if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
						{
							int start = sci.PositionFromLine(line)-((sci.EOLMode == 0)? 2:1);
							sci.SetSel(start, position);
                            sci.ReplaceSel((PluginSettings.UpperCaseHtmlTags) ? "<BR/>" : "<br/>");
							sci.SetSel(start+5, start+5);
							return;
						}
					}
                    if (PluginSettings.SmartIndenter)
					{
                        // Get last non-empty line
						String text = "";
                        Int32 line2 = line - 1;
						while (line2 >= 0 && text.Length == 0)
						{
							text = sci.GetLine(line2).TrimEnd();
							line2--;
						}
						if ((text.EndsWith(">") && !text.EndsWith("?>") && !text.EndsWith("%>") && !closingTag.IsMatch(text)) || text.EndsWith("<!--") || text.EndsWith("<![CDATA["))
						{
                            // Get the previous tag
                            do
                            {
								position--;
								c = (Char)sci.CharAt(position);
							}
							while (position > 0 && c != '>');
							ctag = GetXMLContextTag(sci, c == '>' ? position + 1 : position);
							if ((Char)sci.CharAt(position-1) == '/') return;
                            // Insert blank line if we pressed Enter between a tag & it's closing tag
                            Int32 indent = sci.GetLineIndentation(line2 + 1);
							String checkStart = null;
                            bool subIndent = true;
							if (text.EndsWith("<!--")) { checkStart = "-->"; subIndent = false; }
                            else if (text.EndsWith("<![CDATA[")) { checkStart = "]]>"; subIndent = false; }
                            else if (ctag.Closed) subIndent = false;
                            else if (ctag.Name != null)
                            {
                                checkStart = "</" + ctag.Name;
                                if (ctag.Name.ToLower() == "script" || ctag.Name.ToLower() == "style") 
                                    subIndent = false;
                                if (ctag.Tag.IndexOf('\r') > 0 || ctag.Tag.IndexOf('\n') > 0)
                                    subIndent = false;
                            }
							if (checkStart != null)
							{
								text = sci.GetLine(line).TrimStart();
								if (text.StartsWith(checkStart))
								{
									sci.SetLineIndentation(line, indent);
									sci.InsertText(sci.PositionFromLine(line), LineEndDetector.GetNewLineMarker(sci.EOLMode));
								}
							}
                            // Indent the code
                            if (subIndent) indent += sci.Indent;
                            sci.SetLineIndentation(line, indent);
							position = sci.LineIndentPosition(line);
							sci.SetSel(position, position);
							return;
						}
					}
					break;
					
				case '<':
				case '/':
					if (value == '/')
					{
						if ((position < 2) || ((Char)sci.CharAt(position-2) != '<')) return;
                        ctag = new XMLContextTag();
                        ctag.Closing = true;
					}
					else 
					{
						ctag = GetXMLContextTag(sci, position);
						if (ctag.Tag != null) return;
					}
                    // Allow another plugin to handle this
                    de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled) return;

                    // New tag
                    if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
					{
                        List<ICompletionListItem> items = new List<ICompletionListItem>();
						String previous = null;
                        foreach (string ns in namespaces)
                        {
                            items.Add(new NamespaceItem(ns));
                        }
                        foreach (HTMLTag tag in knownTags) 
						    if (tag.Name != previous && (tag.NS == "" || tag.NS == defaultNS)) 
                            {
							    items.Add( new HtmlTagItem(tag.Name, tag.Tag));
							    previous = tag.Name;
						    }
                        items.Sort(new ListItemComparer());
                        CompletionList.Show(items, true);
					}
					return;

                case ':':
                    ctag = GetXMLContextTag(sci, position);
                    if (ctag.NameSpace == null || position - ctag.Position > ctag.Name.Length + 2) return;
                    // Allow another plugin to handle this
                    de = new DataEvent(EventType.Command, "XMLCompletion.Namespace", ctag);
                    EventManager.DispatchEvent(PluginBase.MainForm, de);
                    if (de.Handled) return;

                    // Show namespace's tags
                    if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                    {
                        List<ICompletionListItem> items = new List<ICompletionListItem>();
                        String previous = null;
                        foreach (HTMLTag tag in knownTags)
                            if (tag.Name != previous && tag.NS == ctag.NameSpace)
                            {
                                items.Add(new HtmlTagItem(tag.Name, tag.Name));
                                previous = tag.Name;
                            }
                        CompletionList.Show(items, true);
                    }
                    return;

				case '>':
                    if (PluginSettings.CloseTags)
					{
						ctag = GetXMLContextTag(sci, position);
						if (ctag.Name != null && !ctag.Closed)
						{
                            // Allow another plugin to handle this
                            de = new DataEvent(EventType.Command, "XMLCompletion.CloseElement", ctag);
                            EventManager.DispatchEvent(PluginBase.MainForm, de);
                            if (de.Handled) return;

                            if (ctag.Closing) return;

							Boolean isLeaf = false;
							if (cType == XMLType.Known)
							foreach(HTMLTag tag in knownTags)
							{
								if (String.Compare(tag.Tag, ctag.Name, true) == 0)
								{
									isLeaf = tag.IsLeaf;
									break;
								}
							}
							if (isLeaf)
							{
								sci.SetSel(position-1,position);
								sci.ReplaceSel("/>");
								sci.SetSel(position+1, position+1);
							}
							else
							{
								String closeTag = "</"+ctag.Name+">";
								sci.ReplaceSel(closeTag);
								sci.SetSel(position, position);
							}
						}
					}
					return;
					
				case ' ':
					c = (char)sci.CharAt(position);
					if (c > 32 && c != '/' && c != '>' && c != '<') return;
					ctag = GetXMLContextTag(sci, position);
                    if (ctag.Tag != null)
                    {
                        if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('=')) return;
                        // Allow another plugin to handle this
                        Object[] obj = new Object[] { ctag, "" };
                        de = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj);
                        EventManager.DispatchEvent(PluginBase.MainForm, de);
                        if (de.Handled) return;
                        
                        if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known)
                        {
                            foreach (HTMLTag tag in knownTags)
                                if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                                {
                                    List<ICompletionListItem> items = new List<ICompletionListItem>();
                                    String previous = null;
                                    foreach (String attr in tag.Attributes)
                                        if (attr != previous)
                                        {
                                            items.Add(new HtmlAttributeItem(attr));
                                            previous = attr;
                                        }
                                    CompletionList.Show(items, true);
                                    return;
                                }
                        }
                    }
                    /*else
                    {
                        if (Control.ModifierKeys == Keys.Shift)
                        {
                            sci.SetSel(position - 1, position);
                            sci.ReplaceSel("&nbsp;");
                        }
                    }*/
					return;
				
				case '=':
					if (PluginSettings.InsertQuotes)
					{
						ctag = GetXMLContextTag(sci, position);
						position = sci.CurrentPos-2;
						if (ctag.Tag != null && !ctag.Tag.StartsWith("<!") && !InQuotes(ctag.Tag) && (GetWordLeft(sci, ref position).Length > 0))
						{
							position = sci.CurrentPos;
							c = (Char)sci.CharAt(position);
							if (c > 32 && c != '>') sci.ReplaceSel("\"\" ");
							else sci.ReplaceSel("\"\"");
							sci.SetSel(position+1, position+1);
                            justInsertedQuotesAt = position+1;
                            // Allow another plugin to handle this
                            de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new XMLContextTag());
                            EventManager.DispatchEvent(PluginBase.MainForm, de);
						}
					}
					return;

                case '"':
                    ctag = GetXMLContextTag(sci, position);
                    if (position > 1 && ctag.Tag != null && !ctag.Tag.StartsWith("<!"))
                    {
                        // TODO  Colorize text change to highlight what's been done
                        if (justInsertedQuotesAt == position - 1)
                        {
                            justInsertedQuotesAt = -1;
                            c = (Char)sci.CharAt(position - 2);
                            if (c == '"' && (Char)sci.CharAt(position-2) == '"')
                            {
                                sci.SetSel(position - 2, position);
                                sci.ReplaceSel("\"");
                            }
                            // Allow another plugin to handle this
                            de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new XMLContextTag());
                            EventManager.DispatchEvent(PluginBase.MainForm, de);
                        }
                        else
                        {
                            c = (Char)sci.CharAt(position - 1);
                            if (c == '"' && (Char)sci.CharAt(position) == '"')
                            {
                                sci.SetSel(position - 1, position + 1);
                                sci.ReplaceSel("\"");
                            }
                        }
                    }
                    break;
					
				case '?':
				case '%':
					if (PluginSettings.CloseTags && position > 1)
					{
						ctag = GetXMLContextTag(sci, position-2);
						if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
						{
							if ((Char)sci.CharAt(position-2) == '<')
							{
								sci.ReplaceSel((Char)value + ">");
								sci.SetSel(position, position);
							}
						}
					}
					break;
				
				case '!':
                    if (PluginSettings.CloseTags && position > 1)
					{
						ctag = GetXMLContextTag(sci, position-2);
						if (ctag.Tag == null || ctag.Tag.EndsWith(">"))
						{
							if ((Char)sci.CharAt(position-2) == '<')
							{
								CompletionList.Show(xmlBlocks, true);
							}
						}						
					}
					break;
			}
		}
Beispiel #11
0
		static private XMLContextTag GetXMLContextTag(ScintillaControl sci, int position)
		{
			XMLContextTag xtag = new XMLContextTag();
			if ((position == 0) || (sci == null))
				return xtag;
			StringBuilder tag = new StringBuilder();
			char c = (char)sci.CharAt(position-1);
			position -= 2;
			tag.Append(c);
			while (position >= 0)
			{
				c = (char)sci.CharAt(position);
				tag.Insert(0, c);
				if (c == '>') return xtag;
				if (c == '<') break;
				position--;
			}
			//
			xtag.Position = position;
			xtag.Tag = tag.ToString();
			Match mTag = re_TagName.Match(xtag.Tag+" ");
			if (mTag.Success)
			{
				xtag.Name = mTag.Groups["name"].Value;
				if (xtag.Name.IndexOf(':') > 0)
				{
					xtag.NameSpace = xtag.Name.Substring(0, xtag.Name.IndexOf(':'));
				}
			}
			return xtag;
		}
Beispiel #12
0
        static public bool OnShortCut(Keys keys)
        {
            if (keys == (Keys.Control | Keys.Space))
            {
                // context
                ScintillaControl sci = mainForm.CurSciControl;
                if (sci == null)
                {
                    return(false);
                }
                XMLContextTag ctag = GetXMLContextTag(sci, sci.CurrentPos);

                // starting tag
                if (ctag.Tag == null && (sci.CurrentPos > 0))
                {
                    if ((char)sci.CharAt(sci.CurrentPos - 1) == '<')
                    {
                        ctag.Tag  = "<";
                        ctag.Name = "";
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (ctag.Tag.EndsWith(">"))
                {
                    return(false);
                }
                // closing tag
                else if (ctag.Tag.StartsWith("</") && (ctag.Tag.IndexOf(' ') < 0))
                {
                    ctag.Name = ctag.Tag.Substring(2);
                    ctag.Tag  = "<" + ctag.Name;
                }

                // element completion
                if (ctag.Name != null && (ctag.Tag.Length == ctag.Name.Length + 1))
                {
                    if (cType == XMLType.Known)
                    {
                        ArrayList items    = new ArrayList();
                        string    previous = null;
                        foreach (HTMLTag tag in knownTags)
                        {
                            if (tag.Name != previous)
                            {
                                items.Add(new HtmlTagItem(tag.Name, tag.Tag));
                                previous = tag.Name;
                            }
                        }
                        CompletionList.Show(items, false, ctag.Name);
                    }
                    else
                    {
                        // allow another plugin to handle this
                        mainForm.DispatchEvent(new DataEvent(EventType.CustomData, "XMLCompletion.Element", ctag));
                    }
                }

                // attributes completion
                else
                {
                    if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('='))
                    {
                        return(true);
                    }

                    // get word
                    int    position = sci.CurrentPos - 1;
                    string word     = GetWordLeft(sci, ref position);

                    if (cType == XMLType.Known)
                    {
                        foreach (HTMLTag tag in knownTags)
                        {
                            if (String.Compare(tag.Tag, ctag.Name, true) == 0)
                            {
                                ArrayList items    = new ArrayList();
                                string    previous = null;
                                foreach (string attr in tag.Attributes)
                                {
                                    if (attr != previous)
                                    {
                                        items.Add(new HtmlAttributeItem(attr));
                                        previous = attr;
                                    }
                                }
                                CompletionList.Show(items, true, word.Trim());
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        // allow another plugin to handle this
                        object[] o = new object[] { ctag, word };
                        mainForm.DispatchEvent(new DataEvent(EventType.CustomData, "XMLCompletion.Attribute", o));
                    }
                }
                return(true);
            }
            return(false);
        }