mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-01 05:16:05 +01:00
33730: vim style text objects for selecting words
This commit is contained in:
parent
0151ab0749
commit
58da0f495c
7 changed files with 426 additions and 3 deletions
|
@ -1,3 +1,9 @@
|
|||
2014-11-21 Oliver Kiddle <opk@zsh.org>
|
||||
|
||||
* 33730: Doc/Zsh/zle.yo, Src/Zle/iwidgets.list,
|
||||
Src/Zle/textobjects.c, Src/Zle/zle.mdd, Src/Zle/zle_keymap.c,
|
||||
Test/X02zlevi.ztst: vim style text objects for selecting words
|
||||
|
||||
2014-11-21 Peter Stephenson <p.stephenson@samsung.com>
|
||||
|
||||
* Sebastien Alaiwan: 33728: Completion/Unix/Command/_bzr:
|
||||
|
@ -20,7 +26,7 @@
|
|||
2014-11-17 Oliver Kiddle <opk@zsh.org>
|
||||
|
||||
* 33704: Doc/Zsh/zle.yo, Src/Zle/zle_bindings.c,
|
||||
Src/Zle/zle_keX4aymap.c, Src/Zle/zle_refresh.c, Src/Zle/zle_vi.c,
|
||||
Src/Zle/zle_keymap.c, Src/Zle/zle_refresh.c, Src/Zle/zle_vi.c,
|
||||
Test/X02zlevi.ztst, Test/comptest: key bindings, documentation,
|
||||
tests and minor fixes for vim style visual selection changes
|
||||
|
||||
|
|
|
@ -1975,7 +1975,7 @@ When a previous completion displayed a list below the prompt, this
|
|||
widget can be used to move the prompt below the list.
|
||||
)
|
||||
enditem()
|
||||
texinode(Miscellaneous)()(Completion)(Zle Widgets)
|
||||
texinode(Miscellaneous)(Text Objects)(Completion)(Zle Widgets)
|
||||
subsect(Miscellaneous)
|
||||
startitem()
|
||||
tindex(accept-and-hold)
|
||||
|
@ -2333,6 +2333,50 @@ If the last command executed was a digit as part of an argument,
|
|||
continue the argument. Otherwise, execute vi-beginning-of-line.
|
||||
)
|
||||
enditem()
|
||||
texinode(Text Objects)()(Miscellaneous)(Zle Widgets)
|
||||
subsect(Text Objects)
|
||||
cindex(text objects)
|
||||
Text objects are commands that can be used to select a block of text
|
||||
according to some criteria. They are a feature of the vim text editor
|
||||
and so are primarily intended for use with vi operators or from visual
|
||||
selection mode. However, they can also be used from vi-insert or emacs
|
||||
mode. Key bindings listed below apply to the tt(viopp) and tt(visual)
|
||||
keymaps.
|
||||
|
||||
startitem()
|
||||
tindex(select-a-blank-word)
|
||||
item(tt(select-a-blank-word) (aW))(
|
||||
Select a word including adjacent blanks, where a word is defined as a
|
||||
series of non-blank characters. With a numeric argument, multiple words
|
||||
will be selected.
|
||||
)
|
||||
tindex(select-a-shell-word)
|
||||
item(tt(select-a-shell-word) (aa))(
|
||||
Select the current command argument applying the normal rules for
|
||||
quoting.
|
||||
)
|
||||
tindex(select-a-word)
|
||||
item(tt(select-a-word) (aw))(
|
||||
Select a word including adjacent blanks, using the normal vi-style word
|
||||
definition. With a numeric argument, multiple words will be selected.
|
||||
)
|
||||
tindex(select-in-blank-word)
|
||||
item(tt(select-in-blank-word) (iW))(
|
||||
Select a word, where a word is defined as a series of non-blank
|
||||
characters. With a numeric argument, multiple words will be selected.
|
||||
)
|
||||
tindex(select-in-shell-word)
|
||||
item(tt(select-in-shell-word) (ia))(
|
||||
Select the current command argument applying the normal rules for
|
||||
quoting. If the argument begins and ends with matching quote characters,
|
||||
these are not included in the selection.
|
||||
)
|
||||
tindex(select-in-word)
|
||||
item(tt(select-in-word) (iw))(
|
||||
Select a word, using the normal vi-style word definition. With a numeric
|
||||
argument, multiple words will be selected.
|
||||
)
|
||||
enditem()
|
||||
|
||||
texinode(Character Highlighting)()(Zle Widgets)(Zsh Line Editor)
|
||||
sect(Character Highlighting)
|
||||
|
|
|
@ -100,6 +100,12 @@
|
|||
"reset-prompt", resetprompt, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"select-a-word", selectword, ZLE_KEEPSUFFIX
|
||||
"select-in-word", selectword, ZLE_KEEPSUFFIX
|
||||
"select-a-blank-word", selectword, ZLE_KEEPSUFFIX
|
||||
"select-in-blank-word", selectword, ZLE_KEEPSUFFIX
|
||||
"select-a-shell-word", selectargument, ZLE_KEEPSUFFIX
|
||||
"select-in-shell-word", selectargument, ZLE_KEEPSUFFIX
|
||||
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"send-break", sendbreak, 0
|
||||
|
|
321
Src/Zle/textobjects.c
Normal file
321
Src/Zle/textobjects.c
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* textobjects.c - ZLE module implementing Vim style text objects
|
||||
*
|
||||
* This file is part of zsh, the Z shell.
|
||||
*
|
||||
* Copyright (c) 2014 Oliver Kiddle
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and to distribute modified versions of this software for any
|
||||
* purpose, provided that the above copyright notice and the following
|
||||
* two paragraphs appear in all copies of this software.
|
||||
*
|
||||
* In no event shall Oliver Kiddle or the Zsh Development Group be liable
|
||||
* to any party for direct, indirect, special, incidental, or consequential
|
||||
* damages arising out of the use of this software and its documentation,
|
||||
* even if Oliver Kiddle and the Zsh Development Group have been advised of
|
||||
* the possibility of such damage.
|
||||
*
|
||||
* Oliver Kiddle and the Zsh Development Group specifically disclaim any
|
||||
* warranties, including, but not limited to, the implied warranties of
|
||||
* merchantability and fitness for a particular purpose. The software
|
||||
* provided hereunder is on an "as is" basis, and Oliver Kiddle and the
|
||||
* Zsh Development Group have no obligation to provide maintenance,
|
||||
* support, updates, enhancements, or modifications.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "zle.mdh"
|
||||
#include "textobjects.pro"
|
||||
|
||||
/* class of character: 0 is whitespace, 1 is word character, 2 is other */
|
||||
static int
|
||||
wordclass(ZLE_CHAR_T x)
|
||||
{
|
||||
return (ZC_iblank(x) ? 0 : ((ZC_ialnum(x) || (ZWC('_') == x)) ? 1 : 2));
|
||||
}
|
||||
|
||||
static int
|
||||
blankwordclass(ZLE_CHAR_T x)
|
||||
{
|
||||
return (ZC_iblank(x) ? 0 : 1);
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
selectword(UNUSED(char **args))
|
||||
{
|
||||
int n = zmult;
|
||||
int all = (bindk == t_selectaword || bindk == t_selectablankword);
|
||||
int (*viclass)(ZLE_CHAR_T) = (bindk == t_selectaword ||
|
||||
bindk == t_selectinword) ? wordclass : blankwordclass;
|
||||
int sclass = viclass(zleline[zlecs]);
|
||||
int doblanks = all && sclass;
|
||||
|
||||
if (!invicmdmode()) {
|
||||
region_active = 1;
|
||||
mark = zlecs;
|
||||
}
|
||||
if (!region_active || zlecs == mark) {
|
||||
/* search back to first character of same class as the start position
|
||||
* also stop at the beginning of the line */
|
||||
mark = zlecs;
|
||||
while (mark) {
|
||||
int pos = mark;
|
||||
DECPOS(pos);
|
||||
if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass)
|
||||
break;
|
||||
mark = pos;
|
||||
}
|
||||
/* similarly scan forward over characters of the same class */
|
||||
while (zlecs < zlell) {
|
||||
INCCS();
|
||||
int pos = zlecs;
|
||||
/* single newlines within blanks are included */
|
||||
if (all && !sclass && pos < zlell && zleline[pos] == ZWC('\n'))
|
||||
INCPOS(pos);
|
||||
|
||||
if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass)
|
||||
break;
|
||||
}
|
||||
|
||||
if (all) {
|
||||
int nclass = viclass(zleline[zlecs]);
|
||||
/* if either start or new position is blank advance over
|
||||
* a new block of characters of a common type */
|
||||
if (!nclass || !sclass) {
|
||||
while (zlecs < zlell) {
|
||||
INCCS();
|
||||
if (zleline[zlecs] == ZWC('\n') ||
|
||||
viclass(zleline[zlecs]) != nclass)
|
||||
break;
|
||||
}
|
||||
if (n < 2)
|
||||
doblanks = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* For visual mode, advance one char so repeated
|
||||
* invocations select subsequent words */
|
||||
if (zlecs > mark) {
|
||||
if (zlecs < zlell)
|
||||
INCCS();
|
||||
} else if (zlecs)
|
||||
DECCS();
|
||||
if (zlecs < mark) {
|
||||
/* visual mode with the cursor before the mark: move cursor back */
|
||||
while (n-- > 0) {
|
||||
int pos = zlecs;
|
||||
/* first over blanks */
|
||||
if (all && (!viclass(zleline[pos]) ||
|
||||
zleline[pos] == ZWC('\n'))) {
|
||||
all = 0;
|
||||
while (pos) {
|
||||
DECPOS(pos);
|
||||
if (zleline[pos] == ZWC('\n'))
|
||||
break;
|
||||
zlecs = pos;
|
||||
if (viclass(zleline[pos]))
|
||||
break;
|
||||
}
|
||||
} else if (zlecs && zleline[zlecs] == ZWC('\n')) {
|
||||
/* for in widgets pass over one newline */
|
||||
DECPOS(pos);
|
||||
if (zleline[pos] != ZWC('\n'))
|
||||
zlecs = pos;
|
||||
}
|
||||
pos = zlecs;
|
||||
sclass = viclass(zleline[zlecs]);
|
||||
/* now retreat over non-blanks */
|
||||
while (zleline[pos] != ZWC('\n') &&
|
||||
viclass(zleline[pos]) == sclass) {
|
||||
zlecs = pos;
|
||||
if (!pos) {
|
||||
zlecs = 0;
|
||||
break;
|
||||
}
|
||||
DECPOS(pos);
|
||||
}
|
||||
/* blanks again but only if there were none first time */
|
||||
if (all && zlecs) {
|
||||
pos = zlecs;
|
||||
DECPOS(pos);
|
||||
if (!viclass(zleline[pos])) {
|
||||
while (pos) {
|
||||
DECPOS(pos);
|
||||
if (zleline[pos] == ZWC('\n') ||
|
||||
viclass(zleline[pos]))
|
||||
break;
|
||||
zlecs = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
n++;
|
||||
doblanks = 0;
|
||||
}
|
||||
region_active = !!region_active; /* force to character wise */
|
||||
|
||||
/* for each digit argument, advance over further block of one class */
|
||||
while (--n > 0) {
|
||||
if (zlecs < zlell && zleline[zlecs] == ZWC('\n'))
|
||||
INCCS();
|
||||
sclass = viclass(zleline[zlecs]);
|
||||
while (zlecs < zlell) {
|
||||
INCCS();
|
||||
if (zleline[zlecs] == ZWC('\n') ||
|
||||
viclass(zleline[zlecs]) != sclass)
|
||||
break;
|
||||
}
|
||||
/* for 'a' widgets, advance extra block if either consists of blanks */
|
||||
if (all) {
|
||||
if (zlecs < zlell && zleline[zlecs] == ZWC('\n'))
|
||||
INCCS();
|
||||
if (!sclass || !viclass(zleline[zlecs]) ) {
|
||||
sclass = viclass(zleline[zlecs]);
|
||||
if (n == 1 && !sclass)
|
||||
doblanks = 0;
|
||||
while (zlecs < zlell) {
|
||||
INCCS();
|
||||
if (zleline[zlecs] == ZWC('\n') ||
|
||||
viclass(zleline[zlecs]) != sclass)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if we didn't remove blanks at either end we remove some at the start */
|
||||
if (doblanks) {
|
||||
int pos = mark;
|
||||
while (pos) {
|
||||
DECPOS(pos);
|
||||
/* don't remove blanks at the start of the line, i.e indentation */
|
||||
if (zleline[pos] == ZWC('\n'))
|
||||
break;
|
||||
if (!ZC_iblank(zleline[pos])) {
|
||||
INCPOS(pos);
|
||||
mark = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Adjustment: vi operators don't include the cursor position, in insert
|
||||
* or emacs mode the region also doesn't but for vi visual mode it is
|
||||
* included. */
|
||||
if (zlecs && zlecs > mark && !virangeflag)
|
||||
DECCS();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
selectargument(UNUSED(char **args))
|
||||
{
|
||||
int ne = noerrs, ocs = zlemetacs;
|
||||
int owb = wb, owe= we, oadx = addedx, ona = noaliases;
|
||||
char *p;
|
||||
int ll, cs;
|
||||
char *linein;
|
||||
int wend = 0, wcur = 0;
|
||||
int n = zmult;
|
||||
int *wstarts;
|
||||
int tmpsz;
|
||||
|
||||
if (n < 1 || 2*n > zlell + 1)
|
||||
return 1;
|
||||
|
||||
/* if used from emacs mode enable the region */
|
||||
if (!invicmdmode()) {
|
||||
region_active = 1;
|
||||
mark = zlecs;
|
||||
}
|
||||
|
||||
wstarts = (int *) zhalloc(n * sizeof(int));
|
||||
memset(wstarts, 0, n * sizeof(int));
|
||||
|
||||
addedx = 0;
|
||||
noerrs = 1;
|
||||
lexsave();
|
||||
lexflags = LEXFLAGS_ACTIVE;
|
||||
linein = zlegetline(&ll, &cs);
|
||||
zlemetall = ll;
|
||||
zlemetacs = cs;
|
||||
|
||||
if (!isfirstln && chline) {
|
||||
p = (char *) zhalloc(hptr - chline + zlemetall + 2);
|
||||
memcpy(p, chline, hptr - chline);
|
||||
memcpy(p + (hptr - chline), linein, ll);
|
||||
p[(hptr - chline) + ll] = '\0';
|
||||
inpush(p, 0, NULL);
|
||||
zlemetacs += hptr - chline;
|
||||
} else {
|
||||
p = (char *) zhalloc(ll + 1);
|
||||
memcpy(p, linein, ll);
|
||||
p[ll] = '\0';
|
||||
inpush(p, 0, NULL);
|
||||
}
|
||||
if (zlemetacs)
|
||||
zlemetacs--;
|
||||
strinbeg(0);
|
||||
noaliases = 1;
|
||||
do {
|
||||
wstarts[wcur++] = wend;
|
||||
wcur %= n;
|
||||
ctxtlex();
|
||||
if (tok == ENDINPUT || tok == LEXERR)
|
||||
break;
|
||||
wend = zlemetall - inbufct;
|
||||
} while (tok != ENDINPUT && tok != LEXERR && wend <= zlemetacs);
|
||||
noaliases = ona;
|
||||
strinend();
|
||||
inpop();
|
||||
errflag = 0;
|
||||
noerrs = ne;
|
||||
lexrestore();
|
||||
zlemetacs = ocs;
|
||||
wb = owb;
|
||||
we = owe;
|
||||
addedx = oadx;
|
||||
|
||||
/* convert offsets for mark and zlecs back to ZLE internal format */
|
||||
linein[wend] = '\0'; /* a bit of a hack to get two offsets */
|
||||
free(stringaszleline(linein, wstarts[wcur], &zlecs, &tmpsz, &mark));
|
||||
|
||||
if (bindk == t_selectinshellword) {
|
||||
ZLE_CHAR_T *match = ZWS("`\'\"");
|
||||
ZLE_CHAR_T *lmatch = ZWS("\'({"), *rmatch = ZWS("\')}");
|
||||
ZLE_CHAR_T *ematch = match, *found;
|
||||
int start, end = zlecs;
|
||||
/* for 'in' widget, don't include initial blanks ... */
|
||||
while (mark < zlecs && ZC_iblank(zleline[mark]))
|
||||
INCPOS(mark);
|
||||
/* ... or a matching pair of quotes */
|
||||
start = mark;
|
||||
if (zleline[start] == ZWC('$')) {
|
||||
match = lmatch;
|
||||
ematch = rmatch;
|
||||
INCPOS(start);
|
||||
}
|
||||
found = ZS_strchr(match, zleline[start]);
|
||||
if (found) {
|
||||
DECPOS(end);
|
||||
if (zleline[end] == ematch[found-match]) {
|
||||
zlecs = end;
|
||||
INCPOS(start);
|
||||
mark = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjustment: vi operators don't include the cursor position */
|
||||
if (!virangeflag)
|
||||
DECCS();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -7,7 +7,8 @@ autofeatures="b:bindkey b:vared b:zle"
|
|||
|
||||
objects="zle_bindings.o zle_hist.o zle_keymap.o zle_main.o \
|
||||
zle_misc.o zle_move.o zle_params.o zle_refresh.o \
|
||||
zle_thingy.o zle_tricky.o zle_utils.o zle_vi.o zle_word.o"
|
||||
zle_thingy.o zle_tricky.o zle_utils.o zle_vi.o zle_word.o \
|
||||
textobjects.o"
|
||||
|
||||
headers="zle.h zle_things.h"
|
||||
|
||||
|
|
|
@ -1343,6 +1343,12 @@ default_bindings(void)
|
|||
add_cursor_key(kptr, TCDOWNCURSOR, t_downline, 'B');
|
||||
bindkey(kptr, "k", refthingy(t_upline), NULL);
|
||||
bindkey(kptr, "j", refthingy(t_downline), NULL);
|
||||
bindkey(kptr, "aa", refthingy(t_selectashellword), NULL);
|
||||
bindkey(kptr, "ia", refthingy(t_selectinshellword), NULL);
|
||||
bindkey(kptr, "aw", refthingy(t_selectaword), NULL);
|
||||
bindkey(kptr, "iw", refthingy(t_selectinword), NULL);
|
||||
bindkey(kptr, "aW", refthingy(t_selectablankword), NULL);
|
||||
bindkey(kptr, "iW", refthingy(t_selectinblankword), NULL);
|
||||
}
|
||||
/* escape in operator pending cancels the operation */
|
||||
bindkey(oppmap, "\33", refthingy(t_vicmdmode), NULL);
|
||||
|
|
|
@ -380,6 +380,45 @@
|
|||
zletest $'- word word\e4|2daw'
|
||||
0:delete all word with numeric argument
|
||||
>BUFFER: -
|
||||
>CURSOR: 0
|
||||
|
||||
zletest $'---- word ----word\eo \eo----\eodone\eh' \
|
||||
'vhawmaawmbawmcawmdawmeawmfawmgv`ara`brb`crc$r$`drd`ere`frf`grg'
|
||||
0:all word with existing selection and cursor before mark
|
||||
>BUFFER: g---f worde ----dord
|
||||
>c $
|
||||
>b---
|
||||
>aone
|
||||
>CURSOR: 0
|
||||
|
||||
zletest $'---- word word----\e0lvlawmaawmbawmcawvrd`ara`brb`crc'
|
||||
0:all word with existing selection and mark before cursor
|
||||
>BUFFER: ---- aword bworc---d
|
||||
>CURSOR: 19
|
||||
|
||||
zletest $' --ww ww---\eo\eoww\evhiwiw' m{a,b,c,d,e}iw vrE \`{a,b,c,d,e}r.
|
||||
0:in word with existing selection and cursor before mark
|
||||
>BUFFER: E.-.w. .w.--
|
||||
>
|
||||
>ww
|
||||
>CURSOR: 1
|
||||
|
||||
zletest $' --ww ww--\eO \ev0o' m{a,b,c,d,e}iw vrE \`{a,b,c,d,e}r.
|
||||
0:in word with existing selection and mark before cursor
|
||||
>BUFFER: .
|
||||
> .-.w. .wE--
|
||||
>CURSOR: 10
|
||||
|
||||
zletest $' `one` $(echo two) " three " $\'four\'\C-v\tfive ${six:-6}\e' \
|
||||
vaaom{a,b,c,d,e,f}v \`{a,b,c,d,e,f}rX
|
||||
0:all argument for different arguments
|
||||
>BUFFER: X `one`X $(echo two)X" three "X$'four'XfiveX${six:-6}
|
||||
>CURSOR: 0
|
||||
|
||||
zletest $'{ls `echo x` $((3+4)) "a b" $\'\\t\\n\' ${d%/}\e' \
|
||||
cia{6,5,4,3,2,1}$'\eBB'
|
||||
0:in argument for different arguments
|
||||
>BUFFER: 1ls `2` $(3) "4" $'5' ${6}
|
||||
>CURSOR: 0
|
||||
|
||||
%clean
|
||||
|
|
Loading…
Reference in a new issue