Index: gcalctool/functions.c
===================================================================
--- gcalctool/functions.c	(revision 1877)
+++ gcalctool/functions.c	(working copy)
@@ -253,113 +253,165 @@
 }
 
 
-int
-exp_insert(char *text, int cursor)
+static char *
+get_substitute(char *token)
 {
-    char buf[MAXLINE], *display;
+    int i, MP_reg[MP_SIZE];
     struct exprm_state *e = get_state();
     
-    if (cursor < 0) {
-        SNPRINTF(buf, MAXLINE, "%s%s", e->expression, text);
+    if (strcmp(token, "Ans") == 0) {
+        return make_number(e->ans, v->base, FALSE);
+    } else if (token[0] == 'R' && (token[1] >= '0' && token[1] <= '9') && token[2] == '\0') {
+        i = token[1] - '0';
+        do_rcl_reg(i, MP_reg);
+        return make_number(MP_reg, v->base, FALSE);
     } else {
-        display = ui_get_display();
-        SNPRINTF(buf, MAXLINE, "%.*s%s%s", cursor, display, text, display + cursor);
-        cursor += strlen(text);
+        assert(FALSE);
     }
-    exp_replace(buf);
-    
-    return cursor;
 }
 
 
-void
-exp_clear()
+static gboolean
+startswith(char *line, char *word)
 {
-    exp_replace("Ans");
+    char *c, *l;
+    
+    for(c = word, l = line; *c && *l && *c == *l; c++, l++);
+    return *c == '\0';
 }
 
 
-int
-usable_num(int MPnum[MP_SIZE])
+/* 
+ * Expand the expression if the cursor is inside a token (Ans, R0-R9).
+ * 
+ * @param cursor         the cursor location in the displayed expression.
+ * @param expand_before  if TRUE expand if the cursor is at the start of a token.
+ * @param expand_after   if TRUE expand if the cursor is at the end of a token.
+ * 
+ * @returns  the cursor location in the updated expression.
+ */
+static int
+exp_expand(int cursor, gboolean expand_before, gboolean expand_after)
 {
+    int i, token_length = 0, substitute_length = 0;
+    int exp_offset = 0, disp_offset = 0;
+    char *equation_ptr;
+    char output[MAXLINE];
     struct exprm_state *e = get_state();
-    return ce_parse(e->expression, MPnum);
-}
+    static char *subs[] = {"Ans", "R0", "R1", "R2", "R3", "R4",
+                           "R5", "R6", "R7", "R8", "R9", NULL};
+    
+    for (equation_ptr = e->expression; *equation_ptr;) {
+        /* Look for tokens to replace */
+        token_length = 1;
+        substitute_length = 1;
+        for(i = 0; subs[i]; i++) {
+            char *key, *value;
+            int value_length, substitute_offset;
+            
+            key = subs[i];
+            value = get_substitute(key);
+            value_length = strlen(value);
 
+            if(startswith(equation_ptr, key)) {
+                token_length = strlen(key);
+                substitute_length = value_length;
+                
+                /* If the cursor is beside or inside this token then
+                 * perform the substitution */
+                substitute_offset = cursor - disp_offset;
+                if ((substitute_offset > 0 && substitute_offset < substitute_length) ||
+                    (expand_before && (substitute_offset == substitute_length)) ||
+                    (expand_after && (substitute_offset == 0))) {
+                    SNPRINTF(output, MAXLINE, "%.*s%s%s",
+                             exp_offset, e->expression,
+                             value,
+                             e->expression + exp_offset + token_length);
+                    free(e->expression);
+                    e->expression = strdup(output);
 
-static int
-exp_has_postfix(char *str, char *postfix)
-{
-    int len, plen;
+                    return exp_offset + substitute_offset;
+                }
 
-    if (!str) {
-        return(0);
-    }
+                break;
+            }
+        }
 
-    assert(postfix);
+        /* Update offset in display and expression */
+        disp_offset += substitute_length;
 
-    len = strlen(str);
-    plen = strlen(postfix);
+        /* Stop if past the cursor */
+        if (disp_offset > cursor)
+            break;
+        
+        exp_offset += token_length;
 
-    if (plen > len) {
-        return(0);
+        /* Skip over the token */
+        equation_ptr += token_length;
     }
 
-    if (!strcasecmp(str + len - plen, postfix)) {
-        return(1);
-    } else {
-        return(0);
-    }
+    return exp_offset;
 }
 
 
+int
+exp_insert(char *text, int cursor)
+{
+    char buf[MAXLINE];
+    int c;
+    struct exprm_state *e = get_state();
+    
+    c = exp_expand(cursor, FALSE, FALSE);
+    SNPRINTF(buf, MAXLINE, "%.*s%s%s", c, e->expression, text, e->expression + c);
+    exp_replace(buf);    
+    
+    return cursor + strlen(text);
+}
+
+
+void
+exp_clear()
+{
+    exp_replace("Ans");
+}
+
+
+int
+usable_num(int MPnum[MP_SIZE])
+{
+    struct exprm_state *e = get_state();
+    return ce_parse(e->expression, MPnum);
+}
+
+
 static int
 exp_backspace(int cursor)
 {
-    char buf[MAXLINE] = "", *display;
     struct exprm_state *e = get_state();
-    int i, MP_reg[MP_SIZE];
+    int c;
+    char buf[MAXLINE];
 
-    /* If cursor is at end of the line then delete the last character preserving accuracy */
-    if (cursor < 0) {
-        if (exp_has_postfix(e->expression, "Ans")) {
-            char *ans = make_number(e->ans, v->base, FALSE);
-            str_replace(&e->expression, "Ans", ans);
-        } else {
-            for (i = 0; i < 10; i++) {
-                SNPRINTF(buf, MAXLINE, "R%d", i);
-                if (exp_has_postfix(e->expression, buf)) {
-                    do_rcl_reg(i, MP_reg);
-                    display = make_number(MP_reg, v->base, FALSE);
-                    /* Remove "Rx" postfix and replace with backspaced number */
-                    SNPRINTF(buf, MAXLINE, "%.*s%s", strlen(e->expression) - 2, e->expression - 3, display);
-                    exp_replace(buf);
-                    return cursor - 1;
-                }
-            }
-        }
-
-        SNPRINTF(buf, MAXLINE, "%.*s", strlen(e->expression) - 1, e->expression);
-    } else if (cursor > 0) {
-        display = ui_get_display();
-        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor - 1, display, display + cursor);
+    c = exp_expand(cursor, TRUE, FALSE);
+    if (c > 0) {
+        SNPRINTF(buf, MAXLINE, "%.*s%s", c - 1, e->expression, e->expression + c);
+        exp_replace(buf);
+        return cursor - 1;
     } else {
-        return cursor; /* At the start of the line */
+        return cursor;
     }
-
-    exp_replace(buf);
-    return cursor - 1;
 }
 
 
 static int
 exp_delete(int cursor)
 {
-    char buf[MAXLINE] = "", *display;
+    struct exprm_state *e = get_state();
+    int c;
+    char buf[MAXLINE];
     
-    if (cursor >= 0) {
-        display = ui_get_display();
-        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor, display, display + cursor + 1);
+    c = exp_expand(cursor, FALSE, TRUE);
+    if (e->expression[c] != '\0') {
+        SNPRINTF(buf, MAXLINE, "%.*s%s", cursor, e->expression, e->expression + cursor + 1);
         exp_replace(buf);
     }
 
@@ -370,8 +422,7 @@
 void
 exp_replace(char *text)
 {
-    struct exprm_state *e;
-    e = get_state();
+    struct exprm_state *e = get_state();
     if (e->expression != NULL) {
         free(e->expression);
     }
Index: gcalctool/gtk.c
===================================================================
--- gcalctool/gtk.c	(revision 1877)
+++ gcalctool/gtk.c	(working copy)
@@ -992,13 +992,9 @@
     char localized[MAX_LOCALIZED];
     GtkTextIter iter;
 
-    if (str == NULL || str[0] == '\0') {
-        str = " ";
-    } else {
-        if (v->noparens == 0) {
-            localize_number(localized, str);
-            str = localized;
-        }
+    if (v->noparens == 0) {
+        localize_number(localized, str);
+        str = localized;
     }
     
     gtk_text_buffer_set_text(X->display_buffer, str, -1);
@@ -1141,13 +1137,7 @@
 {
     gint pos;
     g_object_get(G_OBJECT(X->display_buffer), "cursor-position", &pos, NULL);
-    
-    /* Convert the last position to -1 */
-    if (pos == gtk_text_buffer_get_char_count(X->display_buffer)) {
-        return (-1);
-    } else {
-        return (pos);
-    }
+    return (pos);
 }
 
 
