ecere/gui/EditBox: Clearing Undo buffer on setting contents
[sdk] / ecere / src / gui / controls / EditBox.ec
index 0ff9de8..05816d5 100644 (file)
@@ -11,6 +11,16 @@ import "FindDialog"
 import "GoToDialog"
 import "Array"
 
+char * strchrmax(const char * s, int c, int max)
+{
+   int i;
+   char ch;
+   for(i = 0; i < max && (ch = s[i]); i++)
+      if(ch == c)
+         return (char *)s + i;
+   return null;
+}
+
 public class SyntaxColorScheme
 {
 public:
@@ -47,28 +57,48 @@ public:
       byte b = (string)[0]; \
       int i; \
       byte mask = 0x7F; \
-      numBytes = 1; \
+      numBytes = b ? 1 : 0; \
       ch = 0; \
-      if(b & 0x80 && b & 0x40) \
+      if(b & 0x80) \
       { \
-         mask >>= 2; \
-         numBytes++; \
-         if(b & 0x20) \
+         if(b & 0x40) \
          { \
+            mask >>= 2; \
             numBytes++; \
-            mask >>= 1; \
-            if(b & 0x10) \
+            if(b & 0x20) \
             { \
                numBytes++; \
                mask >>= 1; \
+               if(b & 0x10) \
+               { \
+                  if(b & 0x08) { numBytes = 0; } \
+                  numBytes++; \
+                  mask >>= 1; \
+               } \
             } \
          } \
+         else \
+            numBytes = 0; \
       } \
       for(i = 0; i<numBytes; i++) \
       { \
          ch <<= 6; \
-         ch |= (string)[i] & mask; \
+         ch |= (b = (string)[i]) & mask; \
          mask = 0x3F; \
+         if(i > 1 && (!(b & 0x80) || (b & 0x40))) \
+         { \
+            numBytes = 0; \
+            ch = 0; \
+         } \
+      } \
+      if(i < numBytes || \
+         ch > 0x10FFFF || (ch >= 0xD800 && ch <= 0xDFFF) || \
+        (ch < 0x80 && numBytes > 1) || \
+        (ch < 0x800 && numBytes > 2) || \
+        (ch < 0x10000 && numBytes > 3))\
+      { \
+         ch = 0; \
+         numBytes = 0; \
       } \
       ch; \
    })
@@ -79,11 +109,11 @@ class EditBoxBits
    bool noCaret:1, noSelect:1, tabKey:1, useTab:1, tabSel:1, allCaps:1, syntax:1, wrap:1;
 
    // Syntax States
-   bool inMultiLineComment:1, inPrep:1, escaped:1, continuedSingleLineComment:1;
+   bool inMultiLineComment:1, inPrep:1, escaped:1, continuedSingleLineComment:1, wasInMultiLine:1, continuedString:1, continuedQuotes:1;
 
    bool recomputeSyntax:1;
    bool cursorFollowsView:1;
-   
+
    // bool lineNumbers:1;
    bool autoSize:1;
 };
@@ -106,15 +136,13 @@ private:
 
 static class ArrayImpl
 {
-   uint size;
    Class type;
+   uint size;
    byte * array;
 };
 
 public class OldArray
 {
-   uint size;
-
    ~OldArray()
    {
       int c;
@@ -128,7 +156,7 @@ public class OldArray
       delete ((ArrayImpl)this).array;
    }
 
-public:   
+public:
    Class type;
    property uint size
    {
@@ -136,7 +164,7 @@ public:
       {
          if(((ArrayImpl)this).array)
          {
-            if(value == size) 
+            if(value == size)
                return;
             ((ArrayImpl)this).array = renew0 ((ArrayImpl)this).array byte[type.typeSize * value];
          }
@@ -153,12 +181,16 @@ public:
          memcpy(((ArrayImpl)this).array, value, type.typeSize * size);
       }
    }
+private:
+   uint size;
 };
 
 public class UndoAction : struct
 {
 public:
    subclass(UndoAction) type;
+   bool continued;
+
    virtual void Undo(void * data) { type.Undo(this, data); }
    virtual void Redo(void * data) { type.Redo(this, data); }
 #ifdef _DEBUG
@@ -180,6 +212,8 @@ public:
    void * data;
    int dontRecord;
    bool insideRedo;
+   bool recordAsOne;
+   bool firstEvent;
 
    dontRecord = 0;
 
@@ -187,38 +221,46 @@ public:
    {
       actions.Free();
    }
-   
+
    void Undo()
    {
-      dontRecord++;
-      if(curAction > 0)
+      bool continued = true;
+      while(curAction > 0 && continued)
       {
          UndoAction action = actions[--curAction];
+         dontRecord++;
+
 #ifdef _DEBUG
          /*Print("Undoing: ");
          action.Print(data);*/
 #endif
          action.Undo(data);
+         dontRecord--;
+
+         continued = curAction > 0 && actions[curAction-1].continued;
       }
-      dontRecord--;
    }
 
    void Redo()
    {
-      dontRecord++;
-      insideRedo = true;
-      if(curAction < count)
+      bool continued = true;
+      while(curAction < count && continued)
       {
          UndoAction action = actions[curAction];
+         continued = action.continued;
+         dontRecord++;
+         insideRedo = true;
+
          curAction++;
 #ifdef _DEBUG
          /*Print("Redoing: ");
          action.Print(data);*/
 #endif
          action.Redo(data);
+
+         insideRedo = false;
+         dontRecord--;
       }
-      insideRedo = false;
-      dontRecord--;
    }
 
    void Record(UndoAction action)
@@ -241,6 +283,12 @@ public:
          /*Print("Recording: ");
          action.Print(data);*/
 #endif
+         if(recordAsOne)
+         {
+            if(!firstEvent && count > 0)
+               actions[count-1].continued = true;
+            firstEvent = false;
+         }
          actions[count++] = action;
          curAction = count;
 
@@ -250,21 +298,33 @@ public:
       else
          delete action;
    }
+
+   void Clear()
+   {
+      actions.Free();
+      actions.size = 8;
+      count = 0;
+      curAction = 0;
+      firstEvent = true;
+   }
 };
 
 static class AddCharAction : UndoAction
 {
    int y, x;
    unichar ch;
-   int addedSpaces, addedTabs;
+   int addedSpaces, addedTabs, xAdjustment;
    type = class(AddCharAction);
 
    void Undo(EditBox editBox)
    {
-      editBox.GoToPosition(null, (ch == '\n') ? (y + 1) : y, (ch == '\n') ? 0 : (x + 1));
+      editBox.GoToPosition(null, (ch == '\n') ? (y + 1) : y, (ch == '\n') ? 0 : (x + 1) - xAdjustment);
       editBox.BackSpace();
       if(addedTabs || addedSpaces)
-         editBox.DelCh(editBox.line, y, x - (addedSpaces + addedTabs), editBox.line, y, x, false);
+      {
+         editBox.DelCh(editBox.line, y, x - xAdjustment - (addedSpaces + addedTabs), editBox.line, y, x - xAdjustment, false);
+         editBox.GoToPosition(editBox.line, y, x);
+      }
       editBox.UpdateDirty();
    }
 
@@ -286,7 +346,7 @@ static class AddTextAction : UndoAction
 {
    int y1, x1, y2, x2;
    char * string;
-   int addedSpaces, addedTabs;
+   int addedSpaces, addedTabs, xAdjustment;
    type = class(AddTextAction);
 
 #ifdef _DEBUG
@@ -329,14 +389,14 @@ static class DelTextAction : UndoAction
 {
    int y1, x1, y2, x2;
    char * string;
-   bool placeAfter;
+   bool placeAfter, noHighlight;
    int addedSpaces;
    type = class(DelTextAction);
 
 #ifdef _DEBUG
    void Print(EditBox editBox)
    {
-      PrintLn("DelText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", string = ", string, ", addedSpaces = ", addedSpaces, ", placeAfter = ", placeAfter);   
+      PrintLn("DelText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", string = ", string, ", addedSpaces = ", addedSpaces, ", placeAfter = ", placeAfter);
    }
 #endif
    void Undo(EditBox editBox)
@@ -347,8 +407,11 @@ static class DelTextAction : UndoAction
       if(!placeAfter)
       {
          editBox.GoToPosition(null, y1, x1);
-         editBox.selY = y2;
-         editBox.selX = x2;
+         if(!noHighlight)
+         {
+            editBox.selY = y2;
+            editBox.selX = x2;
+         }
          { int c; editBox.selLine = editBox.lines.first; for(c = 0; c < editBox.selY && editBox.selLine; c++, editBox.selLine = editBox.selLine.next); }
          //editBox.SetViewToCursor(true);
 
@@ -356,10 +419,13 @@ static class DelTextAction : UndoAction
             editBox.DelCh(editBox.line, y1, x1 - addedSpaces, editBox.line, y1, x1, false);
       }
       else
-      {  
-         editBox.selY = y1;
-         editBox.selX = x1;
-         { int c; editBox.selLine = editBox.lines.first; for(c = 0; c < editBox.selY && editBox.selLine; c++, editBox.selLine = editBox.selLine.next); }         
+      {
+         if(!noHighlight)
+         {
+            editBox.selY = y1;
+            editBox.selX = x1;
+         }
+         { int c; editBox.selLine = editBox.lines.first; for(c = 0; c < editBox.selY && editBox.selLine; c++, editBox.selLine = editBox.selLine.next); }
          //editBox.SetViewToCursor(true);
 
          if(addedSpaces)
@@ -395,14 +461,14 @@ static class ReplaceTextAction : UndoAction
    char * oldString;
    char * newString;
    bool placeAfter;
-   int addedSpaces, addedTabs;
+   int addedSpaces, addedTabs, xAdjustment;
 
    type = class(ReplaceTextAction);
 
 #ifdef _DEBUG
    void Print(EditBox editBox)
    {
-      PrintLn("ReplaceText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", y3 = ", y3, ", x3 = ", x3, ", oldString = ", oldString, ", newString = ", newString, ", addedSpaces = ", addedSpaces, ", addedTabs = ", addedTabs, ", placeAfter = ", placeAfter);   
+      PrintLn("ReplaceText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", y3 = ", y3, ", x3 = ", x3, ", oldString = ", oldString, ", newString = ", newString, ", addedSpaces = ", addedSpaces, ", addedTabs = ", addedTabs, ", placeAfter = ", placeAfter);
    }
 #endif
    void Undo(EditBox editBox)
@@ -461,7 +527,7 @@ static class ReplaceTextAction : UndoAction
 /*
 static class MoveTextAction : UndoAction
 {
-   int fy1, fx1, fy2, fx2; 
+   int fy1, fx1, fy2, fx2;
    int ty, tx;
    type = class(MoveTextAction);
 
@@ -484,7 +550,7 @@ public class EditLine : struct
    int length;
    EditBox editBox;
 public:
-   property char * text
+   property const char * text
    {
       set
       {
@@ -510,7 +576,7 @@ private:
    {
       char * buffer;
       int newSize;
-      
+
       // Adds '\0' byte
       count = count+1;
 
@@ -572,7 +638,7 @@ public struct BufferLocation
             if(y > end.y)
                y -= end.y - start.y;
             // Location is the last touched line
-            else 
+            else
             {
                if(x >= end.x)
                {
@@ -604,7 +670,7 @@ public struct BufferLocation
                for(c = 0, line = start.line; c<numLines; c++)
                   line = line.next;
                y += numLines;
-               //x += numLines ? end.x : (end.x - start.x);            
+               //x += numLines ? end.x : (end.x - start.x);
                x += end.x - start.x;
             }
          }
@@ -614,17 +680,18 @@ public struct BufferLocation
 
 public enum EditBoxFindResult { notFound, found, wrapped };
 
-static char * keyWords1[] =
+static const char * keyWords1[] =
 {
    // C
    "return","break","continue","default","switch","case","if","else","for","while", "do","long","short",
-   "void", "char","int","float","double","unsigned","static", "extern", "struct", "union", "typedef","enum",
+   "void", "char","int","float","double","signed","unsigned","static", "extern", "struct", "union", "typedef","enum",
    "const",   "sizeof",
    "#include", "#define", "#pragma", "#if", "#else", "#elif", "#ifdef", "#ifndef", "#endif", "#undef", "#line",
    "__attribute__", "__stdcall", "_stdcall",
    "__declspec", "goto",
     "inline", "__inline__", "_inline", "__inline", "__typeof","__extension__",
    "asm", "__asm", "_asm", "volatile", "#cpu", "__stdcall__",
+   "__restrict__", "__restrict", "restrict",
 
    // eC
    "class", "private", "public",
@@ -651,12 +718,14 @@ static char * keyWords1[] =
    null
 };
 
-static char * keyWords2[] =
+static const char * keyWords2[] =
 {
-   "defined", "warning", null
+   "defined", "warning",
+   "include", "pragma", "elif", "ifdef", "ifndef", "endif", "undef", "line",
+   null
 };
 
-static char ** keyWords[] = { keyWords1, keyWords2 };
+static const char ** keyWords[] = { keyWords1, keyWords2 };
 #define NUM_KEYWORD_GROUPS (sizeof(keyWords) / sizeof(char **))
 //static int * keyLen[NUM_KEYWORD_GROUPS];
 static int keyLen[NUM_KEYWORD_GROUPS][sizeof(keyWords1)];
@@ -715,7 +784,7 @@ public:
    property bool textVertScroll { property_category $"Behavior" set { style.vScroll = value; } get { return style.vScroll; } };
    property bool readOnly
    {
-      property_category $"Behavior" 
+      property_category $"Behavior"
       set
       {
          style.readOnly = value;
@@ -749,13 +818,16 @@ public:
    property EditLine firstLine { get { return lines.first; } };      // Change these to a List<EditLine>... (this.lines[10].text)
    property EditLine lastLine  { get { return lines.last; } };
    property EditLine line { get { return this.line; } }; // TODO: Add Set   this.line = this.lines[10]
-   property char * contents
+   property const char * contents
    {
-      property_category $"Data" 
+      property_category $"Data"
       set
       {
          if(this)
          {
+            undoBuffer.Clear();
+
+            undoBuffer.dontRecord++;
             Deselect();
             DelCh(this.lines.first, 0, 0, this.lines.last, this.lineCount-1, ((EditLine)(this.lines.last)).count, true);
             if(value)
@@ -763,6 +835,7 @@ public:
             //SetViewToCursor(true);
             UpdateDirty();
             Home();
+            undoBuffer.dontRecord--;
          }
       }
 
@@ -774,7 +847,7 @@ public:
             /* Can't implement this right now because of memory leak... Need string reference counting...
             if(style.multiLine)
             {
-               
+
                EditLine line;
                int len = 0;
 
@@ -807,7 +880,7 @@ public:
          char * buffer = null;
          if(style.multiLine)
          {
-            
+
             EditLine line;
             int len = 0;
 
@@ -823,7 +896,7 @@ public:
                len += lineLen;
                if(line.next) buffer[len++] = '\n';
             }
-            buffer[len] = '\0';         
+            buffer[len] = '\0';
          }
          return buffer;
       }
@@ -839,7 +912,7 @@ public:
       return null;
    }
 
-   void SetLineText(char * text)
+   void SetLineText(const char * text)
    {
       if(this)
       {
@@ -850,6 +923,7 @@ public:
    property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
    property Color selectionText  { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
    property SyntaxColorScheme syntaxColorScheme { set { delete colorScheme; colorScheme = value; incref colorScheme; } }
+   property bool recordUndoEvent { set { undoBuffer.recordAsOne = value; undoBuffer.firstEvent = true; } get { return undoBuffer.recordAsOne; } };
 
    // selectionStart.line, selectionStart.column (With Set)
    // selection.line1, selection.line2, selection.column1, selection.column2  (Read only)
@@ -865,7 +939,7 @@ private:
    int lineCount;
    // Font Space size
    Size space, large;
-   
+
    // Position of Caret (Not necessarily displayed position)
    int x,y;
    int col;
@@ -881,7 +955,7 @@ private:
    // ViewX is x offset in pixels, ViewY is y offset in lines
    int viewX, viewY;
    // viewLine is first displayed line
-   EditLine viewLine; 
+   EditLine viewLine;
 
    // start and end of area to redraw
    int startY, endY;
@@ -915,7 +989,7 @@ private:
 
    bool modified;
 
-   void (* FontExtent)(Display display, Font font, char * text, int len, int * width, int * height);
+   void (* FontExtent)(Display display, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang);
 
    Color backColor;
    bool rightButtonDown;
@@ -923,7 +997,7 @@ private:
    int caretX, caretY;
    UndoBuffer undoBuffer { data = this };
    int savedAction;
-   Color selectionColor, selectionText;
+   ColorAlpha selectionColor, selectionText;
    SyntaxColorScheme colorScheme { };
 
    menu = Menu { };
@@ -954,7 +1028,7 @@ private:
    MenuItem itemEditPaste
    {
       editMenu, $"Paste\tCtrl+V", p;
-   
+
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
          if(!(style.readOnly))
@@ -1069,7 +1143,7 @@ private:
       {
          ReplaceDialog dialog
          {
-            master = master, 
+            master = master,
             isModal = true,
             searchString = searchString,
             replaceString = replaceString,
@@ -1082,7 +1156,7 @@ private:
             void NotifyDestroyed(Window window, DialogResult result)
             {
                ReplaceDialog dialog = (ReplaceDialog)window;
-               char * replace = dialog.replaceString;
+               const char * replace = dialog.replaceString;
                if(replace)
                   strcpy(replaceString, replace);
                strcpy(searchString, dialog.searchString);
@@ -1126,7 +1200,7 @@ private:
    EditBox()
    {
       static bool syntaxInit = false;
-      if(!syntaxInit) 
+      if(!syntaxInit)
       {
          int g,c;
          syntaxInit = true;
@@ -1148,9 +1222,9 @@ private:
          colorScheme.keywordColors = [ blue, blue ];
       }
 
-      FontExtent = Display::FontExtent;
+      FontExtent = Display::FontExtent2;
       font = fontObject;
-      lines.offset = (uint)&((EditLine)0).prev;
+      lines.offset = (uint)(uintptr)&((EditLine)0).prev;
 
       style = EditBoxBits { hScroll = true };
 
@@ -1164,7 +1238,7 @@ private:
       maxLineSize = MAXINT;
 
       tabSize = 3;
-      
+
       overwrite = false;
       mouseSelect = this.mouseMove = false;
       line = null;
@@ -1173,7 +1247,7 @@ private:
       col = 0;
       y = -1;
       line = selLine = null;
-      viewX = 0;   
+      viewX = 0;
       viewY = 0;
       maxLength = 0;
       maxLine = null;
@@ -1204,7 +1278,7 @@ private:
       lines.Free(EditLine::Free);
    }
 
-   void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int numSpaces, Box box)
+   void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int * previousGlyph, int * oh, int numSpaces, bool drawSpaces, Box box)
    {
       int count = wc - *renderStart;
       if(count)
@@ -1215,28 +1289,34 @@ private:
 
             if(!numSpaces)
             {
+               int coh;
                //FontExtent(display, font, line.buffer + *renderStart, count, &w, null);
                surface.TextFont(font);
-               surface.TextExtent(line.buffer + *renderStart, count, &w, null);
-               if(*x + w + XOFFSET > 0)
-                  surface.WriteText(XOFFSET + *x,y, line.buffer + *renderStart, count);
+               surface.TextExtent2(line.buffer + *renderStart, count, &w, null, *previousGlyph, null, &coh);
+
+               if(*x + w + coh + XOFFSET > 0)
+               {
+                  surface.WriteText2(XOFFSET + *x,y, line.buffer + *renderStart, count, *previousGlyph, previousGlyph);
+                  *oh = coh;
+                  //surface.WriteText(XOFFSET + *x,y, line.buffer + *renderStart, count);
+               }
                *x += w;
             }
             else
             {
                w = numSpaces; // * space.w;
-               if(*x + w + XOFFSET > 0 && surface.GetTextOpacity())
-                  surface.Area(XOFFSET + *x - 1, y, XOFFSET + *x + w, y + space.h-1);
+               if(*x + w + XOFFSET > 0 && (drawSpaces))
+                  surface.Area(XOFFSET + *x /*- 1*/ + *oh, y, XOFFSET + *x + w, y + space.h-1);
                   // WHATS UP WITH THIS...  surface.Area(XOFFSET + *x, y, XOFFSET + *x + w, y + space.h-1);
                *x += w;
-            }      
+            }
          }
          *renderStart = wc;
       }
    }
 
-   int CheckColors(EditLine line, int wc, bool selection, int selX, int editX, bool *selected, 
-                   Color selectionForeground, Color selectionBackground, Color textColor, Color *foreground, Color *background, bool *opacity, bool *overwrite)
+   bool CheckColors(EditLine line, int wc, bool selection, int selX, int editX, bool *selected,
+                    Color selectionForeground, Color selectionBackground, Color textColor, Color *foreground, Color *background, bool *opacity, int *overwrite)
    {
       bool flush = false;
 
@@ -1260,7 +1340,7 @@ private:
          if((style.stuckCaret && wc == line.count && !line.next) ||
             (!mouseMove && line == this.line && wc == editX))
          {
-            *overwrite = true;
+            *overwrite = 1;
             flush = true;
          }
       }
@@ -1272,12 +1352,15 @@ private:
       if(style.syntax)
       {
          bool inMultiLineComment = reset ? false : style.inMultiLineComment;
+         bool wasInMultiLine = reset ? false : style.wasInMultiLine;
          bool inString = false;
          bool inQuotes = false;
          bool inPrep = reset ? false : style.inPrep;
          bool inSingleLineComment = false;
          bool escaped = reset ? false : style.escaped;
          bool continuedSingleLineComment = reset ? false : style.continuedSingleLineComment;
+         bool continuedString = reset ? false : style.continuedString;
+         bool continuedQuotes = reset ? false : style.continuedQuotes;
 
          EditLine line = reset ? lines.first : firstLine;
          // int maxBackUp = 1000, c;
@@ -1292,16 +1375,18 @@ private:
             if(!escaped) inPrep = false;
             inSingleLineComment = continuedSingleLineComment;
             escaped = false;
-            inString = false;
-            inQuotes = false;
+            inString = continuedString;
+            inQuotes = continuedQuotes;
 
             firstWord = true;
             for(c = 0; (ch = text[c]); c++)
             {
                bool wasEscaped = escaped;
                bool backLastWasStar = lastWasStar;
+               bool backWasInMultiLine = wasInMultiLine;
                escaped = false;
                lastWasStar = false;
+               wasInMultiLine = inMultiLineComment;
                if(ch == '/')
                {
                   if(!inSingleLineComment && !inMultiLineComment && !inQuotes && !inString)
@@ -1320,7 +1405,7 @@ private:
                }
                else if(ch == '*')
                {
-                  if(!c || text[c-1] != '/') lastWasStar = true;
+                  if(backWasInMultiLine) lastWasStar = true;
                }
                else if(ch == '\"' && !inSingleLineComment && !inMultiLineComment && !inQuotes)
                {
@@ -1357,16 +1442,30 @@ private:
                else if(ch != ' ' && ch != '\t')
                   firstWord = false;
             }
-            continuedSingleLineComment = inSingleLineComment && (line.count && line.text[line.count - 1] == '\\');
+            if(line.count && line.text[line.count - 1] == '\\')
+            {
+               continuedSingleLineComment = inSingleLineComment;
+               continuedString = inString;
+               continuedQuotes = inQuotes;
+            }
+            else
+            {
+               continuedSingleLineComment = false;
+               continuedString = false;
+               continuedQuotes = false;
+            }
          }
-         
+
          style.continuedSingleLineComment = continuedSingleLineComment;
+         style.continuedString = continuedString;
+         style.continuedQuotes = continuedQuotes;
          style.inMultiLineComment = inMultiLineComment;
+         style.wasInMultiLine = wasInMultiLine;
          style.inPrep = inPrep;
          style.escaped = escaped;
       }
    }
-   
+
    /*void OnDrawOverChildren(Surface surface)
    {
       if(style.lineNumbers)
@@ -1384,18 +1483,37 @@ private:
             else
                surface.SetBackground(Color{230, 230, 230});
             surface.textOpacity = true;
-            
+
             sprintf(lineText,"%5u ", currentLineNumber % 100000);
             if(currentLineNumber > this.lineCount)
                surface.WriteText(0,i*space.h+1,"      ",6);
             else
                surface.WriteText(0,i*space.h+1,lineText,6);
-            
+
             currentLineNumber++;
          }
       }
    }*/
 
+   static inline int countTabsExtraSpaces(char * buffer, int tabSize, int start, int end)
+   {
+      // TODO: Handle tabs position properly with UTF-8 (and everywhere else)
+      int p = 0, i, extra = 0;
+      for(i = 0; i < end; i++)
+      {
+         if(buffer[i] == '\t')
+         {
+            int t = tabSize - (p % tabSize);
+            p += t;
+            if(i >= start)
+               extra += t-1;
+         }
+         else
+            p++;
+      }
+      return extra;
+   }
+
    void OnRedraw(Surface surface)
    {
       EditLine line;
@@ -1408,14 +1526,14 @@ private:
       Color textColor;
       Box box;
       int maxW = clientSize.w;
-      
+
       Color foreground, background;
       bool opacity;
 
       // Overwrite Caret Stuff
-      bool overWrite = false;
-      int overWriteX, overWriteY;
-      byte overWriteCh;
+      int overWrite = 0;
+      int overWriteX = 0, overWriteY = 0;
+      char overWriteCh;
 
       // ****** SYNTAX STATES ******
       bool inMultiLineComment = style.inMultiLineComment;
@@ -1425,15 +1543,25 @@ private:
       bool inSingleLineComment = false;
       bool escaped = style.escaped;
       bool continuedSingleLineComment = style.continuedSingleLineComment;
+      bool continuedString = style.continuedString;
+      bool continuedQuotes = style.continuedQuotes;
+      bool wasInMultiLine = style.wasInMultiLine;
       // ****** ************* ******
 
+      // For drawing selection background
+      EditLine selStartLine = this.y < this.selY ? this.line : this.selLine;
+      EditLine selEndLine   = this.y < this.selY ? this.selLine : this.line;
+      int selStartX = this.y < this.selY || (this.y == this.selY && this.x < this.selX) ? this.x : this.selX;
+      int selEndX   = this.y > this.selY || (this.y == this.selY && this.x > this.selX) ? this.x : this.selX;
+      ///////////////////////////////////
+
       if(!isEnabled)
          defaultTextColor = Color { 85, 85, 85 };
       textColor = defaultTextColor;
 
       if(
-         Abs(selectionBackground.r - property::background.r) + 
-         Abs(selectionBackground.g - property::background.g) + 
+         Abs(selectionBackground.r - property::background.r) +
+         Abs(selectionBackground.g - property::background.g) +
          Abs(selectionBackground.b - property::background.b) < 92)
       {
          selectionBackground = formColor;
@@ -1461,7 +1589,7 @@ private:
          selX  = this.selX;
       }
       else
-      {  
+      {
          editX = Min(this.x,this.line.count);
          selX  = Min(this.selX,this.selLine.count);
       }
@@ -1477,7 +1605,7 @@ private:
    */
       surface.SetForeground(foreground);
       surface.SetBackground(background);
-      surface.TextOpacity(opacity);
+      surface.TextOpacity(false);
 
       surface.GetBox(box);
 
@@ -1489,16 +1617,17 @@ private:
          int start = 0;
          Color newTextColor = textColor = defaultTextColor;
          bool lineComplete = false;
-        
+         int overHang = 0;
 
          // ****** SYNTAX HIGHLIGHTING ******
          bool lastWasStar = false;
+         bool trailingSpace = false;
          bool firstWord = true;
          if(!escaped) inPrep = false;
          inSingleLineComment = continuedSingleLineComment;
          escaped = false;
-         inString = false;
-         inQuotes = false;
+         inString = continuedString;
+         inQuotes = continuedQuotes;
          // *********************************
 
    /*   === DEBUGGING TOOL FOR MAXLINE ===
@@ -1514,7 +1643,65 @@ private:
             surface.SetBackground(selected ? SELECTION_COLOR|0xFF000000 : BLACK|0xFF000000);
          }
    */
-         
+
+         // Draw Selection Background all at once here
+         if(selected || line == this.line || line == this.selLine)
+         {
+            int sx = XOFFSET + x, sy = y;
+            int tw, th;
+            int oh = 0;
+            char * buffer = line.buffer;
+            if(line != this.line && line != this.selLine)
+            {
+               if(style.freeCaret)
+               {
+                  tw = clientSize.w - sx;
+                  th = space.h;
+               }
+               else
+               {
+                  surface.TextExtent2(buffer, line.count, &tw, &th, 0, null, &oh);
+                  tw += countTabsExtraSpaces(buffer, tabSize, 0, line.count) * space.w;
+               }
+            }
+            else if(line == selStartLine)
+            {
+               int prevGlyph = 0;
+               int start = Min(line.count, selStartX);
+               int end   = Min(line.count, selEndX);
+               surface.TextExtent2(buffer, start, &tw, &th, 0, &prevGlyph, null);
+               sx += tw;
+               sx += countTabsExtraSpaces(buffer, tabSize, 0, start) * space.w;
+               if(selStartX > start) sx += space.w * (selStartX - start);
+               if(style.freeCaret && line != selEndLine)
+               {
+                  tw = clientSize.w - sx;
+                  th = space.h;
+               }
+               else if(line != selEndLine)
+               {
+                  surface.TextExtent2(buffer + start, line.count - start, &tw, &th, prevGlyph, null, &oh);
+                  tw += countTabsExtraSpaces(buffer, tabSize, start, line.count) * space.w;
+               }
+               else
+               {
+                  surface.TextExtent2(buffer + start, end - start, &tw, &th, prevGlyph, null, &oh);
+                  tw += countTabsExtraSpaces(buffer, tabSize, start, end) * space.w;
+                  end = Max(end, selStartX);
+                  if(selEndX > end) { tw += space.w * (selEndX - end); th = space.h; }
+               }
+            }
+            else if(line == selEndLine)
+            {
+               int end = Min(line.count, selEndX);
+               surface.TextExtent2(buffer, end, &tw, &th, 0, null, &oh);
+               tw += countTabsExtraSpaces(buffer, tabSize, 0, end) * space.w;
+               if(selEndX - end) { tw += space.w * (selEndX - end); th = space.h; }
+            }
+            tw += oh;
+            surface.Area(sx, sy, sx + tw-1, sy + th-1);
+         }
+
          if(line == this.selLine && line == this.line)
          {
             end = Max(line.count, this.x);
@@ -1541,7 +1728,7 @@ private:
                y += space.h;
                lineComplete = false;
             }
-            
+
             textColor = newTextColor;
             if(!selected)
             {
@@ -1571,21 +1758,24 @@ private:
                   unichar bf = (wordLen == 1) ? line.buffer[c-1] : 0;
                   //if(ch == ' ' || ch == '\t' || (wordLen && (ch == '(' || ch == ')' || ch == ';' || ch == ':')) || (wordLen == 1 && line.buffer[c-1] == '('))
                   if(CharMatchCategories(ch, separators) || /*ch == ' ' ||*/ ch == '\t' ||
-                     (wordLen && !CharMatchCategories(ch, numbers|letters|marks|connector) && ch != '#' /*&& ch != '_'*/) || 
+                     (wordLen && !CharMatchCategories(ch, numbers|letters|marks|connector) && ch != '#' /*&& ch != '_'*/) ||
                      (bf && !CharMatchCategories(bf, numbers|letters|separators|marks|connector) && bf != '#' && bf != '\t' /*&& bf != '_' && bf != ' '*/))
                      break;
                   wordLen++;
+                  trailingSpace = false;
                }
 
                if(!wordLen)
                {
-               
+
                   for(; c<line.count; c++)
                   {
                      unichar ch = line.buffer[c];
                      if(ch == '\t' || ch == ' ')
                      {
                         cantHaveWords = true;
+                        if(ch == ' ' && c == line.count-1)
+                           trailingSpace = true;
                         if(bufferLen)
                            break;
                      }
@@ -1621,6 +1811,7 @@ private:
                      bool backInQuotes = inQuotes;
                      bool backInPrep = inPrep;
                      bool backInSingleLineComment = inSingleLineComment;
+                     bool backWasInMultiLine = wasInMultiLine;
 
                      char * word = line.buffer + c - wordLen;
                      int g,ccc;
@@ -1628,6 +1819,8 @@ private:
                      escaped = false;
                      lastWasStar = false;
 
+                     wasInMultiLine = inMultiLineComment;
+
                      // Determine Syntax Highlighting
                      newTextColor = defaultTextColor;
                      if(style.syntax)
@@ -1668,7 +1861,7 @@ private:
                         }
                         else if(wordLen == 1 && word[0] == '*')
                         {
-                           if(!c || word[-1] != '/')
+                           if(backWasInMultiLine)
                               lastWasStar = true;
                         }
                         else if(!inSingleLineComment && !inMultiLineComment && !inQuotes && wordLen == 1 && word[0] == '\"')
@@ -1698,10 +1891,82 @@ private:
                            if(!wasEscaped)
                               escaped = true;
                         }
-                        else if(!inQuotes && !inString && !inMultiLineComment && !inSingleLineComment && 
-                           ( ( isdigit(word[0]) /*&& (!c || word[-1] == ' ' || word[-1] == '\t')*/ ) || (word[0] == '.' && isdigit(word[1]))))
+                        else if(x < box.right && !inQuotes && !inString && !inMultiLineComment && !inSingleLineComment && (isdigit(word[0]) || (word[0] == '.' && isdigit(word[1]))))
                         {
-                           newTextColor = colorScheme.numberColor;
+                           char * dot = word[wordLen] == '.' ? word + wordLen : (word[0] == '.' && (word == line.buffer || word[-1] == '-' || isspace(word[-1])) ? word : null);
+                           bool isReal = dot != null;
+                           char * s = null;
+                           if(dot)
+                              isReal = true;
+                           else
+                           {
+                              char * exponent;
+                              bool isHex = (word[0] == '0' && (word[1] == 'x' || word[1] == 'X'));
+                              if(isHex)
+                              {
+                                 exponent = strchrmax(word, 'p', wordLen);
+                                 if(!exponent) exponent = strchrmax(word, 'P', wordLen);
+                              }
+                              else
+                              {
+                                 exponent = strchrmax(word, 'e', wordLen);
+                                 if(!exponent) exponent = strchrmax(word, 'E', wordLen);
+                              }
+                              isReal = exponent != null;
+                           }
+                           if(isReal)
+                              strtod(word, &s);      // strtod() seems to break on hex floats (e.g. 0x23e3p12, 0x1.fp3)
+                           else
+                              strtol(word, &s, 0);
+                           if(s && s != word)
+                           {
+                              // Check suffixes
+                              char ch;
+                              int i;
+                              int gotF = 0, gotL = 0, gotU = 0, gotI = 0;
+                              bool valid = true;
+
+                              for(i = 0; valid && i < 5 && (ch = s[i]) && (isalnum(ch) || ch == '_'); i++)
+                              {
+                                 switch(ch)
+                                 {
+                                    case 'f': case 'F': gotF++; if(gotF > 1 || !isReal) valid = false; break;
+                                    case 'l': case 'L':
+                                       gotL++;
+                                       if(gotL > 2 || (isReal && (gotL == 2 || gotF)) || (gotL == 2 && (s[i-1] != ch)))
+                                       valid = false;
+                                       break;
+                                    case 'u': case 'U': gotU++; if(gotU > 1 || isReal) valid = false; break;
+                                    case 'i': case 'I': case 'j': case 'J': gotI++; if(gotI > 1) valid = false; break;
+                                    default: valid = false;
+                                 }
+                              }
+
+                              // Don't highlight numbers with too many decimal points
+                              if(s[0] == '.' && isdigit(s[1]))
+                              {
+                                 int newWordLen;
+                                 while(s[0] == '.' && isdigit(s[1]))
+                                 {
+                                    int newWordLen = s - word;
+                                    c += newWordLen - wordLen;
+                                    wordLen = newWordLen;
+                                    strtod(s, &s);
+                                 }
+                                 newWordLen = s - word;
+                                 c += newWordLen - wordLen;
+                                 wordLen = newWordLen;
+                              }
+                              else if(valid)
+                              {
+                                 int newWordLen = s + i - word;
+                                 newTextColor = colorScheme.numberColor;
+                                 c += newWordLen - wordLen;
+                                 wordLen = newWordLen;
+                              }
+                              else if(dot && dot > word && dot < s)
+                                 newTextColor = colorScheme.numberColor;
+                           }
                         }
                         else
                         {
@@ -1710,14 +1975,14 @@ private:
                               if(firstWord)
                               {
                                  inPrep = true;
-                                 newTextColor = colorScheme.preprocessorColor; 
+                                 newTextColor = wordLen == 1 ? colorScheme.keywordColors[1] : colorScheme.preprocessorColor;
                               }
                            }
-                           if(!inQuotes && !inString && !inMultiLineComment && !inSingleLineComment)
+                           if(x < box.right && !inQuotes && !inString && !inMultiLineComment && !inSingleLineComment)
                            {
                               for(g = 0; g < ((inPrep && word[0] != '#') ? 2 : 1); g++)
                               {
-                                 char ** keys = keyWords[g];
+                                 const char ** keys = keyWords[g];
                                  int * len = keyLen[g];
                                  for(ccc = 0; keys[ccc]; ccc++)
                                  {
@@ -1748,6 +2013,7 @@ private:
                               inQuotes = backInQuotes;
                               inPrep = backInPrep;
                               inSingleLineComment = backInSingleLineComment;
+                              wasInMultiLine = backWasInMultiLine;
                               break;
                            }
                            else
@@ -1762,7 +2028,7 @@ private:
                         }
                      }
                   }
-               
+
                   // If we're not breaking, this can't be rendered as spacing anymore
                   spacing = false;
 
@@ -1772,7 +2038,8 @@ private:
                      //if(!numSpaces)
                      {
                         int tw;
-                        FontExtent(display, font, line.buffer + start, bufferLen + wordLen, &tw, null);
+                        int oh;
+                        FontExtent(display, font, line.buffer + start, bufferLen + wordLen, &tw, null, 0, null, &oh);
                         w = tw;
                      }
                      /*else
@@ -1781,9 +2048,13 @@ private:
                      }*/
                      if(x + viewX + w > maxW)
                      {
-                        c -= wordLen;
-                        lineComplete = true;                        
-                        break;
+                        // Avoid an endless loop until we fix wrapping
+                        if(c - wordLen > start)
+                        {
+                           c -= wordLen;
+                           lineComplete = true;
+                           break;
+                        }
                      }
                   }
                }
@@ -1794,15 +2065,17 @@ private:
             {
                int renderStart = start;
                bool flush = false;
+               bool flagTrailingSpace = false;
                int numSpaces = 0;
                int wc;
+               int previousGlyph = 0;
 
                // Render checking if we need to split because of selection or to find where to draw insert caret
                for(wc = start; wc < start + bufferLen; wc++)
                {
                   flush = CheckColors(line, wc, selection, selX, editX, &selected, selectionForeground,
                      selectionBackground, textColor, &foreground, &background, &opacity, &overWrite);
-                  if(overWrite == true)
+                  if(overWrite == 1)
                   {
                      overWriteCh = (wc < line.count) ? line.buffer[wc] : ' ';
                      if(overWriteCh == '\t') overWriteCh = ' ';
@@ -1810,8 +2083,11 @@ private:
 
                   if(flush)
                   {
-                     FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, box);
-                     if(overWrite == true)
+                     flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line;
+                     if(flagTrailingSpace) surface.SetBackground(red);
+                     FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box);
+                     if(flagTrailingSpace) surface.SetBackground(background);
+                     if(overWrite == 1)
                      {
                         overWriteX = x;
                         overWriteY = y;
@@ -1819,8 +2095,6 @@ private:
                      }
                      numSpaces = 0;
 
-                     surface.TextOpacity(opacity);
-                     surface.SetBackground(background);
                      surface.SetForeground(foreground);
 
                      flush = false;
@@ -1838,7 +2112,10 @@ private:
                      }
                   }
                }
-               FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, box);
+               flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line;
+               if(flagTrailingSpace) surface.SetBackground(red);
+               FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box);
+               if(flagTrailingSpace) surface.SetBackground(background);
                start += bufferLen;
             }
          }
@@ -1846,38 +2123,32 @@ private:
          if(CheckColors(line, c, selection, selX, editX, &selected, selectionForeground,
                         selectionBackground, textColor, &foreground, &background, &opacity, &overWrite))
          {
-            if(overWrite == true)
+            if(overWrite == 1)
             {
                overWriteX = x;
                overWriteY = y;
                overWriteCh = ' ';
                overWrite = 2;
             }
-            surface.TextOpacity(opacity);
             surface.SetBackground(background);
             surface.SetForeground(foreground);
          }
 
-         if(style.freeCaret && selected)
+         if(line.count && line.text[line.count - 1] == '\\')
          {
-            surface.SetBackground(selectionBackground);
-            surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1);
-            // TEST: surface.Area(x + XOFFSET,y,clientSize.w-1,y+this.space.h-1);
+            continuedSingleLineComment = inSingleLineComment;
+            continuedString = inString;
+            continuedQuotes = inQuotes;
          }
-
-
-         /*
-         if(style.freeCaret && selected)
+         else
          {
-            surface.SetBackground(selectionBackground);
-            surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1);
+            continuedSingleLineComment = false;
+            continuedString = false;
+            continuedQuotes = false;
          }
-         */
-         
-         continuedSingleLineComment = inSingleLineComment && (line.count && line.text[line.count - 1] == '\\');
 
          y+=this.space.h;
-         if(y > box.bottom) // >=clientSize.h) 
+         if(y > box.bottom) // >=clientSize.h)
             break;
       }
 
@@ -1901,12 +2172,12 @@ private:
             if(x > selX)
             {
                if(x > line.count)
-                  width = Max(line.length + (x - line.count) * space.w, maxLength);
+                  width = Max(line.length + (x - line.count) * space.w, maxLength + XOFFSET);
             }
             else
             {
                if(selX > selLine.count)
-                  width = Max(selLine.length + (selX - selLine.count) * space.w, maxLength);
+                  width = Max(selLine.length + (selX - selLine.count) * space.w, maxLength + XOFFSET);
             }
          }
 
@@ -1919,8 +2190,6 @@ private:
    void ComputeLength(EditLine line)
    {
       int c;
-      int tabOccur = 0;
-      int tabWidth;
       int x = 0;
 
       for(c = 0; c < line.count; )
@@ -1955,7 +2224,10 @@ private:
                len = 1;
             }
             else
-               FontExtent(display, font, line.buffer + start, len, &w, null); 
+            {
+               int oh;
+               FontExtent(display, font, line.buffer + start, len, &w, null, 0, null, &oh);
+            }
          }
          else
          {
@@ -1963,13 +2235,15 @@ private:
             c++;
          }
          x += w;
-      }               
+      }
       line.length = x;
 
       if(line.length > this.maxLength)
       {
          this.maxLine = line;
          this.maxLength = line.length;
+
+         if(style.autoSize) AutoSize();
       }
    }
 
@@ -1988,13 +2262,15 @@ private:
             this.maxLine = line;
          }
       }
+
+      if(style.autoSize) AutoSize();
    }
 
    void SelDirty()
    {
       if(this.selY != this.y)
          DirtyAll();
-      else if(this.selX != this.x)  // commented out to erase caret: if(this.selX != this.x) 
+      else if(this.selX != this.x)  // commented out to erase caret: if(this.selX != this.x)
          DirtyLine(this.y);
    }
 
@@ -2004,9 +2280,8 @@ private:
       int c, position = 0;
       unichar ch;
       int nb;
-      for(c = 0; c<this.line.count && c<this.x; c+= nb)
+      for(c = 0; c<this.line.count && c<this.x && (ch = UTF8_GET_CHAR(this.line.buffer + c, nb)); c+= nb)
       {
-         ch = UTF8_GET_CHAR(this.line.buffer + c, nb);
          // TODO: MIGHT WANT TO RETHINK WHAT COLUMN SHOULD BE REGARDING TABS
          if(ch == '\t')
             position += this.tabSize - (position % this.tabSize);
@@ -2017,16 +2292,16 @@ private:
       this.col = position;
    }
 
-   int DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter)
+   void DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter)
    {
-      return _DelCh(l1, y1, c1, l2, y2, c2, placeAfter, null);
+      _DelCh(l1, y1, c1, l2, y2, c2, placeAfter, true, null);
    }
-   
+
    bool HasCommentOrEscape(EditLine line)
    {
       bool hadComment = strstr(line.buffer, "/*") || strstr(line.buffer, "*/");
       int c;
-      
+
       if(!hadComment)
       {
          for(c = line.count-1; c >= 0; c--)
@@ -2043,8 +2318,8 @@ private:
       }
       return hadComment;
    }
-   
-   int _DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter, int * addedSpacesPtr)
+
+   int _DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter, bool highlight, int * addedSpacesPtr)
    {
       EditLine line = l1, next;
       char * buffer;
@@ -2073,7 +2348,7 @@ private:
       {
          byte ch = buffer[c1];
          if(UTF8_IS_FIRST(ch)) break;
-         c1--;         
+         c1--;
          extras++;
       }
       oldCount2 = l2.count;
@@ -2090,10 +2365,10 @@ private:
       {
          int len;
          char * string;
-         
+
          len = GetText(null, l1, y1, start, l2, y2, c2, false, false);
          string = new char[len];
-         action = DelTextAction { y1 = y1, x1 = start, y2 = y2, x2 = c2, string = string, placeAfter = placeAfter };
+         action = DelTextAction { y1 = y1, x1 = start, y2 = y2, x2 = c2, string = string, placeAfter = placeAfter, noHighlight = !highlight };
          GetText(string, l1, y1, start, l2, y2, c2, false, false);
          Record(action);
       }
@@ -2118,14 +2393,16 @@ private:
          buffer = new char[line.size ? line.size : 1];
          */
          buffer = new char[line.size];
-         if(!buffer) return;
+         // TODO: Better handling of these allocation failures
+         if(!buffer) return extras;
          CopyBytes(buffer,l2.buffer,oldCount1 + 1/*line.count + 1*//*line.size*/);
       }
       else
          buffer = l2.buffer;
 
-      if(!line.AdjustBuffer(newLineCount)) 
-         return;
+      // TODO: Better handling of these allocation failures
+      if(!line.AdjustBuffer(newLineCount))
+         return extras;
 
 #ifdef _DEBUG
       /*if(newLineCount > 4000 || newLineCount < 0)
@@ -2177,7 +2454,7 @@ private:
          {
             this.lineCount--;
             delete line.buffer;
-       
+
             if(line == this.viewLine)
             {
                if(this.viewLine.next)
@@ -2186,7 +2463,7 @@ private:
                   //this.viewY++;
                   style.recomputeSyntax = true;
                }
-               else 
+               else
                {
                   this.viewLine = this.viewLine.prev;
                   this.viewY--;
@@ -2203,7 +2480,7 @@ private:
                   this.x = this.line.count;
                   //this.y++;
                }
-               else 
+               else
                {
                   this.line = this.line.prev;
                   this.x = this.line.count;
@@ -2220,7 +2497,7 @@ private:
                   this.dropLine = this.dropLine.next;
                   this.dropX = this.dropLine.count;
                }
-               else 
+               else
                {
                   this.dropLine = this.dropLine.prev;
                   this.dropX = this.dropLine.count;
@@ -2236,7 +2513,7 @@ private:
                   this.selLine = this.selLine.next;
                   this.selX = this.selLine.count;
                }
-               else 
+               else
                {
                   this.selLine = this.selLine.prev;
                   this.selX = this.selLine.count;
@@ -2251,7 +2528,6 @@ private:
       }
       ComputeLength(l1);
       FindMaxLine();
-      if(style.autoSize) AutoSize();
       if(style.syntax && (hadComment || HasCommentOrEscape(this.line)))
       {
          DirtyAll();
@@ -2266,28 +2542,28 @@ private:
       {
          if(this.selY < this.y)
          {
-            _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, addedSpacesPtr);
+            _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, true, addedSpacesPtr);
             this.x = this.selX;
             this.y = this.selY;
             this.line = this.selLine;
          }
          else if(this.selY > this.y)
          {
-            _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, addedSpacesPtr);
+            _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, true, addedSpacesPtr);
             this.selX = this.x;
             this.selY = this.y;
             this.selLine = this.line;
          }
          else if(this.selX < this.x)
          {
-            _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, addedSpacesPtr);
+            _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, true, addedSpacesPtr);
             this.x = this.selX;
             this.y = this.selY;
             this.line = this.selLine;
          }
          else
          {
-            _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, addedSpacesPtr);
+            _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, true, addedSpacesPtr);
             this.selX = this.x;
             this.selY = this.y;
             this.selLine = this.line;
@@ -2298,12 +2574,12 @@ private:
       return false;
    }
 
-   bool AddToLine(char * stringLine, int count, bool LFComing, int * addedSpacesPtr, int * addedTabsPtr)
+   bool AddToLine(const char * stringLine, int count, bool LFComing, int * addedSpacesPtr, int * addedTabsPtr, int * xAdjustmentPtr)
    {
       bool hadComment = false;
       // Add the line here
       EditLine line = this.line;
-         
+
       // The purpose of this is solely to lock a max number of characters if no HSCROLLING is present
       if(!style.hScroll && created)
       {
@@ -2324,7 +2600,7 @@ private:
          {
             int w;
             int numBytes = 1;
-            char * string;
+            const char * string;
             if(c < Min(this.x, line.count))
                string = line.buffer + c;
             else if(c < endX)
@@ -2340,12 +2616,13 @@ private:
             }
             else
             {
+               int oh;
                numBytes = UTF8_NUM_BYTES(*string);
-               FontExtent(display, this.font, string, numBytes, &w, null);
+               FontExtent(display, this.font, string, numBytes, &w, null, 0, null, &oh);
             }
             x += w;
 
-            if(x >= clientSize.w) 
+            if(x >= clientSize.w)
             {
                count = c - max;
                break;
@@ -2358,7 +2635,8 @@ private:
       {
          int addedSpaces = 0;
          int addedTabs = 0;
-         
+         int xAdjustment = 0;
+
          // Add blank spaces if EES_FREECARET
          if(this.x > line.count)
          {
@@ -2384,6 +2662,8 @@ private:
                      addedSpaces = wantedPosition - position;
                   else
                   {
+                     xAdjustment = wantedPosition - position;
+
                      // Put a first tab
                      addedTabs = 1;
                      position += this.tabSize - (position % this.tabSize);
@@ -2392,6 +2672,8 @@ private:
                      position += (addedTabs-1) * this.tabSize;
                      // Finish off with spaces
                      addedSpaces = wantedPosition - position;
+
+                     xAdjustment -= addedSpaces + addedTabs;
                   }
                }
                else
@@ -2415,12 +2697,11 @@ private:
          {
             BufferLocation before = { this.line, this.y, this.x }, after = { this.line, this.y, this.x };
             bool hasComment;
-         
+
             memmove(line.buffer+this.x+count, line.buffer+this.x,line.count-this.x);
             CopyBytes(line.buffer + this.x + addedTabs + addedSpaces, stringLine, count);
             if(addedTabs)
             {
-               *addedTabsPtr = addedTabs;
                FillBytes(line.buffer+line.count,'\t',addedTabs);
 #ifdef _DEBUG
       if(addedTabs > 4000 || addedTabs < 0)
@@ -2428,8 +2709,7 @@ private:
 #endif
                line.count += addedTabs;
             }
-            else if(addedTabs)
-               *addedTabsPtr = 0;
+
             if(addedSpaces)
             {
                FillBytes(line.buffer+line.count,' ',addedSpaces);
@@ -2438,10 +2718,11 @@ private:
          printf("Warning");
 #endif
                line.count += addedSpaces;
-               if(addedSpacesPtr) *addedSpacesPtr = addedSpaces;
-            }      
-            else if(addedSpacesPtr)
-               *addedSpacesPtr = 0;
+            }
+
+            if(addedTabsPtr) *addedTabsPtr = addedTabs;
+            if(addedSpacesPtr) *addedSpacesPtr = addedSpaces;
+            if(xAdjustmentPtr) *xAdjustmentPtr = xAdjustment;
 #ifdef _DEBUG
       if(count > 4000 || count < 0)
          printf("Warning");
@@ -2457,7 +2738,7 @@ private:
             ComputeLength(line);
             ComputeColumn();
 
-            after.x = this.x; 
+            after.x = this.x;
 
             hasComment = HasCommentOrEscape(line);
             if(!undoBuffer.insideRedo)
@@ -2465,7 +2746,6 @@ private:
                int backDontRecord = undoBuffer.dontRecord;
                undoBuffer.dontRecord = 0;
                NotifyCharsAdded(master, this, &before, &after, this.pasteOperation);
-               if(style.autoSize) AutoSize();
                undoBuffer.dontRecord = backDontRecord;
             }
             if(style.syntax && (hadComment || hasComment || line != this.line))
@@ -2499,7 +2779,7 @@ private:
          this.x = this.line.count;
          ComputeColumn();
          if(deselect)
-            Deselect();
+            _Deselect();
       }
    }
 
@@ -2516,16 +2796,15 @@ private:
          this.x = 0;
          this.col = 0;
          if(deselect)
-            Deselect();
+            _Deselect();
       }
    }
 
    // Returns true if it needs scrolling
    bool FindMouse(int px, int py, int * tx, int * ty, EditLine * tline, bool half)
    {
-      int w;
       int c;
-      int x, y;
+      int y;
       EditLine line;
       bool needHScroll = false;
 
@@ -2590,7 +2869,7 @@ private:
       this.endY = clientSize.h-1;
       //ErrorLog("DirtyEnd %d\n", y);
    }
-        
+
    void DirtyLine(int y)
    {
       if(y >= this.viewY)
@@ -2669,7 +2948,7 @@ private:
    {
       if(line)
       {
-         if(mouseMove || (!overwrite && !style.noCaret))
+         if(mouseMove || !style.noCaret)
          {
             int max = this.mouseMove ? this.dropX : this.x;
             int y = this.mouseMove ? this.dropY : this.y;
@@ -2712,7 +2991,10 @@ private:
                         len = 1;
                      }
                      else
-                        FontExtent(display, this.font, line.buffer + start, len, &w, null); 
+                     {
+                        int oh;
+                        FontExtent(display, this.font, line.buffer + start, len, &w, null, 0, null, &oh);
+                     }
                   }
                   else
                   {
@@ -2720,16 +3002,20 @@ private:
                      c++;
                   }
                   x += w;
-               }               
+               }
             }
             if(setCaret)
                caretX = x;
             caretY = y * this.space.h;
-            SetCaret(x + XOFFSET-2, y * space.h + YOFFSET, space.h);
+            if(!overwrite)
+               SetCaret(x + XOFFSET-2, y * space.h + YOFFSET, space.h);
+            else
+               SetCaret(0, 0, 0);
          }
          else
             SetCaret(0, 0, 0);
 
+         // TOFIX: Mismatch between NotifyCaretMove() and NotifyDropped() / GoToPosition()
          NotifyCaretMove(master, this, y + 1, x + 1);
 
          SelectionEnables();
@@ -2784,7 +3070,6 @@ private:
       while(true)
       {
          int start = c;
-         int numBytes = 1;
          int len = 1;
          int w;
          if(c < Min(max, line.count))
@@ -2814,20 +3099,23 @@ private:
                len = 1;
             }
             else
-               FontExtent(display, font, line.buffer + start, len, &w, null); 
+            {
+               int oh;
+               FontExtent(display, font, line.buffer + start, len, &w, null, 0, null, &oh);
+            }
          }
-         else 
+         else
          {
             if(style.freeCaret && c < max)
                w = space.w;
-            else 
+            else
             {
                if(px) *px = x;
                return c;
             }
             c++;
          }
-         if(x + (((half && len == 1) ? (w / 2) : w)) >= position) 
+         if(x + (((half && len == 1) ? (w / 2) : w)) >= position)
          {
             int lastW;
             while(len > 0)
@@ -2839,7 +3127,10 @@ private:
                else
                   a--;
                if(a > start)
-                  FontExtent(display, font, line.buffer + start, a - start, &w, null);
+               {
+                  int oh;
+                  FontExtent(display, font, line.buffer + start, a - start, &w, null, 0, null, &oh);
+               }
                else
                   w = 0;
                if(position > x + (half ? ((w + lastW) / 2) : lastW)) break;
@@ -2862,7 +3153,7 @@ private:
       if(this.x < c)
          this.x = x;
       else
-      { 
+      {
          c = AdjustXPosition(line, viewX + clientSize.w - 1, false, &x, MAXINT, c);
          if(this.x > c)
             this.x = c;
@@ -2885,7 +3176,7 @@ private:
    {
       int c, numLines;
       EditLine oldLine = this.line;
-      
+
       bool selecting = this.x != this.selX || this.y != this.selY;
 
       numLines = clientSize.h / this.space.h;
@@ -2929,7 +3220,7 @@ private:
    }
 
    /*
-   bool SaveFile(char * fileName)
+   bool SaveFile(const char * fileName)
    {
       File f = eFile_Open(fileName, FO_WRITE);
       if(f)
@@ -2980,39 +3271,9 @@ private:
 
    void AutoSize()
    {
-      //if(created)
-      {
-         if(multiLine)
-         {
-            // todo: resize width based on largest on-screen-line extent...
-            int sh = 0;
-            display.FontExtent(font, " ", 1, null, &sh);
-            if(sh)
-            {
-               int nh = 0;
-               nh = lineCount * sh + 2;
-               size.h = nh < minClientSize.h ? minClientSize.h : nh;
-            }
-         }
-         else
-         {
-            int tw = 0;
-            int sh = 0;
-            int nw = 0;
-            int nh = 0;
-            MinMaxValue dw = 0;
-            MinMaxValue dh = 0;
-            int len = line ? strlen(line.text) : 0;
-            GetDecorationsSize(&dw, &dh);
-            display.FontExtent(font, " ", 1, null, &sh);
-            if(len) display.FontExtent(font, line.text, len, &tw, null);
-            nw = dw+tw+12;
-            if(nw < minClientSize.w) nw = minClientSize.w;
-            nh = dh+sh+4;
-            if(nh < minClientSize.h) nh = minClientSize.h;
-            size = { nw, nh };
-         }
-      }
+      int aw = maxLength + 12, ah = Max(lineCount, 1) * space.h + 2;
+      int nw = minClientSize.w, nh = minClientSize.h, xw = maxClientSize.w, xh = maxClientSize.h;
+      clientSize = { nw && aw < nw ? nw : xw && aw > xw ? xw : aw, nh && ah < nh ? nh : xh && ah > xh ? xh : ah };
    }
 
    bool OnResizing(int *w, int *h)
@@ -3071,7 +3332,7 @@ private:
 
          popup = PopupMenu { master = this, menu = contextMenu,
    /*
-            nonClient = true, interim = false, parent = parent, 
+            nonClient = true, interim = false, parent = parent,
             position = { x + clientStart.x + parent.clientStart.x + position.x, y + cientStart.y + parent.sy + clientStart.y + position.y };
    */
             position = { x + clientStart.x + absPosition.x - guiApp.desktop.position.x, y + clientStart.y + absPosition.y - guiApp.desktop.position.y }
@@ -3134,17 +3395,16 @@ private:
             this.y = y;
             this.line = line;
             DirtyLine(this.y);
-            this.selLine = this.line;
-            this.selX = this.x;
-            this.selY = this.y;
-            //Deselect();
+            _Deselect();
          }
          ComputeColumn();
       }
-      
+
       UpdateDirty();
       UpdateCaretPosition(true);
-      return true;
+      // Return false because DataBoxes automatically set EditBox editor's clickThrough to true for MouseMove events
+      // ( for tool tips -- see 95ee4962c4c7bc3fe0a04aa6a4f98cacada40884)
+      return false;
    }
 
    bool OnLeftButtonUp(int x, int y, Modifiers mods)
@@ -3153,9 +3413,9 @@ private:
 
       mouseSelect = false;
       wordSelect = false;
-      
+
       x -= XOFFSET;
-      
+
       ReleaseCapture();
       if(!style.readOnly)
       {
@@ -3196,12 +3456,16 @@ private:
                               moveX = this.selX - this.x;
                         }
                      }
+
+                     recordUndoEvent = true;
                      DelSel(null);
                      this.dropX -= moveX;
                      this.selX = this.x = this.dropX;
                      this.selY = this.y = this.dropY;
                      this.selLine = this.line = this.dropLine;
                      AddS(text);
+                     recordUndoEvent = false;
+
                      SetViewToCursor(true);
                      delete text;
                      Modified();
@@ -3233,7 +3497,7 @@ private:
                this.line = line;
                ComputeColumn();
                DirtyLine(this.y);
-               Deselect();
+               _Deselect();
                UpdateDirty();
             }
          }
@@ -3251,7 +3515,9 @@ private:
          }
       }
       mouseMove = false;
-      return true;
+      // Return false because DataBoxes automatically set EditBox editor's clickThrough to true for MouseMove events
+      // ( for tool tips -- see 95ee4962c4c7bc3fe0a04aa6a4f98cacada40884)
+      return false;
    }
 
    bool OnMouseMove(int mx, int my, Modifiers mods)
@@ -3260,10 +3526,10 @@ private:
       EditLine line;
       bool needScroll;
 
-      if(mods != -1 && mods.isSideEffect) 
-      { 
-         SetSelectCursor(); 
-         return true; 
+      if(mods != -1 && mods.isSideEffect)
+      {
+         SetSelectCursor();
+         return true;
       }
       if(style.noSelect) return true;
       if(wordSelect) return true;
@@ -3276,11 +3542,11 @@ private:
       {
          if(!needScroll)
             timer.Stop();
-         else 
+         else
          {
             if(needScroll)
                timer.Start();
-            if(mods != -1 && 
+            if(mods != -1 &&
                ((style.hScroll) || (style.vScroll)))
                return true;
          }
@@ -3349,7 +3615,7 @@ private:
             for(c = start; c<line.count; c += numBytes)
             {
                unichar ch = UTF8_GET_CHAR(line.buffer + c, numBytes);
-               if(!IS_ALUNDER(ch))
+               if(!ch || !IS_ALUNDER(ch))
                   break;
             }
             SelDirty();
@@ -3384,8 +3650,9 @@ private:
    {
       if(FontExtent)
       {
-         FontExtent(display, font, " ", 1, (int *)&space.w, (int *)&space.h);
-         FontExtent(display, font, "W", 1, (int *)&large.w, (int *)&large.h);
+         int oh;
+         FontExtent(display, font, " ", 1, (int *)&space.w, (int *)&space.h, 0, null, &oh);
+         FontExtent(display, font, "W", 1, (int *)&large.w, (int *)&large.h, 0, null, &oh);
 
          space.w = Max(space.w, 1);
          large.w = Max(large.w, 1);
@@ -3410,7 +3677,7 @@ private:
 
    bool OnLoadGraphics()
    {
-      FontExtent = Display::FontExtent;
+      FontExtent = Display::FontExtent2;
       font = fontObject;
       ComputeFont();
       // UpdateCaretPosition(true);
@@ -3432,6 +3699,8 @@ private:
       {
          key.code = (SmartKey)key.code;
       }
+      else if(!ch && key.alt)
+         key.code = 0;
 
       switch(key.code) //(ch || key.alt || key.ctrl) ? key.code : (Key)(SmartKey)key.code)
       {
@@ -3447,10 +3716,10 @@ private:
                int y;
                bool done = false;
                EditLine line = this.line;
-               int c;
+               int c = 0;
                for(y = this.y; y>= 0; y--)
                {
-                  c = (y == this.y) ? (this.x-1) : line.count-1;
+                  c = (y == this.y) ? (Min(this.x-1, line.count-1)) : line.count-1;
 
                   // Slow down when going on lines...
                   if(y != this.y) break;
@@ -3477,9 +3746,10 @@ private:
                   else
                      break;
                }
+
                //if(this.x != 0)
                {
-                  DelCh(line,y,c+1,this.line,this.y,this.x, true);
+                  _DelCh(line, y, c+1, this.line, this.y, this.x, true, false, null);
                   this.x = this.selX = Min(c+1, line.count);
                   this.y = this.selY = y;
                   this.line = this.selLine = line;
@@ -3510,51 +3780,52 @@ private:
                   SetViewToCursor(true);
                   Modified();
                }
-               // Delete word
-               else if(key.ctrl)
-               {
-                  if(this.x < this.line.count)
-                  {
-                     int i;
-                     int length;
-                     for(i = this.x; i < this.line.count; i++)
-                     {
-                        if(!IS_ALUNDER(this.line.buffer[i]))
-                           break;
-                     }
-                     
-                     for(; i < this.line.count; i++)
-                     {
-                        //Delete trailing whitespace
-                        if(IS_ALUNDER(this.line.buffer[i]))
-                           break;
-                     }
-                     DelCh(this.line, this.y, this.x, this.line, this.y, i, false);
-                     SetViewToCursor(true);
-                     Modified();
-                  }
-                  else if(this.line.next)
-                  {
-                     DelCh(this.line, this.y, this.x, this.line.next, this.y+1, 0, false);
-                     SetViewToCursor(true);
-                     Modified();
-                  }
-               }
-               else 
+               else
                {
-                  if(!(style.freeCaret))
+                  EditLine line1 = this.line, line2 = this.line;
+                  int x1, y1 = this.y, x2, y2 = this.y;
+                  if(!style.freeCaret)
                   {
                      this.selX = this.x = Min(this.x, this.line.count);
                      ComputeColumn();
                   }
-                  if(this.x < this.line.count)
+                  x1 = this.x;
+
+                  if(x1 < line1.count)
                   {
-                     DelCh(this.line, this.y, this.x, this.line, this.y, this.x+1, false);
+                     // Delete word
+                     if(key.ctrl)
+                     {
+                        int i;
+                        char * buffer = line1.buffer;
+                        for(i = x1; i < line1.count; i++)
+                        {
+                           if(!IS_ALUNDER(buffer[i]))
+                              break;
+                        }
+
+                        for(; i < line1.count; i++)
+                        {
+                           // Delete trailing whitespace
+                           if(IS_ALUNDER(buffer[i]))
+                              break;
+                        }
+                        x2 = i;
+                     }
+                     else
+                        x2 = x1 + 1;
                   }
-                  else if(this.line.next)
+                  else
                   {
-                     DelCh(this.line, this.y, this.x, this.line.next, this.y+1, 0, false);
+                     // Avoid creating trailing spaces if there is no content on next line
+                     line2 = line1.next;
+                     y2++;
+                     if(line2 && !line2.count)
+                        x1 = line1.count;
+                     x2 = 0;
                   }
+                  if(line2)
+                     _DelCh(line1, y1, x1, line2, y2, x2, false, false, null);
                   SetViewToCursor(true);
                   Modified();
                }
@@ -3571,6 +3842,8 @@ private:
                bool stuffAfter = false;
                char * addString;
                int len = 0;
+               /*bool resetX = false;
+               int backX;*/
 
                if(style.stuckCaret) GoToEnd(true);
                if(style.readOnly) break;
@@ -3585,19 +3858,31 @@ private:
                   else
                      break;
                }
+
+               // Prevent adding trailing spaces if at the head of a line
+               /*if(c && c == this.x && c < this.line.count && this.x == this.selX && this.y == this.selY)
+               {
+                  position = 0;
+                  backX = this.x;
+                  this.x = 0;
+                  this.selX = 0;
+                  resetX = true;
+               }*/
+
                if(!line.count)
                   position = x;
 
                if(this.x < this.line.count)
                   stuffAfter = true;
-                  
+
                //If last character is a { indent one tab
-               if(this.line.buffer[this.x - 1] == '{')
+               c = Min(x, line.count);
+               if(c > 0 && line.buffer[c - 1] == '{')
                {
                   //Except if the next non space character is a }
                   bool indent = false;
                   int i;
-                  for(i = this.x; i < this.line.size; i++)
+                  for(i = c; i <= this.line.count; i++)   // indent will be set to true on nul terminating char
                      if(this.line.buffer[i] != ' ' && this.line.buffer[i] != '\t')
                      {
                         if(this.line.buffer[i] != '}')
@@ -3629,9 +3914,27 @@ private:
                   }
                   addString[len] = '\0';
                }
+               recordUndoEvent = true;
                if(AddS(addString))
                {
-                  if(!stuffAfter && style.freeCaret)
+                  EditLine prevLine = this.line.prev;
+                  if(prevLine)
+                  {
+                     // Nuke spaces if that is all that is left on previous line
+                     int i;
+                     char * buffer = prevLine.buffer;
+                     for(i = 0; i < prevLine.count; i++)
+                        if(buffer[i] != ' ' && buffer[i] != '\t')
+                           break;
+                     if(i == prevLine.count)
+                        DelCh(prevLine, this.y - 1, 0, prevLine, this.y - 1, prevLine.count, false);
+                  }
+                  /*if(resetX)
+                  {
+                     this.x = this.selX = backX;
+                     ComputeColumn();
+                  }
+                  else */if(!stuffAfter && style.freeCaret)
                   {
                      this.x = this.selX = position;
                      ComputeColumn();
@@ -3640,6 +3943,7 @@ private:
                   SetViewToCursor(true);
                   Modified();
                }
+               recordUndoEvent = false;
                delete addString;
                return false;
             }
@@ -3660,8 +3964,8 @@ private:
                bool foundAlpha = false;
                bool found = false;
                int y = this.y;
-               EditLine line, lastLine;
-               int lastC, lastY;
+               EditLine line, lastLine = null;
+               int lastC = 0, lastY = 0;
 
                for(line = this.line; (line && !found); line = line.prev, y--)
                {
@@ -3699,14 +4003,14 @@ private:
                            break;
                         }
                      }
-                     while(--c)
+                     while(--c >= 0)
                      {
                         byte ch = line.buffer[c];
                         if(UTF8_IS_FIRST(ch)) break;
-                     } 
+                     }
 
                   }
-                  // No next word found, 
+                  // No next word found,
                   if(!found && ( this.x > 0 || (!line.count && this.x)))
                   {
                      foundAlpha = true;
@@ -3732,12 +4036,12 @@ private:
                {
                   if(x <= line.count)
                   {
-                     byte * buffer = line.buffer;
+                     byte * buffer = (byte *)line.buffer;
                      while(--x)
                      {
                         byte ch = buffer[x];
                         if(UTF8_IS_FIRST(ch)) break;
-                     } 
+                     }
                   }
                   else
                      x--;
@@ -3753,7 +4057,7 @@ private:
                }
                ComputeColumn();
             }
-            if(!shift) Deselect();
+            if(!shift) _Deselect();
             SetViewToCursor(true);
             //break;
             return false;
@@ -3782,18 +4086,18 @@ private:
                {
                   bool foundAlpha = false;
                   bool found = false;
-                  EditLine line, lastLine;
+                  EditLine line = null, lastLine = null;
                   int y = this.y;
-                  int lastC, lastY, lastNumBytes;
-                  
+                  int lastC = 0, lastY = 0, lastNumBytes = 0;
+
                   for(line = this.line; (line && !found); line = line.next, y++)
                   {
                      int start = (line == this.line) ? this.x : 0;
                      int c;
                      int numBytes;
-                     for(c = start; c < line.count; c += numBytes)
+                     unichar ch;
+                     for(c = start; c < line.count && (ch = UTF8_GET_CHAR(line.buffer + c, numBytes)); c += numBytes)
                      {
-                        unichar ch = UTF8_GET_CHAR(line.buffer + c, numBytes);
                         if(IS_ALUNDER(ch))
                         {
                            foundAlpha = true;
@@ -3817,7 +4121,7 @@ private:
                         lastY = y;
                         break;
                      }
-                  }  
+                  }
                   if(found)
                   {
                      DirtyLine(this.y);
@@ -3840,9 +4144,9 @@ private:
                      int start = (line == this.line) ? this.x : 0;
                      int c;
                      int numBytes;
-                     for(c = start; c < line.count; c += numBytes)
+                     unichar ch;
+                     for(c = start; c < line.count && (ch = UTF8_GET_CHAR(line.buffer + c, numBytes)); c += numBytes)
                      {
-                        unichar ch = UTF8_GET_CHAR(line.buffer + c, numBytes);
                         if(!IS_ALUNDER(ch))
                            foundAlpha = true;
                         else if(foundAlpha)
@@ -3857,7 +4161,7 @@ private:
                            break;
                         }
                      }
-                     // No next word found, 
+                     // No next word found,
                      if(!found && (c != this.x || line != this.line))
                      {
                         found = true;
@@ -3878,12 +4182,12 @@ private:
                {
                   if(x < line.count)
                   {
-                     byte * buffer = line.buffer;
+                     byte * buffer = (byte *)line.buffer;
                      while(++x)
                      {
                         byte ch = buffer[x];
                         if(UTF8_IS_FIRST(ch)) break;
-                     } 
+                     }
                   }
                   else
                      x++;
@@ -3903,7 +4207,7 @@ private:
                   }
                }
             }
-            if(!shift) Deselect();
+            if(!shift) _Deselect();
             SetViewToCursor(true);
             // break;
             return false;
@@ -3918,7 +4222,7 @@ private:
             else
             {
                if(style.stuckCaret) break;
-               
+
                if(!shift) SelDirty();
                DirtyLine(this.y);
 
@@ -3931,9 +4235,9 @@ private:
                   this.y--;
                   this.x = AdjustXPosition(line, caretX, true, null, MAXINT, 0);
                }
-               
+
                DirtyLine(this.y);
-               if(!shift) Deselect();
+               if(!shift) _Deselect();
                ComputeColumn();
                SetViewToCursor(false);
 
@@ -3984,7 +4288,7 @@ private:
                            len = (nextSpace - (text + textPos));
                         else
                            len = line.count - textPos;
-                        
+
                         if(textPos < line.count)
                         {
                            display.FontExtent(font, text + textPos, len, &w, null);
@@ -4019,7 +4323,7 @@ private:
                            }
 
                            DirtyLine(this.y);
-                           if(!shift) Deselect();
+                           if(!shift) _Deselect();
                            ComputeColumn();
                            SetViewToCursor(false);
                            return false;
@@ -4037,7 +4341,7 @@ private:
                            this.x = line.count;
 
                         DirtyLine(this.y);
-                        if(!shift) Deselect();
+                        if(!shift) _Deselect();
                         ComputeColumn();
                         SetViewToCursor(false);
                         return false;
@@ -4047,13 +4351,13 @@ private:
                   } while(textPos < line.count);
 
                   DirtyLine(this.y);
-                  if(!shift) Deselect();
+                  if(!shift) _Deselect();
                   ComputeColumn();
                   SetViewToCursor(false);
                   return false;
                }
                */
-               
+
                // PREVIOUS CODE
                /*
                if(this.line.prev)
@@ -4066,7 +4370,7 @@ private:
 
                   DirtyLine(this.y);
                   this.x = x;
-                  if(!shift) Deselect();
+                  if(!shift) _Deselect();
 
                   ComputeColumn();
 
@@ -4089,15 +4393,17 @@ private:
             {
                if(style.stuckCaret) break;
                {
+                  /*
                   int th = space.h;
                   int textPos = 0;
                   int sx = 0, sy = this.y * this.space.h;
                   int maxW = clientSize.w - sx;
                   char * text = line.buffer;
+                  */
 
                   if(!shift) SelDirty();
                   DirtyLine(this.y);
-                  
+
                   if(style.wrap)
                   {
                      /*
@@ -4114,12 +4420,11 @@ private:
                      this.x = AdjustXPosition(line, caretX, true, null, MAXINT, 0);
                   }
 
-                  if(!shift) Deselect();
+                  DirtyLine(this.y);
+                  if(!shift) _Deselect();
                   ComputeColumn();
-                  if(this.selX != this.x || this.selY != this.y)
-                     DirtyLine(this.y);
                   SetViewToCursor(false);
-                  
+
                   /*
                   while(!textPos || (style.freeCaret || textPos<line.count))
                   {
@@ -4142,7 +4447,7 @@ private:
                            len = (nextSpace - (text + textPos));
                         else
                            len = line.count - textPos;
-                        
+
                         if(textPos < line.count)
                         {
                            display.FontExtent(font, text + textPos, len, &w, &th);
@@ -4171,12 +4476,12 @@ private:
                                  this.x--;
                               else
                                  while(this.x > 0 && !UTF8_IS_FIRST(text[--this.x]));
-                                 
+
                               len = this.x - startPos;
                               display.FontExtent(font, text + startPos, len, &x, null);
                            }
-                           
-                           if(!shift) Deselect();
+
+                           if(!shift) _Deselect();
                            ComputeColumn();
 
                            SetViewToCursor(false);
@@ -4188,12 +4493,12 @@ private:
                         this.x = line.count;
 
                         DirtyLine(this.y);
-                        if(!shift) Deselect();
+                        if(!shift) _Deselect();
                         ComputeColumn();
 
                         SetViewToCursor(false);
                         return false;
-                     } 
+                     }
                      else if(textPos >= line.count && line.next)
                      {
                         startPos = 0;
@@ -4218,7 +4523,7 @@ private:
                      this.x = Min(this.x, line.count);
                      //int x = AdjustXPosition(this.line, this.line.next, true, null, MAXINT, 0);
                      this.y++;
-                     if(!shift) Deselect();
+                     if(!shift) _Deselect();
                      ComputeColumn();
 
                      if(this.selX != this.x || this.selY != this.y)
@@ -4237,7 +4542,7 @@ private:
                   DirtyLine(this.y);
                   this.y++;
                   this.x = x;
-                  if(!shift) Deselect();
+                  if(!shift) _Deselect();
                   ComputeColumn();
 
                   if(this.selX != this.x || this.selY != this.y)
@@ -4252,6 +4557,7 @@ private:
          case home:
          {
             if(style.stuckCaret) break;
+            if(!style.multiLine && key.ctrl) break;
             if(!(style.freeCaret))
                this.selX = Min(this.selX, this.selLine.count);
 
@@ -4274,22 +4580,22 @@ private:
                   for(c=0; line.buffer[c]; c++)
                      if(line.buffer[c] != ' ' && line.buffer[c] != '\t')
                         break;
-                  if(c != 0 || this.x)
+                  if(overwrite || (shift && (c != 0 || this.x)))
                      DirtyLine(this.y);
-                  if(this.x != c) 
+                  if(this.x != c)
                      this.x = c;
                   else
                      this.x = 0;
                }
                else
                {
-                  /*if(this.x != 0)
-                     DirtyLine(this.y);*/
+                  if(overwrite || (shift && this.x != 0))
+                     DirtyLine(this.y);
                   this.x = 0;
                }
                ComputeColumn();
             }
-            if(!shift) Deselect();
+            if(!shift) _Deselect();
             SetViewToCursor(true);
             //break;
             return false;
@@ -4297,7 +4603,8 @@ private:
          case end:
          {
             if(style.stuckCaret) break;
-            if(!(style.freeCaret))
+            if(!style.multiLine && key.ctrl) break;
+            if(!style.freeCaret)
                this.selX = Min(this.selX, this.selLine.count);
 
             if(!shift) SelDirty();
@@ -4308,10 +4615,11 @@ private:
             else if(this.x != this.line.count)
             {
                this.x = this.line.count;
-               //DirtyLine(this.y);
+               if(overwrite || shift)
+                  DirtyLine(this.y);
                ComputeColumn();
             }
-            if(!shift) Deselect();
+            if(!shift) _Deselect();
             SetViewToCursor(true);
             //break;
             return false;
@@ -4374,10 +4682,9 @@ private:
                               Record(action);
                            }
                            memmove(line.buffer,line.buffer+lastC,line.size-lastC);
-                           if(!line.AdjustBuffer(line.count-lastC)) 
+                           if(!line.AdjustBuffer(line.count-lastC))
                               break;
                            line.count-=lastC;
-                           if(style.autoSize) AutoSize();
                            DirtyLine(y);
                         }
 
@@ -4398,11 +4705,10 @@ private:
                                  {
                                     BufferLocation before = { line, y, 0 }, after = { line, y, 1 };
 
-                                    if(!line.AdjustBuffer(line.count+1)) 
+                                    if(!line.AdjustBuffer(line.count+1))
                                        break;
 
                                     NotifyCharsAdded(master, this, &before, &after, this.pasteOperation);
-                                    if(style.autoSize) AutoSize();
                                     {
                                        AddCharAction action { ch = '\t', x = 0, y = y };
                                        Record(action);
@@ -4420,9 +4726,8 @@ private:
                                     int c;
                                     BufferLocation before = { line, y, 0 }, after = { line, y, this.tabSize };
                                     NotifyCharsAdded(master, this, &before, &after, this.pasteOperation);
-                                    if(style.autoSize) AutoSize();
 
-                                    if(!line.AdjustBuffer(line.count+this.tabSize)) 
+                                    if(!line.AdjustBuffer(line.count+this.tabSize))
                                        break;
 
                                     {
@@ -4444,6 +4749,7 @@ private:
                         if(line == lastLine) break;
                      }
                   }
+                  ComputeLength(maxLine);
                }
                else
                {
@@ -4479,76 +4785,85 @@ private:
             }
             break;
          case pageDown:
-            if(key.ctrl)
+            if(style.multiLine)
             {
-               if(!(style.hScroll) || hasHorzScroll) break;
-               if(this.viewX < this.maxLength)
+               if(key.ctrl)
                {
-                  //this.viewX+=this.space.w*this.tabSize;
-                  //DirtyAll();
-                  SetScrollPosition((this.viewX + this.space.w*this.tabSize), this.viewY * this.space.h);
+                  if(!(style.hScroll) || hasHorzScroll) break;
+                  if(this.viewX < this.maxLength)
+                  {
+                     //this.viewX+=this.space.w*this.tabSize;
+                     //DirtyAll();
+                     SetScrollPosition((this.viewX + this.space.w*this.tabSize), this.viewY * this.space.h);
+                  }
                }
+               else
+               {
+                  PageDown();
+                  DirtyAll();
+                  if(!shift) _Deselect();
+                  SetCursorToViewX();
+                  SetCursorToViewY();
+               }
+               return false;
             }
-            else
-            {
-               PageDown();
-               DirtyAll();
-               if(!shift) Deselect();
-               SetCursorToViewX();
-               SetCursorToViewY();
-            }
-            return false;
-            // break;
+            break;
          case pageUp:
-            if(key.ctrl)
+            if(style.multiLine)
             {
-               if(!(style.hScroll) || hasHorzScroll) break;
-               if(this.viewX > 0)
+               if(key.ctrl)
                {
-                  //this.viewX-=this.space.w*this.tabSize;
-                  //this.viewX = Max(this.viewX,0);
-                  //DirtyAll();
-                  SetScrollPosition((this.viewX-this.space.w*this.tabSize), this.viewY * this.space.h);
-                  // SetCursorToView();
+                  if(!(style.hScroll) || hasHorzScroll) break;
+                  if(this.viewX > 0)
+                  {
+                     //this.viewX-=this.space.w*this.tabSize;
+                     //this.viewX = Max(this.viewX,0);
+                     //DirtyAll();
+                     SetScrollPosition((this.viewX-this.space.w*this.tabSize), this.viewY * this.space.h);
+                     // SetCursorToView();
+                  }
                }
+               else
+               {
+                  PageUp();
+                  DirtyAll();
+                  if(!shift) _Deselect();
+                  SetCursorToViewX();
+                  SetCursorToViewY();
+               }
+               return false;
             }
-            else
-            {
-               PageUp();
-               DirtyAll();
-               if(!shift) Deselect();
-               SetCursorToViewX();
-               SetCursorToViewY();
-            }
-            // break;
-            return false;
+            break;
          case insert:
             if(key.ctrl)
             {
                Copy();
                return false;
             }
-            else if(key.shift)
+            else if(!style.readOnly)
             {
-               if(!(style.readOnly))
-                  Paste();
-               return false;
-            }
-            else
-            {
-               this.overwrite ^= 1;
-               UpdateCaretPosition(true);
-               if(this.overwrite)
-                  SetCaret(0,0,0);
-               DirtyLine(this.y);
-               UpdateDirty();
-               NotifyOvrToggle(master, this, this.overwrite);
+               if(key.shift)
+               {
+                  if(!(style.readOnly))
+                     Paste();
+                  return false;
+               }
+               else
+               {
+                  this.overwrite ^= 1;
+                  UpdateCaretPosition(true);
+                  if(this.overwrite)
+                     SetCaret(0,0,0);
+                  DirtyLine(this.y);
+                  UpdateDirty();
+                  NotifyOvrToggle(master, this, this.overwrite);
+               }
             }
             break;
-         case hotKey: 
+         case hotKey:
             break;
          default:
-            
+
             switch(key)
             {
                case ctrlA:
@@ -4559,7 +4874,7 @@ private:
                      //Save current view position
                      int tempX = this.viewX;
                      int tempY = this.viewY;
-                     
+
                      this.selX = 0;
                      this.selY = 0;
                      this.selLine = this.lines.first;
@@ -4569,10 +4884,10 @@ private:
                      ComputeColumn();
                      DirtyAll();
                      SetViewToCursor(true);
-                     
+
                      //Restore previous view position
                      SetScrollPosition(tempX, tempY * this.space.h);
-                     
+
                      UpdateDirty();
                      SetSelectCursor();
                      SelectionEnables();
@@ -4615,14 +4930,14 @@ private:
                   {
                      //Only indent back if you are exactly at one tab.
                      {
-                        bool whitespace = true;
+                        //bool whitespace = true;
                         int i;
                         char * newline;
                         int putsize;
-                        
-                        int indentwidth;
+
+                        int indentwidth = 0;
                         EditLine line = this.line;
-                        
+
                         //Only remove one tab if there is nothing else on the line.
                         for(i = 0; i < this.line.count; i++)
                         {
@@ -4632,13 +4947,13 @@ private:
                               return false;
                            }
                         }
-                        
+
                         //Find opening {
                         i = 1;
                         while(i && line)
                         {
                            int pos;
-                           
+
                            indentwidth = 0;
                            for(pos = line.count - 1; pos >= 0; pos--)
                            {
@@ -4657,35 +4972,36 @@ private:
                            }
                            line = line.prev;
                         }
-                        
+
                         //Place the } to get an undo:
                         PutCh(ch);
-                        
+
                         this.x = this.line.count;
                         this.selX = 0;
-                        
+
                         if(!style.useTab)
                            putsize = indentwidth;
                         else
                            putsize = indentwidth / this.tabSize + indentwidth % this.tabSize;
-                        
+
                         newline = new char[putsize+2];
                         newline[putsize] = '}';
                         newline[putsize+1] = '\0';
-                        
+
                         i = 0;
                         if(style.useTab)
                            for(; i < indentwidth / this.tabSize; i++)
                               newline[i] = '\t';
                         for(;i < putsize; i++)
                            newline[i] = ' ';
-                        
+
                         AddS(newline);
-                        
+
                         delete newline;
                      }
                      return false;
-                  } else if(!key.ctrl && !key.alt && ch != 128 && ch >= 32)
+                  }
+                  else if(!key.ctrl && !key.alt && ch != 128 && ch >= 32)
                   {
                      PutCh(ch);
                      return false;
@@ -4732,7 +5048,7 @@ private:
          for(; position > this.viewY && this.viewLine.next; this.viewLine = this.viewLine.next, this.viewY++);
          FigureStartSyntaxStates(oldViewLine, false);
       }
-      
+
       if(action != setRange)
       {
          if(!this.mouseMove && style.cursorFollowsView && !SelSize()) SetCursorToViewY();
@@ -4748,8 +5064,8 @@ private:
          int numLines = clientSize.h / this.space.h;
          int y;
          if(Abs(this.viewY - oldViewY) < numLines)
-            
-         
+
+
          if(this.viewY > oldViewY)
          {
             for(y = oldViewY; y <this.viewY; y++)
@@ -4769,25 +5085,25 @@ private:
          Box box { 0,0, clientSize.w-1, YOFFSET-1 };
          Update(box);
       }
-      
+
       UpdateDirty();
    }
 
-   bool _AddCh(unichar ch, int * addedSpacesPtr, int * addedTabsPtr)
+   bool _AddCh(unichar ch, int * addedSpacesPtr, int * addedTabsPtr, int * xAdjustmentPtr)
    {
       EditLine line;
-      int length, endX;
+      int length, endX = 0;
       bool result;
       ReplaceTextAction replaceAction = null;
       AddCharAction addCharAction = null;
-      int addedSpaces = 0, addedTabs = 0;
+      int addedSpaces = 0, addedTabs = 0, xAdjustment = 0;
 
       if(ch == '\r') return true;
-      if(style.stuckCaret /*|EES_READONLY)*/ ) 
+      if(style.stuckCaret /*|EES_READONLY)*/ )
          GoToEnd(true);
-   
+
       if(ch == '\n' && !(style.multiLine) && this.line) return false;
-      
+
       if(!undoBuffer.dontRecord)
       {
          if(selX != x || selY != y)
@@ -4836,7 +5152,7 @@ private:
             else
                return false;
          }
-         if(!(style.vScroll)) 
+         if(!(style.autoSize && (!maxClientSize.h || maxClientSize.h > clientSize.h + this.space.h)) && !(style.vScroll))
          {
             // Make sure it fits, but we need a default line is this.font is too big for window
             if(this.space.h * (this.lineCount+1) > clientSize.h && this.line)
@@ -4867,7 +5183,7 @@ private:
                length = this.line.count - endX;
             }
          }
-         if(!line.AdjustBuffer(length)) 
+         if(!line.AdjustBuffer(length))
             return false;
          if(this.line)
          {
@@ -4890,14 +5206,14 @@ private:
             this.line = line;
             this.x = 0;
             this.col = 0;
-
-            ComputeLength(this.line);
+            line.count = length;
 
 #ifdef _DEBUG
       if(length > 4000 || length < 0)
          printf("Warning");
 #endif
-            line.count = length;
+            ComputeLength(this.line);
+
             DirtyEnd(this.y);
             this.y++;
             this.lineCount++;
@@ -4907,7 +5223,6 @@ private:
             after.line = this.line, after.y = this.y, after.x = this.x;
 
             NotifyCharsAdded(master, this, &before, &after, this.pasteOperation);
-            if(style.autoSize) AutoSize();
          }
       }
       else
@@ -4915,9 +5230,10 @@ private:
          char string[5];
          int count = UTF32toUTF8Len(&ch, 1, string, 5);
          DelSel(&addedSpaces);
-         result = AddToLine(string, count, false, addedSpaces ? null : &addedSpaces, &addedTabs);
+         result = AddToLine(string, count, false, addedSpaces ? null : &addedSpaces, &addedTabs, &xAdjustment);
          if(addedSpacesPtr) *addedSpacesPtr = addedSpaces;
          if(addedTabsPtr) *addedTabsPtr = addedTabs;
+         if(xAdjustmentPtr) *xAdjustmentPtr = xAdjustment;
       }
       this.selX = this.x;
       this.selY = this.y;
@@ -4949,7 +5265,7 @@ public:
 
    bool AddCh(unichar ch)
    {
-      return _AddCh(ch, null, null);
+      return _AddCh(ch, null, null, null);
    }
 
    void Modified()
@@ -4962,7 +5278,7 @@ public:
    void Delete(EditLine line1, int y1, int x1, EditLine line2, int y2, int x2)
    {
       Deselect();
-      DelCh(line1, y1, x1, line2, y2, x2, false);
+      _DelCh(line1, y1, x1, line2, y2, x2, false, false, null);
       SetViewToCursor(true);
       UpdateDirty();
       Modified();
@@ -4973,6 +5289,11 @@ public:
       undoBuffer.Undo();
       itemEditUndo.disabled = undoBuffer.curAction == 0;
       itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count;
+
+      UpdateDirty();
+      SetSelectCursor();
+      SelectionEnables();
+
       if(savedAction == undoBuffer.curAction)
       {
          modifiedDocument = false;
@@ -4986,6 +5307,11 @@ public:
       undoBuffer.Redo();
       itemEditUndo.disabled = undoBuffer.curAction == 0;
       itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count;
+
+      UpdateDirty();
+      SetSelectCursor();
+      SelectionEnables();
+
       if(savedAction == undoBuffer.curAction)
       {
          modifiedDocument = false;
@@ -5038,20 +5364,20 @@ public:
    }
 
    // BASIC OUTPUT
-   bool AddS(char * string)
+   bool AddS(const char * string)
    {
       if(this)
       {
          bool ret = true;
-         char * line;
+         const char * line;
          int c, count;
-         int addedSpaces = 0, addedTabs = 0;
+         int addedSpaces = 0, addedTabs = 0, xAdjustment = 0;
          AddTextAction action = null;
          ReplaceTextAction replaceAction = null;
 
          this.pasteOperation = true;
 
-         if(style.stuckCaret /*|EES_READONLY)*/ ) 
+         if(style.stuckCaret /*|EES_READONLY)*/ )
             GoToEnd(true);
 
          if(!undoBuffer.dontRecord)
@@ -5060,7 +5386,7 @@ public:
             if(!style.multiLine)
             {
                int i;
-               char ch; 
+               char ch;
                for(i = 0; (ch = placeString[i]); i++)
                   if(ch == '\n')
                   {
@@ -5069,7 +5395,7 @@ public:
                      break;
                   }
             }
-            
+
             if(selX != x || selY != y)
             {
                char * newString;
@@ -5102,7 +5428,7 @@ public:
                   action = AddTextAction { y1 = y, x1 = Min(this.line.count, x), string = placeString };
                else
                   action = AddTextAction { y1 = y, x1 = x, string = placeString };
-               
+
                Record(action);
             }
             else
@@ -5118,7 +5444,7 @@ public:
          {
             if(string[c] == '\n' || string[c] == '\r')
             {
-               if(!AddToLine(line,count, true, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs))
+               if(!AddToLine(line, count, true, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs, xAdjustment ? null : &xAdjustment))
                {
                   ret = false;
                   break;
@@ -5136,7 +5462,7 @@ public:
                count = 0;
                line = string+c+1;
                /*
-               if(string[c] == '\r' && *line == '\n') 
+               if(string[c] == '\r' && *line == '\n')
                {
                   line++;
                   c++;
@@ -5153,7 +5479,7 @@ public:
 
          // Add the line here
          if(ret && count)
-            if(!AddToLine(line,count,false, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs))
+            if(!AddToLine(line,count,false, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs, xAdjustment ? null : &xAdjustment))
             {
                ret = false;
             }
@@ -5166,6 +5492,7 @@ public:
             action.x2 = x;
             action.addedSpaces = addedSpaces;
             action.addedTabs = addedTabs;
+            action.xAdjustment = xAdjustment;
          }
          else if(replaceAction)
          {
@@ -5173,6 +5500,7 @@ public:
             replaceAction.x3 = x;
             replaceAction.addedSpaces = addedSpaces;
             replaceAction.addedTabs = addedTabs;
+            replaceAction.xAdjustment = xAdjustment;
          }
 
          UpdateCaretPosition(true);
@@ -5200,18 +5528,18 @@ public:
    void PutCh(unichar ch)
    {
       bool result;
-      
-      if((ch >= 32 /*&& ch <=126*/) || ch == '\n')
+
+      if((ch >= 32 /*&& ch <=126*/) || ch == '\n' || ch == '\t')
       //if((ch >= 32) || ch == '\n')
       {
-         int addedSpaces = 0, addedTabs = 0;
+         int addedSpaces = 0, addedTabs = 0, xAdjustment = 0;
          ReplaceTextAction replaceAction = null;
          AddCharAction addCharAction = null;
 
          if(style.allCaps)
             ch = (ch < 128) ? toupper(ch) : ch;     // TODO: UNICODE TO UPPER
 
-         if(this.x < this.line.count && this.overwrite)
+         if(this.overwrite && selX == x && selY == y && this.x < this.line.count)
          {
             char buffer[5];
             char * newString;
@@ -5268,19 +5596,20 @@ public:
             }
          }
          undoBuffer.dontRecord++;
-         result = _AddCh(ch, &addedSpaces, &addedTabs);
+         result = _AddCh(ch, &addedSpaces, &addedTabs, &xAdjustment);
          if(replaceAction)
          {
             replaceAction.x3 = x;
             replaceAction.y3 = y;
             replaceAction.addedSpaces = addedSpaces;
             replaceAction.addedTabs = addedTabs;
-         }  
+            replaceAction.addedTabs = xAdjustment;
+         }
          if(addCharAction)
          {
-            addCharAction.x -= addedTabs * (tabSize-1);
             addCharAction.addedSpaces = addedSpaces;
             addCharAction.addedTabs = addedTabs;
+            addCharAction.xAdjustment = xAdjustment;
          }
          undoBuffer.dontRecord--;
          if(ch == '\n')
@@ -5290,7 +5619,7 @@ public:
       }
    }
 
-   void PutS(char * string)
+   void PutS(const char * string)
    {
       if(this)
       {
@@ -5300,7 +5629,7 @@ public:
       }
    }
 
-   void Printf(char * format, ...)
+   void Printf(const char * format, ...)
    {
       if(this)
       {
@@ -5314,10 +5643,11 @@ public:
       }
    }
 
-   void SetContents(char * format, ...)
+   void SetContents(const char * format, ...)
    {
       if(this)
       {
+         undoBuffer.dontRecord++;
          Deselect();
          DelCh(this.lines.first, 0, 0, this.lines.last, this.lineCount-1, ((EditLine)(this.lines.last)).count, true);
          if(format)
@@ -5333,6 +5663,7 @@ public:
          }
          UpdateDirty();
          Home();
+         undoBuffer.dontRecord--;
       }
    }
 
@@ -5342,7 +5673,10 @@ public:
       {
          if(x > 0)
          {
-            x -= 1 + DelCh(line, y, x-1, line, y, x, true);
+            if(x > line.count)
+               x--;
+            else
+               x -= 1 + _DelCh(line, y, x-1, line, y, x, true, false, null);
             Modified();
          }
          else if(this.line.prev)
@@ -5351,7 +5685,7 @@ public:
             int x = line.count;
             int y = this.y;
 
-            DelCh(line, this.y-1, x, this.line, this.y, this.x, true);
+            _DelCh(line, this.y-1, x, this.line, this.y, this.x, true, false, null);
             this.line = line;
             this.y = y-1;
             this.x = x;
@@ -5412,7 +5746,7 @@ public:
                DirtyLine(c);
             this.y = c;
             this.line = line;
-            Deselect();
+            _Deselect();
             SetViewToCursor(true);
             return true;
          }
@@ -5420,6 +5754,7 @@ public:
       return false;
    }
 
+   // NOTE: Mismatch with NotifyCaretMove() for x/y + 1
    bool GoToPosition(EditLine line, int y, int x)
    {
       /*
@@ -5445,7 +5780,7 @@ public:
          this.y = y;
          this.line = line;
          ComputeColumn();
-         Deselect();
+         _Deselect();
          SetViewToCursor(true);
          return true;
       }
@@ -5457,8 +5792,7 @@ public:
    {
       if(created)
       {
-         int w;
-         int c, numLines;
+         int numLines;
          EditLine line;
          int x;
          int checkX, checkY;
@@ -5470,7 +5804,7 @@ public:
          FixScrollArea();
 
          selected = selX != this.x || selY != y;
-         
+
          viewX = this.viewX;
          viewY = this.viewY;
 
@@ -5518,7 +5852,7 @@ public:
             }
          }
 
-         if(!dontScroll) 
+         if(!dontScroll)
          {
             if(style.vScroll)
             {
@@ -5541,13 +5875,13 @@ public:
                   for(;dropLine && dropLine.prev && dropY >= numLines;)
                   {
                      dropLine = dropLine.prev;
-                     dropY--;                  
+                     dropY--;
                   }
                else
                   for(;this.line && this.line.prev && this.y >= numLines;)
                   {
                      this.line = this.line.prev;
-                     y--;                  
+                     y--;
                   }
             }
 
@@ -5621,7 +5955,7 @@ public:
       }
       else
       {
-         EditLine oldLine = this.line;
+         //EditLine oldLine = this.line;
          bool lastOne = false;
          EditLine oldViewLine = this.viewLine;
          bool figureSyntax = false;
@@ -5657,7 +5991,7 @@ public:
    {
       int c, numLines;
       EditLine line;
-      
+
       if(this.y == 0) return;
 
       numLines = clientSize.h / this.space.h;
@@ -5669,8 +6003,6 @@ public:
       }
       else
       {
-         EditLine oldLine = this.line;
-
          for(c=0, line = this.line.prev; line && c<numLines; line = line.prev, c++)
          {
             this.line = line;
@@ -5712,7 +6044,7 @@ public:
          //DirtyAll();
          // this.viewLine = this.viewLine.next;
          // this.viewY++;
-         
+
          SetScrollPosition(this.viewX, (this.viewY + 1) * this.space.h);
       }
    }
@@ -5756,11 +6088,11 @@ public:
       }
       nx1 = Min(x1,l1.count);
       nx2 = Min(x2,l2.count);
-      
+
       // Find Number of Bytes Needed
       size = 0;
       for(line = l1; line; line = line.next)
-      {  
+      {
          if(line == l1) start = nx1; else start = 0;
          if(line == l2) end = nx2; else end = line.count;
          size += end-start;
@@ -5878,16 +6210,16 @@ public:
 
       // Copy text
       for(line = l1; line; line = line.next)
-      {  
+      {
          if(line == l1) start = nx1; else start = 0;
          if(line == l2) end = nx2; else end = line.count;
          if(text)
          {
             CopyBytes(text, line.buffer + start, end - start);
             text += end-start;
-         } 
+         }
          numChars += end-start;
-         
+
          if(style.freeCaret && line == l2 && addSpaces)
          {
             if(l1 == l2)
@@ -5909,10 +6241,10 @@ public:
             if(text)
                *(text++) = '\r';
             numChars++;
-         } 
+         }
          if(text)
             *(text++) = '\n';
-         numChars++; 
+         numChars++;
       }
       // '\0' terminate Terminate
       if(text)
@@ -5926,12 +6258,17 @@ public:
       GetText(text, line, y, x, selLine, selY, selX, addCr, true);
    }
 
+   private void _Deselect()   // This assumes marking lines as dirty is handled by the caller
+   {
+      selLine = line;
+      selX = x;
+      selY = y;
+   }
+
    void Deselect()
    {
       SelDirty();
-      this.selLine = this.line;
-      this.selX = this.x;
-      this.selY = this.y;
+      _Deselect();
    }
 
    // CLIPBOARD
@@ -5946,7 +6283,7 @@ public:
             ClipBoard clipBoard { };
             if(clipBoard.Allocate(size+1))
             {
-               GetSel(clipBoard.memory, true);   
+               GetSel(clipBoard.memory, true);
                // Save clipboard
                clipBoard.Save();
             }
@@ -5996,8 +6333,8 @@ public:
       savedAction = undoBuffer.curAction;
 
       for(line = this.lines.first; line; line = line.next)
-      {  
-         f.Write(line.buffer, line.count,1);
+      {
+         f.Write(line.buffer, line.count, 1);
          if(line.next)
          {
             if(cr) f.Putc('\r');
@@ -6013,7 +6350,7 @@ public:
       if(f)
       {
          char buffer[BUFFER_SIZE];
-     
+
          for(;;)
          {
             int count = f.Read(buffer, 1, BUFFER_SIZE-1);
@@ -6030,7 +6367,7 @@ public:
       itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count;
    }
 
-   EditBoxFindResult Find(char * text, bool matchWord, bool matchCase, bool isSearchDown)
+   EditBoxFindResult Find(const char * text, bool matchWord, bool matchCase, bool isSearchDown)
    {
       EditLine line;
       int num;
@@ -6044,7 +6381,7 @@ public:
       {
          char * string;
 
-         if(!line) 
+         if(!line)
          {
             if(isSearchDown)
             {
@@ -6059,7 +6396,7 @@ public:
                result = wrapped;
             }
          }
-         
+
          if(isSearchDown)
             string = SearchString(line.buffer, firstPass ? Min(this.x,line.count) : 0,text,matchCase,matchWord);
          else
@@ -6069,7 +6406,7 @@ public:
          {
             Select((void *)line,num,string - line.buffer,(void *)line,num,string - line.buffer + strlen(text));
             return result;
-         } 
+         }
          if(line == this.line && !firstPass) break;
 
          if(isSearchDown)
@@ -6088,7 +6425,7 @@ public:
       return notFound;
    }
 
-   EditBoxFindResult FindInSelection(char * text, bool matchWord, bool matchCase, EditLine l2, int y2, int x2)
+   EditBoxFindResult FindInSelection(const char * text, bool matchWord, bool matchCase, EditLine l2, int y2, int x2)
    {
       EditLine line;
       int y;
@@ -6100,7 +6437,7 @@ public:
          {
             Select((void *)line,y,string - line.buffer,(void *)line,y,string - line.buffer + strlen(text));
             return found;
-         } 
+         }
       }
       return notFound;
    }
@@ -6112,7 +6449,7 @@ public:
 #endif
       if(!NotifyKeyDown(master, this, key, ch))
          return false;
-      else 
+      else
       {
          switch(key)
          {
@@ -6218,7 +6555,7 @@ public:
             y++;
          }
          else
-            break;         
+            break;
       }
 
       editBox.line = editBox.selLine = line;
@@ -6322,13 +6659,13 @@ public:
       }
       return result;
    }
-   
-   bool Puts(char * string)
+
+   bool Puts(const char * string)
    {
       EditBox editBox = this.editBox;
       BufferLocation start { editBox.line, editBox.y, editBox.x };
       BufferLocation pos;
-      
+
       numBytes = 0;
       editBox.AddS(string);
 
@@ -6353,7 +6690,7 @@ public:
       {
          utf8Bytes[numBytes++] = ch;
          utf8Bytes[numBytes] = 0;
-         if(UTF8Validate(utf8Bytes))
+         if(UTF8Validate((char *)utf8Bytes))
          {
             editBox.AddCh(UTF8_GET_CHAR(utf8Bytes, numBytes));
             numBytes = 0;
@@ -6365,7 +6702,7 @@ public:
          }
          return true;
       }
-      return false; 
+      return false;
    }
 
    bool Getc(char * ch)
@@ -6403,7 +6740,7 @@ public:
          start.AdjustDelete(pos, end);
          sel.AdjustDelete(pos, end);
 
-         editBox.DelCh(pos.line, pos.y, pos.x, end.line, end.y, end.x, true);
+         editBox._DelCh(pos.line, pos.y, pos.x, end.line, end.y, end.x, true, false, null);
       }
    }
 };