]> git.mdlowis.com Git - projs/tide.git/commitdiff
added tests for text editing keyboard shortcuts
authorMichael D. Lowis <mike.lowis@gentex.com>
Wed, 7 Dec 2016 20:36:10 +0000 (15:36 -0500)
committerMichael D. Lowis <mike.lowis@gentex.com>
Wed, 7 Dec 2016 20:36:10 +0000 (15:36 -0500)
TODO.md
config.mk
inc/edit.h
libedit/view.c
tests/xedit.c
xedit.c

diff --git a/TODO.md b/TODO.md
index ae3df7d37f899a466462578b4bea2ea04fbf62a4..18124f2d41c80b417bd4d47b0675785398e175a3 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -1,5 +1,6 @@
 # Implementation Tweaks and Bug Fixes
 
+* investigate weird behavior when editing CRLF files and copy-pasting
 * Expand tabs setting should be disabled if opened file contains tabs
 * Add tag for ctags lookup and line number jump
 * add a shortcut to autocomplete ctag
 * check for file changes when window regains focus
 * check for file changes on save
 * backspace should delete indent if preceded by whitespace
+* indenting with a reverse selection  expands the selection the wrong way
+* add command line flags to toggle options (Tabs, Indent, etc..)
+* shift+click to extend selection
+* drag with middle and right mouse buttons causes infinite loops
 
 # Auxillary Programs
 
index 85d96ed61df1a821cf5273de7b4f7216e10852c3..1002217dd20506d033f0f52b6e77ad156799c4ae 100644 (file)
--- a/config.mk
+++ b/config.mk
@@ -24,5 +24,5 @@ LIBS += -L/usr/X11/lib
 INCS += -I/usr/include/freetype2
 
 # Gcov Coverage
-#CFLAGS  += --coverage
-#LDFLAGS += --coverage
+CFLAGS  += --coverage
+LDFLAGS += --coverage
index e3da9fac73606dd96e5c084b6c722a7881d712cd..cef36be9fbd38618d28f3b6c3ffda61e08da5b9e 100644 (file)
@@ -143,6 +143,7 @@ void view_selext(View* view, size_t row, size_t col);
 void view_selword(View* view, size_t row, size_t col);
 void view_selprev(View* view);
 void view_select(View* view, size_t row, size_t col);
+size_t view_selsize(View* view);
 char* view_fetch(View* view, size_t row, size_t col);
 void view_find(View* view, size_t row, size_t col);
 void view_findstr(View* view, char* str);
index 97b23240dd9697cc5a1bb0b7b6fe226b554b86d6..c2da6118eb588db4e5c2ee150ff66ff41015bbcc 100644 (file)
@@ -360,6 +360,10 @@ void view_select(View* view, size_t row, size_t col) {
     view->selection = sel;
 }
 
+size_t view_selsize(View* view) {
+    return num_selected(view->selection);
+}
+
 char* view_fetch(View* view, size_t row, size_t col) {
     char* str = NULL;
     size_t off = getoffset(view, row, col);
index 8abfffe6ea6db492a93b5992b4723080c04b3eb1..89673c38fbe26e29bd79e6d27ba7e9a843e4f12b 100644 (file)
@@ -14,6 +14,11 @@ void setup_view(enum RegionId id, char* text, unsigned cursor) {
     getsel(id)->col = buf_getcol(getbuf(id), getsel(id)->end);
 }
 
+void send_keys(int mods, Rune key) {
+    Mods = mods;
+    key_handler(mods, key);
+}
+
 /* Stubbed Functions
  *****************************************************************************/
 bool x11_keymodsset(int mask) {
@@ -39,133 +44,332 @@ TEST_SUITE(XeditTests) {
      *************************************************************************/
     TEST(left should do nothing for empty buffer) {
         setup_view(EDIT, "", 0);
-        key_handler(ModNone, KEY_LEFT);
+        send_keys(ModNone, KEY_LEFT);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+left should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, KEY_LEFT);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
     TEST(left should do nothing at beginning of buffer) {
         setup_view(EDIT, "AB", 0);
-        key_handler(ModNone, KEY_LEFT);
+        send_keys(ModNone, KEY_LEFT);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+left should do nothing at beginning of buffer) {
+        setup_view(EDIT, "AB", 0);
+        send_keys(ModCtrl, KEY_LEFT);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+left should move left by one word) {
+        setup_view(EDIT, "AB CD", 3);
+        send_keys(ModCtrl, KEY_LEFT);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
     TEST(left should move left by one rune) {
         setup_view(EDIT, "AB", 1);
-        key_handler(ModNone, KEY_LEFT);
+        send_keys(ModNone, KEY_LEFT);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
     TEST(right should do nothing for empty buffer) {
         setup_view(EDIT, "", 0);
-        key_handler(ModNone, KEY_RIGHT);
+        send_keys(ModNone, KEY_RIGHT);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
-    TEST(right should do nothing at end of buffer) {
+    TEST(right should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, KEY_RIGHT);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+right should do nothing at end of buffer) {
+        setup_view(EDIT, "AB", 2);
+        send_keys(ModNone, KEY_RIGHT);
+        CHECK(getsel(EDIT)->beg == 2);
+        CHECK(getsel(EDIT)->end == 2);
+    }
+    
+    TEST(ctrl+right should do nothing at end of buffer) {
         setup_view(EDIT, "AB", 2);
-        key_handler(ModNone, KEY_RIGHT);
+        send_keys(ModCtrl, KEY_RIGHT);
         CHECK(getsel(EDIT)->beg == 2);
         CHECK(getsel(EDIT)->end == 2);
     }
     
+    TEST(ctrl+right should move right by one word) {
+        setup_view(EDIT, "AB CD", 0);
+        send_keys(ModCtrl, KEY_RIGHT);
+        CHECK(getsel(EDIT)->beg == 3);
+        CHECK(getsel(EDIT)->end == 3);
+    }
+    
     TEST(right should move right by one rune) {
         setup_view(EDIT, "AB", 1);
-        key_handler(ModNone, KEY_RIGHT);
+        send_keys(ModNone, KEY_RIGHT);
         CHECK(getsel(EDIT)->beg == 2);
         CHECK(getsel(EDIT)->end == 2);
     }
     
     TEST(up should do nothing for empty buffer) {
         setup_view(EDIT, "", 0);
-        key_handler(ModNone, KEY_UP);
+        send_keys(ModNone, KEY_UP);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
     TEST(up should move cursor up one line) {
         setup_view(EDIT, "AB\nCD", 4);
-        key_handler(ModNone, KEY_UP);
+        send_keys(ModNone, KEY_UP);
         CHECK(getsel(EDIT)->beg == 1);
         CHECK(getsel(EDIT)->end == 1);
     }
     
     TEST(up should do nothing for first line) {
         setup_view(EDIT, "AB\nCD", 1);
-        key_handler(ModNone, KEY_UP);
+        send_keys(ModNone, KEY_UP);
         CHECK(getsel(EDIT)->beg == 1);
         CHECK(getsel(EDIT)->end == 1);
     }
     
     TEST(down should do nothing for empty buffer) {
         setup_view(EDIT, "", 0);
-        key_handler(ModNone, KEY_DOWN);
+        send_keys(ModNone, KEY_DOWN);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }    
     
     TEST(down should move down one line) {
         setup_view(EDIT, "AB\nCD", 1);
-        key_handler(ModNone, KEY_DOWN);
+        send_keys(ModNone, KEY_DOWN);
         CHECK(getsel(EDIT)->beg == 4);
         CHECK(getsel(EDIT)->end == 4);
     }
     
     TEST(down should do nothing on last line) {
         setup_view(EDIT, "AB\nCD", 4);
-        key_handler(ModNone, KEY_DOWN);
+        send_keys(ModNone, KEY_DOWN);
         CHECK(getsel(EDIT)->beg == 4);
         CHECK(getsel(EDIT)->end == 4);
     }
     
     TEST(home should do nothing for empty buffer) {
         setup_view(EDIT, "", 0);
-        key_handler(ModNone, KEY_HOME);
+        send_keys(ModNone, KEY_HOME);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+home should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, KEY_HOME);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+home should move to beginning of buffer) {
+        setup_view(EDIT, "ABCD", 4);
+        send_keys(ModCtrl, KEY_HOME);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
     TEST(home should move to beginning of indented content) {
         setup_view(EDIT, "    ABCD", 7);
-        key_handler(ModNone, KEY_HOME);
+        send_keys(ModNone, KEY_HOME);
         CHECK(getsel(EDIT)->beg == 4);
         CHECK(getsel(EDIT)->end == 4);
     }
     
     TEST(home should move to beginning of line if at beginning of indented content) {
         setup_view(EDIT, "    ABCD", 7);
-        key_handler(ModNone, KEY_HOME);
+        send_keys(ModNone, KEY_HOME);
         CHECK(getsel(EDIT)->beg == 4);
         CHECK(getsel(EDIT)->end == 4);
     }
     
     TEST(home should move to beginning of indented content when at beginning of line) {
         setup_view(EDIT, "    ABCD", 0);
-        key_handler(ModNone, KEY_HOME);
+        send_keys(ModNone, KEY_HOME);
         CHECK(getsel(EDIT)->beg == 4);
         CHECK(getsel(EDIT)->end == 4);
     }
     
     TEST(end should do nothing for empty buffer) {
         setup_view(EDIT, "", 0);
-        key_handler(ModNone, KEY_END);
+        send_keys(ModNone, KEY_END);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+end should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, KEY_END);
         CHECK(getsel(EDIT)->beg == 0);
         CHECK(getsel(EDIT)->end == 0);
     }
     
+    TEST(ctrl+end should move to end of buffer) {
+        setup_view(EDIT, "ABCD", 0);
+        send_keys(ModCtrl, KEY_END);
+        CHECK(getsel(EDIT)->beg == 4);
+        CHECK(getsel(EDIT)->end == 4);
+    }
+    
     TEST(end should do nothing at end of line) {
         setup_view(EDIT, "AB\nCD", 2);
-        key_handler(ModNone, KEY_END);
+        send_keys(ModNone, KEY_END);
         CHECK(getsel(EDIT)->beg == 2);
         CHECK(getsel(EDIT)->end == 2);
     }
     
     TEST(end should move to end of line) {
         setup_view(EDIT, "AB\nCD", 0);
-        key_handler(ModNone, KEY_END);
+        send_keys(ModNone, KEY_END);
+        CHECK(getsel(EDIT)->beg == 2);
+        CHECK(getsel(EDIT)->end == 2);
+    }
+    
+    /* Key Handling - Unix Standard Shortcuts
+     *************************************************************************/
+    TEST(ctrl+u should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, 'u');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+u should delete to beginning of line) {
+        setup_view(EDIT, "\nABC\n", 2);
+        send_keys(ModCtrl, 'u');
+        CHECK(getsel(EDIT)->beg == 1);
+        CHECK(getsel(EDIT)->end == 1);
+        CHECK(buf_end(getbuf(EDIT)) == 4);
+    }
+    
+    TEST(ctrl+u should delete entire lines contents) {
+        setup_view(EDIT, "\nABC\n", 3);
+        send_keys(ModCtrl, 'u');
+        CHECK(getsel(EDIT)->beg == 1);
+        CHECK(getsel(EDIT)->end == 1);
+        CHECK(buf_end(getbuf(EDIT)) == 3);
+    }
+    
+    TEST(ctrl+k should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, 'k');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(buf_end(getbuf(EDIT)) == 0);
+    }
+    
+    TEST(ctrl+k should delete to end of line) {
+        setup_view(EDIT, "\nABC\n", 2);
+        send_keys(ModCtrl, 'k');
+        CHECK(getsel(EDIT)->beg == 2);
+        CHECK(getsel(EDIT)->end == 2);
+        CHECK(buf_end(getbuf(EDIT)) == 3);
+    }
+    
+    TEST(ctrl+k should delete entire lines contents) {
+        setup_view(EDIT, "\nABC\n", 1);
+        send_keys(ModCtrl, 'k');
+        CHECK(getsel(EDIT)->beg == 1);
+        CHECK(getsel(EDIT)->end == 1);
+        CHECK(buf_end(getbuf(EDIT)) == 2);
+    }
+    
+    TEST(ctrl+w should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, 'w');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(buf_end(getbuf(EDIT)) == 0);
+    }
+    
+    TEST(ctrl+w should delete previous word) {
+        setup_view(EDIT, "abc def", 4);
+        send_keys(ModCtrl, 'w');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(buf_end(getbuf(EDIT)) == 3);
+    }
+    
+    TEST(ctrl+h should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, 'h');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+h should delete previous character) {
+        setup_view(EDIT, "AB", 1);
+        send_keys(ModCtrl, 'h');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(buf_end(getbuf(EDIT)) == 1);
+    }
+    
+    TEST(ctrl+a should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, 'a');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+a should move to beginning of indented content) {
+        setup_view(EDIT, "    ABCD", 7);
+        send_keys(ModCtrl, 'a');
+        CHECK(getsel(EDIT)->beg == 4);
+        CHECK(getsel(EDIT)->end == 4);
+    }
+    
+    TEST(ctrl+a should move to beginning of line if at beginning of indented content) {
+        setup_view(EDIT, "    ABCD", 7);
+        send_keys(ModCtrl, 'a');
+        CHECK(getsel(EDIT)->beg == 4);
+        CHECK(getsel(EDIT)->end == 4);
+    }
+    
+    TEST(ctrl+a should move to beginning of indented content when at beginning of line) {
+        setup_view(EDIT, "    ABCD", 0);
+        send_keys(ModCtrl, 'a');
+        CHECK(getsel(EDIT)->beg == 4);
+        CHECK(getsel(EDIT)->end == 4);
+    }
+    
+    TEST(ctrl+e should do nothing for empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModCtrl, 'e');
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+    }
+    
+    TEST(ctrl+e should do nothing at end of line) {
+        setup_view(EDIT, "AB\nCD", 2);
+        send_keys(ModCtrl, 'e');
+        CHECK(getsel(EDIT)->beg == 2);
+        CHECK(getsel(EDIT)->end == 2);
+    }
+    
+    TEST(ctrl+e should move to end of line) {
+        setup_view(EDIT, "AB\nCD", 0);
+        send_keys(ModCtrl, 'e');
         CHECK(getsel(EDIT)->beg == 2);
         CHECK(getsel(EDIT)->end == 2);
     }
diff --git a/xedit.c b/xedit.c
index e7b76480d328e721333bff2f16f636302bde5874..a9575f5d7a778030f65758588adadeea3300abf0 100644 (file)
--- a/xedit.c
+++ b/xedit.c
@@ -26,6 +26,7 @@ static void redraw(int width, int height);
 // UI Callbacks
 static void delete(void);
 static void del_to_bol(void);
+static void del_to_eol(void);
 static void del_to_bow(void);
 static void backspace(void);
 static void cursor_bol(void);
@@ -116,14 +117,17 @@ void (*MouseActs[MOUSE_BTN_COUNT])(enum RegionId id, size_t count, size_t row, s
 };
 
 static KeyBinding Bindings[] = {
-    /* Function Keys */
-    //{ KEY_CTRL_F1,    welcome     },
-    //{ KEY_CTRL_F2,    ctags_scan  },
-    //{ KEY_CTRL_F11,   fullscreen  },
-
+    /* Cursor Movements */
+    { ModAny, KEY_HOME,  cursor_home  },
+    { ModAny, KEY_END,   cursor_end   },
+    { ModAny, KEY_UP,    cursor_up    },
+    { ModAny, KEY_DOWN,  cursor_dn    },
+    { ModAny, KEY_LEFT,  cursor_left  },
+    { ModAny, KEY_RIGHT, cursor_right },
+    
     /* Standard Unix Shortcuts */
     { ModCtrl, 'u', del_to_bol  },
-    //{ ModCtrl, 'k', del_to_eol  },
+    { ModCtrl, 'k', del_to_eol  },
     { ModCtrl, 'w', del_to_bow  },
     { ModCtrl, 'h', backspace   },
     { ModCtrl, 'a', cursor_bol  },
@@ -147,14 +151,6 @@ static KeyBinding Bindings[] = {
     { ModAny,  KEY_DELETE,    delete    },
     { ModAny,  KEY_BACKSPACE, backspace },
 
-    /* Cursor Movements */
-    { ModAny, KEY_HOME,  cursor_home  },
-    { ModAny, KEY_END,   cursor_end   },
-    { ModAny, KEY_UP,    cursor_up    },
-    { ModAny, KEY_DOWN,  cursor_dn    },
-    { ModAny, KEY_LEFT,  cursor_left  },
-    { ModAny, KEY_RIGHT, cursor_right },
-
     /* Implementation Specific */
     { ModNone, KEY_ESCAPE, select_prev  },
     { ModCtrl, 't',        change_focus },
@@ -388,12 +384,20 @@ static void delete(void) {
 
 static void del_to_bol(void) {
     view_bol(currview(), true);
-    delete();
+    if (view_selsize(currview()) > 0) 
+        delete();
+}
+
+static void del_to_eol(void) {
+    view_eol(currview(), true);
+    if (view_selsize(currview()) > 0) 
+        delete();
 }
 
 static void del_to_bow(void) {
     view_byword(currview(), LEFT, true);
-    delete();
+    if (view_selsize(currview()) > 0) 
+        delete();
 }
 
 static void backspace(void) {