public TextWord(IDocument document, LineSegment word, int offset, int length, HighlightColor color, bool hasDefaultColor)
        {
            Debug.Assert(document != null);
            Debug.Assert(word != null);
            Debug.Assert(color != null);

            this.document = document;
            this.word  = word;
            this.offset = offset;
            this.length = length;
            this.color = color;
            this.hasDefaultColor = hasDefaultColor;
            this.type  = TextWordType.Word;
        }
        /// <summary>
        /// Get the object, which was inserted under the keyword (line, at offset, with length length),
        /// returns null, if no such keyword was inserted.
        /// </summary>
        public object this[IDocument document, LineSegment line, int offset, int length]
        {
            get {
                if(length == 0) {
                    return null;
                }
                Node next = root;

                int wordOffset = line.Offset + offset;
                if (casesensitive) {
                    for (int i = 0; i < length; ++i) {
                        int index = ((int)document.GetCharAt(wordOffset + i)) % 256;
                        next = next.leaf[index];

                        if (next == null) {
                            return null;
                        }

                        if (next.color != null && TextUtility.RegionMatches(document, wordOffset, length, next.word)) {
                            return next.color;
                        }
                    }
                } else {
                    for (int i = 0; i < length; ++i) {
                        int index = ((int)Char.ToUpper(document.GetCharAt(wordOffset + i))) % 256;

                        next = next.leaf[index];

                        if (next == null) {
                            return null;
                        }

                        if (next.color != null && TextUtility.RegionMatches(document, casesensitive, wordOffset, length, next.word)) {
                            return next.color;
                        }
                    }
                }
                return null;
            }
        }
 /// <remarks>
 /// Returns true, if the line lineNumber is empty or filled with whitespaces.
 /// </remarks>
 public static bool IsEmptyLine(IDocument document, LineSegment line)
 {
     for (int i = line.Offset; i < line.Offset + line.Length; ++i) {
         char ch = document.GetCharAt(i);
         if (!Char.IsWhiteSpace(ch)) {
             return false;
         }
     }
     return true;
 }
        // OLD 'SAFE & TESTED' CreateLines
        //        int CreateLines(string text, int insertPosition, int offset)
        //        {
        //            int count = 0;
        //            int start = 0;
        //            ISegment nextDelimiter = NextDelimiter(text, 0);
        //            while (nextDelimiter != null && nextDelimiter.Offset >= 0) {
        //                int index = nextDelimiter.Offset + (nextDelimiter.Length - 1);
        //                
        //                LineSegment newLine = new LineSegment(offset + start, offset + index, nextDelimiter.Length);
        //                
        //                markLines.Add(newLine);
        //                
        //                if (insertPosition + count >= lineCollection.Count) {
        //                    lineCollection.Add(newLine);
        //                } else {
        //                    lineCollection.Insert(insertPosition + count, newLine);
        //                }
        //                
        //                ++count;
        //                start = index + 1;
        //                nextDelimiter = NextDelimiter(text, start);
        //            }
        //            
        //            if (start < text.Length) {
        //                if (insertPosition + count < lineCollection.Count) {
        //                    LineSegment l = (LineSegment)lineCollection[insertPosition + count];
        //                    
        //                    int delta = text.Length - start;
        //                    
        //                    l.Offset -= delta;
        //                    l.TotalLength += delta;
        //                } else {
        //                    LineSegment newLine = new LineSegment(offset + start, text.Length - start);
        //                    
        //                    markLines.Add(newLine);
        //                    lineCollection.Add(newLine);
        //                    ++count;
        //                }
        //            }
        //            OnLineCountChanged(new LineManagerEventArgs(document, insertPosition, count));
        //            return count;
        //        }
        int CreateLines(string text, int insertPosition, int offset)
        {
            int start = 0;
            ISegment nextDelimiter = NextDelimiter(text, 0);

            ArrayList newLines = new ArrayList();
            while (nextDelimiter != null && nextDelimiter.Offset >= 0) {
                int index = nextDelimiter.Offset + (nextDelimiter.Length - 1);

                LineSegment newLine = new LineSegment(offset + start, offset + index, nextDelimiter.Length);
                newLines.Add(newLine);

                start = index + 1;
                nextDelimiter = NextDelimiter(text, start);
            }

            if (start < text.Length) {
                if (insertPosition + newLines.Count < lineCollection.Count) {
                    LineSegment l = (LineSegment)lineCollection[insertPosition];

                    int delta = text.Length - start;
                    l.Offset      -= delta;
                    l.TotalLength += delta;
                } else {
                    LineSegment newLine = new LineSegment(offset + start, text.Length - start);
                    newLines.Add(newLine);
                }
            }

            if (insertPosition >= lineCollection.Count) {
                lineCollection.AddRange(newLines);
            } else {
                lineCollection.InsertRange(insertPosition, newLines);
            }
            markLines.AddRange(newLines);

            OnLineCountChanged(new LineManagerEventArgs(document, insertPosition, newLines.Count));
            return newLines.Count;
        }
        int Insert(int lineNumber, int offset, string text)
        {
            if (text == null || text.Length == 0) {
                return 0;
            }

            textLength += text.Length;

            if (lineCollection.Count == 0 || lineNumber >= lineCollection.Count) {
                return CreateLines(text, lineCollection.Count, offset);
            }

            LineSegment line = (LineSegment)lineCollection[lineNumber];

            ISegment nextDelimiter = NextDelimiter(text, 0);
            if (nextDelimiter == null || nextDelimiter.Offset < 0) {
                line.TotalLength += text.Length;
                markLines.Add(line);
                return 0;
            }

            int restLength = line.Offset + line.TotalLength - offset;

            if (restLength > 0) {
                LineSegment lineRest = new LineSegment(offset, restLength);
                lineRest.DelimiterLength = line.DelimiterLength;

                lineRest.Offset += text.Length;
                markLines.Add(lineRest);

                if (restLength - line.DelimiterLength < 0) {
                    throw new ApplicationException("tried to insert inside delimiter string " + lineRest.ToString() + "!!!");
                }

                lineCollection.Insert(lineNumber + 1, lineRest);
                OnLineCountChanged(new LineManagerEventArgs(document, lineNumber - 1, 1));
            }

            line.DelimiterLength = nextDelimiter.Length;
            int nextStart = offset + nextDelimiter.Offset + nextDelimiter.Length;
            line.TotalLength = nextStart - line.Offset;

            markLines.Add(line);
            text = text.Substring(nextDelimiter.Offset + nextDelimiter.Length);

            return CreateLines(text, lineNumber + 1, nextStart) + 1;
        }
 HighlightColor GetColor(HighlightRuleSet ruleSet, IDocument document, LineSegment currentSegment, int currentOffset, int currentLength)
 {
     if (ruleSet != null) {
         if (ruleSet.Reference != null) {
             return ruleSet.Highlighter.GetColor(document, currentSegment, currentOffset, currentLength);
         } else {
             return (HighlightColor)ruleSet.KeyWords[document,  currentSegment, currentOffset, currentLength];
         }
     }
     return null;
 }
        bool MarkTokensInLine(IDocument document, int lineNumber, ref bool spanChanged)
        {
            bool processNextLine = false;
            LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null);

            currentSpanStack = ((previousLine != null && previousLine.HighlightSpanStack != null) ? ((Stack)(previousLine.HighlightSpanStack.Clone())) : null);
            if(currentSpanStack != null) {
                while (currentSpanStack.Count > 0 && ((Span)currentSpanStack.Peek()).StopEOL) {
                    currentSpanStack.Pop();
                }
                if (currentSpanStack.Count == 0) {
                    currentSpanStack = null;
                }
            }

            currentLine = (LineSegment)document.LineSegmentCollection[lineNumber];

            if (currentLine.Length == -1) { // happens when buffer is empty !
                return false;
            }

            ArrayList words = ParseLine(document);

            if (currentSpanStack != null && currentSpanStack.Count == 0) {
                currentSpanStack = null;
            }

            // Check if the span state has changed, if so we must re-render the next line
            // This check may seem utterly complicated but I didn't want to introduce any function calls
            // or alllocations here for perf reasons.
            if(currentLine.HighlightSpanStack != currentSpanStack) {
                if (currentLine.HighlightSpanStack == null) {
                    processNextLine = false;
                    foreach (Span sp in currentSpanStack) {
                        if (!sp.StopEOL) {
                            spanChanged = true;
                            processNextLine = true;
                            break;
                        }
                    }
                } else if (currentSpanStack == null) {
                    processNextLine = false;
                    foreach (Span sp in currentLine.HighlightSpanStack) {
                        if (!sp.StopEOL) {
                            spanChanged = true;
                            processNextLine = true;
                            break;
                        }
                    }
                } else {
                    IEnumerator e1 = currentSpanStack.GetEnumerator();
                    IEnumerator e2 = currentLine.HighlightSpanStack.GetEnumerator();
                    bool done = false;
                    while (!done) {
                        bool blockSpanIn1 = false;
                        while (e1.MoveNext()) {
                            if (!((Span)e1.Current).StopEOL) {
                                blockSpanIn1 = true;
                                break;
                            }
                        }
                        bool blockSpanIn2 = false;
                        while (e2.MoveNext()) {
                            if (!((Span)e2.Current).StopEOL) {
                                blockSpanIn2 = true;
                                break;
                            }
                        }
                        if (blockSpanIn1 || blockSpanIn2) {
                            if (blockSpanIn1 && blockSpanIn2) {
                                if (e1.Current != e2.Current) {
                                    done = true;
                                    processNextLine = true;
                                    spanChanged = true;
                                }
                            } else {
                                spanChanged = true;
                                done = true;
                                processNextLine = true;
                            }
                        } else {
                            done = true;
                            processNextLine = false;
                        }
                    }
                }
            } else {
                processNextLine = false;
            }

            currentLine.Words = words;
            currentLine.HighlightSpanStack = (currentSpanStack != null && currentSpanStack.Count > 0) ? currentSpanStack : null;

            return processNextLine;
        }
        public void MarkTokens(IDocument document)
        {
            if (Rules.Count == 0) {
                return;
            }

            int lineNumber = 0;

            while (lineNumber < document.TotalNumberOfLines) {
                LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null);
                if (lineNumber >= document.LineSegmentCollection.Count) { // may be, if the last line ends with a delimiter
                    break;                                                // then the last line is not in the collection :)
                }

                currentSpanStack = ((previousLine != null && previousLine.HighlightSpanStack != null) ? ((Stack)(previousLine.HighlightSpanStack.Clone())) : null);

                if (currentSpanStack != null) {
                    while (currentSpanStack.Count > 0 && ((Span)currentSpanStack.Peek()).StopEOL)
                    {
                        currentSpanStack.Pop();
                    }
                    if (currentSpanStack.Count == 0) currentSpanStack = null;
                }

                currentLine = (LineSegment)document.LineSegmentCollection[lineNumber];

                if (currentLine.Length == -1) { // happens when buffer is empty !
                    return;
                }

                ArrayList words = ParseLine(document);
                currentLine.Words = words;
                currentLine.HighlightSpanStack = (currentSpanStack==null || currentSpanStack.Count==0) ? null : currentSpanStack;

                ++lineNumber;
            }
            document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
            document.CommitUpdate();
        }
 public HighlightColor GetColor(IDocument document, LineSegment currentSegment, int currentOffset, int currentLength)
 {
     return GetColor(defaultRuleSet, document, currentSegment, currentOffset, currentLength);
 }
        int GetLogicalColumn(LineSegment line, int xPos)
        {
            int currentColumn = 0;
            int realColumn = 0;
            float spaceWidth = GetWidth(' ');
            float physicalXPos = 0;
            int tabIndent  = Document.TextEditorProperties.TabIndent;
            LineSegment currentLine = line;

            if (currentLine == null || currentLine.Words == null) {
                return 0;
            }
             			for (int i = 0; i < currentLine.Words.Count && xPos + spaceWidth/2 > physicalXPos; ++i) {
                TextWord currentWord = ((TextWord)currentLine.Words[i]);
                switch (currentWord.Type) {
                    case TextWordType.Space:
                        physicalXPos += spaceWidth;
                        currentColumn++;
                        realColumn++;
                        break;

                    case TextWordType.Tab:
                        int ind = realColumn % tabIndent;
                        int hop = tabIndent - ind;
                        physicalXPos += hop * spaceWidth;
                        currentColumn++;
                        realColumn += hop;
                        break;

                    case TextWordType.Word:
                        string word    = currentWord.Word;

                        if (physicalXPos + MeasureString(FontContainer.DefaultFont, word) > xPos + spaceWidth/2) {
                            do {
                                word = word.Substring(0, word.Length - 1);
                            } while (physicalXPos + MeasureString(FontContainer.DefaultFont, word) > xPos + spaceWidth/2);
                            return currentColumn + word.Length;
                        }
                        physicalXPos += MeasureString(FontContainer.DefaultFont, word);
                        currentColumn += word.Length;
                        realColumn += word.Length;
                        break;
                }
            }
            return currentColumn; // FIXME!!!
            //			return (int)(physicalXPos - textArea.VirtualTop.X * spaceWidth);
        }
        public int GetVisualColumn(LineSegment line, int logicalColumn)
        {
            int tabIndent = Document.TextEditorProperties.TabIndent;
            int column    = 0;
            for (int i = 0; i < logicalColumn; ++i) {
                char ch;
                if (i >= line.Length) {
                    ch = ' ';
                } else {
                    ch = Document.GetCharAt(line.Offset + i);
                }

                switch (ch) {
                    case '\t':
                        int oldColumn = column;
                        column += tabIndent;
                        column = (column / tabIndent) * tabIndent;
                        break;
                    default:
                        ++column;
                        break;
                }
            }
            return column;
        }
        public int GetDrawingXPos(LineSegment line, int logicalColumn)
        {
            int currentColumn = 0;
            int realColumn = 0;
            float physicalXPos = 0;
            float spaceWidth = GetWidth(' ');
            int tabIndent  = Document.TextEditorProperties.TabIndent;
            LineSegment currentLine = line;
            if (currentLine.Words == null) {
                return (int)(physicalXPos - textArea.VirtualTop.X * spaceWidth);
            }
            for (int i = 0; i < currentLine.Words.Count && currentColumn < logicalColumn; ++i) {
                TextWord currentWord = ((TextWord)currentLine.Words[i]);
                switch (currentWord.Type) {
                    case TextWordType.Space:
                        physicalXPos += spaceWidth;
                        currentColumn++;
                        realColumn++;
                        break;

                    case TextWordType.Tab:
                        int ind = realColumn % tabIndent;
                        int hop = tabIndent - ind;
                        physicalXPos += hop * spaceWidth;
                        currentColumn++;
                        realColumn += hop;
                        break;

                    case TextWordType.Word:
                        string word    = currentWord.Word;
                        if (currentColumn + word.Length > logicalColumn) {
                            word = word.Substring(0, logicalColumn - currentColumn);
                        }
                        float  lastPos = physicalXPos;

                        physicalXPos += MeasureString(FontContainer.DefaultFont, word);
                        currentColumn += word.Length;
                        realColumn += word.Length;
                        break;
                }
            }
            return (int)(physicalXPos /*- textArea.VirtualTop.X * spaceWidth*/);
        }