diff --git a/haskell/System/Console/Isocline.hs b/haskell/System/Console/Isocline.hs
--- a/haskell/System/Console/Isocline.hs
+++ b/haskell/System/Console/Isocline.hs
@@ -605,7 +605,9 @@
           = let len = (fromIntegral clen :: Int)
             in if (len <= 0) then return (cbool False)
                 else do s <- peekCStringLen (cstr,len)
-                        return (if null s then (cbool False) else cbool (isInClass (head s)))
+                        return (cbool (case s of 
+                                        ""    -> False
+                                        (c:_) -> isInClass c))
     in do ic_make_charclassfun charClassFun
           
 
diff --git a/include/isocline.h b/include/isocline.h
--- a/include/isocline.h
+++ b/include/isocline.h
@@ -44,8 +44,8 @@
 /// The basic readline interface.
 /// \{
 
-/// Isocline version: 102 = 1.0.2.
-#define IC_VERSION   (104)  
+/// Isocline version: 110 = 1.1.0.
+#define IC_VERSION   (110)  
 
 
 /// Read input from the user using rich editing abilities.
diff --git a/isocline.cabal b/isocline.cabal
--- a/isocline.cabal
+++ b/isocline.cabal
@@ -1,14 +1,14 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.34.6.
+-- This file has been generated from package.yaml by hpack version 0.39.1.
 --
 -- see: https://github.com/sol/hpack
 
 name:           isocline
-version:        1.0.9
+version:        1.1.0
 synopsis:       A portable alternative to GNU Readline
 description:    ![logo](https://raw.githubusercontent.com/daanx/isocline/main/doc/isocline-inline.svg) A Haskell wrapper around the [Isocline C library](https://github.com/daanx/isocline#readme) which can provide an alternative to GNU Readline. (The Isocline library is included whole and there are no runtime dependencies).
-                Please see the [readme](https://github.com/daanx/isocline/haskell#readme) on GitHub for more information.
+                Please see the [readme](https://github.com/daanx/isocline#readme) on GitHub for more information.
 category:       console
 homepage:       https://github.com/daanx/isocline#readme
 bug-reports:    https://github.com/daanx/isocline/issues
@@ -67,8 +67,8 @@
       src/isocline.c
   build-depends:
       base >=3.0 && <5
-    , bytestring
-    , text
+    , bytestring >=0.9 && <2
+    , text >=0.1 && <3
   default-language: Haskell2010
 
 executable example
@@ -79,9 +79,9 @@
       test
   build-depends:
       base >=3.0 && <5
-    , bytestring
+    , bytestring >=0.9 && <2
     , isocline
-    , text
+    , text >=0.1 && <3
   default-language: Haskell2010
 
 test-suite test-example
@@ -93,7 +93,7 @@
       test
   build-depends:
       base >=3.0 && <5
-    , bytestring
+    , bytestring >=0.9 && <2
     , isocline
-    , text
+    , text >=0.1 && <3
   default-language: Haskell2010
diff --git a/src/common.c b/src/common.c
--- a/src/common.c
+++ b/src/common.c
@@ -231,11 +231,11 @@
     if (count != NULL) *count = 2;
     return (((c0 & 0x1F) << 6) | (s[1] & 0x3F));
   }
-  // 3 bytes: reject overlong and surrogate halves
+  // 3 byte encoding; reject overlong and utf-16 surrogate halves (0xD800 - 0xDFFF)
   else if (len >= 3 && 
            ((c0 == 0xE0 && s[1] >= 0xA0 && s[1] <= 0xBF && utf8_is_cont(s[2])) ||
-            (c0 >= 0xE1 && c0 <= 0xEC && utf8_is_cont(s[1]) && utf8_is_cont(s[2])) 
-          ))
+            (c0 >= 0xE1 && c0 <= 0xEF && c0 != 0xED && utf8_is_cont(s[1]) && utf8_is_cont(s[2])) ||
+            (c0 == 0xED && s[1] > 0x80 && s[1] <= 0x9F && utf8_is_cont(s[2]))))
   {
     if (count != NULL) *count = 3;
     return (((c0 & 0x0F) << 12) | ((unicode_t)(s[1] & 0x3F) << 6) | (s[2] & 0x3F));
diff --git a/src/completers.c b/src/completers.c
--- a/src/completers.c
+++ b/src/completers.c
@@ -23,6 +23,7 @@
 typedef struct word_closure_s {
   long                  delete_before_adjust;
   void*                 prev_env;
+  const char*           postfix;          // content after the cursor
   ic_completion_fun_t*  prev_complete;
 } word_closure_t;
 
@@ -31,7 +32,8 @@
 static bool token_add_completion_ex(ic_env_t* env, void* closure, const char* replacement, const char* display, const char* help, long delete_before, long delete_after) {
   word_closure_t* wenv = (word_closure_t*)(closure);
   // call the previous completer with an adjusted delete-before
-  return (*wenv->prev_complete)(env, wenv->prev_env, replacement, display, help, wenv->delete_before_adjust + delete_before, delete_after);
+  const long delete_after_adjust = (long)ic_count_end_overlap(replacement, wenv->postfix);
+  return (*wenv->prev_complete)(env, wenv->prev_env, replacement, display, help, wenv->delete_before_adjust + delete_before, delete_after_adjust + delete_after);
 }
 
 
@@ -61,6 +63,7 @@
   wenv.delete_before_adjust = (long)(len - pos);
   wenv.prev_complete = cenv->complete;
   wenv.prev_env = cenv->env;
+  wenv.postfix = cenv->input + cenv->cursor;
   cenv->complete = &token_add_completion_ex;
   cenv->closure = &wenv;
 
@@ -77,6 +80,8 @@
 // Quoted word completion (with escape characters)
 //-------------------------------------------------------------
 
+
+
 // free variables for word completion
 typedef struct qword_closure_s {
   char         escape_char;
@@ -84,6 +89,7 @@
   long         delete_before_adjust;
   stringbuf_t* sbuf;
   void*        prev_env;
+  const char*  postfix;      // follows the current input position
   ic_is_char_class_fun_t* is_word_char;
   ic_completion_fun_t*    prev_complete;
 } qword_closure_t;
@@ -112,7 +118,8 @@
     }
   }
   // and call the previous completion function
-  return (*wenv->prev_complete)( env, wenv->prev_env, sbuf_string(wenv->sbuf), display, help, wenv->delete_before_adjust + delete_before, delete_after );  
+  const long delete_after_adjust = (long)ic_count_end_overlap(sbuf_string(wenv->sbuf), wenv->postfix);
+  return (*wenv->prev_complete)( env, wenv->prev_env, sbuf_string(wenv->sbuf), display, help, wenv->delete_before_adjust + delete_before, delete_after_adjust + delete_after );  
 }
 
 
@@ -236,7 +243,8 @@
   wenv.escape_char    = escape_char;
   wenv.delete_before_adjust = (long)(len - pos);
   wenv.prev_complete  = cenv->complete;
-  wenv.prev_env       =  cenv->env;
+  wenv.prev_env       = cenv->env;
+  wenv.postfix        = cenv->input + cenv->cursor;
   wenv.sbuf = sbuf_new(cenv->env->mem);
   if (wenv.sbuf == NULL) { mem_free(cenv->env->mem, word); return; }
   cenv->complete = &qword_add_completion_ex;
diff --git a/src/completions.c b/src/completions.c
--- a/src/completions.c
+++ b/src/completions.c
@@ -175,7 +175,7 @@
   ssize_t n = cm->delete_before + cm->delete_after;
   if (ic_strlen(cm->replacement) == n && strncmp(sbuf_string_at(sbuf,start), cm->replacement, to_size_t(n)) == 0) {
     // no changes
-    return -1;
+    return start + n;
   }
   else {
     sbuf_delete_from_to( sbuf, start, pos + cm->delete_after );
@@ -244,6 +244,7 @@
   memset(&cprefix,0,sizeof(cprefix));
   cprefix.delete_before = delete_before;
   cprefix.replacement   = prefix;
+  cprefix.delete_after  = ic_count_end_overlap(prefix, sbuf_string_at(sbuf, pos));
   ssize_t newpos = completion_apply( &cprefix, sbuf, pos);
   if (newpos < 0) return newpos;  
 
diff --git a/src/editline.c b/src/editline.c
--- a/src/editline.c
+++ b/src/editline.c
@@ -938,17 +938,17 @@
       if (eb.pos == 0 && editor_pos_is_at_end(&eb)) break; // ctrl+D on empty quits with NULL
       edit_delete_char(env,&eb);     // otherwise it is like delete
     } 
-    else if (c == KEY_CTRL_C || c == KEY_EVENT_STOP) {
-      break; // ctrl+C or STOP event quits with NULL
+    else if (c == KEY_EVENT_STOP) {
+      break; // STOP event quits with NULL
     }
     else if (c == KEY_ESC) {
       if (eb.pos == 0 && editor_pos_is_at_end(&eb)) break;  // ESC on empty input returns with empty input
       edit_delete_all(env,&eb);      // otherwise delete the current input
       // edit_delete_line(env,&eb);  // otherwise delete the current line
     }
-    else if (c == KEY_BELL /* ^G */) {
+    else if (c == KEY_BELL /* ^G */ || c == KEY_CTRL_C) {
       edit_delete_all(env,&eb);
-      break; // ctrl+G cancels (and returns empty input)
+      break; // ctrl+G or ctrl+c cancels (and returns empty input)
     }
 
     // Editing Operations
@@ -1112,7 +1112,7 @@
   
   // save result
   char* res; 
-  if ((c == KEY_CTRL_D && sbuf_len(eb.input) == 0) || c == KEY_CTRL_C || c == KEY_EVENT_STOP) {
+  if ((c == KEY_CTRL_D && sbuf_len(eb.input) == 0) || c == KEY_EVENT_STOP) {
     res = NULL;
   }
   else if (!tty_is_utf8(env->tty)) {
diff --git a/src/editline_completion.c b/src/editline_completion.c
--- a/src/editline_completion.c
+++ b/src/editline_completion.c
@@ -261,8 +261,9 @@
     if (!autotab) { term_beep(env->term); }
   }
   else if (count == 1) {
+    ssize_t old_pos = eb->pos;
     // complete if only one match    
-    if (edit_complete(env,eb,0 /*idx*/) && env->complete_autotab) {
+    if (edit_complete(env,eb,0 /*idx*/) && env->complete_autotab && eb->pos > old_pos) {
       tty_code_pushback(env->tty,KEY_EVENT_AUTOTAB);
     }    
   }
diff --git a/src/editline_help.c b/src/editline_help.c
--- a/src/editline_help.c
+++ b/src/editline_help.c
@@ -95,7 +95,7 @@
 
 static const char* help_initial = 
   "[ic-info]"
-  "Isocline v1.0, copyright (c) 2021 Daan Leijen.\n"
+  "Isocline v1.1, copyright (c) 2021-2026 Daan Leijen.\n"
   "This is free software; you can redistribute it and/or\n"
   "modify it under the terms of the MIT License.\n"
   "See <[url]https://github.com/daanx/isocline[/url]> for further information.\n"
diff --git a/src/isocline.c b/src/isocline.c
--- a/src/isocline.c
+++ b/src/isocline.c
@@ -13,7 +13,12 @@
 // $ gcc -c src/isocline.c 
 //-------------------------------------------------------------
 #if !defined(IC_SEPARATE_OBJS)
-# define _CRT_SECURE_NO_WARNINGS  // for msvc
+# ifndef _CRT_NONSTDC_NO_WARNINGS
+#  define _CRT_NONSTDC_NO_WARNINGS // for msvc
+# endif
+# ifndef _CRT_SECURE_NO_WARNINGS
+#  define _CRT_SECURE_NO_WARNINGS  // for msvc
+# endif
 # define _XOPEN_SOURCE   700      // for wcwidth
 # define _DEFAULT_SOURCE          // ensure usleep stays visible with _XOPEN_SOURCE >= 700
 # include "attr.c"
diff --git a/src/stringbuf.c b/src/stringbuf.c
--- a/src/stringbuf.c
+++ b/src/stringbuf.c
@@ -679,8 +679,9 @@
 }
 
 ic_private stringbuf_t* sbuf_split_at( stringbuf_t* sb, ssize_t pos ) {
+  if (pos < 0) return NULL;
   stringbuf_t* res = sbuf_new(sb->mem);
-  if (res==NULL || pos < 0) return NULL;
+  if (res==NULL) return NULL;
   if (pos < sb->count) {
     sbuf_append_n(res, sb->buf + pos, sb->count - pos);
     sb->count = pos;
@@ -889,6 +890,27 @@
   return s;
 }
 
+
+
+static int ic_strncmp(const char* s1, const char* s2, ssize_t n) {
+  return strncmp(s1, s2, to_size_t(n));
+}
+
+ic_private ssize_t ic_count_end_overlap(const char* s, const char* postfix) {
+  if (s==NULL || postfix==NULL) return 0;
+  const ssize_t slen = ic_strlen(s);
+  for (ssize_t count = ic_strlen(postfix); count > 0; count--) {
+    if (count <= slen) {
+      if (ic_strncmp(&s[slen - count], postfix, count) == 0) {
+        return count;
+      }
+    }
+  }
+  return 0;
+}
+
+
+
 //-------------------------------------------------------------
 // String helpers
 //-------------------------------------------------------------
@@ -1000,11 +1022,6 @@
     i += next;
   }
   return (long)(i - pos);
-}
-
-
-static int ic_strncmp(const char* s1, const char* s2, ssize_t n) {
-  return strncmp(s1, s2, to_size_t(n));
 }
 
 // Convenience: Does this match the specified token? 
diff --git a/src/stringbuf.h b/src/stringbuf.h
--- a/src/stringbuf.h
+++ b/src/stringbuf.h
@@ -69,6 +69,8 @@
 ic_private ssize_t sbuf_find_ws_word_start( stringbuf_t* sbuf, ssize_t pos );
 ic_private ssize_t sbuf_find_ws_word_end( stringbuf_t* sbuf, ssize_t pos );
 
+ic_private ssize_t ic_count_end_overlap(const char* s, const char* postfix);
+
 // parse a decimal 
 ic_private bool ic_atoz(const char* s, ssize_t* i);
 // parse two decimals separated by a semicolon
diff --git a/src/term.c b/src/term.c
--- a/src/term.c
+++ b/src/term.c
@@ -1031,7 +1031,7 @@
   #if __APPLE__
   // otherwise use OSC 4 escape sequence query
   if (tty_start_raw(term->tty)) {
-    for(ssize_t i = 0; i < 16; i++) {
+    for(int i = 0; i < 16; i++) {
       uint32_t color;
       if (!term_esc_query_color_raw(term, i, &color)) break;
       debug_msg("term ansi color %d: 0x%06x\n", i, color);
diff --git a/src/tty.h b/src/tty.h
--- a/src/tty.h
+++ b/src/tty.h
@@ -152,7 +152,7 @@
 #define KEY_CTRL_END      (WITH_CTRL(KEY_END))
 #define KEY_CTRL_DEL      (WITH_CTRL(KEY_DEL))
 #define KEY_CTRL_PAGEUP   (WITH_CTRL(KEY_PAGEUP))
-#define KEY_CTRL_PAGEDOWN (WITH_CTRL(KEY_PAGEDOWN)))
+#define KEY_CTRL_PAGEDOWN (WITH_CTRL(KEY_PAGEDOWN))
 #define KEY_CTRL_INS      (WITH_CTRL(KEY_INS))
 
 #define KEY_SHIFT_TAB     (WITH_SHIFT(KEY_TAB))
