From e25a12b1156f4bd03fb3aa587b0d6e971dc85295 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Tue, 2 May 2017 20:09:42 -0400 Subject: [PATCH] Changed ctrl+h to highlight the thing under cursor rather than backspace --- TODO.md | 1 - inc/edit.h | 1 + inc/win.h | 2 +- lib/view.c | 9 +++-- lib/win.c | 38 ++++++++++----------- lib/x11.c | 20 +++++------ tests/xedit.c | 92 ++++++++++++++++++++++++++++++++++++++++++--------- xedit.c | 26 +++++++++------ 8 files changed, 130 insertions(+), 59 deletions(-) diff --git a/TODO.md b/TODO.md index 320bc0e..a098bd2 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,6 @@ Up Next: * refactor x11.c and win.c -* Add keyboard shortcut to highlight the thing under the cursor * Make Fn keys execute nth command in the tags buffers * Run commands in the background and don't block the main thread. * check for file changes on save diff --git a/inc/edit.h b/inc/edit.h index 5d0e952..fc39bc7 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -157,6 +157,7 @@ void view_append(View* view, char* str); char* view_getstr(View* view, Sel* sel); char* view_getcmd(View* view); char* view_getctx(View* view); +void view_selctx(View* view); void view_scroll(View* view, int move); void view_scrollpage(View* view, int move); void view_setln(View* view, size_t line); diff --git a/inc/win.h b/inc/win.h index 2272e56..a3f8d06 100644 --- a/inc/win.h +++ b/inc/win.h @@ -48,7 +48,7 @@ WinRegion win_getregion(void); bool win_setregion(WinRegion id); void win_setscroll(double offset, double visible); -/* These functions must be implemented by any appliation that wishes +/* These functions must be implemented by any appliation that wishes to use this module */ void onshutdown(void); void onupdate(void); diff --git a/lib/view.c b/lib/view.c index 0422982..9567bae 100644 --- a/lib/view.c +++ b/lib/view.c @@ -517,11 +517,16 @@ char* view_getcmd(View* view) { return view_getstr(view, &sel); } -char* view_getctx(View* view) { +void view_selctx(View* view) { if (!num_selected(view->selection)) { selcontext(view, &(view->selection)); - view->selection.end++; + view->selection.end = buf_byrune( + &(view->buffer), view->selection.end, RIGHT); } +} + +char* view_getctx(View* view) { + view_selctx(view); return view_getstr(view, NULL); } diff --git a/lib/win.c b/lib/win.c index 33278f9..d7d4b36 100644 --- a/lib/win.c +++ b/lib/win.c @@ -152,7 +152,7 @@ static void layout(int width, int height) { View* statview = win_view(STATUS); View* tagview = win_view(TAGS); View* editview = win_view(EDIT); - + /* update the text views and region positions and sizes */ for (int i = 0; i < SCROLL; i++) { Regions[i].x = 2; @@ -162,10 +162,10 @@ static void layout(int width, int height) { Regions[i].width = (width - 4); Regions[i].height = fheight; } - + /* place the status region */ view_resize(statview, 1, Regions[STATUS].width / fwidth); - + /* Place the tag region relative to status */ Regions[TAGS].y = 5 + Regions[STATUS].y + Regions[STATUS].height; size_t maxtagrows = ((height - Regions[TAGS].y - 5) / 4) / fheight; @@ -173,35 +173,35 @@ static void layout(int width, int height) { size_t tagrows = view_limitrows(tagview, maxtagrows, tagcols); Regions[TAGS].height = tagrows * fheight; view_resize(tagview, tagrows, tagcols); - + /* Place the scroll region relative to tags */ Regions[SCROLL].x = 0; Regions[SCROLL].y = 5 + Regions[TAGS].y + Regions[TAGS].height; Regions[SCROLL].height = (height - Regions[EDIT].y - 5); Regions[SCROLL].width = 5 + fwidth; - + /* Place the edit region relative to tags */ Regions[EDIT].x = 3 + Regions[SCROLL].width; Regions[EDIT].y = 5 + Regions[TAGS].y + Regions[TAGS].height; Regions[EDIT].height = (height - Regions[EDIT].y - 5); - Regions[EDIT].width = width - Regions[SCROLL].width - 5; + Regions[EDIT].width = width - Regions[SCROLL].width - 5; view_resize(editview, Regions[EDIT].height / fheight, Regions[EDIT].width / fwidth); } static void onredraw(int width, int height) { size_t fheight = x11_font_height(Font); size_t fwidth = x11_font_width(Font); - + layout(width, height); onupdate(); // Let the user program update the status and other content view_update(win_view(STATUS), &(Regions[STATUS].csrx), &(Regions[STATUS].csry)); view_update(win_view(TAGS), &(Regions[TAGS].csrx), &(Regions[TAGS].csry)); view_update(win_view(EDIT), &(Regions[EDIT].csrx), &(Regions[EDIT].csry)); onlayout(); // Let the user program update the scroll bar - + for (int i = 0; i < SCROLL; i++) { View* view = win_view(i); - x11_draw_rect((i == TAGS ? CLR_BASE02 : CLR_BASE03), + x11_draw_rect((i == TAGS ? CLR_BASE02 : CLR_BASE03), 0, Regions[i].y - 3, width, Regions[i].height + 8); x11_draw_rect(CLR_BASE01, 0, Regions[i].y - 3, width, 1); if ((i == EDIT) && (Ruler != 0)) @@ -211,7 +211,7 @@ static void onredraw(int width, int height) { draw_glyphs(Regions[i].x, Regions[i].y + ((y+1) * fheight), row->cols, row->rlen, row->len); } } - + /* draw the scroll region */ size_t thumbreg = (Regions[SCROLL].height - Regions[SCROLL].y + 9); size_t thumboff = (size_t)((thumbreg * ScrollOffset) + (Regions[SCROLL].y - 2)); @@ -220,15 +220,15 @@ static void onredraw(int width, int height) { x11_draw_rect(CLR_BASE01, Regions[SCROLL].width, Regions[SCROLL].y - 2, 1, Regions[SCROLL].height); x11_draw_rect(CLR_BASE00, 0, Regions[SCROLL].y - 2, Regions[SCROLL].width, thumbreg); x11_draw_rect(CLR_BASE03, 0, thumboff, Regions[SCROLL].width, thumbsz); - + /* place the cursor on screen */ if (Regions[Focused].csrx != SIZE_MAX && Regions[Focused].csry != SIZE_MAX) { - x11_draw_rect(CLR_BASE3, - Regions[Focused].x + (Regions[Focused].csrx * fwidth), - Regions[Focused].y + (Regions[Focused].csry * fheight), + x11_draw_rect(CLR_BASE3, + Regions[Focused].x + (Regions[Focused].csrx * fwidth), + Regions[Focused].y + (Regions[Focused].csry * fheight), 1, fheight); } - + /* adjust the mouse location */ if (Regions[Focused].warp_ptr) { Regions[Focused].warp_ptr = false; @@ -251,11 +251,11 @@ static void oninput(int mods, Rune key) { return; } } - + /* fallback to just inserting the rune if it doesn't fall in the private use area. * the private use area is used to encode special keys */ if (key < 0xE000 || key > 0xF8FF) { - if (key == '\n' && win_view(FOCUSED)->buffer.crlf) + if (key == '\n' && win_view(FOCUSED)->buffer.crlf) key = RUNE_CRLF; view_insert(win_view(FOCUSED), true, key); } @@ -271,12 +271,12 @@ static void onclick(MouseAct act, MouseBtn btn, int x, int y) { case MOUSE_BTN_LEFT: view_scroll(win_view(EDIT), -row); break; - case MOUSE_BTN_MIDDLE: + case MOUSE_BTN_MIDDLE: onscroll((double)(y - Regions[SCROLL].y) / (double)(Regions[SCROLL].height - Regions[SCROLL].y)); break; case MOUSE_BTN_RIGHT: - view_scroll(win_view(EDIT), +row); + view_scroll(win_view(EDIT), +row); break; case MOUSE_BTN_WHEELUP: view_scroll(win_view(id), -ScrollLines); diff --git a/lib/x11.c b/lib/x11.c index 69c720a..d3bc4de 100644 --- a/lib/x11.c +++ b/lib/x11.c @@ -119,11 +119,11 @@ void x11_window(char* name, int width, int height) { X.height, 0, X.depth, Config->palette[0]); - + /* register interest in the delete window message */ Atom wmDeleteMessage = XInternAtom(X.display, "WM_DELETE_WINDOW", False); XSetWMProtocols(X.display, X.window, &wmDeleteMessage, 1); - + /* setup window attributes and events */ XSetWindowAttributes swa; swa.backing_store = WhenMapped; @@ -137,15 +137,15 @@ void x11_window(char* name, int width, int height) { | ButtonMotionMask | KeyPressMask ); - + /* set input methods */ if ((X.xim = XOpenIM(X.display, 0, 0, 0))) X.xic = XCreateIC(X.xim, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, X.window, XNFocusWindow, X.window, NULL); - + /* initialize pixmap and drawing context */ X.pixmap = XCreatePixmap(X.display, X.window, width, height, X.depth); X.xft = XftDrawCreate(X.display, X.pixmap, X.visual, X.colormap); - + /* initialize the graphics context */ XGCValues gcv; gcv.foreground = WhitePixel(X.display, X.screen); @@ -572,7 +572,7 @@ static void selrequest(XEvent* evnt) { s.xselection.selection = evnt->xselectionrequest.selection; s.xselection.target = evnt->xselectionrequest.target; s.xselection.time = evnt->xselectionrequest.time; - + Atom target = evnt->xselectionrequest.target; Atom xatargets = XInternAtom(X.display, "TARGETS", 0); Atom xastring = XInternAtom(X.display, "STRING", 0); @@ -580,16 +580,16 @@ static void selrequest(XEvent* evnt) { /* respond with the supported type */ XChangeProperty( X.display, - s.xselection.requestor, + s.xselection.requestor, s.xselection.property, XA_ATOM, 32, PropModeReplace, (unsigned char*)&SelTarget, 1); } else if (target == SelTarget || target == xastring) { XChangeProperty( - X.display, + X.display, s.xselection.requestor, s.xselection.property, - SelTarget, 8, PropModeReplace, + SelTarget, 8, PropModeReplace, (unsigned char*)sel->text, strlen(sel->text)); } XSendEvent(X.display, s.xselection.requestor, True, 0, &s); @@ -602,7 +602,7 @@ bool x11_sel_get(int selid, void(*cbfn)(char*)) { if (owner == X.window) { cbfn(sel->text); } else if (owner != None){ - sel->callback = cbfn; + sel->callback = cbfn; XConvertSelection(X.display, sel->atom, SelTarget, sel->atom, X.window, CurrentTime); } return true; diff --git a/tests/xedit.c b/tests/xedit.c index 89fc834..0dac7ed 100644 --- a/tests/xedit.c +++ b/tests/xedit.c @@ -371,21 +371,6 @@ TEST_SUITE(UnitTests) { CHECK(buf_end(win_buf(EDIT)) == 3); } - TEST(ctrl+h should do nothing for empty buffer) { - setup_view(EDIT, "", CRLF, 0); - send_keys(ModCtrl, XK_h); - CHECK(win_sel(EDIT)->beg == 0); - CHECK(win_sel(EDIT)->end == 0); - } - - TEST(ctrl+h should delete previous character) { - setup_view(EDIT, "AB", CRLF, 1); - send_keys(ModCtrl, XK_h); - CHECK(win_sel(EDIT)->beg == 0); - CHECK(win_sel(EDIT)->end == 0); - CHECK(buf_end(win_buf(EDIT)) == 1); - } - TEST(ctrl+a should do nothing for empty buffer) { setup_view(EDIT, "", CRLF, 0); send_keys(ModCtrl, XK_a); @@ -622,6 +607,83 @@ TEST_SUITE(UnitTests) { CHECK(win_view(EDIT)->selection.beg == 0); CHECK(win_view(EDIT)->selection.end == 3); } + + TEST(ctrl+h should nothing for empty buffer) { + setup_view(EDIT, "", CRLF, 0); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 0); + CHECK(win_sel(EDIT)->end == 0); + } + + TEST(ctrl+h should highlight content in parens from left paren) { + setup_view(EDIT, " (foo bar) ", CRLF, 1); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 2); + CHECK(win_sel(EDIT)->end == 9); + } + + TEST(ctrl+h should highlight content in parens from right paren) { + setup_view(EDIT, " (foo bar) ", CRLF, 9); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 9); + CHECK(win_sel(EDIT)->end == 2); + } + + TEST(ctrl+h should highlight content in parens from left bracket) { + setup_view(EDIT, " [foo bar] ", CRLF, 1); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 2); + CHECK(win_sel(EDIT)->end == 9); + } + + TEST(ctrl+h should highlight content in parens from right bracket) { + setup_view(EDIT, " [foo bar] ", CRLF, 9); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 9); + CHECK(win_sel(EDIT)->end == 2); + } + + TEST(ctrl+h should highlight content in parens from left brace) { + setup_view(EDIT, " {foo bar} ", CRLF, 1); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 2); + CHECK(win_sel(EDIT)->end == 9); + } + + TEST(ctrl+h should highlight content in parens from right brace) { + setup_view(EDIT, " {foo bar} ", CRLF, 9); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 9); + CHECK(win_sel(EDIT)->end == 2); + } + + TEST(ctrl+h should highlight whole line from bol) { + setup_view(EDIT, "foo bar\n", CRLF, 0); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 0); + CHECK(win_sel(EDIT)->end == 8); + } + + TEST(ctrl+h should highlight whole line from eol) { + setup_view(EDIT, "foo bar\n", CRLF, 7); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 0); + CHECK(win_sel(EDIT)->end == 8); + } + + TEST(ctrl+h should highlight word under cursor) { + setup_view(EDIT, " foo.bar \n", CRLF, 1); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 1); + CHECK(win_sel(EDIT)->end == 4); + } + + TEST(ctrl+h should highlight word under cursor) { + setup_view(EDIT, " foo.bar \n", CRLF, 4); + send_keys(ModCtrl, XK_h); + CHECK(win_sel(EDIT)->beg == 1); + CHECK(win_sel(EDIT)->end == 8); + } /* Mouse Input Handling *************************************************************************/ diff --git a/xedit.c b/xedit.c index e349f47..82e3195 100644 --- a/xedit.c +++ b/xedit.c @@ -72,10 +72,10 @@ static void cmd_exec(char* cmd) { if (op != '<') dest = win_getregion(); output = cmdread(ShellCmd, &error); } - + if (error) view_append(win_view(TAGS), chomp(error)); - + if (output) { if (op == '>') view_append(win_view(dest), chomp(output)); @@ -192,19 +192,19 @@ void onmouseright(WinRegion id, size_t count, size_t row, size_t col) { ******************************************************************************/ static void del_to_bol(void) { view_bol(win_view(FOCUSED), true); - if (view_selsize(win_view(FOCUSED)) > 0) + if (view_selsize(win_view(FOCUSED)) > 0) delete(); } static void del_to_eol(void) { view_eol(win_view(FOCUSED), true); - if (view_selsize(win_view(FOCUSED)) > 0) + if (view_selsize(win_view(FOCUSED)) > 0) delete(); } static void del_to_bow(void) { view_byword(win_view(FOCUSED), LEFT, true); - if (view_selsize(win_view(FOCUSED)) > 0) + if (view_selsize(win_view(FOCUSED)) > 0) delete(); } @@ -445,6 +445,10 @@ static void newline(void) { view_insert(view, true, '\n'); } +void highlight(void) { + view_selctx(win_view(FOCUSED)); +} + /* Main Routine ******************************************************************************/ static Tag Builtins[] = { @@ -462,7 +466,7 @@ static Tag Builtins[] = { { .tag = "Indent", .action.noarg = indent }, { .tag = "Eol", .action.noarg = eol_mode }, { .tag = NULL, .action.noarg = NULL } -}; +}; static KeyBinding Bindings[] = { /* Cursor Movements */ @@ -472,12 +476,11 @@ static KeyBinding Bindings[] = { { 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, 'w', del_to_bow }, - { ModCtrl, 'h', backspace }, { ModCtrl, 'a', cursor_bol }, { ModCtrl, 'e', cursor_eol }, @@ -488,7 +491,7 @@ static KeyBinding Bindings[] = { { ModCtrl, 'x', cut }, { ModCtrl, 'c', copy }, { ModCtrl, 'v', paste }, - + /* Block Indent */ { ModCtrl, '[', del_indent }, { ModCtrl, ']', add_indent }, @@ -503,6 +506,7 @@ static KeyBinding Bindings[] = { { ModNone, KEY_ESCAPE, select_prev }, { ModCtrl, 't', change_focus }, { ModCtrl, 'q', quit }, + { ModCtrl, 'h', highlight }, { ModCtrl, 'f', search }, { ModCtrl|ModShift, 'f', search }, { ModCtrl|ModAlt, 'f', search }, @@ -521,7 +525,7 @@ static KeyBinding Bindings[] = { void onscroll(double percent) { size_t bend = buf_end(win_buf(EDIT)); size_t off = (size_t)((double)bend * percent); - view_scrollto(win_view(EDIT), (off >= bend ? bend : off)); + view_scrollto(win_view(EDIT), (off >= bend ? bend : off)); } void onupdate(void) { @@ -543,7 +547,7 @@ void onupdate(void) { win_view(STATUS)->selection = (Sel){0,0,0}; } -void onlayout(void) { +void onlayout(void) { /* calculate and update scroll region */ View* view = win_view(EDIT); size_t bend = buf_end(win_buf(EDIT)); -- 2.54.0