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
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);
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);
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);
}
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;
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;
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))
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));
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;
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);
}
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);
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;
| 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);
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);
/* 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);
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;
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);
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
*************************************************************************/
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));
******************************************************************************/
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();
}
view_insert(view, true, '\n');
}
+void highlight(void) {
+ view_selctx(win_view(FOCUSED));
+}
+
/* Main Routine
******************************************************************************/
static Tag Builtins[] = {
{ .tag = "Indent", .action.noarg = indent },
{ .tag = "Eol", .action.noarg = eol_mode },
{ .tag = NULL, .action.noarg = NULL }
-};
+};
static KeyBinding Bindings[] = {
/* Cursor Movements */
{ 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 },
{ ModCtrl, 'x', cut },
{ ModCtrl, 'c', copy },
{ ModCtrl, 'v', paste },
-
+
/* Block Indent */
{ ModCtrl, '[', del_indent },
{ ModCtrl, ']', add_indent },
{ 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 },
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) {
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));