Module features
---------------
+### lib-askpass
+
+- [ ] New module which server can use to ask for a password.
+ When an external program is run, we pass SSH_ASKPASS=client
+ and SSH_ASKPASS_REQUIRE=force.
+
### lib-linecount
- [X] when used in 'view' mode, stack the counting pane with all the
- [X] popup menu to which we can add entries, pop it at a location, get
a selection
- [ ] menu-bar to which we can add menus from which commands are sent
+- [ ] track movement so entry under cursor can be highlighted
+- [ ] support positioning above the target is no space below.
+- [ ] support single-click to open modal menu.??
+- [ ] improve hack for communicating action position. Maybe require
+ an 'is-button' attribute and report button height (and width?)
+ in num and num2.
### lib-url
return Efalse;
}
+DEF_CMD(mouse_grab)
+{
+ struct input_mode *im = ci->home->data;
+
+ im->grab = ci->focus;
+ pane_add_notify(ci->home, ci->focus, "Notify:Close");
+ return 1;
+}
+
DEF_CMD(refocus)
{
struct input_mode *im = ci->home->data;
im_map = key_alloc();
key_add(im_map, "Keystroke", &keystroke);
key_add(im_map, "Mouse-event", &mouse_event);
+ key_add(im_map, "Mouse-grab", &mouse_grab);
key_add(im_map, "Mode:set-mode", &set_mode);
key_add(im_map, "Mode:set-num", &set_num);
key_add(im_map, "Mode:set-num2", &set_num2);
DEF_CMD(menu_attach)
{
struct pane *docp, *p, *p2;
- /* Multi-line popup with x,y location provided. */
- const char *mode = "Mx";
+ /* Multi-line temporary popup with x,y location provided. */
+ const char *mode = "Mtx";
const char *mmode = ci->str ?: "";
if (strchr(mmode, 'D'))
/* per-display, not per-pane */
- mode = "DMx";
+ mode = "DMtx";
docp = call_ret(pane, "attach-doc-list", ci->focus);
if (!docp)
p2 = pane_register(p2, 0, &menu_handle.c);
if (!p2)
return Efail;
+ call("Mouse-grab", p2);
return comm_call(ci->comm2, "cb:attach", p2);
}
struct popup_info *ppi;
const char *style = ci->str;
char *in_popup;
+ struct xy xy;
int z = 1;
if (!style)
return Efail;
ppi->style = strdup(style);
popup_set_style(p);
- popup_resize(p, style, ci->x, ci->y);
+ xy = pane_mapxy(ci->focus, root, ci->x, ci->y, True);
+ popup_resize(p, style, xy.x, xy.y);
attr_set_str(&p->attrs, "render-wrap", "no");
pane_add_notify(p, ppi->target, "Notify:Close");
static int flush_line(struct pane *p safe, struct pane *focus safe, int dodraw,
struct render_list **rlp safe,
- int y, int scale, int wrap_pos, int *wrap_margin safe,
+ int y, int ascent, int scale, int wrap_pos, int *wrap_margin safe,
int *wrap_prefix_sizep,
const char **xypos, const char **xyattr, const char **cursattr)
{
if (dodraw)
home_call(focus, "Draw:text", p, cp, NULL, rl->text,
scale, NULL, rl->attr,
- x, y);
- x += rl->width;
+ x, y + ascent);
if (xypos && rl->xypos) {
*xypos = rl->xypos;
- if (xyattr)
- *xyattr = strsave(p, rl->attr);
+ if (xyattr) {
+ /* FIXME this is a bit of a hack.
+ * We still the x,y co-ords of the start
+ * of the current attr in front of the
+ * attrs so render-lines can provide a
+ * good location for a menu
+ */
+ char buf[100];
+ struct render_list *rl2;
+ int ax = 0;
+ for (rl2 = *rlp; rl2 != rl; rl2 = rl2->next)
+ if (strcmp(rl2->attr, rl->attr) == 0)
+ ax = rl2->x;
+ snprintf(buf, sizeof(buf), "%dx%d,", ax, y);
+ *xyattr = strconcat(p, buf, rl->attr);
+ }
}
+ x += rl->width;
if (cp >= 0 && cursattr)
*cursattr = strsave(p, rl->attr);
}
if (cp >= 0 && dodraw)
home_call(focus, "Draw:text", p, cp, NULL, rl->text,
scale, NULL, rl->attr,
- rl->x, y);
+ rl->x, y + ascent);
x = rl->x + rl->width;
}
/* Draw the wrap-tail */
char *e = get_last_attr(last_rl->attr, "wrap-tail");
home_call(focus, "Draw:text", p, -1, NULL, e ?: "\\",
scale, NULL, "underline,fg:blue",
- wrap_pos, y);
+ wrap_pos, y + ascent);
free(e);
}
if (wrap && *line && *line != '\n') {
int wrap_prefix_size;
int len = flush_line(p, focus, dodraw, &rlst,
- y+ascent, scale,
+ y, ascent, scale,
p->w - mwidth, &wrap_margin,
&wrap_prefix_size,
&xypos, &xyattr, &cursattr);
break;
case '\n':
xypos = line-1;
- flush_line(p, focus, dodraw, &rlst, y+ascent, scale, 0,
+ flush_line(p, focus, dodraw, &rlst, y, ascent, scale, 0,
&wrap_margin, NULL, &xypos, &xyattr, &cursattr);
y += line_height;
x = 0;
posx, scale);
}
- flush_line(p, focus, dodraw, &rlst, y+ascent, scale, 0,
+ flush_line(p, focus, dodraw, &rlst, y, ascent, scale, 0,
&wrap_margin, NULL, &xypos, &xyattr, &cursattr);
if (want_xypos == 1) {
return 1;
}
+DEF_CMD(emacs_menu_open)
+{
+ /* If there is a menu action here, activate it. */
+
+ return call("Move-CursorXY", ci->focus, 3, ci->mark, "menu",
+ 0, NULL, NULL, ci->x, ci->y);
+}
+
+DEF_CMD(emacs_menu_select)
+{
+ /* If a menu was opened it should have claimed the mouse focus
+ * so ci->focus is now the menu. We want to activate the entry
+ * under the mouse
+ */
+ return call("Move-CursorXY", ci->focus, 3, ci->mark, "activate",
+ 0, NULL, NULL, ci->x, ci->y);
+}
+
DEF_CMD(emacs_motion)
{
struct mark *p = call_ret(mark, "doc:point", ci->focus);
key_add(m, "M:Press-1", &emacs_press);
key_add(m, "M:Release-1", &emacs_release);
+ key_add(m, "M:Press-3", &emacs_menu_open);
+ key_add(m, "M:Release-3", &emacs_menu_select);
key_add(m, "M:DPress-1", &emacs_press);
key_add(m, "M:Click-2", &emacs_paste);
key_add(m, "M:C:Click-1", &emacs_paste);
if not str1 or not mark or not comm2:
return edlib.Efallthrough
if str1 == "render:spell-incorrect":
- comm2("cb", focus, int(str2), mark, "fg:red-80,underline", 120)
+ comm2("cb", focus, int(str2), mark, "fg:red-80,underline,action-menu:autospell-menu", 120)
return edlib.Efallthrough
+ def handle_click(self, key, focus, mark, xy, str1, **a):
+ "handle:autospell-menu"
+ mp = self.call("attach-menu", "", "autospell-choice", xy, ret='pane')
+ self.wordend = mark.dup()
+ st = mark.dup()
+ w = focus.call("Spell:ThisWord", focus, mark, st, ret='str')
+ self.thisword = w
+ mp.call("menu-add", "+", "[Insert in dict]")
+ mp.call("menu-add", "!", "[Accept for now]")
+ focus.call("Spell:Suggest", w, lambda key, str1, **a: mp.call("menu-add", str1))
+ mp.call("doc:file", -1)
+ self.menu = mp
+ self.add_notify(mp, "Notify:Close")
+ return 1
+
+ def handle_choice(self, key, focus, mark, str1, **a):
+ "handle:autospell-choice"
+ if not str1:
+ return None
+ m = self.wordend
+ self.wordend = None
+ st = m.dup()
+ w = focus.call("Spell:ThisWord", m, st, ret='str')
+ if str1 == "+":
+ focus.call("Spell:AddWord", 1, self.thisword)
+ focus.call("spell:dict-changed", st, m)
+ return 1
+ if str1 == '!':
+ focus.call("Spell:AddWord", 0, self.thisword)
+ focus.call("spell:dict-changed", st, m)
+ return 1
+ if w == self.thisword:
+ focus.call("doc:replace", st, m, str1)
+ return 1
+
def handle_recheck(self, key, **a):
"handle:spell:recheck"
self.sched()
if (action) {
xyattr = pane_attr_get(m->mdata, "xyattr");
tag = get_action_tag(action, xyattr);
- if (tag)
+ if (tag) {
+ int x, y;
+ /* This is a hack to get the start of these
+ * attrs so menu can be placed correctly.
+ * Only works for menus below the line.
+ */
+ if (sscanf(xyattr, "%dx%d,", &x, &y) == 2) {
+ cih.x = x;
+ cih.y = m->mdata->y + y +
+ attr_find_int(m->mdata->attrs,
+ "line-height");
+;
+ }
call(tag, focus, 0, m2, xyattr,
- 0, ci->mark);
+ 0, ci->mark, NULL,
+ cih.x, cih.y);
+ }
}
m = m2;
} else {