implement new evaluate-region editing command (!MKSH_SMALL)
while here, fixup x_redraw refactoring x_clrtoeol, x_pprompt, and x_lastpos
This commit is contained in:
239
edit.c
239
edit.c
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#ifndef MKSH_NO_CMDLINE_EDITING
|
#ifndef MKSH_NO_CMDLINE_EDITING
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.301 2016/07/26 20:43:14 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.302 2016/07/26 21:37:24 tg Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in later versions we might use libtermcap for this, but since external
|
* in later versions we might use libtermcap for this, but since external
|
||||||
@ -961,7 +961,6 @@ static size_t x_fword(bool);
|
|||||||
static void x_goto(char *);
|
static void x_goto(char *);
|
||||||
static char *x_bs0(char *, char *) MKSH_A_PURE;
|
static char *x_bs0(char *, char *) MKSH_A_PURE;
|
||||||
static void x_bs3(char **);
|
static void x_bs3(char **);
|
||||||
static int x_size_str(char *);
|
|
||||||
static int x_size2(char *, char **);
|
static int x_size2(char *, char **);
|
||||||
static void x_zots(char *);
|
static void x_zots(char *);
|
||||||
static void x_zotc3(char **);
|
static void x_zotc3(char **);
|
||||||
@ -986,6 +985,7 @@ static void x_e_puts(const char *);
|
|||||||
static int x_fold_case(int);
|
static int x_fold_case(int);
|
||||||
#endif
|
#endif
|
||||||
static char *x_lastcp(void);
|
static char *x_lastcp(void);
|
||||||
|
static void x_lastpos(void);
|
||||||
static void do_complete(int, Comp_type);
|
static void do_complete(int, Comp_type);
|
||||||
static size_t x_nb2nc(size_t) MKSH_A_PURE;
|
static size_t x_nb2nc(size_t) MKSH_A_PURE;
|
||||||
|
|
||||||
@ -1121,6 +1121,7 @@ static struct x_defbindings const x_defbindings[] = {
|
|||||||
#endif
|
#endif
|
||||||
#ifndef MKSH_SMALL
|
#ifndef MKSH_SMALL
|
||||||
/* more non-standard ones */
|
/* more non-standard ones */
|
||||||
|
{ XFUNC_eval_region, 1, CTRL('E') },
|
||||||
{ XFUNC_edit_line, 2, 'e' }
|
{ XFUNC_edit_line, 2, 'e' }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@ -1380,15 +1381,11 @@ x_ins(const char *s)
|
|||||||
x_lastcp();
|
x_lastcp();
|
||||||
x_adj_ok = tobool(xcp >= xlp);
|
x_adj_ok = tobool(xcp >= xlp);
|
||||||
x_zots(cp);
|
x_zots(cp);
|
||||||
/* has x_adjust() been called? */
|
|
||||||
if (adj == x_adj_done) {
|
|
||||||
/* no */
|
|
||||||
cp = xlp;
|
|
||||||
while (cp > xcp)
|
|
||||||
x_bs3(&cp);
|
|
||||||
}
|
|
||||||
if (xlp == xep - 1)
|
if (xlp == xep - 1)
|
||||||
x_redraw('\r');
|
x_redraw('\r');
|
||||||
|
else if (adj == x_adj_done)
|
||||||
|
/* x_adjust() has not been called */
|
||||||
|
x_lastpos();
|
||||||
x_adj_ok = true;
|
x_adj_ok = true;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1495,10 +1492,7 @@ x_delete(size_t nc, bool push)
|
|||||||
/*x_goto(xcp);*/
|
/*x_goto(xcp);*/
|
||||||
x_adj_ok = true;
|
x_adj_ok = true;
|
||||||
xlp_valid = false;
|
xlp_valid = false;
|
||||||
cp = x_lastcp();
|
x_lastpos();
|
||||||
while (cp > xcp)
|
|
||||||
x_bs3(&cp);
|
|
||||||
|
|
||||||
x_modified();
|
x_modified();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1617,15 +1611,6 @@ x_bs3(char **p)
|
|||||||
x_e_putc2('\b');
|
x_e_putc2('\b');
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
x_size_str(char *cp)
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
while (*cp)
|
|
||||||
size += x_size2(cp, &cp);
|
|
||||||
return (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
x_size2(char *cp, char **dcp)
|
x_size2(char *cp, char **dcp)
|
||||||
{
|
{
|
||||||
@ -2066,67 +2051,70 @@ x_cls(int c MKSH_A_UNUSED)
|
|||||||
return (KSTD);
|
return (KSTD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* output cr (if ≠ 0), then redraw the line, clearing to EOL if needed */
|
/*
|
||||||
|
* clear line from x_col (current cursor position) to xx_cols - 2,
|
||||||
|
* then output lastch, then go back to x_col; if lastch is space,
|
||||||
|
* clear with termcap instead of spaces, or not if line_was_cleared;
|
||||||
|
* lastch MUST be an ASCII character with wcwidth(lastch) == 1
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
x_redraw(int cr)
|
x_clrtoeol(int lastch, bool line_was_cleared)
|
||||||
{
|
{
|
||||||
int i, j;
|
int col;
|
||||||
char *cp;
|
|
||||||
int limit = xx_cols; /*XXX tbm in the next commit */
|
|
||||||
|
|
||||||
x_adj_ok = false;
|
if (lastch == ' ' && !line_was_cleared && x_term_mode == 1) {
|
||||||
x_e_putc2(cr ? cr : '\r');
|
shf_puts("\033[K", shl_out);
|
||||||
x_flush();
|
line_was_cleared = true;
|
||||||
if (xbp == xbuf) {
|
}
|
||||||
|
if (lastch == ' ' && line_was_cleared)
|
||||||
|
return;
|
||||||
|
|
||||||
|
col = x_col;
|
||||||
|
while (col < (xx_cols - 2)) {
|
||||||
|
x_putc(' ');
|
||||||
|
++col;
|
||||||
|
}
|
||||||
|
x_putc(lastch);
|
||||||
|
++col;
|
||||||
|
while (col > x_col) {
|
||||||
|
x_putc('\b');
|
||||||
|
--col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output the prompt, assuming a line has just been started */
|
||||||
|
static void
|
||||||
|
x_pprompt(void)
|
||||||
|
{
|
||||||
if (prompt_trunc != -1)
|
if (prompt_trunc != -1)
|
||||||
pprompt(prompt, prompt_trunc);
|
pprompt(prompt, prompt_trunc);
|
||||||
x_col = pwidth;
|
x_col = pwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* output CR, then redraw the line, clearing to EOL if needed (cr ≠ 0, LF) */
|
||||||
|
static void
|
||||||
|
x_redraw(int cr)
|
||||||
|
{
|
||||||
|
int lch;
|
||||||
|
|
||||||
|
x_adj_ok = false;
|
||||||
|
/* clear the line */
|
||||||
|
x_e_putc2(cr ? cr : '\r');
|
||||||
|
x_flush();
|
||||||
|
/* display the prompt */
|
||||||
|
if (xbp == xbuf)
|
||||||
|
x_pprompt();
|
||||||
x_displen = xx_cols - 2 - x_col;
|
x_displen = xx_cols - 2 - x_col;
|
||||||
|
/* display the line content */
|
||||||
xlp_valid = false;
|
xlp_valid = false;
|
||||||
x_zots(xbp);
|
x_zots(xbp);
|
||||||
if (limit >= xx_cols || xbp != xbuf || xep > xlp)
|
/* check whether there is more off-screen */
|
||||||
limit = xx_cols;
|
lch = xep > xlp ? (xbp > xbuf ? '*' : '>') : (xbp > xbuf) ? '<' : ' ';
|
||||||
if (limit == xx_cols && x_term_mode == 1 && xbp == xbuf && xep <= xlp)
|
/* clear the rest of the line */
|
||||||
shf_puts("\033[K", shl_out);
|
x_clrtoeol(lch, !cr || cr == '\n');
|
||||||
else if (limit >= 0) {
|
/* go back to actual cursor position */
|
||||||
if (xep > xlp)
|
x_lastpos();
|
||||||
/* we fill the line */
|
|
||||||
i = 0;
|
|
||||||
else {
|
|
||||||
char *cpl = xbp;
|
|
||||||
|
|
||||||
i = limit;
|
|
||||||
while (cpl < xlp)
|
|
||||||
i -= x_size2(cpl, &cpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
while ((j < i) || (x_col < (xx_cols - 2))) {
|
|
||||||
if (!(x_col < (xx_cols - 2)))
|
|
||||||
break;
|
|
||||||
x_e_putc2(' ');
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
i = ' ';
|
|
||||||
if (xep > xlp) {
|
|
||||||
/* more off screen */
|
|
||||||
if (xbp > xbuf)
|
|
||||||
i = '*';
|
|
||||||
else
|
|
||||||
i = '>';
|
|
||||||
} else if (xbp > xbuf)
|
|
||||||
i = '<';
|
|
||||||
x_e_putc2(i);
|
|
||||||
j++;
|
|
||||||
while (j--)
|
|
||||||
x_e_putc2('\b');
|
|
||||||
}
|
|
||||||
cp = xlp;
|
|
||||||
while (cp > xcp)
|
|
||||||
x_bs3(&cp);
|
|
||||||
x_adj_ok = true;
|
x_adj_ok = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -3240,22 +3228,10 @@ x_fold_case(int c)
|
|||||||
* NAME:
|
* NAME:
|
||||||
* x_lastcp - last visible char
|
* x_lastcp - last visible char
|
||||||
*
|
*
|
||||||
* SYNOPSIS:
|
|
||||||
* x_lastcp()
|
|
||||||
*
|
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
* This function returns a pointer to that char in the
|
* This function returns a pointer to that char in the
|
||||||
* edit buffer that will be the last displayed on the
|
* edit buffer that will be the last displayed on the
|
||||||
* screen. The sequence:
|
* screen.
|
||||||
*
|
|
||||||
* cp = x_lastcp();
|
|
||||||
* while (cp > xcp)
|
|
||||||
* x_bs3(&cp);
|
|
||||||
*
|
|
||||||
* Will position the cursor correctly on the screen.
|
|
||||||
*
|
|
||||||
* RETURN VALUE:
|
|
||||||
* cp or NULL
|
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
x_lastcp(void)
|
x_lastcp(void)
|
||||||
@ -3277,6 +3253,16 @@ x_lastcp(void)
|
|||||||
return (xlp);
|
return (xlp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* correctly position the cursor on the screen from end of visible area */
|
||||||
|
static void
|
||||||
|
x_lastpos(void)
|
||||||
|
{
|
||||||
|
char *cp = x_lastcp();
|
||||||
|
|
||||||
|
while (cp > xcp)
|
||||||
|
x_bs3(&cp);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
x_mode(bool onoff)
|
x_mode(bool onoff)
|
||||||
{
|
{
|
||||||
@ -5087,9 +5073,7 @@ redraw_line(bool newl)
|
|||||||
x_putc('\r');
|
x_putc('\r');
|
||||||
x_putc('\n');
|
x_putc('\n');
|
||||||
}
|
}
|
||||||
if (prompt_trunc != -1)
|
x_pprompt();
|
||||||
pprompt(prompt, prompt_trunc);
|
|
||||||
x_col = pwidth;
|
|
||||||
morec = ' ';
|
morec = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5244,9 +5228,7 @@ ed_mov_opt(int col, char *wb)
|
|||||||
if (col < x_col) {
|
if (col < x_col) {
|
||||||
if (col + 1 < x_col - col) {
|
if (col + 1 < x_col - col) {
|
||||||
x_putc('\r');
|
x_putc('\r');
|
||||||
if (prompt_trunc != -1)
|
x_pprompt();
|
||||||
pprompt(prompt, prompt_trunc);
|
|
||||||
x_col = pwidth;
|
|
||||||
while (x_col++ < col)
|
while (x_col++ < col)
|
||||||
x_putcf(*wb++);
|
x_putcf(*wb++);
|
||||||
} else {
|
} else {
|
||||||
@ -5539,4 +5521,79 @@ x_initterm(const char *termtype)
|
|||||||
if (!strcmp(termtype, "screen") || !strncmp(termtype, "screen-", 7))
|
if (!strcmp(termtype, "screen") || !strncmp(termtype, "screen-", 7))
|
||||||
x_term_mode = 1;
|
x_term_mode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MKSH_SMALL
|
||||||
|
static char *
|
||||||
|
x_eval_region_helper(const char *cmd, size_t len)
|
||||||
|
{
|
||||||
|
char * volatile cp;
|
||||||
|
newenv(E_ERRH);
|
||||||
|
|
||||||
|
if (!kshsetjmp(e->jbuf)) {
|
||||||
|
char *wds = alloc(len + 3, ATEMP);
|
||||||
|
|
||||||
|
wds[0] = FUNSUB;
|
||||||
|
memcpy(wds + 1, cmd, len);
|
||||||
|
wds[len + 1] = '\0';
|
||||||
|
wds[len + 2] = EOS;
|
||||||
|
|
||||||
|
cp = evalstr(wds, DOSCALAR);
|
||||||
|
strdupx(cp, cp, AEDIT);
|
||||||
|
} else
|
||||||
|
cp = NULL;
|
||||||
|
quitenv(NULL);
|
||||||
|
return (cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
x_eval_region(int c MKSH_A_UNUSED)
|
||||||
|
{
|
||||||
|
char *evbeg, *evend, *cp;
|
||||||
|
size_t newlen;
|
||||||
|
/* only for LINE overflow checking */
|
||||||
|
size_t restlen;
|
||||||
|
|
||||||
|
if (xmp == NULL) {
|
||||||
|
evbeg = xbuf;
|
||||||
|
evend = xep;
|
||||||
|
} else if (xmp < xcp) {
|
||||||
|
evbeg = xmp;
|
||||||
|
evend = xcp;
|
||||||
|
} else {
|
||||||
|
evbeg = xcp;
|
||||||
|
evend = xmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
x_e_putc2('\r');
|
||||||
|
x_clrtoeol(' ', false);
|
||||||
|
x_flush();
|
||||||
|
x_mode(false);
|
||||||
|
cp = x_eval_region_helper(evbeg, evend - evbeg);
|
||||||
|
x_mode(true);
|
||||||
|
|
||||||
|
if (cp == NULL) {
|
||||||
|
/* command cannot be parsed */
|
||||||
|
x_eval_region_err:
|
||||||
|
x_e_putc2(7);
|
||||||
|
x_redraw('\r');
|
||||||
|
return (KSTD);
|
||||||
|
}
|
||||||
|
|
||||||
|
newlen = strlen(cp);
|
||||||
|
restlen = xep - evend;
|
||||||
|
/* check for LINE overflow, until this is dynamically allocated */
|
||||||
|
if (evbeg + newlen + restlen >= xend)
|
||||||
|
goto x_eval_region_err;
|
||||||
|
|
||||||
|
xmp = evbeg;
|
||||||
|
xcp = evbeg + newlen;
|
||||||
|
xep = xcp + restlen;
|
||||||
|
memmove(xcp, evend, restlen + /* NUL */ 1);
|
||||||
|
memcpy(xmp, cp, newlen);
|
||||||
|
afree(cp, AEDIT);
|
||||||
|
x_adjust();
|
||||||
|
x_modified();
|
||||||
|
return (KSTD);
|
||||||
|
}
|
||||||
|
#endif /* !MKSH_SMALL */
|
||||||
#endif /* !MKSH_NO_CMDLINE_EDITING */
|
#endif /* !MKSH_NO_CMDLINE_EDITING */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009, 2010, 2015
|
* Copyright (c) 2009, 2010, 2015, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(EMACSFN_DEFNS)
|
#if defined(EMACSFN_DEFNS)
|
||||||
__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.7 2015/12/12 21:08:44 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.8 2016/07/26 21:37:25 tg Exp $");
|
||||||
#define FN(cname,sname,flags) static int x_##cname(int);
|
#define FN(cname,sname,flags) static int x_##cname(int);
|
||||||
#elif defined(EMACSFN_ENUMS)
|
#elif defined(EMACSFN_ENUMS)
|
||||||
#define FN(cname,sname,flags) XFUNC_##cname,
|
#define FN(cname,sname,flags) XFUNC_##cname,
|
||||||
@ -54,6 +54,7 @@ FN(end_of_text, "eot", 0)
|
|||||||
FN(enumerate, "list", 0)
|
FN(enumerate, "list", 0)
|
||||||
FN(eot_del, "eot-or-delete", XF_ARG)
|
FN(eot_del, "eot-or-delete", XF_ARG)
|
||||||
FN(error, "error", 0)
|
FN(error, "error", 0)
|
||||||
|
FN(eval_region, "evaluate-region", 0)
|
||||||
FN(expand, "expand-file", 0)
|
FN(expand, "expand-file", 0)
|
||||||
#ifndef MKSH_SMALL
|
#ifndef MKSH_SMALL
|
||||||
FN(fold_capitalise, "capitalize-word", XF_ARG)
|
FN(fold_capitalise, "capitalize-word", XF_ARG)
|
||||||
|
9
mksh.1
9
mksh.1
@ -1,4 +1,4 @@
|
|||||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.404 2016/07/25 21:05:23 tg Exp $
|
.\" $MirOS: src/bin/mksh/mksh.1,v 1.405 2016/07/26 21:37:26 tg Exp $
|
||||||
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
|
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
|
||||||
.\"-
|
.\"-
|
||||||
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
||||||
@ -76,7 +76,7 @@
|
|||||||
.\" with -mandoc, it might implement .Mx itself, but we want to
|
.\" with -mandoc, it might implement .Mx itself, but we want to
|
||||||
.\" use our own definition. And .Dd must come *first*, always.
|
.\" use our own definition. And .Dd must come *first*, always.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: July 25 2016 $
|
.Dd $Mdocdate: July 26 2016 $
|
||||||
.\"
|
.\"
|
||||||
.\" Check which macro package we use, and do other -mdoc setup.
|
.\" Check which macro package we use, and do other -mdoc setup.
|
||||||
.\"
|
.\"
|
||||||
@ -5618,6 +5618,11 @@ otherwise,
|
|||||||
.Ic delete\-char\-forward .
|
.Ic delete\-char\-forward .
|
||||||
.It error: (not bound)
|
.It error: (not bound)
|
||||||
Error (ring the bell).
|
Error (ring the bell).
|
||||||
|
.It evaluate\-region: \*(ha[\*(haE
|
||||||
|
Evaluates the text between the mark and the cursor position
|
||||||
|
.Pq the entire line if no mark is set
|
||||||
|
as function substitution (if it cannot be parsed, the editing state is
|
||||||
|
unchanged and the bell is rung to signal an error); $? is updated accordingly.
|
||||||
.It exchange\-point\-and\-mark: \*(haX\*(haX
|
.It exchange\-point\-and\-mark: \*(haX\*(haX
|
||||||
Places the cursor where the mark is and sets the mark to where the cursor was.
|
Places the cursor where the mark is and sets the mark to where the cursor was.
|
||||||
.It expand\-file: \*(ha[*
|
.It expand\-file: \*(ha[*
|
||||||
|
Reference in New Issue
Block a user