2007-10-01 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextControl.cs
index e664258beaa71bcfba80b4e5131b7710c2e85c79..62e5ef4bc8c113c4d70624e73bec2acb78e1b762 100644 (file)
@@ -64,15 +64,6 @@ namespace System.Windows.Forms {
                Line            // Selection=Line under caret
        }
 
-       internal class FontDefinition {
-               internal String         face;
-               internal int            size;
-               internal FontStyle      add_style;
-               internal FontStyle      remove_style;
-               internal Color          color;
-               internal Font           font_obj;
-       }
-
        [Flags]
        internal enum FormatSpecified {
                None,
@@ -103,6 +94,16 @@ namespace System.Windows.Forms {
                CharBackNoWrap      // Move a char backward, but don't wrap onto the previous line
        }
 
+       internal enum LineEnding {
+               Wrap,    // line wraps to the next line
+               Limp,    // \r
+               Hard,    // \r\n
+               Soft,    // \r\r\n
+               Rich,    // \n
+
+               None
+       }
+       
        // Being cloneable should allow for nice line and document copies...
        internal class Line : ICloneable, IComparable {
                #region Local Variables
@@ -120,11 +121,10 @@ namespace System.Windows.Forms {
                internal int                    ascent;                 // Ascent of the line (ascent of the tallest tag)
                internal HorizontalAlignment    alignment;              // Alignment of the line
                internal int                    align_shift;            // Pixel shift caused by the alignment
-               internal bool                   soft_break;             // Tag is 'broken soft' and continuation from previous line
                internal int                    indent;                 // Left indent for the first line
                internal int                    hanging_indent;         // Hanging indent (left indent for all but the first line)
                internal int                    right_indent;           // Right indent for all lines
-               internal bool carriage_return;
+               internal LineEnding ending;
 
 
                // Stuff that's important for the tree
@@ -134,12 +134,10 @@ namespace System.Windows.Forms {
                internal LineColor              color;                  // We're doing a black/red tree. this is the node color
                internal int                    DEFAULT_TEXT_LEN;       // 
                internal bool                   recalc;                 // Line changed
-               internal int left_margin = 2;  // A left margin for all lines
-               internal int top_margin = 2;
                #endregion      // Local Variables
 
                #region Constructors
-               internal Line (Document document)
+               internal Line (Document document, LineEnding ending)
                {
                        this.document = document; 
                        color = LineColor.Red;
@@ -148,39 +146,50 @@ namespace System.Windows.Forms {
                        parent = null;
                        text = null;
                        recalc = true;
-                       soft_break = false;
-                       alignment = HorizontalAlignment.Left;
+                       alignment = document.alignment;
+
+                       this.ending = ending;
                }
 
-               internal Line(Document document, int LineNo, string Text, Font font, SolidBrush color) : this (document) {
+               internal Line(Document document, int LineNo, string Text, Font font, SolidBrush color, LineEnding ending) : this (document, ending)
+               {
                        space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
 
                        text = new StringBuilder(Text, space);
                        line_no = LineNo;
+                       this.ending = ending;
 
                        widths = new float[space + 1];
+
+                       
                        tags = new LineTag(this, 1);
                        tags.font = font;
-                       tags.color = color;
+                       tags.color = color;                             
                }
 
-               internal Line(Document document, int LineNo, string Text, HorizontalAlignment align, Font font, SolidBrush color) : this(document) {
+               internal Line(Document document, int LineNo, string Text, HorizontalAlignment align, Font font, SolidBrush color, LineEnding ending) : this(document, ending)
+               {
                        space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
 
                        text = new StringBuilder(Text, space);
                        line_no = LineNo;
+                       this.ending = ending;
                        alignment = align;
 
                        widths = new float[space + 1];
+
+                       
                        tags = new LineTag(this, 1);
                        tags.font = font;
                        tags.color = color;
                }
 
-               internal Line(Document document, int LineNo, string Text, LineTag tag) : this(document) {
+               internal Line(Document document, int LineNo, string Text, LineTag tag, LineEnding ending) : this(document, ending)
+               {
                        space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
 
                        text = new StringBuilder(Text, space);
+                       this.ending = ending;
                        line_no = LineNo;
 
                        widths = new float[space + 1];
@@ -193,10 +202,9 @@ namespace System.Windows.Forms {
 
                internal int Y {
                        get {
-                               int tm = document.owner.actual_border_style == BorderStyle.FixedSingle ? top_margin : 0;
                                if (!document.multiline)
-                                       return tm;
-                               return tm + offset;
+                                       return document.top_margin;
+                               return document.top_margin + offset;
                        }
                }
 
@@ -204,7 +212,7 @@ namespace System.Windows.Forms {
                        get {
                                if (document.multiline)
                                        return align_shift;
-                               return offset;
+                               return offset + align_shift;
                        }
                }
 
@@ -308,6 +316,45 @@ namespace System.Windows.Forms {
                #endregion      // Internal Properties
 
                #region Internal Methods
+
+               // This doesn't do exactly what you would think, it just pulls of the \n part of the ending
+               internal string TextWithoutEnding ()
+               {
+                       return text.ToString (0, text.Length - document.LineEndingLength (ending));
+               }
+
+               internal int TextLengthWithoutEnding ()
+               {
+                       return text.Length - document.LineEndingLength (ending);
+               }
+
+               internal void DrawEnding (Graphics dc, float y)
+               {
+                       if (document.multiline)
+                               return;
+                       LineTag last = tags;
+                       while (last.next != null)
+                               last = last.next;
+
+                       string end_str = null;
+                       switch (document.LineEndingLength (ending)) {
+                       case 0:
+                               return;
+                       case 1:
+                               end_str = "\u0013";
+                               break;
+                       case 2:
+                               end_str = "\u0013\u0013";
+                               break;
+                       case 3:
+                               end_str = "\u0013\u0013\u0013";
+                               break;
+                       }
+                       dc.DrawString (end_str, last.font, last.color,  X + widths [TextLengthWithoutEnding ()] - document.viewport_x,
+                                       y, Document.string_format);
+               }
+
+               
                // Make sure we always have enoughs space in text and widths
                internal void Grow(int minimum) {
                        int     length;
@@ -420,7 +467,7 @@ namespace System.Windows.Forms {
                        tag.shift = 0;
 
                        this.recalc = false;
-                       widths[0] = left_margin + indent;
+                       widths[0] = document.left_margin + indent;
 
                        w = g.MeasureString(doc.password_char, tags.font, 10000, Document.string_format).Width;
 
@@ -454,7 +501,7 @@ namespace System.Windows.Forms {
                        int     len;
                        SizeF   size;
                        float   w;
-                       int     prev_height;
+                       int     prev_offset;
                        bool    retval;
                        bool    wrapped;
                        Line    line;
@@ -463,15 +510,15 @@ namespace System.Windows.Forms {
                        pos = 0;
                        len = this.text.Length;
                        tag = this.tags;
-                       prev_height = this.height;      // For drawing optimization calculations
+                       prev_offset = this.offset;      // For drawing optimization calculations
                        this.height = 0;                // Reset line height
                        this.ascent = 0;                // Reset the ascent for the line
                        tag.shift = 0;
 
-                       if (this.soft_break) {
-                               widths[0] = left_margin + hanging_indent;
+                       if (ending == LineEnding.Wrap) {
+                               widths[0] = document.left_margin + hanging_indent;
                        } else {
-                               widths[0] = left_margin + indent;
+                               widths[0] = document.left_margin + indent;
                        }
 
                        this.recalc = false;
@@ -502,8 +549,8 @@ namespace System.Windows.Forms {
 
                                                pos = wrap_pos;
                                                len = text.Length;
-                                               doc.Split(this, tag, pos, this.soft_break);
-                                               this.soft_break = true;
+                                               doc.Split(this, tag, pos);
+                                               ending = LineEnding.Wrap;
                                                len = this.text.Length;
                                                
                                                retval = true;
@@ -514,15 +561,15 @@ namespace System.Windows.Forms {
                                                // Make sure to set the last width of the line before wrapping
                                                widths [pos + 1] = widths [pos] + w;
 
-                                               doc.Split(this, tag, pos, this.soft_break);
-                                               this.soft_break = true;
+                                               doc.Split(this, tag, pos);
+                                               ending = LineEnding.Wrap;
                                                len = this.text.Length;
                                                retval = true;
                                                wrapped = true;
                                        }
                                }
 
-                               // Contract all soft lines that follow back into our line
+                               // Contract all wrapped lines that follow back into our line
                                if (!wrapped) {
                                        pos++;
 
@@ -530,7 +577,7 @@ namespace System.Windows.Forms {
 
                                        if (pos == len) {
                                                line = doc.GetLine(this.line_no + 1);
-                                               if ((line != null) && soft_break) {
+                                               if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None)) {
                                                        // Pull the two lines together
                                                        doc.Combine(this.line_no, this.line_no + 1);
                                                        len = this.text.Length;
@@ -583,7 +630,7 @@ namespace System.Windows.Forms {
                                tag.height = this.height;
                        }
 
-                       if (prev_height != this.height) {
+                       if (prev_offset != offset) {
                                retval = true;
                        }
                        return retval;
@@ -612,7 +659,7 @@ namespace System.Windows.Forms {
                public object Clone() {
                        Line    clone;
 
-                       clone = new Line (document);
+                       clone = new Line (document, ending);
 
                        clone.text = text;
 
@@ -630,7 +677,7 @@ namespace System.Windows.Forms {
                internal object CloneLine() {
                        Line    clone;
 
-                       clone = new Line (document);
+                       clone = new Line (document, ending);
 
                        clone.text = text;
 
@@ -771,6 +818,7 @@ namespace System.Windows.Forms {
                private int update_start = 1;
 
                internal bool           multiline;
+               internal HorizontalAlignment alignment;
                internal bool           wrap;
 
                internal UndoManager    undo;
@@ -798,10 +846,15 @@ namespace System.Windows.Forms {
                internal TextBoxBase    owner;                  // Who's owning us?
                static internal int     caret_width = 1;
                static internal int     caret_shift = 1;
+
+               internal int left_margin = 2;  // A left margin for all lines
+               internal int top_margin = 2;
+               internal int right_margin = 2;
                #endregion      // Local Variables
 
                #region Constructors
-               internal Document(TextBoxBase owner) {
+               internal Document (TextBoxBase owner)
+               {
                        lines = 0;
 
                        this.owner = owner;
@@ -812,7 +865,7 @@ namespace System.Windows.Forms {
                        recalc_pending = false;
 
                        // Tree related stuff
-                       sentinel = new Line (this);
+                       sentinel = new Line (this, LineEnding.None);
                        sentinel.color = LineColor.Black;
 
                        document = sentinel;
@@ -821,9 +874,7 @@ namespace System.Windows.Forms {
                        owner.HandleCreated += new EventHandler(owner_HandleCreated);
                        owner.VisibleChanged += new EventHandler(owner_VisibleChanged);
 
-                       Add(1, "", owner.Font, ThemeEngine.Current.ResPool.GetSolidBrush(owner.ForeColor));
-                       Line l = GetLine (1);
-                       l.soft_break = true;
+                       Add (1, String.Empty, owner.Font, ThemeEngine.Current.ResPool.GetSolidBrush (owner.ForeColor), LineEnding.None);
 
                        undo = new UndoManager (this);
 
@@ -851,7 +902,9 @@ namespace System.Windows.Forms {
                        document_id = random.Next();
 
                        string_format.Trimming = StringTrimming.None;
-                       string_format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
+                       string_format.FormatFlags = StringFormatFlags.DisplayFormatControl;
+
+                       UpdateMargins ();
                }
                #endregion
 
@@ -1027,6 +1080,27 @@ namespace System.Windows.Forms {
 
                #region Private Methods
 
+               internal void UpdateMargins ()
+               {
+                       switch (owner.actual_border_style) {
+                               case BorderStyle.None:
+                                       left_margin = 0;
+                                       top_margin = 0;
+                                       right_margin = 1;
+                                       break;
+                               case BorderStyle.FixedSingle:
+                                       left_margin = 2;
+                                       top_margin = 2;
+                                       right_margin = 3;
+                                       break;
+                               case BorderStyle.Fixed3D:
+                                       left_margin = 1;
+                                       top_margin = 1;
+                                       right_margin = 2;
+                                       break;
+                       }
+               }
+
                internal void SuspendRecalc ()
                {
                        recalc_suspended++;
@@ -1065,8 +1139,8 @@ namespace System.Windows.Forms {
 
                        total = 1;
 
-                       Console.Write("Line {0} [# {1}], Y: {2}, soft: {3},  Text: '{4}'",
-                                       line.line_no, line.GetHashCode(), line.Y, line.soft_break,
+                       Console.Write("Line {0} [# {1}], Y: {2}, ending style: {3},  Text: '{4}'",
+                                       line.line_no, line.GetHashCode(), line.Y, line.ending,
                                        line.text != null ? line.text.ToString() : "undefined");
 
                        if (line.left == sentinel) {
@@ -1395,33 +1469,40 @@ namespace System.Windows.Forms {
 
                        if (recalc_suspended > 0) {
                                recalc_start = Math.Min (recalc_start, line.line_no);
-                               recalc_end = Math.Max (recalc_end, line.line_no + line_count - 1);
+                               recalc_end = Math.Max (recalc_end, line.line_no + line_count);
                                recalc_optimize = true;
                                recalc_pending = true;
                                return;
                        }
 
-                       if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no + line_count - 1, true)) {
+                       int start_line_top = line.Y;                    
+
+                       int end_line_bottom;
+                       Line end_line;
+
+                       end_line = GetLine (line.line_no + line_count);
+                       if (end_line == null)
+                               end_line = GetLine (lines);
+
+
+                       end_line_bottom = end_line.Y + end_line.height;
+                       
+                       if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no + line_count, true)) {
                                // Lineheight changed, invalidate the rest of the document
                                if ((line.Y - viewport_y) >=0 ) {
                                        // We formatted something that's in view, only draw parts of the screen
-//blah Console.WriteLine("TextControl.cs(981) Invalidate called in UpdateView(line, line_count, pos)");
                                        owner.Invalidate(new Rectangle(0, line.Y - viewport_y, viewport_width, owner.Height - line.Y - viewport_y));
                                } else {
                                        // The tag was above the visible area, draw everything
-//blah Console.WriteLine("TextControl.cs(985) Invalidate called in UpdateView(line, line_count, pos)");
                                        owner.Invalidate();
                                }
                        } else {
-                               Line    end_line;
-
-                               end_line = GetLine(line.line_no + line_count -1);
-                               if (end_line == null) {
-                                       end_line = line;
-                               }
+                               int x = 0 - viewport_x;
+                               int w = viewport_width;
+                               int y = Math.Min (start_line_top - viewport_y, line.Y - viewport_y);
+                               int h = Math.Max (end_line_bottom - y, end_line.Y + end_line.height - y);
 
-//blah Console.WriteLine("TextControl.cs(996) Invalidate called in UpdateView(line, line_count, pos)");
-                               owner.Invalidate(new Rectangle(0 - viewport_x, line.Y - viewport_y, (int)line.widths[line.text.Length], end_line.Y + end_line.height));
+                               owner.Invalidate (new Rectangle (x, y, w, h));
                        }
                }
                #endregion      // Private Methods
@@ -1434,9 +1515,7 @@ namespace System.Windows.Forms {
                        lines = 0;
 
                        // We always have a blank line
-                       Add(1, "", owner.Font, ThemeEngine.Current.ResPool.GetSolidBrush(owner.ForeColor));
-                       Line l = GetLine (1);
-                       l.soft_break = true;
+                       Add (1, String.Empty, owner.Font, ThemeEngine.Current.ResPool.GetSolidBrush (owner.ForeColor), LineEnding.None);
                        
                        this.RecalculateDocument(owner.CreateGraphicsInternal());
                        PositionCaret(0, 0);
@@ -1497,7 +1576,7 @@ namespace System.Windows.Forms {
                        caret.line = caret.tag.line;
                        caret.height = caret.tag.height;
 
-                       if (owner.Focused) {
+                       if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) {
                                XplatUI.CreateCaret (owner.Handle, caret_width, caret.height);
                                XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.shift - viewport_y + caret_shift);
                        }
@@ -1513,7 +1592,7 @@ namespace System.Windows.Forms {
                                DisplayCaret ();
                        }
 
-                       if (owner.IsHandleCreated && selection_visible) {
+                       if (owner.IsHandleCreated && SelectionLength () > 0) {
                                InvalidateSelectionArea ();
                        }
                }
@@ -1559,10 +1638,11 @@ namespace System.Windows.Forms {
                                }
                        }
 
-                       XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.shift - viewport_y + caret_shift);
-
-                       DisplayCaret ();
-
+                       if (owner.Focused) {
+                               XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.shift - viewport_y + caret_shift);
+                               DisplayCaret ();
+                       }
+                       
                        if (CaretMoved != null) CaretMoved(this, EventArgs.Empty);
                }
 
@@ -1612,7 +1692,7 @@ namespace System.Windows.Forms {
                                        goto case CaretDirection.CharForward;
                                case CaretDirection.CharForward: {
                                        caret.pos++;
-                                       if (caret.pos > caret.line.text.Length) {
+                                       if (caret.pos > caret.line.TextLengthWithoutEnding ()) {
                                                if (!nowrap) {
                                                        // Go into next line
                                                        if (caret.line.line_no < this.lines) {
@@ -1650,7 +1730,7 @@ namespace System.Windows.Forms {
                                        } else {
                                                if (caret.line.line_no > 1 && !nowrap) {
                                                        caret.line = GetLine(caret.line.line_no - 1);
-                                                       caret.pos = caret.line.text.Length;
+                                                       caret.pos = caret.line.TextLengthWithoutEnding ();
                                                        caret.tag = LineTag.FindTag(caret.line, caret.pos);
                                                }
                                        }
@@ -1750,8 +1830,8 @@ namespace System.Windows.Forms {
                                }
 
                                case CaretDirection.End: {
-                                       if (caret.pos < caret.line.text.Length) {
-                                               caret.pos = caret.line.text.Length;
+                                       if (caret.pos < caret.line.TextLengthWithoutEnding ()) {
+                                               caret.pos = caret.line.TextLengthWithoutEnding ();
                                                caret.tag = LineTag.FindTag(caret.line, caret.pos);
                                                UpdateCaret();
                                        }
@@ -1760,56 +1840,38 @@ namespace System.Windows.Forms {
 
                                case CaretDirection.PgUp: {
 
-                                       int new_y, y_offset;
-
-                                       if (viewport_y == 0) {
-
-                                               // This should probably be handled elsewhere
-                                               if (!(owner is RichTextBox)) {
-                                                       // Page down doesn't do anything in a regular TextBox
-                                                       // if the bottom of the document
-                                                       // is already visible, the page and the caret stay still
-                                                       return;
-                                               }
-
-                                               // We're just placing the caret at the end of the document, no scrolling needed
+                                       if (viewport_y == 0 && owner.richtext) {
                                                owner.vscroll.Value = 0;
                                                Line line = GetLine (1);
                                                PositionCaret (line, 0);
                                        }
 
-                                       y_offset = caret.line.Y - viewport_y;
-                                       new_y = caret.line.Y - viewport_height;
+                                       int y_offset = caret.line.Y + caret.line.height - 1 - viewport_y;
+                                       int index;
+                                       LineTag top = FindCursor ((int) caret.line.widths [caret.pos],
+                                                       viewport_y - viewport_height, out index);
+
+                                       owner.vscroll.Value = Math.Min (top.line.Y, owner.vscroll.Maximum - viewport_height);
+                                       PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y);
 
-                                       owner.vscroll.Value = Math.Max (new_y, 0);
-                                       PositionCaret ((int)caret.line.widths[caret.pos], y_offset + viewport_y);
                                        return;
                                }
 
                                case CaretDirection.PgDn: {
-                                       int new_y, y_offset;
-
-                                       if ((viewport_y + viewport_height) > document_y) {
-
-                                               // This should probably be handled elsewhere
-                                               if (!(owner is RichTextBox)) {
-                                                       // Page up doesn't do anything in a regular TextBox
-                                                       // if the bottom of the document
-                                                       // is already visible, the page and the caret stay still
-                                                       return;
-                                               }
 
-                                               // We're just placing the caret at the end of the document, no scrolling needed
+                                       if (viewport_y + viewport_height >= document_y && owner.richtext) {
                                                owner.vscroll.Value = owner.vscroll.Maximum - viewport_height + 1;
                                                Line line = GetLine (lines);
                                                PositionCaret (line, line.Text.Length);
                                        }
 
-                                       y_offset = caret.line.Y - viewport_y;
-                                       new_y = caret.line.Y + viewport_height;
-                                       
-                                       owner.vscroll.Value = Math.Min (new_y, owner.vscroll.Maximum - viewport_height + 1);
-                                       PositionCaret ((int)caret.line.widths[caret.pos], y_offset + viewport_y);
+                                       int y_offset = caret.line.Y - viewport_y;
+                                       int index;
+                                       LineTag top = FindCursor ((int) caret.line.widths [caret.pos],
+                                                       viewport_y + viewport_height, out index);
+
+                                       owner.vscroll.Value = Math.Min (top.line.Y, owner.vscroll.Maximum - viewport_height);
+                                       PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y);
                                        
                                        return;
                                }
@@ -1847,7 +1909,7 @@ namespace System.Windows.Forms {
 
                                case CaretDirection.CtrlEnd: {
                                        caret.line = GetLine(lines);
-                                       caret.pos = caret.line.text.Length;
+                                       caret.pos = caret.line.TextLengthWithoutEnding ();
                                        caret.tag = LineTag.FindTag(caret.line, caret.pos);
 
                                        UpdateCaret();
@@ -1876,14 +1938,15 @@ namespace System.Windows.Forms {
 
                internal void DumpDoc ()
                {
-                       Console.WriteLine ("<doc>");
-                       for (int i = 1; i < lines; i++) {
+                       Console.WriteLine ("<doc lines='{0}'>", lines);
+                       for (int i = 1; i <= lines ; i++) {
                                Line line = GetLine (i);
-                               Console.WriteLine ("<line no='{0}'>", line.line_no);
+                               Console.WriteLine ("<line no='{0}' ending='{1}'>", line.line_no, line.ending);
 
                                LineTag tag = line.tags;
                                while (tag != null) {
-                                       Console.Write ("\t<tag type='{0}' span='{1}->{2}'>", tag.GetType (), tag.start, tag.length);
+                                       Console.Write ("\t<tag type='{0}' span='{1}->{2}' font='{3}' color='{4}'>",
+                                                       tag.GetType (), tag.start, tag.length, tag.font, tag.color.Color);
                                        Console.Write (tag.Text ());
                                        Console.WriteLine ("</tag>");
                                        tag = tag.next;
@@ -1922,7 +1985,7 @@ namespace System.Windows.Forms {
                        /// We draw the single border ourself
                        ///
                        if (owner.actual_border_style == BorderStyle.FixedSingle) {
-                               ControlPaint.DrawBorder (g, owner.Bounds, Color.Black, ButtonBorderStyle.Solid);
+                               ControlPaint.DrawBorder (g, owner.ClientRectangle, Color.Black, ButtonBorderStyle.Solid);
                        }
 
                        /// Make sure that we aren't drawing one more line then we need to
@@ -2050,40 +2113,95 @@ namespace System.Windows.Forms {
                                                }
 
                                                tag.Draw (g, current_brush,
-                                                               line.widths [Math.Max (0, old_tag_pos - 1)] + line.X - viewport_x,
+                                                               line.X - viewport_x,
                                                                line_y + tag.shift,
-                                                               old_tag_pos - 1, Math.Min (tag.length, tag_pos - old_tag_pos),
+                                                               old_tag_pos - 1, Math.Max (tag.length, tag_pos - old_tag_pos),
                                                                text.ToString() );
                                        }
                                        tag = tag.next;
                                }
+
+                               line.DrawEnding (g, line_y);
                                line_no++;
                        }
                }
 
-               private void InsertLineString (Line line, int pos, string s)
+               internal int GetLineEnding (string line, int start, out LineEnding ending)
                {
-                       bool carriage_return = false;
+                       int res;
 
-                       if (s.EndsWith ("\r")) {
-                               s = s.Substring (0, s.Length - 1);
-                               carriage_return = true;
+                       res = line.IndexOf ('\r', start);
+                       if (res != -1) {
+                               if (res + 2 < line.Length && line [res + 1] == '\r' && line [res + 2] == '\n') {
+                                       ending = LineEnding.Soft;
+                                       return res;
+                               }
+                               if (res + 1 < line.Length && line [res + 1] == '\n') {
+                                       ending = LineEnding.Hard;
+                                       return res;
+                               }
+                               ending = LineEnding.Limp;
+                               return res;
                        }
 
-                       InsertString (line, pos, s);
+                       res = line.IndexOf ('\n', start);
+                       if (res != -1) {
+                               ending = LineEnding.Rich;
+                               return res;
+                       }
+
+                       ending = LineEnding.Wrap;
+                       return line.Length;
+               }
 
-                       if (carriage_return) {
-                               Line l = GetLine (line.line_no);
-                               l.carriage_return = true;
+               internal int LineEndingLength (LineEnding ending)
+               {
+                       int res = 0;
+
+                       switch (ending) {
+                       case LineEnding.Limp:
+                       case LineEnding.Rich:
+                               res = 1;
+                               break;
+                       case LineEnding.Hard:
+                               res = 2;
+                               break;
+                       case LineEnding.Soft:
+                               res = 3;
+                               break;
                        }
+
+                       return res;
                }
 
+               internal string LineEndingToString (LineEnding ending)
+               {
+                       string res = String.Empty;
+                       switch (ending) {
+                       case LineEnding.Limp:
+                               res = "\r";
+                               break;
+                       case LineEnding.Hard:
+                               res = "\r\n";
+                               break;
+                       case LineEnding.Soft:
+                               res = "\r\r\n";
+                               break;
+                       case LineEnding.Rich:
+                               res = "\n";
+                               break;
+                       }
+                       return res;
+               }
+
+               
                // Insert multi-line text at the given position; use formatting at insertion point for inserted text
                internal void Insert(Line line, int pos, bool update_caret, string s) {
                        int break_index;
                        int base_line;
                        int old_line_count;
                        int count = 1;
+                       LineEnding ending;
                        LineTag tag = LineTag.FindTag (line, pos);
                        
                        SuspendRecalc ();
@@ -2091,54 +2209,30 @@ namespace System.Windows.Forms {
                        base_line = line.line_no;
                        old_line_count = lines;
 
-                       break_index = s.IndexOf ('\n');
+                       break_index = GetLineEnding (s, 0, out ending);
 
                        // Bump the text at insertion point a line down if we're inserting more than one line
-                       if (break_index > -1) {
-                               Split(line, pos);
-                               line.soft_break = false;
+                       if (break_index != s.Length) {
+                               Split (line, pos);
+                               line.ending = ending;
                                // Remainder of start line is now in base_line + 1
                        }
 
-                       if (break_index == -1)
-                               break_index = s.Length;
-
-                       InsertLineString (line, pos, s.Substring (0, break_index));
-                       break_index++;
-
+                       InsertString (line, pos, s.Substring (0, break_index + LineEndingLength (ending)));
+                       
+                       break_index += LineEndingLength (ending);
                        while (break_index < s.Length) {
-                               bool soft = false;
-                               int next_break = s.IndexOf ('\n', break_index);
-                               int adjusted_next_break;
-                               bool carriage_return = false;
-
-                               if (next_break == -1) {
-                                       next_break = s.Length;
-                                       soft = true;
-                               }
+                               int next_break = GetLineEnding (s, break_index, out ending);
+                               string line_text = s.Substring (break_index, next_break - break_index +
+                                               LineEndingLength (ending));
 
-                               adjusted_next_break = next_break;
-                               if (s [next_break - 1] == '\r') {
-                                       adjusted_next_break--;
-                                       carriage_return = true;
-                               }
-
-                               string line_text = s.Substring (break_index, adjusted_next_break - break_index);
-                               Add (base_line + count, line_text, line.alignment, tag.font, tag.color);
+                               Add (base_line + count, line_text, line.alignment, tag.font, tag.color, ending);
 
-                               if (carriage_return) {
-                                       Line last = GetLine (base_line + count);
-                                       last.carriage_return = true;
-
-                                       if (soft)
-                                               last.soft_break = true;
-                               } else if (soft) {
-                                       Line last = GetLine (base_line + count);
-                                       last.soft_break = true;
-                               }
+                               Line last = GetLine (base_line + count);
+                               last.ending = ending;
 
                                count++;
-                               break_index = next_break + 1;
+                               break_index = next_break + LineEndingLength (ending);
                        }
 
                        ResumeRecalc (true);
@@ -2254,7 +2348,7 @@ namespace System.Windows.Forms {
                
                internal void InsertPicture (Line line, int pos, RTF.Picture picture)
                {
-                       LineTag next_tag;
+                       //LineTag next_tag;
                        LineTag tag;
                        int len;
 
@@ -2267,7 +2361,7 @@ namespace System.Windows.Forms {
 
                        tag = LineTag.FindTag (line, pos);
                        picture_tag.CopyFormattingFrom (tag);
-                       next_tag = tag.Break (pos + 1);
+                       /*next_tag = */tag.Break (pos + 1);
                        picture_tag.previous = tag;
                        picture_tag.next = tag.next;
                        tag.next = picture_tag;
@@ -2357,7 +2451,7 @@ namespace System.Windows.Forms {
                        }
 
                        if (tag == null) {
-                               return;
+                               goto Cleanup;
                        }
 
                        // Check if we're crossing tag boundaries
@@ -2414,7 +2508,25 @@ namespace System.Windows.Forms {
                                line.Streamline(lines);
                        }
 
-                       UpdateView(line, pos);
+               Cleanup:
+                       if (pos >= line.TextLengthWithoutEnding ()) {
+                               LineEnding ending = line.ending;
+                               GetLineEnding (line.text.ToString (), 0, out ending);
+                               if (ending != line.ending) {
+                                       line.ending = ending;
+
+                                       if (!multiline) {
+                                               UpdateView (line, lines, pos);
+                                               owner.Invalidate ();
+                                               return;
+                                       }
+                               }
+                       }
+                       if (!multiline) {
+                               UpdateView (line, lines, pos);
+                               owner.Invalidate ();
+                       } else 
+                               UpdateView(line, pos);
                }
 
                // Deletes a character at or after the given position (depending on forward); it will not delete past line limits
@@ -2440,7 +2552,7 @@ namespace System.Windows.Forms {
                                }
 
                                if (tag == null) {
-                                       return;
+                                       goto Cleanup;
                                }
 
                                //      tag.length--;
@@ -2484,7 +2596,25 @@ namespace System.Windows.Forms {
                                line.Streamline(lines);
                        }
 
-                       UpdateView(line, pos);
+               Cleanup:
+                       if (pos >= line.TextLengthWithoutEnding ()) {
+                               LineEnding ending = line.ending;
+                               GetLineEnding (line.text.ToString (), 0, out ending);
+                               if (ending != line.ending) {
+                                       line.ending = ending;
+
+                                       if (!multiline) {
+                                               UpdateView (line, lines, pos);
+                                               owner.Invalidate ();
+                                               return;
+                                       }
+                               }
+                       }
+                       if (!multiline) {
+                               UpdateView (line, lines, pos);
+                               owner.Invalidate ();
+                       } else 
+                               UpdateView(line, pos);
                }
 
                // Combine two lines
@@ -2496,11 +2626,14 @@ namespace System.Windows.Forms {
                        LineTag last;
                        int     shift;
 
+                       // strip the ending off of the first lines text
+                       first.text.Length = first.text.Length - LineEndingLength (first.ending);
+
                        // Combine the two tag chains into one
                        last = first.tags;
 
                        // Maintain the line ending style
-                       first.soft_break = second.soft_break;
+                       first.ending = second.ending;
 
                        while (last.next != null) {
                                last = last.next;
@@ -2575,20 +2708,19 @@ namespace System.Windows.Forms {
 
                        line = GetLine(LineNo);
                        tag = LineTag.FindTag(line, pos);
-                       Split(line, tag, pos, false);
+                       Split(line, tag, pos);
                }
 
                internal void Split(Line line, int pos) {
                        LineTag tag;
 
                        tag = LineTag.FindTag(line, pos);
-                       Split(line, tag, pos, false);
+                       Split(line, tag, pos);
                }
 
                ///<summary>Split line at given tag and position into two lines</summary>
-               ///<param name="soft">True if the split should be marked as 'soft', indicating that it can be contracted 
                ///if more space becomes available on previous line</param>
-               internal void Split(Line line, LineTag tag, int pos, bool soft) {
+               internal void Split(Line line, LineTag tag, int pos) {
                        LineTag new_tag;
                        Line    new_line;
                        bool    move_caret;
@@ -2613,13 +2745,9 @@ namespace System.Windows.Forms {
 
                        // cover the easy case first
                        if (pos == line.text.Length) {
-                               Add(line.line_no + 1, "", line.alignment, tag.font, tag.color);
+                               Add (line.line_no + 1, String.Empty, line.alignment, tag.font, tag.color, line.ending);
 
-                               new_line = GetLine(line.line_no + 1);
-
-                               line.carriage_return = false;
-                               new_line.carriage_return = line.carriage_return;
-                               new_line.soft_break = soft;
+                               new_line = GetLine (line.line_no + 1);
                                
                                if (move_caret) {
                                        caret.line = new_line;
@@ -2642,15 +2770,11 @@ namespace System.Windows.Forms {
                        }
 
                        // We need to move the rest of the text into the new line
-                       Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.font, tag.color);
+                       Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.font, tag.color, line.ending);
 
                        // Now transfer our tags from this line to the next
                        new_line = GetLine(line.line_no + 1);
 
-                       line.carriage_return = false;
-                       new_line.carriage_return = line.carriage_return;
-                       new_line.soft_break = soft;
-
                        line.recalc = true;
                        new_line.recalc = true;
 
@@ -2726,11 +2850,13 @@ namespace System.Windows.Forms {
 
                // Adds a line of text, with given font.
                // Bumps any line at that line number that already exists down
-               internal void Add(int LineNo, string Text, Font font, SolidBrush color) {
-                       Add(LineNo, Text, HorizontalAlignment.Left, font, color);
+               internal void Add (int LineNo, string Text, Font font, SolidBrush color, LineEnding ending)
+               {
+                       Add (LineNo, Text, alignment, font, color, ending);
                }
 
-               internal void Add(int LineNo, string Text, HorizontalAlignment align, Font font, SolidBrush color) {
+               internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, SolidBrush color, LineEnding ending)
+               {
                        Line    add;
                        Line    line;
                        int     line_no;
@@ -2745,7 +2871,7 @@ namespace System.Windows.Forms {
                                }
                        }
 
-                       add = new Line (this, LineNo, Text, align, font, color);
+                       add = new Line (this, LineNo, Text, align, font, color, ending);
 
                        line = document;
                        while (line != sentinel) {
@@ -2872,7 +2998,7 @@ namespace System.Windows.Forms {
                                line1.line_no = line3.line_no;
                                line1.recalc = line3.recalc;
                                line1.right_indent = line3.right_indent;
-                               line1.soft_break = line3.soft_break;
+                               line1.ending = line3.ending;
                                line1.space = line3.space;
                                line1.tags = line3.tags;
                                line1.text = line3.text;
@@ -3241,9 +3367,10 @@ namespace System.Windows.Forms {
                        }
                }
 
-               internal void SetSelectionStart(Line start, int start_pos) {
+               internal void SetSelectionStart(Line start, int start_pos, bool invalidate) {
                        // Invalidate from the previous to the new start pos
-                       Invalidate(selection_start.line, selection_start.pos, start, start_pos);
+                       if (invalidate)
+                               Invalidate(selection_start.line, selection_start.pos, start, start_pos);
 
                        selection_start.line = start;
                        selection_start.pos = start_pos;
@@ -3262,10 +3389,11 @@ namespace System.Windows.Forms {
                                SetSelectionVisible (false);
                        }
 
-                       Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+                       if (invalidate)
+                               Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
                }
 
-               internal void SetSelectionStart(int character_index) {
+               internal void SetSelectionStart(int character_index, bool invalidate) {
                        Line    line;
                        LineTag tag;
                        int     pos;
@@ -3275,10 +3403,10 @@ namespace System.Windows.Forms {
                        }
 
                        CharIndexToLineTag(character_index, out line, out tag, out pos);
-                       SetSelectionStart(line, pos);
+                       SetSelectionStart(line, pos, invalidate);
                }
 
-               internal void SetSelectionEnd(Line end, int end_pos) {
+               internal void SetSelectionEnd(Line end, int end_pos, bool invalidate) {
 
                        if (end == selection_end.line && end_pos == selection_start.pos) {
                                selection_anchor.line = selection_start.line;
@@ -3314,14 +3442,15 @@ namespace System.Windows.Forms {
 
                        if ((selection_end.line != selection_start.line) || (selection_end.pos != selection_start.pos)) {
                                SetSelectionVisible (true);
-                               Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
+                               if (invalidate)
+                                       Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
                        } else {
                                SetSelectionVisible (false);
                                // ?? Do I need to invalidate here, tests seem to work without it, but I don't think they should :-s
                        }
                }
 
-               internal void SetSelectionEnd(int character_index) {
+               internal void SetSelectionEnd(int character_index, bool invalidate) {
                        Line    line;
                        LineTag tag;
                        int     pos;
@@ -3331,7 +3460,7 @@ namespace System.Windows.Forms {
                        }
 
                        CharIndexToLineTag(character_index, out line, out tag, out pos);
-                       SetSelectionEnd(line, pos);
+                       SetSelectionEnd(line, pos, invalidate);
                }
 
                internal void SetSelection(Line start, int start_pos) {
@@ -3417,8 +3546,11 @@ namespace System.Windows.Forms {
 
                                        undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos);
 
+                                       InvalidateSelectionArea ();
+
                                        // Delete first line
                                        DeleteChars(selection_start.tag, selection_start.pos, selection_start.line.text.Length - selection_start.pos);
+                                       selection_start.line.recalc = true;
 
                                        // Delete last line
                                        DeleteChars(selection_end.line.tags, 0, selection_end.pos);
@@ -3486,14 +3618,14 @@ namespace System.Windows.Forms {
                                line = GetLine(i);
 
                                start = chars;
-                               chars += line.text.Length + (line.soft_break ? 0 : crlf_size);
+                               chars += line.text.Length;
 
                                if (index <= chars) {
                                        // we found the line
                                        tag = line.tags;
 
                                        while (tag != null) {
-                                               if (index < (start + tag.start + tag.length)) {
+                                               if (index < (start + tag.start + tag.length - 1)) {
                                                        line_out = line;
                                                        tag_out = LineTag.GetFinalTag (tag);
                                                        pos = index - start;
@@ -3540,7 +3672,7 @@ namespace System.Windows.Forms {
                        // Count the lines in the middle
 
                        for (i = 1; i < line.line_no; i++) {
-                               length += GetLine(i).text.Length + (line.soft_break ? 0 : crlf_size);
+                               length += GetLine(i).text.Length;
                        }
 
                        length += pos;
@@ -3571,7 +3703,7 @@ namespace System.Windows.Forms {
                                if (start < end) {
                                        for (i = start; i < end; i++) {
                                                Line line = GetLine (i);
-                                               length += line.text.Length + (line.soft_break ? 0 : crlf_size);
+                                               length += line.text.Length + LineEndingLength (line.ending);
                                        }
                                }
 
@@ -3644,7 +3776,7 @@ namespace System.Windows.Forms {
                }
 
                internal Line ParagraphStart(Line line) {
-                       while (line.soft_break) {
+                       while (line.ending == LineEnding.Wrap) {
                                line = GetLine(line.line_no - 1);
                        }
                        return line;
@@ -3653,9 +3785,9 @@ namespace System.Windows.Forms {
                internal Line ParagraphEnd(Line line) {
                        Line    l;
    
-                       while (line.soft_break) {
+                       while (line.ending == LineEnding.Wrap) {
                                l = GetLine(line.line_no + 1);
-                               if ((l == null) || (!l.soft_break)) {
+                               if ((l == null) || (l.ending != LineEnding.Wrap)) {
                                        break;
                                }
                                line = l;
@@ -3752,11 +3884,17 @@ namespace System.Windows.Forms {
                        line = GetLineByPixel(multiline ? y : x, false);
                        tag = line.tags;
 
+                       /// Special case going leftwards of the first tag
+                       if (x < tag.X) {
+                               index = 0;
+                               return LineTag.GetFinalTag (tag);
+                       }
+
                        while (true) {
                                if (x >= tag.X && x < (tag.X+tag.width)) {
                                        int     end;
 
-                                       end = tag.end;
+                                       end = tag.TextEnd;
 
                                        for (int pos = tag.start - 1; pos < end; pos++) {
                                                // When clicking on a character, we position the cursor to whatever edge
@@ -3772,7 +3910,7 @@ namespace System.Windows.Forms {
                                if (tag.next != null) {
                                        tag = tag.next;
                                } else {
-                                       index = line.text.Length;
+                                       index = line.TextLengthWithoutEnding ();
                                        return LineTag.GetFinalTag (tag);
                                }
                        }
@@ -3805,34 +3943,6 @@ namespace System.Windows.Forms {
                        }
                }
 
-               /// <summary>Re-format areas of the document in specified font and color</summary>
-               /// <param name="start_pos">1-based start position on start_line</param>
-               /// <param name="end_pos">1-based end position on end_line </param>
-               /// <param name="font">Font specifying attributes</param>
-               /// <param name="color">Color (or NULL) to apply</param>
-               /// <param name="apply">Attributes from font and color to apply</param>
-               internal void FormatText(Line start_line, int start_pos, Line end_line, int end_pos, FontDefinition attributes) {
-                       Line    l;
-
-                       // First, format the first line
-                       if (start_line != end_line) {
-                               // First line
-                               LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, attributes);
-
-                               // Format last line
-                               LineTag.FormatText(end_line, 1, end_pos - 1, attributes);
-
-                               // Now all the lines inbetween
-                               for (int i = start_line.line_no + 1; i < end_line.line_no; i++) {
-                                       l = GetLine(i);
-                                       LineTag.FormatText(l, 1, l.text.Length, attributes);
-                               }
-                       } else {
-                               // Special case, single line
-                               LineTag.FormatText(start_line, start_pos, end_pos - start_pos, attributes);
-                       }
-               }
-
                internal void RecalculateAlignments ()
                {
                        Line    line;
@@ -3840,6 +3950,8 @@ namespace System.Windows.Forms {
 
                        line_no = 1;
 
+
+
                        while (line_no <= lines) {
                                line = GetLine(line_no);
 
@@ -3852,7 +3964,7 @@ namespace System.Windows.Forms {
                                                line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2;
                                                break;
                                        case HorizontalAlignment.Right:
-                                               line.align_shift = viewport_width - (int)line.widths[line.text.Length];
+                                               line.align_shift = viewport_width - (int)line.widths[line.text.Length] - right_margin;
                                                break;
                                        }
                                }
@@ -3952,7 +4064,7 @@ namespace System.Windows.Forms {
                                if (multiline)
                                        offset += line.height;
                                else
-                                       offset += (int) line.widths [line.text.Length] + 2;
+                                       offset += (int) line.widths [line.text.Length];
 
                                if (line_no > lines) {
                                        break;
@@ -3995,20 +4107,21 @@ namespace System.Windows.Forms {
                        }
                }
 
-               internal static bool IsWordSeparator(char ch) {
-                       switch(ch) {
-                               case ' ':
-                               case '\t':
-                               case '(':
-                               case ')': {
-                                       return true;
-                               }
-
-                               default: {
-                                       return false;
-                               }
+               internal static bool IsWordSeparator (char ch)
+               {
+                       switch (ch) {
+                       case ' ':
+                       case '\t':
+                       case '(':
+                       case ')':
+                       case '\r':
+                       case '\n':
+                               return true;
+                       default:
+                               return false;
                        }
                }
+
                internal int FindWordSeparator(Line line, int pos, bool forward) {
                        int len;
 
@@ -4131,7 +4244,7 @@ namespace System.Windows.Forms {
                                                Line    prev_line;
 
                                                prev_line = GetLine(line_no - 1);
-                                               if (prev_line.soft_break) {
+                                               if (prev_line.ending == LineEnding.Wrap) {
                                                        if (IsWordSeparator(prev_line.text[prev_line.text.Length - 1])) {
                                                                word = true;
                                                        } else {
@@ -4161,6 +4274,7 @@ namespace System.Windows.Forms {
                                }
 
                                while (pos < line_len) {
+
                                        if (word_option && (current == search_string.Length)) {
                                                if (IsWordSeparator(line.text[pos])) {
                                                        if (!reverse) {
@@ -4181,6 +4295,7 @@ namespace System.Windows.Forms {
                                        }
 
                                        if (c == search_string[current]) {
+                                               
                                                if (current == 0) {
                                                        result.line = line;
                                                        result.pos = pos;
@@ -4215,7 +4330,7 @@ namespace System.Windows.Forms {
 
                                if (word_option) {
                                        // Mark that we just saw a word boundary
-                                       if (!line.soft_break) {
+                                       if (line.ending != LineEnding.Wrap || line.line_no == lines - 1) {
                                                word = true;
                                        }
 
@@ -4345,14 +4460,14 @@ namespace System.Windows.Forms {
                        return (int) (picture.Height + 0.5F);
                }
 
-               internal override void Draw (Graphics dc, Brush brush, float x, float y, int start, int end)
+               internal override void Draw (Graphics dc, Brush brush, float xoff, float y, int start, int end)
                {
-                       picture.DrawImage (dc, x, y, false);
+                       picture.DrawImage (dc, xoff + line.widths [start], y, false);
                }
 
-               internal override void Draw (Graphics dc, Brush brush, float x, float y, int start, int end, string text)
+               internal override void Draw (Graphics dc, Brush brush, float xoff, float y, int start, int end, string text)
                {
-                       picture.DrawImage (dc, x, y, false);
+                       picture.DrawImage (dc, xoff + + line.widths [start], y, false);
                }
 
                public override string Text ()
@@ -4408,6 +4523,10 @@ namespace System.Windows.Forms {
                        get { return start + length; }
                }
 
+               public int TextEnd {
+                       get { return start + TextLength; }
+               }
+
                public float width {
                        get {
                                if (length == 0)
@@ -4428,13 +4547,41 @@ namespace System.Windows.Forms {
                        }
                }
 
+               public int TextLength {
+                       get {
+                               int res = 0;
+                               if (next != null)
+                                       res = next.start - start;
+                               else
+                                       res = line.TextLengthWithoutEnding () - (start - 1);
+
+                               return res > 0 ? res : 0;
+                       }
+               }
+
                public virtual bool IsTextTag {
                        get { return true; }
                }
 
                internal virtual SizeF SizeOfPosition (Graphics dc, int pos)
                {
-                       return dc.MeasureString (line.text.ToString (pos, 1), font, 10000, Document.string_format);
+                       if (pos >= line.TextLengthWithoutEnding () && line.document.multiline)
+                               return SizeF.Empty;
+
+                       string text = line.text.ToString (pos, 1);
+                       switch ((int) text [0]) {
+                       case '\t':
+                               if (!line.document.multiline)
+                                       goto case 10;
+                               SizeF res = dc.MeasureString (" ", font, 10000, Document.string_format);
+                               res.Width *= 8.0F;
+                               return res;
+                       case 10:
+                       case 13:
+                               return dc.MeasureString ("\u0013", font, 10000, Document.string_format);
+                       }
+                       
+                       return dc.MeasureString (text, font, 10000, Document.string_format);
                }
 
                internal virtual int MaxHeight ()
@@ -4447,9 +4594,21 @@ namespace System.Windows.Forms {
                        dc.DrawString (line.text.ToString (start, end), font, brush, x, y, StringFormat.GenericTypographic);
                }
 
-               internal virtual void Draw (Graphics dc, Brush brush, float x, float y, int start, int end, string text)
+               internal virtual void Draw (Graphics dc, Brush brush, float xoff, float y, int start, int end, string text)
                {
-                       dc.DrawString (text.Substring (start, end), font, brush, x, y, StringFormat.GenericTypographic);
+                       while (start < end) {
+                               int tab_index = text.IndexOf ("\t", start);
+                               if (tab_index == -1)
+                                       tab_index = end;
+                               dc.DrawString (text.Substring (start, tab_index - start), font, brush, xoff + line.widths [start],
+                                               y, StringFormat.GenericTypographic);
+
+                               // non multilines get the unknown char 
+                               if (!line.document.multiline && tab_index != end)
+                                       dc.DrawString ("\u0013", font, brush,  xoff + line.widths [tab_index], y, Document.string_format);
+                                       
+                               start = tab_index + 1;
+                       }
                }
 
                ///<summary>Break a tag into two with identical attributes; pos is 1-based; returns tag starting at &gt;pos&lt; or null if end-of-line</summary>
@@ -4491,49 +4650,6 @@ namespace System.Windows.Forms {
                        back_color = other.back_color;
                }
 
-               ///<summary>Create new font and brush from existing font and given new attributes. Returns true if fontheight changes</summary>
-               internal static bool GenerateTextFormat(Font font_from, SolidBrush color_from, FontDefinition attributes, out Font new_font, out SolidBrush new_color) {
-                       float           size;
-                       string          face;
-                       FontStyle       style;
-                       GraphicsUnit    unit;
-
-                       if (attributes.font_obj == null) {
-                               size = font_from.SizeInPoints;
-                               unit = font_from.Unit;
-                               face = font_from.Name;
-                               style = font_from.Style;
-
-                               if (attributes.face != null) {
-                                       face = attributes.face;
-                               }
-                               
-                               if (attributes.size != 0) {
-                                       size = attributes.size;
-                               }
-
-                               style |= attributes.add_style;
-                               style &= ~attributes.remove_style;
-
-                               // Create new font
-                               new_font = new Font(face, size, style, unit);
-                       } else {
-                               new_font = attributes.font_obj;
-                       }
-
-                       // Create 'new' color brush
-                       if (attributes.color != Color.Empty) {
-                               new_color = new SolidBrush(attributes.color);
-                       } else {
-                               new_color = color_from;
-                       }
-
-                       if (new_font.Height == font_from.Height) {
-                               return false;
-                       }
-                       return true;
-               }
-
                /// <summary>Applies 'font' and 'brush' to characters starting at 'start' for 'length' chars; 
                /// Removes any previous tags overlapping the same area; 
                /// returns true if lineheight has changed</summary>
@@ -4568,7 +4684,6 @@ namespace System.Windows.Forms {
                        }
 
                        start_tag = FindTag (line, start);
-
                        tag = start_tag.Break (start);
 
                        while (tag != null && tag.end <= end) {
@@ -4576,14 +4691,15 @@ namespace System.Windows.Forms {
                                tag = tag.next;
                        }
 
-                       if (end != line.text.Length) {
-                               /// Now do the last tag
-                               end_tag = FindTag (line, end);
+                       if (tag != null && tag.end == end)
+                               return retval;
 
-                               if (end_tag != null) {
-                                       end_tag.Break (end);
-                                       SetFormat (end_tag, font, color, back_color, specified);
-                               }
+                       /// Now do the last tag
+                       end_tag = FindTag (line, end);
+
+                       if (end_tag != null) {
+                               end_tag.Break (end);
+                               SetFormat (end_tag, font, color, back_color, specified);
                        }
 
                        return retval;
@@ -4601,67 +4717,6 @@ namespace System.Windows.Forms {
                        // Console.WriteLine ("setting format:   {0}  {1}   new color {2}", color.Color, specified, tag.color.Color);
                }
 
-               /// <summary>Applies font attributes specified to characters starting at 'start' for 'length' chars; 
-               /// Breaks tags at start and end point, keeping middle tags with altered attributes.
-               /// Returns true if lineheight has changed</summary>
-               /// <param name="start">1-based character position on line</param>
-               internal static bool FormatText(Line line, int start, int length, FontDefinition attributes) {
-                       LineTag tag;
-                       LineTag start_tag;
-                       LineTag end_tag;
-                       bool    retval = false;         // Assume line-height doesn't change
-
-                       line.recalc = true;             // This forces recalculation of the line in RecalculateDocument
-
-                       // A little sanity, not sure if it's needed, might be able to remove for speed
-                       if (length > line.text.Length) {
-                               length = line.text.Length;
-                       }
-
-                       tag = line.tags;
-
-                       // Common special case
-                       if ((start == 1) && (length == tag.length)) {
-                               tag.ascent = 0;
-                               GenerateTextFormat(tag.font, tag.color, attributes, out tag.font, out tag.color);
-                               return retval;
-                       }
-
-                       start_tag = FindTag(line, start);
-                       
-                       if (start_tag == null) {
-                               if (length == 0) {
-                                       // We are 'starting' after all valid tags; create a new tag with the right attributes
-                                       start_tag = FindTag(line, line.text.Length - 1);
-                                       start_tag.next = new LineTag(line, line.text.Length + 1);
-                                       start_tag.next.CopyFormattingFrom (start_tag);
-                                       start_tag.next.previous = start_tag;
-                                       start_tag = start_tag.next;
-                               } else {
-                                       throw new Exception(String.Format("Could not find start_tag in document at line {0} position {1}", line.line_no, start));
-                               }
-                       } else {
-                               start_tag = start_tag.Break(start);
-                       }
-
-                       end_tag = FindTag(line, start + length);
-                       if (end_tag != null) {
-                               end_tag = end_tag.Break(start + length);
-                       }
-
-                       // start_tag or end_tag might be null; we're cool with that
-                       // we now walk from start_tag to end_tag, applying new attributes
-                       tag = start_tag;
-                       while ((tag != null) && tag != end_tag) {
-                               if (LineTag.GenerateTextFormat(tag.font, tag.color, attributes, out tag.font, out tag.color)) {
-                                       retval = true;
-                               }
-                               tag = tag.next;
-                       }
-                       return retval;
-               }
-
-
                /// <summary>Finds the tag that describes the character at position 'pos' on 'line'</summary>
                internal static LineTag FindTag(Line line, int pos) {
                        LineTag tag = line.tags;
@@ -4795,8 +4850,8 @@ namespace System.Windows.Forms {
                private Stack           undo_actions;
                private Stack           redo_actions;
 
-               private int             caret_line;
-               private int             caret_pos;
+               //private int           caret_line;
+               //private int           caret_pos;
 
                // When performing an action, we lock the queue, so that the action can't be undone
                private bool locked;
@@ -5082,7 +5137,7 @@ namespace System.Windows.Forms {
                        int     end;
                        int     tag_start;
 
-                       line = new Line (start_line.document);
+                       line = new Line (start_line.document, start_line.ending);
                        ret = line;
 
                        for (int i = start_line.line_no; i <= end_line.line_no; i++) {
@@ -5091,7 +5146,7 @@ namespace System.Windows.Forms {
                                if (start_line.line_no == i) {
                                        start = start_pos;
                                } else {
-                                       start = 1;
+                                       start = 0;
                                }
 
                                if (end_line.line_no == i) {
@@ -5105,10 +5160,10 @@ namespace System.Windows.Forms {
 
                                // Text for the tag
                                line.text = new StringBuilder (current.text.ToString (start, end - start));
-                               
+
                                // Copy tags from start to start+length onto new line
                                current_tag = current.FindTag (start);
-                               while ((current_tag != null) && (current_tag.start < end)) {
+                               while ((current_tag != null) && (current_tag.start <= end)) {
                                        if ((current_tag.start <= start) && (start < (current_tag.start + current_tag.length))) {
                                                // start tag is within this tag
                                                tag_start = start;
@@ -5137,10 +5192,10 @@ namespace System.Windows.Forms {
                                }
 
                                if ((i + 1) <= end_line.line_no) {
-                                       line.soft_break = current.soft_break;
+                                       line.ending = current.ending;
 
                                        // Chain them (we use right/left as next/previous)
-                                       line.right = new Line (start_line.document);
+                                       line.right = new Line (start_line.document, start_line.ending);
                                        line.right.left = line;
                                        line = line.right;
                                }
@@ -5191,8 +5246,8 @@ namespace System.Windows.Forms {
                                document.Combine(line.line_no, line.line_no + 1);
 
                                if (select) {
-                                       document.SetSelectionStart (line, pos);
-                                       document.SetSelectionEnd (line, pos + insert.text.Length);
+                                       document.SetSelectionStart (line, pos, false);
+                                       document.SetSelectionEnd (line, pos + insert.text.Length, false);
                                }
 
                                document.UpdateView(line, pos);
@@ -5204,13 +5259,15 @@ namespace System.Windows.Forms {
                        current = insert;
 
                        while (current != null) {
+
                                if (current == insert) {
                                        // Inserting the first line we split the line (and make space)
-                                       document.Split(line, pos);
+                                       document.Split(line.line_no, pos);
                                        //Insert our tags at the end of the line
                                        tag = line.tags;
 
-                                       if (tag != null) {
+                                       
+                                       if (tag != null && tag.length != 0) {
                                                while (tag.next != null) {
                                                        tag = tag.next;
                                                }
@@ -5226,16 +5283,20 @@ namespace System.Windows.Forms {
                                                line.tags.previous = null;
                                                tag = line.tags;
                                        }
+
+                                       line.ending = current.ending;
                                } else {
                                        document.Split(line.line_no, 0);
                                        offset = 0;
                                        line.tags = current.tags;
                                        line.tags.previous = null;
+                                       line.ending = current.ending;
                                        tag = line.tags;
                                }
+
                                // Adjust start locations and line pointers
                                while (tag != null) {
-                                       tag.start += offset;
+                                       tag.start += offset - 1;
                                        tag.line = line;
                                        tag = tag.next;
                                }