// btw. I hate source code duplication ... but this time I don't care !!!!
 float MeasurePrintingHeight(Graphics g, LineSegment line, float maxWidth)
 {
   float xPos = 0;
   float yPos = 0;
   float fontHeight = Font.GetHeight(g);
   _currentTabIndent = 0;
   FontContainer fontContainer = TextEditorProperties.FontContainer;
   foreach (TextWord word in line.Words)
   {
     switch (word.Type)
     {
       case TextWordType.Space:
         Advance(ref xPos, ref yPos, maxWidth, _primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight);
         break;
       case TextWordType.Tab:
         Advance(ref xPos, ref yPos, maxWidth, TabIndent * _primaryTextArea.TextArea.TextView.ColumnWidth, fontHeight);
         break;
       case TextWordType.Word:
         SizeF drawingSize = g.MeasureString(word.Word, word.GetFont(fontContainer), new SizeF(maxWidth, fontHeight * 100), _printingStringFormat);
         Advance(ref xPos, ref yPos, maxWidth, drawingSize.Width, fontHeight);
         break;
     }
   }
   return yPos + fontHeight;
 }
        void DrawLine(Graphics g, LineSegment line, float yPos, RectangleF margin)
        {
            float xPos = 0;
              float fontHeight = Font.GetHeight(g);
              _currentTabIndent = 0;

              FontContainer fontContainer = TextEditorProperties.FontContainer;
              foreach (TextWord word in line.Words)
              {
            switch (word.Type)
            {
              case TextWordType.Space:
            Advance(ref xPos, ref yPos, margin.Width, _primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight);
            break;
              case TextWordType.Tab:
            Advance(ref xPos, ref yPos, margin.Width, TabIndent * _primaryTextArea.TextArea.TextView.ColumnWidth, fontHeight);
            break;
              case TextWordType.Word:
            g.DrawString(word.Word, word.GetFont(fontContainer), BrushRegistry.GetBrush(word.Color), xPos + margin.X, yPos);
            SizeF drawingSize = g.MeasureString(word.Word, word.GetFont(fontContainer), new SizeF(margin.Width, fontHeight * 100), _printingStringFormat);
            Advance(ref xPos, ref yPos, margin.Width, drawingSize.Width, fontHeight);
            break;
            }
              }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TextWord"/> class.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <param name="line">The line.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="length">The length.</param>
        /// <param name="color">The color.</param>
        /// <param name="hasDefaultColor">if set to <c>true</c> [has default color].</param>
        public TextWord(IDocument document, LineSegment line, int offset, int length, HighlightColor color, bool hasDefaultColor)
        {
            Debug.Assert(document != null);
              Debug.Assert(line != null);
              Debug.Assert(color != null);

              _document = document;
              _line = line;
              _offset = offset;
              _length = length;
              _color = color;
              _hasDefaultColor = hasDefaultColor;
        }
    /// <summary>
    /// Replaces the text in a line.
    /// If only whitespace at the beginning and end of the line was changed, this method
    /// only adjusts the whitespace and doesn't replace the other text.
    /// </summary>
    public static void SmartReplaceLine(IDocument document, LineSegment line, string newLineText)
    {
      if (document == null)
        throw new ArgumentNullException("document");
      if (line == null)
        throw new ArgumentNullException("line");
      if (newLineText == null)
        throw new ArgumentNullException("newLineText");
      string newLineTextTrim = newLineText.Trim(_whitespaceChars);
      string oldLineText = document.GetText(line);
      if (oldLineText == newLineText)
        return;
      int pos = oldLineText.IndexOf(newLineTextTrim);
      if (newLineTextTrim.Length > 0 && pos >= 0)
      {
        document.UndoStack.StartUndoGroup();
        try
        {
          // find whitespace at beginning
          int startWhitespaceLength = 0;
          while (startWhitespaceLength < newLineText.Length)
          {
            char c = newLineText[startWhitespaceLength];
            if (c != ' ' && c != '\t')
              break;
            startWhitespaceLength++;
          }
          // find whitespace at end
          int endWhitespaceLength = newLineText.Length - newLineTextTrim.Length - startWhitespaceLength;

          // replace whitespace sections
          int lineOffset = line.Offset;
          document.Replace(lineOffset + pos + newLineTextTrim.Length, line.Length - pos - newLineTextTrim.Length, newLineText.Substring(newLineText.Length - endWhitespaceLength));
          document.Replace(lineOffset, pos, newLineText.Substring(0, startWhitespaceLength));
        }
        finally
        {
          document.UndoStack.EndUndoGroup();
        }
      }
      else
      {
        document.Replace(line.Offset, line.Length, newLineText);
      }
    }
    /// <summary>
    /// Get the object that was inserted under the keyword.
    /// </summary>
    /// <value>The object that was inserted under the keyword.</value>
    /// <remarks>
    /// <para>
    /// The keyword is taken from an <see cref="IDocument"/> at a given location
    /// (line, offset in line, length).
    /// </para>
    /// <para>
    /// Returns null, if no such keyword exists.
    /// </para>
    /// </remarks>
    public object this[IDocument document, LineSegment line, int offsetInLine, int lengthOfWord]
    {
      get
      {
        if (lengthOfWord == 0)
          return null;

        Node next = root;

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

            if (next == null)
              return null;

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

            next = next.leaf[index];

            if (next == null)
              return null;

            if (next.color != null && TextUtilities.RegionMatches(document, casesensitive, wordOffset, lengthOfWord, next.word))
              return next.color;
          }
        }
        return null;
      }
    }
        /// <summary>
        /// Get the object that was inserted under the keyword.
        /// </summary>
        /// <value>The object that was inserted under the keyword.</value>
        /// <remarks>
        /// <para>
        /// The keyword is taken from an <see cref="IDocument"/> at a given location
        /// (line, offset in line, length).
        /// </para>
        /// <para>
        /// Returns <c>null</c>, if no such keyword exists.
        /// </para>
        /// </remarks>
        public object this[IDocument document, LineSegment line, int offsetInLine, int lengthOfWord]
        {
            get
              {
            if (lengthOfWord == 0)
              return null;

            Node next = _root;

            int wordOffset = line.Offset + offsetInLine;
            if (_caseSensitive)
            {
              for (int i = 0; i < lengthOfWord; ++i)
              {
            int index = document.GetCharAt(wordOffset + i) % 256;
            next = next[index];

            if (next == null)
              return null;

            if (next.Color != null && TextHelper.CompareSegment(document, wordOffset, lengthOfWord, next.Word))
              return next.Color;
              }
            }
            else
            {
              for (int i = 0; i < lengthOfWord; ++i)
              {
            int index = Char.ToUpper(document.GetCharAt(wordOffset + i)) % 256;

            next = next[index];

            if (next == null)
              return null;

            if (next.Color != null && TextHelper.CompareSegment(document, wordOffset, lengthOfWord, next.Word, _caseSensitive))
              return next.Color;
              }
            }
            return null;
              }
        }
 public bool Next()
 {
   if (_lineDirty)
   {
     _document.Replace(_line.Offset, _line.Length, _text);
     _lineDirty = false;
     ++_changedLines;
   }
   ++_lineNumber;
   if (_lineNumber > _maxLine) 
     return false;
   _line = _document.GetLineSegment(_lineNumber);
   _text = _document.GetText(_line);
   return true;
 }
        /// <summary>
        /// Marks the tokens. Used internally, do not call.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <remarks>
        /// Used internally, do not call.
        /// </remarks>
        public virtual 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) ? previousLine.HighlightSpanStack.Clone() : null);

            if (_currentSpanStack != null)
            {
              while (!_currentSpanStack.IsEmpty && _currentSpanStack.Peek().StopEOL)
              {
            _currentSpanStack.Pop();
              }
              if (_currentSpanStack.IsEmpty) _currentSpanStack = null;
            }

            _currentLine = document.LineSegmentCollection[lineNumber];

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

            List<TextWord> words = ParseLine(document);
            // Alex: clear old words
            if (_currentLine.Words != null)
            {
              _currentLine.Words.Clear();
            }
            _currentLine.Words = words;
            _currentLine.HighlightSpanStack = (_currentSpanStack == null || _currentSpanStack.IsEmpty) ? null : _currentSpanStack;

            ++lineNumber;
              }
              document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
              document.CommitUpdate();
              _currentLine = null;
        }
        /// <summary>
        /// Marks the tokens in a line.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <param name="lineNumber">The line number.</param>
        /// <param name="spanChanged"><c>true</c> span has changed.</param>
        /// <returns><c>true</c> if the line has been parsed successfully and the next line can be parsed.</returns>
        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) ? previousLine.HighlightSpanStack.Clone() : null);
              if (_currentSpanStack != null)
              {
            while (!_currentSpanStack.IsEmpty && _currentSpanStack.Peek().StopEOL)
            {
              _currentSpanStack.Pop();
            }
            if (_currentSpanStack.IsEmpty)
            {
              _currentSpanStack = null;
            }
              }

              _currentLine = document.LineSegmentCollection[lineNumber];

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

              List<TextWord> words = ParseLine(document);

              if (_currentSpanStack != null && _currentSpanStack.IsEmpty)
              {
            _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 allocations here for perfomance 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
            {
              SpanStack.Enumerator e1 = _currentSpanStack.GetEnumerator();
              SpanStack.Enumerator e2 = _currentLine.HighlightSpanStack.GetEnumerator();
              bool done = false;
              while (!done)
              {
            bool blockSpanIn1 = false;
            while (e1.MoveNext())
            {
              if (!e1.Current.StopEOL)
              {
                blockSpanIn1 = true;
                break;
              }
            }
            bool blockSpanIn2 = false;
            while (e2.MoveNext())
            {
              if (!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;
              }

              // Alex: remove old words
              if (_currentLine.Words != null)
            _currentLine.Words.Clear();
              _currentLine.Words = words;
              _currentLine.HighlightSpanStack = (_currentSpanStack != null && !_currentSpanStack.IsEmpty) ? _currentSpanStack : null;

              return processNextLine;
        }
 void SetSegmentLength(LineSegment segment, int newTotalLength)
 {
   int delta = newTotalLength - segment.TotalLength;
   if (delta != 0)
   {
     lineCollection.SetSegmentLength(segment, newTotalLength);
     OnLineLengthChanged(new LineLengthChangeEventArgs(document, segment, delta));
   }
 }
    /// <summary>
    /// get the string, which matches the regular expression expr,
    /// in string s2 at index
    /// </summary>
    static string GetRegString(LineSegment lineSegment, char[] expr, int index, IDocument document)
    {
      int j = 0;
      StringBuilder regexpr = new StringBuilder();

      for (int i = 0; i < expr.Length; ++i, ++j)
      {
        if (index + j >= lineSegment.Length)
          break;

        switch (expr[i])
        {
          case '@': // "special" meaning
            ++i;
            switch (expr[i])
            {
              case '!': // don't match the following expression
                StringBuilder whatmatch = new StringBuilder();
                ++i;
                while (i < expr.Length && expr[i] != '@')
                {
                  whatmatch.Append(expr[i++]);
                }
                break;
              case '@': // matches @
                regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
                break;
            }
            break;
          default:
            if (expr[i] != document.GetCharAt(lineSegment.Offset + index + j))
            {
              return regexpr.ToString();
            }
            regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
            break;
        }
      }
      return regexpr.ToString();
    }
        /// <summary>
        /// returns true, if the get the string s2 at index matches the expression expr
        /// </summary>
        static bool MatchExpr(LineSegment lineSegment, char[] expr, int index, IDocument document, bool ignoreCase, bool isSingleWord)
        {
            for (int i = 0, j = 0; i < expr.Length; ++i, ++j)
              {
            switch (expr[i])
            {
              case '@': // "special" meaning
            ++i;
            if (i == expr.Length)
              throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @.");
            switch (expr[i])
            {
              case 'C': // match whitespace or punctuation
                if (index + j == lineSegment.Offset || index + j >= lineSegment.Offset + lineSegment.Length)
                {
                  // nothing (EOL or SOL)
                }
                else
                {
                  char ch = document.GetCharAt(lineSegment.Offset + index + j);
                  if (!Char.IsWhiteSpace(ch) && !Char.IsPunctuation(ch))
                  {
                    return false;
                  }
                }
                break;
              case '!': // don't match the following expression
                {
                  StringBuilder whatmatch = new StringBuilder();
                  ++i;
                  while (i < expr.Length && expr[i] != '@')
                  {
                    whatmatch.Append(expr[i++]);
                  }
                  if (lineSegment.Offset + index + j + whatmatch.Length < document.TextLength)
                  {
                    int k = 0;
                    for (; k < whatmatch.Length; ++k)
                    {
                      char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j + k)) : document.GetCharAt(lineSegment.Offset + index + j + k);
                      char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
                      if (docChar != spanChar)
                      {
                        break;
                      }
                    }
                    if (k >= whatmatch.Length)
                    {
                      return false;
                    }
                  }
                  //									--j;
                  break;
                }
              case '-': // don't match the  expression before
                {
                  StringBuilder whatmatch = new StringBuilder();
                  ++i;
                  while (i < expr.Length && expr[i] != '@')
                  {
                    whatmatch.Append(expr[i++]);
                  }
                  if (index - whatmatch.Length >= 0)
                  {
                    int k = 0;
                    for (; k < whatmatch.Length; ++k)
                    {
                      char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k)) : document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k);
                      char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
                      if (docChar != spanChar)
                        break;
                    }
                    if (k >= whatmatch.Length)
                    {
                      return false;
                    }
                  }
                  //									--j;
                  break;
                }
              case '@': // matches @
                if (index + j >= lineSegment.Length || '@' != document.GetCharAt(lineSegment.Offset + index + j))
                {
                  return false;
                }
                break;
            }
            break;
              default:
            {
              if (index + j >= lineSegment.Length)
              {
                return false;
              }
              char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j)) : document.GetCharAt(lineSegment.Offset + index + j);
              char spanChar = ignoreCase ? Char.ToUpperInvariant(expr[i]) : expr[i];
              if (docChar != spanChar)
              {
                return false;
              }
              break;
            }
            }
              }

              if (isSingleWord)
              {
            int length = expr.Length;
            if (index + length < lineSegment.Length)
            {
              char ch = document.GetCharAt(lineSegment.Offset + index + length);
              if (!Char.IsWhiteSpace(ch) && !Char.IsPunctuation(ch))
              {
            return false;
              }
            }
              }
              return true;
        }
 /// <summary>
 /// Counts the visual columns (fast version).
 /// </summary>
 /// <param name="line">The line.</param>
 /// <param name="logicalColumn">The logical column.</param>
 /// <returns>The number of visual columns.</returns>
 public int GetVisualColumnFast(LineSegment line, int logicalColumn)
 {
   int lineOffset = line.Offset;
   int tabIndent = Document.TextEditorProperties.TabIndent;
   int guessedColumn = 0;
   for (int i = 0; i < logicalColumn; ++i)
   {
     char ch = (i >= line.Length) ? ' ' : Document.GetCharAt(lineOffset + i);
     switch (ch)
     {
       case '\t':
         guessedColumn += tabIndent;
         guessedColumn = (guessedColumn / tabIndent) * tabIndent;
         break;
       default:
         ++guessedColumn;
         break;
     }
   }
   return guessedColumn;
 }
        /// <summary>
        /// Splits the <see cref="TextAnchor"/>s of a line if a newline is inserted.
        /// </summary>
        /// <param name="followingLine">The following line.</param>
        internal void SplitTo(LineSegment followingLine)
        {
            // Is called after a newline was inserted into this line, splitting it into this and followingLine.

              if (_anchors != null)
              {
            List<TextAnchor> movedAnchors = null;
            foreach (TextAnchor anchor in _anchors)
            {
              if (anchor.MovementType == AnchorMovementType.BeforeInsertion
              ? anchor.ColumnNumber > Length
              : anchor.ColumnNumber >= Length)
              {
            anchor.Line = followingLine;
            followingLine.AddAnchor(anchor);
            anchor.ColumnNumber -= Length;

            if (movedAnchors == null)
              movedAnchors = new List<TextAnchor>();
            movedAnchors.Add(anchor);
              }
            }

            if (movedAnchors != null)
              foreach (TextAnchor a in movedAnchors)
            _anchors.Remove(a);
              }
        }
    /// <summary>
    /// Initializes a new instance of the <see cref="LineLengthChangedEventArgs"/> class.
    /// </summary>
    /// <param name="document">The document.</param>
    /// <param name="lineSegment">The line segment.</param>
    /// <param name="difference">The difference (new line length - old line length).</param>
    public LineLengthChangedEventArgs(IDocument document, LineSegment lineSegment, int difference)
			: base(document, lineSegment)
		{
      _difference = difference;
		}
 internal TextAnchor(LineSegment lineSegment, int columnNumber)
 {
     _lineSegment = lineSegment;
       _columnNumber = columnNumber;
 }
    /// <summary>
    /// Initializes a new instance of the <see cref="LineLengthChangeEventArgs"/> class.
    /// </summary>
    /// <param name="document">The document.</param>
    /// <param name="lineSegment">The line segment.</param>
    /// <param name="moved">The moved.</param>
		public LineLengthChangeEventArgs(IDocument document, LineSegment lineSegment, int moved)
			: base(document, lineSegment)
		{
			this.lengthDelta = moved;
		}
 /// <summary>
 /// Gets the highlighting color for a certain position in the document.
 /// </summary>
 /// <param name="document">The document.</param>
 /// <param name="currentSegment">The current segment.</param>
 /// <param name="currentOffset">The current offset.</param>
 /// <param name="currentLength">Length of the current.</param>
 /// <returns>The highlighting color.</returns>
 public HighlightColor GetColor(IDocument document, LineSegment currentSegment, int currentOffset, int currentLength)
 {
     return GetColor(_defaultRuleSet, document, currentSegment, currentOffset, currentLength);
 }
 /// <summary>
 /// Determines whether a line is empty or filled with whitespaces.
 /// </summary>
 /// <param name="document">The document.</param>
 /// <param name="line">The line.</param>
 /// <returns>
 /// 	<c>true</c> if line is empty of filled with whitespaces; otherwise, <c>false</c>.
 /// </returns>
 /// <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;
 }
    /// <summary>
    /// Adds the removed line.
    /// </summary>
    /// <param name="line">The line.</param>
	  public void AddRemovedLine(LineSegment line)
		{
      if (_removedLines == null)
        _removedLines = new List<LineSegment>();
      _removedLines.Add(line);
		}
 /// <summary>
 /// Initializes a new instance of the <see cref="LineEventArgs"/> class.
 /// </summary>
 /// <param name="document">The document.</param>
 /// <param name="lineSegment">The line segment.</param>
 public LineEventArgs(IDocument document, LineSegment lineSegment)
 {
   _document = document;
   _lineSegment = lineSegment;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="LineEventArgs"/> class.
 /// </summary>
 /// <param name="document">The document.</param>
 /// <param name="lineSegment">The line segment.</param>
 public LineEventArgs(IDocument document, LineSegment lineSegment)
 {
   this.document = document;
   this.lineSegment = lineSegment;
 }
        /// <summary>
        /// Marks the tokens.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <param name="inputLines">The input lines.</param>
        public virtual void MarkTokens(IDocument document, List<LineSegment> inputLines)
        {
            if (Rules.Count == 0)
            return;

              Dictionary<LineSegment, bool> processedLines = new Dictionary<LineSegment, bool>();

              bool spanChanged = false;
              int documentLineSegmentCount = document.LineSegmentCollection.Count;

              foreach (LineSegment lineToProcess in inputLines)
              {
            if (!processedLines.ContainsKey(lineToProcess))
            {
              int lineNumber = lineToProcess.LineNumber;
              bool processNextLine = true;

              if (lineNumber != -1)
              {
            while (processNextLine && lineNumber < documentLineSegmentCount)
            {
              processNextLine = MarkTokensInLine(document, lineNumber, ref spanChanged);
              processedLines[_currentLine] = true;
              ++lineNumber;
            }
              }
            }
              }

              if (spanChanged || inputLines.Count > 20)
              {
            // if the span was changed (more than inputLines lines had to be reevaluated)
            // or if there are many lines in inputLines, it's faster to update the whole
            // text area instead of many small segments
            document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
              }
              else
              {
            //				document.Caret.ValidateCaretPos();
            //				document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, document.GetLineNumberForOffset(document.Caret.Offset)));
            foreach (LineSegment lineToProcess in inputLines)
            {
              document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineToProcess.LineNumber));
            }

              }
              document.CommitUpdate();
              _currentLine = null;
        }
 internal void Delete(ref DeferredEventList deferredEventList)
 {
     // we cannot fire an event here because this method is called while the LineManager adjusts the
       // lineCollection, so an event handler could see inconsistent state
       _lineSegment = null;
       deferredEventList.AddDeletedAnchor(this);
 }
 /// <summary>
 /// Gets the highlighting color for a certain position in the document.
 /// </summary>
 /// <param name="ruleSet">The rule set.</param>
 /// <param name="document">The document.</param>
 /// <param name="currentSegment">The current segment.</param>
 /// <param name="currentOffset">The current offset.</param>
 /// <param name="currentLength">Length of the current.</param>
 /// <returns></returns>
 protected virtual 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;
 }
    int GetLogicalColumnInternal(Graphics g, LineSegment line, int start, int end, ref int drawingPos, int targetVisualPosX)
    {
      if (start == end)
        return end;
      Debug.Assert(start < end);
      Debug.Assert(drawingPos < targetVisualPosX);

      int tabIndent = Document.TextEditorProperties.TabIndent;

      FontContainer fontContainer = TextEditorProperties.FontContainer;

      List<TextWord> words = line.Words;
      if (words == null) return 0;
      int wordOffset = 0;
      for (int i = 0; i < words.Count; i++)
      {
        TextWord word = words[i];
        if (wordOffset >= end)
        {
          return wordOffset;
        }
        if (wordOffset + word.Length >= start)
        {
          int newDrawingPos;
          switch (word.Type)
          {
            case TextWordType.Space:
              newDrawingPos = drawingPos + _spaceWidth;
              if (newDrawingPos >= targetVisualPosX)
                return IsNearerToAThanB(targetVisualPosX, drawingPos, newDrawingPos) ? wordOffset : wordOffset + 1;
              break;
            case TextWordType.Tab:
              // go to next tab position
              drawingPos = (drawingPos + MinTabWidth) / tabIndent / ColumnWidth * tabIndent * ColumnWidth;
              newDrawingPos = drawingPos + tabIndent * ColumnWidth;
              if (newDrawingPos >= targetVisualPosX)
                return IsNearerToAThanB(targetVisualPosX, drawingPos, newDrawingPos) ? wordOffset : wordOffset + 1;
              break;
            case TextWordType.Word:
              int wordStart = Math.Max(wordOffset, start);
              int wordLength = Math.Min(wordOffset + word.Length, end) - wordStart;
              string text = Document.GetText(line.Offset + wordStart, wordLength);
              Font font = word.GetFont(fontContainer) ?? fontContainer.RegularFont;
              newDrawingPos = drawingPos + MeasureStringWidth(g, text, font);
              if (newDrawingPos >= targetVisualPosX)
              {
                for (int j = 0; j < text.Length; j++)
                {
                  newDrawingPos = drawingPos + MeasureStringWidth(g, text[j].ToString(), font);
                  if (newDrawingPos >= targetVisualPosX)
                  {
                    if (IsNearerToAThanB(targetVisualPosX, drawingPos, newDrawingPos))
                      return wordStart + j;
                    else
                      return wordStart + j + 1;
                  }
                  drawingPos = newDrawingPos;
                }
                return wordStart + text.Length;
              }
              break;
            default:
              throw new NotSupportedException();
          }
          drawingPos = newDrawingPos;
        }
        wordOffset += word.Length;
      }
      return wordOffset;
    }
 /// <summary>
 /// Called when a line has been parsed.
 /// </summary>
 /// <param name="document">The document.</param>
 /// <param name="currentLine">The current line.</param>
 /// <param name="words">The words.</param>
 protected virtual void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words)
 {
 }
        /// <summary>
        /// Merges the <see cref="TextAnchor"/>s of two lines, if a newline is deleted.
        /// </summary>
        /// <param name="deletedLine">The deleted line.</param>
        /// <param name="firstLineLength">The length of the first line.</param>
        internal void MergedWith(LineSegment deletedLine, int firstLineLength)
        {
            // Is called after another line's content is appended to this line because the newline in between
              // was deleted.
              // The DefaultLineManager will call Deleted() on the deletedLine after the MergedWith call.
              // firstLineLength: the length of the line before the merge.

              if (deletedLine._anchors != null)
              {
            foreach (TextAnchor anchor in deletedLine._anchors)
            {
              anchor.Line = this;
              AddAnchor(anchor);
              anchor.ColumnNumber += firstLineLength;
            }
            deletedLine._anchors = null;
              }
        }
        /// <summary>
        /// get the string, which matches the regular expression expr,
        /// in string s2 at index
        /// </summary>
        static string GetRegString(LineSegment lineSegment, char[] expr, int index, IDocument document)
        {
            int j = 0;
              StringBuilder regexpr = new StringBuilder();

              for (int i = 0; i < expr.Length; ++i, ++j)
              {
            if (index + j >= lineSegment.Length)
              break;

            switch (expr[i])
            {
              case '@': // "special" meaning
            ++i;
            if (i == expr.Length)
              throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @.");
            switch (expr[i])
            {
              case '!': // don't match the following expression
                StringBuilder whatmatch = new StringBuilder();
                ++i;
                while (i < expr.Length && expr[i] != '@')
                {
                  whatmatch.Append(expr[i++]);
                }
                break;
              case '@': // matches @
                regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
                break;
            }
            break;
              default:
            if (expr[i] != document.GetCharAt(lineSegment.Offset + index + j))
            {
              return regexpr.ToString();
            }
            regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
            break;
            }
              }
              return regexpr.ToString();
        }
 /// <summary>
 /// returns true, if the get the string s2 at index matches the expression expr
 /// </summary>
 static bool MatchExpr(LineSegment lineSegment, char[] expr, int index, IDocument document, bool ignoreCase)
 {
     return MatchExpr(lineSegment, expr, index, document, ignoreCase, false);
 }
 internal TextAnchor(LineSegment lineSegment, int columnNumber)
 {
     _lineSegment  = lineSegment;
     _columnNumber = columnNumber;
 }