ecere/gui/EditBox: Fixed hanging caused by 308c3f8a022f58c179f5d52f87be2609fba4ddd8
[sdk] / ecere / src / gui / controls / EditBox.ec
index b9520b8..ff0116a 100644 (file)
@@ -47,28 +47,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,12 +99,13 @@ 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;
+   bool inMultiLineComment:1, inPrep:1, escaped:1, continuedSingleLineComment:1;
 
    bool recomputeSyntax:1;
    bool cursorFollowsView:1;
    
    // bool lineNumbers:1;
+   bool autoSize:1;
 };
 
 /* TODO:
@@ -121,7 +142,7 @@ public class OldArray
       if(type.type == normalClass || type.type == noHeadClass)
       {
          for(c = 0; c<size; c++)
-            type._vTbl[__ecereVMethodID_class_OnFree](type, array[c]);
+            ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, array[c]);
       }
       // TODO: Call OnFree for structClass
       delete ((ArrayImpl)this).array;
@@ -170,16 +191,9 @@ public:
    }
 };
 
-
-class ArrayUndoActions : OldArray
-{
-   type = class(UndoAction);
-   UndoAction * _;
-};
-
 public class UndoBuffer
 {
-   ArrayUndoActions actions { size = 8 };
+   Array<UndoAction> actions { size = 8 };
 public:
    int count;
    int curAction;
@@ -188,13 +202,18 @@ public:
    bool insideRedo;
 
    dontRecord = 0;
+
+   ~UndoBuffer()
+   {
+      actions.Free();
+   }
    
    void Undo()
    {
       dontRecord++;
       if(curAction > 0)
       {
-         UndoAction action = actions._[--curAction];
+         UndoAction action = actions[--curAction];
 #ifdef _DEBUG
          /*Print("Undoing: ");
          action.Print(data);*/
@@ -210,7 +229,7 @@ public:
       insideRedo = true;
       if(curAction < count)
       {
-         UndoAction action = actions._[curAction];
+         UndoAction action = actions[curAction];
          curAction++;
 #ifdef _DEBUG
          /*Print("Redoing: ");
@@ -230,7 +249,7 @@ public:
          {
             int c;
             for(c = curAction; c < count; c++)
-               delete actions._[c];
+               delete actions[c];
          }
 
          count = curAction;
@@ -242,7 +261,7 @@ public:
          /*Print("Recording: ");
          action.Print(data);*/
 #endif
-         actions._[count++] = action;
+         actions[count++] = action;
          curAction = count;
 
          if(actions.size > count + count / 2 && count + count / 2 >= 8)
@@ -640,7 +659,7 @@ static char * keyWords1[] =
    "virtual", "thisclass","unichar", "dbtable", "dbindex", "database_open", "dbfield",
 
    // Types
-   "uint", "uint32", "uint16", "uint64", "bool", "byte", "int64",
+   "uint", "uint32", "uint16", "uint64", "bool", "byte", "int64", "uintptr", "intptr", "intsize", "uintsize",
 
    // Values
    "this", "true", "false", "null", "value",
@@ -662,23 +681,12 @@ static char ** keyWords[] = { keyWords1, keyWords2 };
 //static int * keyLen[NUM_KEYWORD_GROUPS];
 static int keyLen[NUM_KEYWORD_GROUPS][sizeof(keyWords1)];
 
-/*
-static FileFilter filters[] =
-{
-   { "All files", null },
-   {
-      "Text Files (*.txt)",
-      "txt"
-   }
-};
-static FileListConfig fileListConfig = { "", "", filters, sizeof(filters), null, 0 };
-*/
 static char searchString[1025], replaceString[1025];
 static bool matchCase = false, wholeWord = false, searchUp = false;
 
 static GoToDialog goToDialog
 {
-   autoCreate = false, isModal = true, text = "Go To"
+   autoCreate = false, isModal = true, text = $"Go To"
 };
 
 public class EditBox : CommonControl
@@ -723,11 +731,11 @@ public:
    };
 
    // Properties
-   property bool textHorzScroll { property_category "Behavior" set { style.hScroll = value; } get { return style.hScroll; } };      // Should cut the text on set to false
-   property bool textVertScroll { property_category "Behavior" set { style.vScroll = value; } get { return style.vScroll; } };
+   property bool textHorzScroll { property_category $"Behavior" set { style.hScroll = value; } get { return style.hScroll; } };      // Should cut the text on set to false
+   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;
@@ -737,20 +745,21 @@ public:
       }
       get { return style.readOnly; }
    };
-   property bool multiLine { property_category "Behavior" set { style.multiLine = value; } get { return style.multiLine; } };
-   property bool freeCaret { property_category "Behavior" set { style.freeCaret = value; } get { return style.freeCaret; } };
-   property bool tabKey { property_category "Behavior" set { style.tabKey = value; } get { return style.tabKey; } };
-   property int tabSize { property_category "Behavior" set { tabSize = value; } get { return tabSize; } };
-   property bool tabSelection { property_category "Behavior" set { style.tabSel = value; if(value) style.tabKey = true; } get { return style.tabSel; } };
-   property bool smartHome { property_category "Behavior" set { style.smartHome = value; } get { return style.smartHome; } };
-   property bool autoEmpty { property_category "Behavior" set { style.autoEmpty = value; } get { return style.autoEmpty; } };
-   property bool noCaret { property_category "Behavior" set { style.noCaret = value; if(value) { style.readOnly = true; style.stuckCaret = true; } } get { return style.noCaret; } };
-   property int maxLineSize { property_category "Behavior" set { maxLineSize = value; } get { return maxLineSize; } };
-   property int maxNumLines { property_category "Behavior" set { maxLines = value; } get { return maxLines; } };
-   property bool useTab { property_category "Behavior" set { style.useTab = value; itemEditInsertTab.checked = value; } get { return style.useTab; } };
-   property bool syntaxHighlighting { property_category "Appearance" set { style.syntax = value; } get { return style.syntax; } };
-   property bool noSelect { property_category "Behavior" set { style.noSelect = value; } get { return style.noSelect; } };
-   property bool allCaps { property_category "Behavior" set { style.allCaps = value; } get { return style.allCaps; } };
+   property bool multiLine { property_category $"Behavior" set { style.multiLine = value; } get { return style.multiLine; } };
+   property bool freeCaret { property_category $"Behavior" set { style.freeCaret = value; } get { return style.freeCaret; } };
+   property bool tabKey { property_category $"Behavior" set { style.tabKey = value; } get { return style.tabKey; } };
+   property int tabSize { property_category $"Behavior" set { tabSize = value; } get { return tabSize; } };
+   property bool tabSelection { property_category $"Behavior" set { style.tabSel = value; if(value) style.tabKey = true; } get { return style.tabSel; } };
+   property bool smartHome { property_category $"Behavior" set { style.smartHome = value; } get { return style.smartHome; } };
+   property bool autoEmpty { property_category $"Behavior" set { style.autoEmpty = value; } get { return style.autoEmpty; } };
+   property bool noCaret { property_category $"Behavior" set { style.noCaret = value; if(value) { style.readOnly = true; style.stuckCaret = true; } } get { return style.noCaret; } };
+   property int maxLineSize { property_category $"Behavior" set { maxLineSize = value; } get { return maxLineSize; } };
+   property int maxNumLines { property_category $"Behavior" set { maxLines = value; } get { return maxLines; } };
+   property bool useTab { property_category $"Behavior" set { style.useTab = value; itemEditInsertTab.checked = value; } get { return style.useTab; } };
+   property bool syntaxHighlighting { property_category $"Appearance" set { style.syntax = value; } get { return style.syntax; } };
+   property bool noSelect { property_category $"Behavior" set { style.noSelect = value; } get { return style.noSelect; } };
+   property bool allCaps { property_category $"Behavior" set { style.allCaps = value; } get { return style.allCaps; } };
+   property bool autoSize { property_category $"Behavior" set { style.autoSize = value; } get { return style.autoSize; } };
    property bool wrap { set { style.wrap = value; Update(null); } get { return style.wrap; } };
    //property bool lineNumbers { set { style.lineNumbers = value; } get { return style.lineNumbers; } };
    property int numLines { get { return this ? lineCount : 0; } };
@@ -762,7 +771,7 @@ public:
    property EditLine line { get { return this.line; } }; // TODO: Add Set   this.line = this.lines[10]
    property char * contents
    {
-      property_category "Data" 
+      property_category $"Data" 
       set
       {
          if(this)
@@ -940,10 +949,10 @@ private:
    menu = Menu { };
 
    // Edit Menu
-   Menu editMenu { menu, "Edit", e };
+   Menu editMenu { menu, $"Edit", e };
    MenuItem itemEditCut
    {
-      editMenu, "Cut\tCtrl+X", t, disabled = true;
+      editMenu, $"Cut\tCtrl+X", t, disabled = true;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -954,7 +963,7 @@ private:
    };
    MenuItem itemEditCopy
    {
-      editMenu, "Copy\tCtrl+C", c, disabled = true;
+      editMenu, $"Copy\tCtrl+C", c, disabled = true;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -964,7 +973,7 @@ private:
    };
    MenuItem itemEditPaste
    {
-      editMenu, "Paste\tCtrl+V", p;
+      editMenu, $"Paste\tCtrl+V", p;
    
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -975,7 +984,7 @@ private:
    };
    MenuItem itemEditDelete
    {
-      editMenu, "Delete\tDel", d, disabled = true;
+      editMenu, $"Delete\tDel", d, disabled = true;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -987,7 +996,7 @@ private:
    MenuDivider { editMenu };
    MenuItem itemEditSelectAll
    {
-      editMenu, "Select All\tCtrl+A", a;
+      editMenu, $"Select All\tCtrl+A", a;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -998,7 +1007,7 @@ private:
    MenuDivider { editMenu };
    MenuItem itemEditUndo
    {
-      editMenu, "Undo\tCtrl+Z", u;
+      editMenu, $"Undo\tCtrl+Z", u;
       disabled = true;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
@@ -1009,7 +1018,7 @@ private:
    };
    MenuItem itemEditRedo
    {
-      editMenu, "Redo\tCtrl+Y", o;
+      editMenu, $"Redo\tCtrl+Y", o;
       disabled = true;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
@@ -1021,7 +1030,7 @@ private:
    MenuDivider { editMenu };
    MenuItem
    {
-      editMenu, "Find Previous\tShift-F3", e, shiftF3;
+      editMenu, $"Find Previous\tShift-F3", e, shiftF3;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -1034,7 +1043,7 @@ private:
    };
    MenuItem
    {
-      editMenu, "Find Next\tF3", n, f3;
+      editMenu, $"Find Next\tF3", n, f3;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -1047,7 +1056,7 @@ private:
    };
    MenuItem itemEditFind
    {
-      editMenu, "Find...\tCtrl+F", f, ctrlF;
+      editMenu, $"Find...\tCtrl+F", f, ctrlF;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -1074,7 +1083,7 @@ private:
    };
    MenuItem
    {
-      editMenu, "Replace...\tCtrl+R", r, ctrlR;
+      editMenu, $"Replace...\tCtrl+R", r, ctrlR;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -1108,7 +1117,7 @@ private:
    MenuDivider { editMenu };
    MenuItem
    {
-      editMenu, "Go To...\tCtrl+G", g, ctrlG;
+      editMenu, $"Go To...\tCtrl+G", g, ctrlG;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -1121,7 +1130,7 @@ private:
    MenuDivider { editMenu };
    MenuItem itemEditInsertTab
    {
-      editMenu, "Insert Tabs", i, checkable = true;
+      editMenu, $"Insert Tabs", i, checkable = true;
 
       bool NotifySelect(MenuItem item, Modifiers mods)
       {
@@ -1288,7 +1297,7 @@ private:
          bool inPrep = reset ? false : style.inPrep;
          bool inSingleLineComment = false;
          bool escaped = reset ? false : style.escaped;
-         bool continuedSingleLineComment = false;
+         bool continuedSingleLineComment = reset ? false : style.continuedSingleLineComment;
 
          EditLine line = reset ? lines.first : firstLine;
          // int maxBackUp = 1000, c;
@@ -1333,7 +1342,7 @@ private:
                {
                   if(!c || text[c-1] != '/') lastWasStar = true;
                }
-               else if(!inSingleLineComment && !inMultiLineComment && !inQuotes && ch == '\"')
+               else if(ch == '\"' && !inSingleLineComment && !inMultiLineComment && !inQuotes)
                {
                   if(inString && !wasEscaped)
                   {
@@ -1344,7 +1353,7 @@ private:
                      inString = true;
                   }
                }
-               else if(!inSingleLineComment && !inMultiLineComment && !inString && ch == '\'')
+               else if(ch == '\'' && !inSingleLineComment && !inMultiLineComment && !inString)
                {
                   if(inQuotes && !wasEscaped)
                      inQuotes = false;
@@ -1358,22 +1367,20 @@ private:
                   if(!wasEscaped)
                      escaped = true;
                }
-               else
+               else if(ch == '#' && !inQuotes && !inString && !inMultiLineComment && !inSingleLineComment)
                {
-                  if(!inQuotes && !inString && !inMultiLineComment && !inSingleLineComment && ch == '#')
+                  if(firstWord)
                   {
-                     if(firstWord)
-                     {
-                        inPrep = true;
-                     }
+                     inPrep = true;
                   }
                }
-               firstWord = false;
+               else if(ch != ' ' && ch != '\t')
+                  firstWord = false;
             }
+            continuedSingleLineComment = inSingleLineComment && (line.count && line.text[line.count - 1] == '\\');
          }
          
-         continuedSingleLineComment = inSingleLineComment && (line.count && line.text[line.count - 1] == '\\');
-
+         style.continuedSingleLineComment = continuedSingleLineComment;
          style.inMultiLineComment = inMultiLineComment;
          style.inPrep = inPrep;
          style.escaped = escaped;
@@ -1437,7 +1444,7 @@ private:
       bool inPrep = style.inPrep;
       bool inSingleLineComment = false;
       bool escaped = style.escaped;
-      bool continuedSingleLineComment = false;
+      bool continuedSingleLineComment = style.continuedSingleLineComment;
       // ****** ************* ******
 
       if(!isEnabled)
@@ -1449,7 +1456,7 @@ private:
          Abs(selectionBackground.g - property::background.g) + 
          Abs(selectionBackground.b - property::background.b) < 92)
       {
-         selectionBackground = activeBorder;
+         selectionBackground = formColor;
          selectionForeground = selectionColor ? selectionColor : SELECTION_COLOR;
       }
 
@@ -1461,7 +1468,7 @@ private:
 
       if(!isEnabled)
       {
-         surface.SetBackground(activeBorder);
+         surface.SetBackground(formColor);
          surface.Area(0,0,clientSize.w, clientSize.h);
       }
 
@@ -1557,7 +1564,10 @@ private:
             
             textColor = newTextColor;
             if(!selected)
+            {
+               foreground = textColor;
                surface.SetForeground(textColor);
+            }
 
             // Look at words
             for(; c<end && !cantHaveWords;)
@@ -1678,7 +1688,7 @@ private:
                         }
                         else if(wordLen == 1 && word[0] == '*')
                         {
-                           if(!c || word[-1] != '/')
+                           if(c < 2 || word[-1] != '/')
                               lastWasStar = true;
                         }
                         else if(!inSingleLineComment && !inMultiLineComment && !inQuotes && wordLen == 1 && word[0] == '\"')
@@ -1764,7 +1774,10 @@ private:
                            {
                               textColor = newTextColor;
                               if(!selected)
+                              {
+                                 foreground = textColor;
                                  surface.SetForeground(textColor);
+                              }
                            }
                         }
                      }
@@ -2011,9 +2024,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);
@@ -2258,6 +2270,7 @@ private:
       }
       ComputeLength(l1);
       FindMaxLine();
+      if(style.autoSize) AutoSize();
       if(style.syntax && (hadComment || HasCommentOrEscape(this.line)))
       {
          DirtyAll();
@@ -2471,6 +2484,7 @@ 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))
@@ -2983,6 +2997,43 @@ private:
       return true;
    }
 
+   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 };
+         }
+      }
+   }
+
    bool OnResizing(int *w, int *h)
    {
       if(!*h)
@@ -3030,12 +3081,12 @@ private:
          PopupMenu popup;
          Menu contextMenu { };
 
-         MenuItem { contextMenu, "Cut\tCtrl+X", t, NotifySelect = itemEditCut.NotifySelect, disabled = !selection || style.readOnly };
-         MenuItem { contextMenu, "Copy\tCtrl+C", c, NotifySelect = itemEditCopy.NotifySelect, disabled = !selection };
-         MenuItem { contextMenu, "Paste\tCtrl+V", p, NotifySelect = itemEditPaste.NotifySelect, disabled = style.readOnly };
-         MenuItem { contextMenu, "Delete\tDel", d, NotifySelect = itemEditDelete.NotifySelect, disabled = !selection || style.readOnly };
+         MenuItem { contextMenu, $"Cut\tCtrl+X", t, NotifySelect = itemEditCut.NotifySelect, disabled = !selection || style.readOnly };
+         MenuItem { contextMenu, $"Copy\tCtrl+C", c, NotifySelect = itemEditCopy.NotifySelect, disabled = !selection };
+         MenuItem { contextMenu, $"Paste\tCtrl+V", p, NotifySelect = itemEditPaste.NotifySelect, disabled = style.readOnly };
+         MenuItem { contextMenu, $"Delete\tDel", d, NotifySelect = itemEditDelete.NotifySelect, disabled = !selection || style.readOnly };
          MenuDivider { contextMenu };
-         MenuItem { contextMenu, "Select All\tCtrl+A", a, NotifySelect = itemEditSelectAll.NotifySelect };
+         MenuItem { contextMenu, $"Select All\tCtrl+A", a, NotifySelect = itemEditSelectAll.NotifySelect };
 
          popup = PopupMenu { master = this, menu = contextMenu,
    /*
@@ -3317,7 +3368,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();
@@ -3335,19 +3386,18 @@ private:
       return true;
    }
 
-   /*
    bool OnPostCreate()
    {
-      if(isDocument)
+      /*if(isDocument)
       {
          Menu fileMenu { menu, "File", F };
          saveDialog = fileDialog;
-         MenuItem { fileMenu, "Save\tCtrl+S", S, CtrlS, NotifySelect = MenuFileSave };
-         MenuItem { fileMenu, "Save As...", A, NotifySelect = MenuFileSaveAs };
-      }
+         MenuItem { fileMenu, $"Save\tCtrl+S", S, CtrlS, NotifySelect = MenuFileSave };
+         MenuItem { fileMenu, $"Save As...", A, NotifySelect = MenuFileSaveAs };
+      }*/
+      if(style.autoSize) AutoSize();
       return true;
    }
-   */
 
    void ComputeFont()
    {
@@ -3486,13 +3536,10 @@ private:
                   {
                      int i;
                      int length;
-                     //Can't delete right away as that would change the line.count
                      for(i = this.x; i < this.line.count; i++)
                      {
                         if(!IS_ALUNDER(this.line.buffer[i]))
                            break;
-                        DelCh(this.line, this.y, this.x, this.line, this.y, this.x+1, false);
-                        i--;
                      }
                      
                      for(; i < this.line.count; i++)
@@ -3500,9 +3547,8 @@ private:
                         //Delete trailing whitespace
                         if(IS_ALUNDER(this.line.buffer[i]))
                            break;
-                        DelCh(this.line, this.y, this.x, this.line, this.y, this.x+1, false);
-                        i--;
                      }
+                     DelCh(this.line, this.y, this.x, this.line, this.y, i, false);
                      SetViewToCursor(true);
                      Modified();
                   }
@@ -3764,9 +3810,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;
@@ -3813,9 +3859,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)
@@ -4350,6 +4396,7 @@ private:
                            if(!line.AdjustBuffer(line.count-lastC)) 
                               break;
                            line.count-=lastC;
+                           if(style.autoSize) AutoSize();
                            DirtyLine(y);
                         }
 
@@ -4374,6 +4421,7 @@ private:
                                        break;
 
                                     NotifyCharsAdded(master, this, &before, &after, this.pasteOperation);
+                                    if(style.autoSize) AutoSize();
                                     {
                                        AddCharAction action { ch = '\t', x = 0, y = y };
                                        Record(action);
@@ -4391,6 +4439,7 @@ 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)) 
                                        break;
@@ -4433,7 +4482,7 @@ private:
                         ComputeColumn();
                      }
                      // Insert spaces
-                     start = this.x;
+                     start = Min(this.x, this.selX);
                      for(c=start; ((c == start) || ((c) % this.tabSize)); c++)
                      {
                         addString[len++] = ' ';
@@ -4877,6 +4926,7 @@ 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
@@ -4902,6 +4952,7 @@ private:
       }
       if(addCharAction)
       {
+         addCharAction.x -= addedTabs * (tabSize-1);
          addCharAction.addedSpaces = addedSpaces;
          addCharAction.addedTabs = addedTabs;
       }
@@ -5246,6 +5297,7 @@ public:
          }  
          if(addCharAction)
          {
+            addCharAction.x -= addedTabs * (tabSize-1);
             addCharAction.addedSpaces = addedSpaces;
             addCharAction.addedTabs = addedTabs;
          }
@@ -5274,7 +5326,8 @@ public:
          char temp[MAX_F_STRING];
          va_list args;
          va_start(args, format);
-         vsprintf(temp, format, args);
+         vsnprintf(temp, sizeof(temp), format, args);
+         temp[sizeof(temp)-1] = 0;
          va_end(args);
          PutS(temp);
       }
@@ -5291,7 +5344,8 @@ public:
             char temp[MAX_F_STRING];
             va_list args;
             va_start(args, format);
-            vsprintf(temp, format, args);
+            vsnprintf(temp, sizeof(temp), format, args);
+            temp[sizeof(temp)-1] = 0;
             va_end(args);
 
             AddS(temp);
@@ -5936,9 +5990,11 @@ public:
       if(this)
       {
          Copy();
-         DelSel(null);
-         SetViewToCursor(true);
-         Modified();
+         if(DelSel(null))
+         {
+            SetViewToCursor(true);
+            Modified();
+         }
       }
    }