mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 13:33:52 +01:00
1501 lines
32 KiB
C
1501 lines
32 KiB
C
/*
|
|
* zle_hist.c - history editing
|
|
*
|
|
* This file is part of zsh, the Z shell.
|
|
*
|
|
* Copyright (c) 1992-1997 Paul Falstad
|
|
* 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 Paul Falstad 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 Paul Falstad and the Zsh Development Group have been advised of
|
|
* the possibility of such damage.
|
|
*
|
|
* Paul Falstad 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 Paul Falstad and the
|
|
* Zsh Development Group have no obligation to provide maintenance,
|
|
* support, updates, enhancements, or modifications.
|
|
*
|
|
*/
|
|
|
|
#include "zle.mdh"
|
|
#include "zle_hist.pro"
|
|
|
|
/* Column position of vi ideal cursor. -1 if it is unknown -- most *
|
|
* movements and changes do this. */
|
|
|
|
/**/
|
|
int lastcol;
|
|
|
|
/* current history line number */
|
|
|
|
/**/
|
|
int histline;
|
|
|
|
/* Previous search string use in an incremental search */
|
|
|
|
/**/
|
|
ZLE_STRING_T previous_search = NULL;
|
|
|
|
/**/
|
|
int previous_search_len = 0;
|
|
|
|
struct zle_text {
|
|
ZLE_STRING_T text;
|
|
int len;
|
|
int alloced;
|
|
};
|
|
|
|
/*
|
|
* Fetch the text of a history line in internal ZLE format.
|
|
* If the line has been edited, returns that, else allocates
|
|
* a converted line.
|
|
*
|
|
* Each use of this must have a matching zletextfree() in order
|
|
* to free up the allocated line, if any. (N.B.: each use *of
|
|
* the function*, not just each use of a struct zle_text.)
|
|
*
|
|
* TODO: This is quite inefficient. We could convert zlinecmp and
|
|
* zlinefind to take a metafied string as input and acquire a (wide)
|
|
* character from it whenever needed, which would also require storing
|
|
* zle_text as a metafied string in remember_edits(). However, the
|
|
* following is good enough for now (although searching a really huge
|
|
* history might not be so much fun).
|
|
*/
|
|
|
|
static void
|
|
zletext(Histent ent, struct zle_text *zt)
|
|
{
|
|
if (ent->zle_text) {
|
|
zt->text = ent->zle_text;
|
|
zt->len = ent->zle_len;
|
|
zt->alloced = 0;
|
|
return;
|
|
}
|
|
|
|
zt->text = stringaszleline((unsigned char *)ent->text, 0,
|
|
&zt->len, NULL, NULL);
|
|
zt->alloced = 1;
|
|
}
|
|
|
|
/* See above. */
|
|
|
|
static void
|
|
zletextfree(struct zle_text *zt)
|
|
{
|
|
if (zt->alloced) {
|
|
free(zt->text);
|
|
zt->alloced = 0;
|
|
}
|
|
}
|
|
|
|
/**/
|
|
void
|
|
remember_edits(void)
|
|
{
|
|
Histent ent = quietgethist(histline);
|
|
if (ent) {
|
|
if (!ent->zle_text || ent->zle_len != zlell ||
|
|
ZS_memcmp(ent->zle_text, zleline, zlell) != 0) {
|
|
if (ent->zle_text)
|
|
free(ent->zle_text);
|
|
ent->zle_text = zalloc(zlell * ZLE_CHAR_SIZE);
|
|
ent->zle_len = zlell;
|
|
ZS_memcpy(ent->zle_text, zleline, zlell);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**/
|
|
void
|
|
forget_edits(void)
|
|
{
|
|
Histent he;
|
|
|
|
for (he = hist_ring; he; he = up_histent(he)) {
|
|
if (he->zle_text) {
|
|
free(he->zle_text);
|
|
he->zle_text = NULL;
|
|
he->zle_len = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**/
|
|
int
|
|
uphistory(UNUSED(char **args))
|
|
{
|
|
int nodups = isset(HISTIGNOREDUPS);
|
|
if (!zle_goto_hist(histline, -zmult, nodups) && isset(HISTBEEP))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
static int
|
|
upline(void)
|
|
{
|
|
int n = zmult;
|
|
|
|
if (n < 0) {
|
|
zmult = -zmult;
|
|
n = -downline();
|
|
zmult = -zmult;
|
|
return n;
|
|
}
|
|
if (lastcol == -1)
|
|
lastcol = zlecs - findbol();
|
|
zlecs = findbol();
|
|
while (n) {
|
|
if (!zlecs)
|
|
break;
|
|
zlecs--;
|
|
zlecs = findbol();
|
|
n--;
|
|
}
|
|
if (!n) {
|
|
int x = findeol();
|
|
|
|
if ((zlecs += lastcol) >= x) {
|
|
zlecs = x;
|
|
if (zlecs > findbol() && invicmdmode())
|
|
zlecs--;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
uplineorhistory(char **args)
|
|
{
|
|
int ocs = zlecs;
|
|
int n = upline();
|
|
if (n) {
|
|
int m = zmult, ret;
|
|
|
|
zlecs = ocs;
|
|
if (virangeflag || !(zlereadflags & ZLRF_HISTORY))
|
|
return 1;
|
|
zmult = n;
|
|
ret = uphistory(args);
|
|
zmult = m;
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
viuplineorhistory(char **args)
|
|
{
|
|
int col = lastcol;
|
|
uplineorhistory(args);
|
|
lastcol = col;
|
|
return vifirstnonblank(args);
|
|
}
|
|
|
|
/**/
|
|
int
|
|
uplineorsearch(char **args)
|
|
{
|
|
int ocs = zlecs;
|
|
int n = upline();
|
|
if (n) {
|
|
int m = zmult, ret;
|
|
|
|
zlecs = ocs;
|
|
if (virangeflag || !(zlereadflags & ZLRF_HISTORY))
|
|
return 1;
|
|
zmult = n;
|
|
ret = historysearchbackward(args);
|
|
zmult = m;
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
static int
|
|
downline(void)
|
|
{
|
|
int n = zmult;
|
|
|
|
if (n < 0) {
|
|
zmult = -zmult;
|
|
n = -upline();
|
|
zmult = -zmult;
|
|
return n;
|
|
}
|
|
if (lastcol == -1)
|
|
lastcol = zlecs - findbol();
|
|
while (n) {
|
|
int x = findeol();
|
|
|
|
if (x == zlell)
|
|
break;
|
|
zlecs = x + 1;
|
|
n--;
|
|
}
|
|
if (!n) {
|
|
int x = findeol();
|
|
|
|
if ((zlecs += lastcol) >= x) {
|
|
zlecs = x;
|
|
if (zlecs > findbol() && invicmdmode())
|
|
zlecs--;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
downlineorhistory(char **args)
|
|
{
|
|
int ocs = zlecs;
|
|
int n = downline();
|
|
if (n) {
|
|
int m = zmult, ret;
|
|
|
|
zlecs = ocs;
|
|
if (virangeflag || !(zlereadflags & ZLRF_HISTORY))
|
|
return 1;
|
|
zmult = n;
|
|
ret = downhistory(args);
|
|
zmult = m;
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
vidownlineorhistory(char **args)
|
|
{
|
|
int col = lastcol;
|
|
downlineorhistory(args);
|
|
lastcol = col;
|
|
return vifirstnonblank(zlenoargs);
|
|
}
|
|
|
|
/**/
|
|
int
|
|
downlineorsearch(char **args)
|
|
{
|
|
int ocs = zlecs;
|
|
int n = downline();
|
|
if (n) {
|
|
int m = zmult, ret;
|
|
|
|
zlecs = ocs;
|
|
if (virangeflag || !(zlereadflags & ZLRF_HISTORY))
|
|
return 1;
|
|
zmult = n;
|
|
ret = historysearchforward(args);
|
|
zmult = m;
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
acceptlineanddownhistory(UNUSED(char **args))
|
|
{
|
|
Histent he = quietgethist(histline);
|
|
|
|
if (he && (he = movehistent(he, 1, HIST_FOREIGN))) {
|
|
zpushnode(bufstack, ztrdup(he->text));
|
|
stackhist = he->histnum;
|
|
}
|
|
done = 1;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
downhistory(UNUSED(char **args))
|
|
{
|
|
int nodups = isset(HISTIGNOREDUPS);
|
|
if (!zle_goto_hist(histline, zmult, nodups) && isset(HISTBEEP))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int histpos, srch_hl, srch_cs = -1;
|
|
static ZLE_STRING_T srch_str;
|
|
|
|
/**/
|
|
int
|
|
historysearchbackward(char **args)
|
|
{
|
|
Histent he;
|
|
int n = zmult, hp;
|
|
ZLE_STRING_T str;
|
|
struct zle_text zt;
|
|
|
|
if (zmult < 0) {
|
|
int ret;
|
|
zmult = -n;
|
|
ret = historysearchforward(args);
|
|
zmult = n;
|
|
return ret;
|
|
}
|
|
if (*args) {
|
|
str = stringaszleline((unsigned char *)*args, 0, &hp, NULL, NULL);
|
|
} else {
|
|
if (histline == curhist || histline != srch_hl || zlecs != srch_cs ||
|
|
mark != 0 || ZS_memcmp(srch_str, zleline, histpos) != 0) {
|
|
zfree(srch_str, histpos);
|
|
for (histpos = 0; histpos < zlell && !ZC_iblank(zleline[histpos]); histpos++) ;
|
|
if (histpos < zlell)
|
|
histpos++;
|
|
srch_str = zalloc(histpos * ZLE_CHAR_SIZE);
|
|
ZS_memcpy(srch_str, zleline, histpos);
|
|
}
|
|
str = srch_str;
|
|
hp = histpos;
|
|
}
|
|
if (!(he = quietgethist(histline))) {
|
|
if (*args)
|
|
free(str);
|
|
return 1;
|
|
}
|
|
while ((he = movehistent(he, -1, hist_skip_flags))) {
|
|
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
|
|
continue;
|
|
zletext(he, &zt);
|
|
if (zlinecmp(zt.text, zt.len, str, hp) < 0 &&
|
|
(*args || zlell != zt.len || ZS_memcmp(zt.text, str, zlell))) {
|
|
if (--n <= 0) {
|
|
zle_setline(he);
|
|
srch_hl = histline;
|
|
srch_cs = zlecs;
|
|
if (*args)
|
|
free(str);
|
|
zletextfree(&zt);
|
|
return 0;
|
|
}
|
|
}
|
|
zletextfree(&zt);
|
|
}
|
|
if (*args)
|
|
free(str);
|
|
return 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
historysearchforward(char **args)
|
|
{
|
|
Histent he;
|
|
int n = zmult, hp;
|
|
ZLE_STRING_T str;
|
|
struct zle_text zt;
|
|
|
|
if (zmult < 0) {
|
|
int ret;
|
|
zmult = -n;
|
|
ret = historysearchbackward(args);
|
|
zmult = n;
|
|
return ret;
|
|
}
|
|
if (*args) {
|
|
str = stringaszleline((unsigned char *)*args, 0, &hp, NULL, NULL);
|
|
} else {
|
|
if (histline == curhist || histline != srch_hl || zlecs != srch_cs ||
|
|
mark != 0 || ZS_memcmp(srch_str, zleline, histpos) != 0) {
|
|
zfree(srch_str, histpos * ZLE_CHAR_SIZE);
|
|
for (histpos = 0; histpos < zlell && !ZC_iblank(zleline[histpos]); histpos++) ;
|
|
if (histpos < zlell)
|
|
histpos++;
|
|
srch_str = zalloc(histpos * ZLE_CHAR_SIZE);
|
|
ZS_memcpy(srch_str, zleline, histpos);
|
|
}
|
|
str = srch_str;
|
|
hp = histpos;
|
|
}
|
|
if (!(he = quietgethist(histline))) {
|
|
if (*args)
|
|
free(str);
|
|
return 1;
|
|
}
|
|
while ((he = movehistent(he, 1, hist_skip_flags))) {
|
|
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
|
|
continue;
|
|
zletext(he, &zt);
|
|
if (zlinecmp(zt.text, zt.len, str, hp) < (he->histnum == curhist) &&
|
|
(*args || zlell != zt.len || ZS_memcmp(zt.text, str, zlell))) {
|
|
if (--n <= 0) {
|
|
zle_setline(he);
|
|
srch_hl = histline;
|
|
srch_cs = zlecs;
|
|
if (*args)
|
|
free(str);
|
|
zletextfree(&zt);
|
|
return 0;
|
|
}
|
|
}
|
|
zletextfree(&zt);
|
|
}
|
|
if (*args)
|
|
free(str);
|
|
return 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
beginningofbufferorhistory(char **args)
|
|
{
|
|
if (findbol())
|
|
zlecs = 0;
|
|
else
|
|
return beginningofhistory(args);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
beginningofhistory(UNUSED(char **args))
|
|
{
|
|
if (!zle_goto_hist(firsthist(), 0, 0) && isset(HISTBEEP))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
endofbufferorhistory(char **args)
|
|
{
|
|
if (findeol() != zlell)
|
|
zlecs = zlell;
|
|
else
|
|
return endofhistory(args);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
endofhistory(UNUSED(char **args))
|
|
{
|
|
zle_goto_hist(curhist, 0, 0);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
insertlastword(char **args)
|
|
{
|
|
int n, nwords, histstep = -1, wordpos = 0, deleteword = 0, len;
|
|
char *s, *t;
|
|
Histent he = NULL;
|
|
LinkList l = NULL;
|
|
LinkNode node;
|
|
ZLE_STRING_T zs;
|
|
|
|
static char *lastinsert;
|
|
static int lasthist, lastpos, lastlen;
|
|
int evhist, save;
|
|
|
|
/*
|
|
* If we have at least one argument, the first is the history
|
|
* step. The default is -1 (go back). Repeated calls take
|
|
* a step in this direction. A value of 0 is allowed and doesn't
|
|
* move the line.
|
|
*
|
|
* If we have two arguments, the second is the position of
|
|
* the word to extract, 1..N. The default is to use the
|
|
* numeric argument, or the last word if that is not set.
|
|
*
|
|
* If we have three arguments, we reset the history pointer to
|
|
* the current history event before applying the history step.
|
|
*/
|
|
if (*args)
|
|
{
|
|
histstep = (int)zstrtol(*args, NULL, 10);
|
|
if (*++args)
|
|
{
|
|
wordpos = (int)zstrtol(*args, NULL, 10);
|
|
if (*++args)
|
|
lasthist = curhist;
|
|
}
|
|
}
|
|
|
|
metafy_line();
|
|
if (lastinsert && lastlen &&
|
|
lastpos <= zlemetacs &&
|
|
lastlen == zlemetacs - lastpos &&
|
|
memcmp(lastinsert, (char *)&zlemetaline[lastpos], lastlen) == 0)
|
|
deleteword = 1;
|
|
else
|
|
lasthist = curhist;
|
|
evhist = histstep ? addhistnum(lasthist, histstep, HIST_FOREIGN) :
|
|
lasthist;
|
|
|
|
if (evhist == curhist) {
|
|
/*
|
|
* The line we are currently editing. If we are going to
|
|
* replace an existing word, delete the old one now to avoid
|
|
* confusion.
|
|
*/
|
|
if (deleteword) {
|
|
int pos = zlemetacs;
|
|
zlemetacs = lastpos;
|
|
foredel(pos - zlemetacs);
|
|
/*
|
|
* Mark that this has been deleted.
|
|
* For consistency with history lines, we really ought to
|
|
* insert it back if the current command later fails. But
|
|
* - we can't be bothered
|
|
* - the problem that this can screw up going to other
|
|
* lines in the history because we don't update
|
|
* the history line isn't really relevant
|
|
* - you can see what you're copying, dammit, so you
|
|
* shouldn't make errors.
|
|
* Of course, I could have implemented it in the time
|
|
* it took to say why I haven't.
|
|
*/
|
|
deleteword = 0;
|
|
}
|
|
/*
|
|
* Can only happen fail if the line is empty, I hope.
|
|
* In that case, we don't need to worry about restoring
|
|
* a deleted word, because that can only have come
|
|
* from a non-empty line. I think.
|
|
*/
|
|
if (!(l = bufferwords(NULL, NULL, NULL)))
|
|
return 1;
|
|
nwords = countlinknodes(l);
|
|
} else {
|
|
/* Some stored line. */
|
|
if (!(he = quietgethist(evhist)) || !he->nwords)
|
|
return 1;
|
|
nwords = he->nwords;
|
|
}
|
|
if (wordpos) {
|
|
n = (wordpos > 0) ? wordpos : nwords + wordpos + 1;
|
|
} else if (zmult > 0) {
|
|
n = nwords - (zmult - 1);
|
|
} else {
|
|
n = 1 - zmult;
|
|
}
|
|
if (n < 1 || n > nwords) {
|
|
/*
|
|
* We can't put in the requested word, but we did find the
|
|
* history entry, so we remember the position in the history
|
|
* list. This avoids getting stuck on a history line with
|
|
* fewer words than expected. The cursor location cs
|
|
* has not changed, and lastinsert is still valid.
|
|
*/
|
|
lasthist = evhist;
|
|
return 1;
|
|
}
|
|
/*
|
|
* Only remove the old word from the command line if we have
|
|
* successfully found a new one to insert.
|
|
*/
|
|
if (deleteword > 0) {
|
|
int pos = zlemetacs;
|
|
zlemetacs = lastpos;
|
|
foredel(pos - zlemetacs);
|
|
}
|
|
if (lastinsert) {
|
|
zfree(lastinsert, lastlen);
|
|
lastinsert = NULL;
|
|
}
|
|
if (l) {
|
|
for (node = firstnode(l); --n; incnode(node))
|
|
;
|
|
s = (char *)getdata(node);
|
|
t = s + strlen(s);
|
|
} else {
|
|
s = he->text + he->words[2*n-2];
|
|
t = he->text + he->words[2*n-1];
|
|
}
|
|
|
|
save = *t;
|
|
*t = '\0'; /* ignore trailing whitespace */
|
|
lasthist = evhist;
|
|
lastpos = zlemetacs;
|
|
lastlen = t - s;
|
|
lastinsert = zalloc(t - s);
|
|
memcpy(lastinsert, s, lastlen);
|
|
n = zmult;
|
|
zmult = 1;
|
|
|
|
unmetafy_line();
|
|
|
|
zs = stringaszleline((unsigned char *)s, 0, &len, NULL, NULL);
|
|
doinsert(zs, len);
|
|
free(zs);
|
|
zmult = n;
|
|
*t = save;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
void
|
|
zle_setline(Histent he)
|
|
{
|
|
remember_edits();
|
|
mkundoent();
|
|
histline = he->histnum;
|
|
|
|
if (he->zle_text) {
|
|
/*
|
|
* Optimise out conversion to metafied string and back.
|
|
* Remember convention of extra 2 characters spare.
|
|
*/
|
|
free(zleline);
|
|
linesz = zlell = he->zle_len;
|
|
zleline = zalloc((zlell + 2) * ZLE_CHAR_SIZE);
|
|
ZS_memcpy(zleline, he->zle_text, zlell);
|
|
|
|
zlecs = zlell;
|
|
if (invicmdmode())
|
|
zlecs--;
|
|
} else {
|
|
setline(he->text, ZSL_COPY|ZSL_TOEND);
|
|
}
|
|
setlastline();
|
|
clearlist = 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
setlocalhistory(UNUSED(char **args))
|
|
{
|
|
if (zmod.flags & MOD_MULT) {
|
|
hist_skip_flags = zmult? HIST_FOREIGN : 0;
|
|
} else {
|
|
hist_skip_flags ^= HIST_FOREIGN;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
zle_goto_hist(int ev, int n, int skipdups)
|
|
{
|
|
Histent he = quietgethist(ev);
|
|
if (!he || !(he = movehistent(he, n, hist_skip_flags)))
|
|
return 1;
|
|
if (skipdups && n) {
|
|
struct zle_text zt;
|
|
|
|
n = n < 0? -1 : 1;
|
|
while (he) {
|
|
int ret;
|
|
|
|
zletext(he, &zt);
|
|
ret = zlinecmp(zt.text, zt.len, zleline, zlell);
|
|
zletextfree(&zt);
|
|
if (ret)
|
|
break;
|
|
he = movehistent(he, n, hist_skip_flags);
|
|
}
|
|
}
|
|
if (!he)
|
|
return 0;
|
|
zle_setline(he);
|
|
return 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
pushline(UNUSED(char **args))
|
|
{
|
|
int n = zmult;
|
|
|
|
if (n < 0)
|
|
return 1;
|
|
zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0));
|
|
while (--n)
|
|
zpushnode(bufstack, ztrdup(""));
|
|
stackcs = zlecs;
|
|
*zleline = ZWC('\0');
|
|
zlell = zlecs = 0;
|
|
clearlist = 1;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
pushlineoredit(char **args)
|
|
{
|
|
int ics, ret;
|
|
ZLE_STRING_T s;
|
|
char *hline = hgetline();
|
|
|
|
if (zmult < 0)
|
|
return 1;
|
|
if (hline && *hline) {
|
|
ZLE_STRING_T zhline = stringaszleline((unsigned char *)hline, 0,
|
|
&ics, NULL, NULL);
|
|
|
|
sizeline(ics + zlell + 1);
|
|
/* careful of overlapping copy */
|
|
for (s = zleline + zlell; --s >= zleline; s[ics] = *s)
|
|
;
|
|
ZS_memcpy(zleline, zhline, ics);
|
|
zlell += ics;
|
|
zlecs += ics;
|
|
free(zhline);
|
|
}
|
|
ret = pushline(args);
|
|
if (!isfirstln)
|
|
errflag = done = 1;
|
|
clearlist = 1;
|
|
return ret;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
pushinput(char **args)
|
|
{
|
|
int i, ret;
|
|
|
|
if (zmult < 0)
|
|
return 1;
|
|
zmult += i = !isfirstln;
|
|
ret = pushlineoredit(args);
|
|
zmult -= i;
|
|
return ret;
|
|
}
|
|
|
|
/* Renamed to avoid clash with library function */
|
|
/**/
|
|
int
|
|
zgetline(UNUSED(char **args))
|
|
{
|
|
unsigned char *s = (unsigned char *)getlinknode(bufstack);
|
|
|
|
if (!s) {
|
|
return 1;
|
|
} else {
|
|
int cc;
|
|
ZLE_STRING_T lineadd = stringaszleline(s, 0, &cc, NULL, NULL);
|
|
|
|
spaceinline(cc);
|
|
ZS_memcpy(zleline + zlecs, lineadd, cc);
|
|
zlecs += cc;
|
|
free(s);
|
|
free(lineadd);
|
|
clearlist = 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
historyincrementalsearchbackward(char **args)
|
|
{
|
|
doisearch(args, -1);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
historyincrementalsearchforward(char **args)
|
|
{
|
|
doisearch(args, 1);
|
|
return 0;
|
|
}
|
|
|
|
static struct isrch_spot {
|
|
int hl; /* This spot's histline */
|
|
unsigned short pos; /* The search position in our metafied str */
|
|
unsigned short cs; /* The visible search position to the user */
|
|
unsigned short len; /* The search string's length */
|
|
unsigned short flags; /* This spot's flags */
|
|
#define ISS_FAILING 1
|
|
#define ISS_FORWARD 2
|
|
} *isrch_spots;
|
|
|
|
static int max_spot = 0;
|
|
|
|
/**/
|
|
void
|
|
free_isrch_spots(void)
|
|
{
|
|
zfree(isrch_spots, max_spot * sizeof(*isrch_spots));
|
|
max_spot = 0;
|
|
isrch_spots = NULL;
|
|
}
|
|
|
|
/**/
|
|
static void
|
|
set_isrch_spot(int num, int hl, int pos, int cs, int len, int dir, int nomatch)
|
|
{
|
|
if (num >= max_spot) {
|
|
if (!isrch_spots) {
|
|
isrch_spots = (struct isrch_spot*)
|
|
zalloc((max_spot = 64) * sizeof *isrch_spots);
|
|
} else {
|
|
isrch_spots = (struct isrch_spot*)realloc((char*)isrch_spots,
|
|
(max_spot += 64) * sizeof *isrch_spots);
|
|
}
|
|
}
|
|
|
|
isrch_spots[num].hl = hl;
|
|
isrch_spots[num].pos = (unsigned short)pos;
|
|
isrch_spots[num].cs = (unsigned short)cs;
|
|
isrch_spots[num].len = (unsigned short)len;
|
|
isrch_spots[num].flags = (dir > 0? ISS_FORWARD : 0)
|
|
+ (nomatch? ISS_FAILING : 0);
|
|
}
|
|
|
|
/**/
|
|
static void
|
|
get_isrch_spot(int num, int *hlp, int *posp, int *csp, int *lenp, int *dirp, int *nomatch)
|
|
{
|
|
*hlp = isrch_spots[num].hl;
|
|
*posp = (int)isrch_spots[num].pos;
|
|
*csp = (int)isrch_spots[num].cs;
|
|
*lenp = (int)isrch_spots[num].len;
|
|
*dirp = (isrch_spots[num].flags & ISS_FORWARD)? 1 : -1;
|
|
*nomatch = (isrch_spots[num].flags & ISS_FAILING);
|
|
}
|
|
|
|
#define ISEARCH_PROMPT ZWS("failing XXX-i-search: ")
|
|
#define NORM_PROMPT_POS 8
|
|
#define FIRST_SEARCH_CHAR (NORM_PROMPT_POS + 14)
|
|
|
|
/**/
|
|
static void
|
|
doisearch(char **args, int dir)
|
|
{
|
|
ZLE_STRING_T ibuf = zhalloc(80 * ZLE_CHAR_SIZE);
|
|
ZLE_STRING_T sbuf = ibuf + FIRST_SEARCH_CHAR;
|
|
ZLE_STRING_T last_line = NULL;
|
|
struct zle_text zt;
|
|
int sbptr = 0, top_spot = 0, pos, sibuf = 80;
|
|
int nomatch = 0, skip_line = 0, skip_pos = 0;
|
|
int odir = dir, sens = zmult == 1 ? 3 : 1;
|
|
int hl = histline, savekeys = -1, feep = 0, last_len;
|
|
Thingy cmd;
|
|
char *okeymap;
|
|
Histent he;
|
|
|
|
if (!(he = quietgethist(hl)))
|
|
return;
|
|
|
|
clearlist = 1;
|
|
|
|
if (*args) {
|
|
int len;
|
|
char *arg;
|
|
savekeys = kungetct;
|
|
arg = getkeystring(*args, &len, 2, NULL);
|
|
ungetbytes(arg, len);
|
|
}
|
|
|
|
ZS_strcpy(ibuf, ISEARCH_PROMPT);
|
|
ZS_memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? ZWS("fwd") : ZWS("bck"), 3);
|
|
remember_edits();
|
|
okeymap = ztrdup(curkeymapname);
|
|
zletext(he, &zt);
|
|
selectkeymap("main", 1);
|
|
pos = zlecs;
|
|
for (;;) {
|
|
/* Remember the current values in case search fails (doesn't push). */
|
|
set_isrch_spot(top_spot, hl, pos, zlecs, sbptr, dir, nomatch);
|
|
if (sbptr == 1 && sbuf[0] == ZWC('^')) {
|
|
zlecs = 0;
|
|
nomatch = 0;
|
|
statusline = ibuf + NORM_PROMPT_POS;
|
|
} else if (sbptr > 0) {
|
|
/*
|
|
* As we may free zt.text as soon as we switch to a new
|
|
* line, we can't keep the pointer to it. This is a bit
|
|
* ghastly.
|
|
*/
|
|
if (last_line)
|
|
free(last_line);
|
|
last_line = zalloc(zt.len * ZLE_CHAR_SIZE);
|
|
ZS_memcpy(last_line, zt.text, zt.len);
|
|
last_len = zt.len;
|
|
|
|
for (;;) {
|
|
ZLE_STRING_T t;
|
|
|
|
if (skip_pos) {
|
|
if (dir < 0) {
|
|
if (pos == 0)
|
|
skip_line = 1;
|
|
else
|
|
pos -= 1;
|
|
} else if (sbuf[0] != ZWC('^')) {
|
|
if (pos >= zt.len - 1)
|
|
skip_line = 1;
|
|
else
|
|
pos += 1;
|
|
} else
|
|
skip_line = 1;
|
|
skip_pos = 0;
|
|
}
|
|
if (!skip_line && ((sbuf[0] == ZWC('^')) ?
|
|
(t = zlinecmp(zt.text, zt.len, sbuf + 1, sbptr - 1) < sens
|
|
? zt.text : NULL) :
|
|
(t = zlinefind(zt.text, zt.len, pos, sbuf,
|
|
sbptr, dir, sens)))) {
|
|
zle_setline(he);
|
|
pos = t - zt.text;
|
|
zlecs = pos +
|
|
(dir == 1 ? sbptr - (sbuf[0] == ZWC('^')) : 0);
|
|
nomatch = 0;
|
|
statusline = ibuf + NORM_PROMPT_POS;
|
|
break;
|
|
}
|
|
if (!(zlereadflags & ZLRF_HISTORY)
|
|
|| !(he = movehistent(he, dir, hist_skip_flags))) {
|
|
if (sbptr == (int)isrch_spots[top_spot-1].len
|
|
&& (isrch_spots[top_spot-1].flags & ISS_FAILING))
|
|
top_spot--;
|
|
get_isrch_spot(top_spot, &hl, &pos, &zlecs, &sbptr,
|
|
&dir, &nomatch);
|
|
if (!nomatch) {
|
|
feep = 1;
|
|
nomatch = 1;
|
|
}
|
|
he = quietgethist(hl);
|
|
zletextfree(&zt);
|
|
zletext(he, &zt);
|
|
skip_line = 0;
|
|
statusline = ibuf;
|
|
break;
|
|
}
|
|
hl = he->histnum;
|
|
zletextfree(&zt);
|
|
zletext(he, &zt);
|
|
pos = (dir == 1) ? 0 : zt.len;
|
|
skip_line = isset(HISTFINDNODUPS) ? !!(he->flags & HIST_DUP)
|
|
: (zt.len == last_len &&
|
|
!ZS_memcmp(zt.text, last_line, zt.len));
|
|
}
|
|
} else {
|
|
top_spot = 0;
|
|
nomatch = 0;
|
|
statusline = ibuf + NORM_PROMPT_POS;
|
|
}
|
|
sbuf[sbptr] = ZWC('_');
|
|
statusll = sbuf - statusline + sbptr + 1;
|
|
ref:
|
|
zrefresh();
|
|
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
|
|
int i;
|
|
get_isrch_spot(0, &hl, &pos, &i, &sbptr, &dir, &nomatch);
|
|
he = quietgethist(hl);
|
|
zle_setline(he);
|
|
zletextfree(&zt);
|
|
zletext(he, &zt);
|
|
zlecs = i;
|
|
break;
|
|
}
|
|
if(cmd == Th(z_clearscreen)) {
|
|
clearscreen(zlenoargs);
|
|
goto ref;
|
|
} else if(cmd == Th(z_redisplay)) {
|
|
redisplay(zlenoargs);
|
|
goto ref;
|
|
} else if(cmd == Th(z_vicmdmode)) {
|
|
if(selectkeymap(invicmdmode() ? "main" : "vicmd", 0))
|
|
feep = 1;
|
|
goto ref;
|
|
} else if(cmd == Th(z_vibackwarddeletechar) ||
|
|
cmd == Th(z_backwarddeletechar)) {
|
|
if (top_spot)
|
|
get_isrch_spot(--top_spot, &hl, &pos, &zlecs, &sbptr,
|
|
&dir, &nomatch);
|
|
else
|
|
feep = 1;
|
|
if (nomatch) {
|
|
statusline = ibuf;
|
|
skip_pos = 1;
|
|
}
|
|
he = quietgethist(hl);
|
|
zletextfree(&zt);
|
|
zletext(he, &zt);
|
|
if (nomatch || !sbptr || (sbptr == 1 && sbuf[0] == ZWC('^'))) {
|
|
int i = zlecs;
|
|
zle_setline(he);
|
|
zlecs = i;
|
|
}
|
|
ZS_memcpy(ibuf + NORM_PROMPT_POS,
|
|
(dir == 1) ? ZWS("fwd") : ZWS("bck"), 3);
|
|
continue;
|
|
} else if(cmd == Th(z_acceptandhold)) {
|
|
acceptandhold(zlenoargs);
|
|
break;
|
|
} else if(cmd == Th(z_acceptandinfernexthistory)) {
|
|
acceptandinfernexthistory(zlenoargs);
|
|
break;
|
|
} else if(cmd == Th(z_acceptlineanddownhistory)) {
|
|
acceptlineanddownhistory(zlenoargs);
|
|
break;
|
|
} else if(cmd == Th(z_acceptline)) {
|
|
acceptline(zlenoargs);
|
|
break;
|
|
} else if(cmd == Th(z_historyincrementalsearchbackward)) {
|
|
set_isrch_spot(top_spot++, hl, pos, zlecs, sbptr, dir, nomatch);
|
|
if (dir != -1)
|
|
dir = -1;
|
|
else
|
|
skip_pos = 1;
|
|
goto rpt;
|
|
} else if(cmd == Th(z_historyincrementalsearchforward)) {
|
|
set_isrch_spot(top_spot++, hl, pos, zlecs, sbptr, dir, nomatch);
|
|
if (dir != 1)
|
|
dir = 1;
|
|
else
|
|
skip_pos = 1;
|
|
goto rpt;
|
|
} else if(cmd == Th(z_virevrepeatsearch)) {
|
|
set_isrch_spot(top_spot++, hl, pos, zlecs, sbptr, dir, nomatch);
|
|
dir = -odir;
|
|
skip_pos = 1;
|
|
goto rpt;
|
|
} else if(cmd == Th(z_virepeatsearch)) {
|
|
set_isrch_spot(top_spot++, hl, pos, zlecs, sbptr, dir, nomatch);
|
|
dir = odir;
|
|
skip_pos = 1;
|
|
rpt:
|
|
if (!sbptr && previous_search_len) {
|
|
if (previous_search_len > sibuf - FIRST_SEARCH_CHAR - 2) {
|
|
ibuf = hrealloc((char *)ibuf, sibuf * ZLE_CHAR_SIZE,
|
|
(sibuf + previous_search_len)
|
|
* ZLE_CHAR_SIZE);
|
|
sbuf = ibuf + FIRST_SEARCH_CHAR;
|
|
sibuf += previous_search_len;
|
|
}
|
|
ZS_memcpy(sbuf, previous_search, sbptr = previous_search_len);
|
|
}
|
|
ZS_memcpy(ibuf + NORM_PROMPT_POS,
|
|
(dir == 1) ? ZWS("fwd") : ZWS("bck"), 3);
|
|
continue;
|
|
} else if(cmd == Th(z_viquotedinsert) ||
|
|
cmd == Th(z_quotedinsert)) {
|
|
if(cmd == Th(z_viquotedinsert)) {
|
|
sbuf[sbptr] = ZWC('^');
|
|
zrefresh();
|
|
}
|
|
if (getfullchar(0) == ZLEEOF)
|
|
feep = 1;
|
|
else
|
|
goto ins;
|
|
} else {
|
|
if(cmd == Th(z_selfinsertunmeta)) {
|
|
fixunmeta();
|
|
} else if (cmd == Th(z_magicspace)) {
|
|
fixmagicspace();
|
|
} else if (cmd == Th(z_selfinsert)) {
|
|
#ifdef ZLE_UNICODE_SUPPORT
|
|
if (!lastchar_wide_valid)
|
|
getrestchar(lastchar);
|
|
#else
|
|
;
|
|
#endif
|
|
} else {
|
|
ungetkeycmd();
|
|
if (cmd == Th(z_sendbreak))
|
|
sbptr = 0;
|
|
break;
|
|
}
|
|
ins:
|
|
if (sbptr == PATH_MAX) {
|
|
feep = 1;
|
|
continue;
|
|
}
|
|
set_isrch_spot(top_spot++, hl, pos, zlecs, sbptr, dir, nomatch);
|
|
if (sbptr >= sibuf - FIRST_SEARCH_CHAR - 2) {
|
|
ibuf = hrealloc((char *)ibuf, sibuf * ZLE_CHAR_SIZE,
|
|
sibuf * 2 * ZLE_CHAR_SIZE);
|
|
sbuf = ibuf + FIRST_SEARCH_CHAR;
|
|
sibuf *= 2;
|
|
}
|
|
/*
|
|
* We've supposedly arranged above that lastchar_wide is
|
|
* always valid at this point.
|
|
*/
|
|
sbuf[sbptr++] = LASTFULLCHAR;
|
|
}
|
|
if (feep)
|
|
handlefeep(zlenoargs);
|
|
feep = 0;
|
|
}
|
|
if (sbptr) {
|
|
zfree(previous_search, previous_search_len);
|
|
previous_search = zalloc(sbptr * ZLE_CHAR_SIZE);
|
|
ZS_memcpy(previous_search, sbuf, previous_search_len = sbptr);
|
|
}
|
|
statusline = NULL;
|
|
selectkeymap(okeymap, 1);
|
|
zsfree(okeymap);
|
|
/*
|
|
* Don't allow unused characters provided as a string to the
|
|
* widget to overflow and be used as separated commands.
|
|
*/
|
|
if (savekeys >= 0 && kungetct > savekeys)
|
|
kungetct = savekeys;
|
|
if (last_line)
|
|
free(last_line);
|
|
zletextfree(&zt);
|
|
}
|
|
|
|
static Histent
|
|
infernexthist(Histent he, UNUSED(char **args))
|
|
{
|
|
for (he = movehistent(he, -2, HIST_FOREIGN);
|
|
he; he = movehistent(he, -1, HIST_FOREIGN)) {
|
|
struct zle_text zt;
|
|
zletext(he, &zt);
|
|
|
|
if (!zlinecmp(zt.text, zt.len, zleline, zlell)) {
|
|
zletextfree(&zt);
|
|
return movehistent(he, 1, HIST_FOREIGN);
|
|
}
|
|
zletextfree(&zt);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
acceptandinfernexthistory(char **args)
|
|
{
|
|
Histent he;
|
|
|
|
if (!(he = infernexthist(hist_ring, args)))
|
|
return 1;
|
|
zpushnode(bufstack, ztrdup(he->text));
|
|
done = 1;
|
|
stackhist = he->histnum;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
infernexthistory(char **args)
|
|
{
|
|
Histent he = quietgethist(histline);
|
|
|
|
if (!he || !(he = infernexthist(he, args)))
|
|
return 1;
|
|
zle_setline(he);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
vifetchhistory(UNUSED(char **args))
|
|
{
|
|
if (zmult < 0)
|
|
return 1;
|
|
if (histline == curhist) {
|
|
if (!(zmod.flags & MOD_MULT)) {
|
|
zlecs = zlell;
|
|
zlecs = findbol();
|
|
return 0;
|
|
}
|
|
}
|
|
if (!zle_goto_hist((zmod.flags & MOD_MULT) ? zmult : curhist, 0, 0) &&
|
|
isset(HISTBEEP)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* the last vi search */
|
|
|
|
static char *visrchstr, *vipenultsrchstr;
|
|
static int visrchsense;
|
|
|
|
/**/
|
|
static int
|
|
getvisrchstr(void)
|
|
{
|
|
ZLE_STRING_T sbuf = zhalloc(80 * ZLE_CHAR_SIZE);
|
|
int sptr = 1, ret = 0, ssbuf = 80, feep = 0;
|
|
Thingy cmd;
|
|
char *okeymap = ztrdup(curkeymapname);
|
|
|
|
if (vipenultsrchstr) {
|
|
zsfree(vipenultsrchstr);
|
|
}
|
|
|
|
if (visrchstr) {
|
|
vipenultsrchstr = visrchstr;
|
|
visrchstr = NULL;
|
|
}
|
|
clearlist = 1;
|
|
statusline = sbuf;
|
|
sbuf[0] = (visrchsense == -1) ? ZWC('?') : ZWC('/');
|
|
selectkeymap("main", 1);
|
|
while (sptr) {
|
|
sbuf[sptr] = ZWC('_');
|
|
statusll = sptr + 1;
|
|
zrefresh();
|
|
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if(cmd == Th(z_magicspace)) {
|
|
fixmagicspace();
|
|
cmd = Th(z_selfinsert);
|
|
}
|
|
if(cmd == Th(z_redisplay)) {
|
|
redisplay(zlenoargs);
|
|
} else if(cmd == Th(z_clearscreen)) {
|
|
clearscreen(zlenoargs);
|
|
} else if(cmd == Th(z_acceptline) ||
|
|
cmd == Th(z_vicmdmode)) {
|
|
int newlen;
|
|
sbuf[sptr] = ZWC('\0');
|
|
visrchstr = (char *)zlelineasstring(sbuf + 1, sptr - 1, 0, &newlen,
|
|
NULL, 0);
|
|
if (!newlen) {
|
|
zsfree(visrchstr);
|
|
visrchstr = ztrdup(vipenultsrchstr);
|
|
}
|
|
ret = 1;
|
|
sptr = 0;
|
|
} else if(cmd == Th(z_backwarddeletechar) ||
|
|
cmd == Th(z_vibackwarddeletechar)) {
|
|
sptr--;
|
|
} else if(cmd == Th(z_backwardkillword) ||
|
|
cmd == Th(z_vibackwardkillword)) {
|
|
while(sptr != 1 && ZC_iblank(sbuf[sptr - 1]))
|
|
sptr--;
|
|
if(ZC_iident(sbuf[sptr - 1]))
|
|
while(sptr != 1 && ZC_iident(sbuf[sptr - 1]))
|
|
sptr--;
|
|
else
|
|
while(sptr != 1 && !ZC_iident(sbuf[sptr - 1]) &&
|
|
!ZC_iblank(sbuf[sptr - 1]))
|
|
sptr--;
|
|
} else if(cmd == Th(z_viquotedinsert) || cmd == Th(z_quotedinsert)) {
|
|
if(cmd == Th(z_viquotedinsert)) {
|
|
sbuf[sptr] = ZWC('^');
|
|
zrefresh();
|
|
}
|
|
if (getfullchar(0) == ZLEEOF)
|
|
feep = 1;
|
|
else
|
|
goto ins;
|
|
} else if(cmd == Th(z_selfinsertunmeta) || cmd == Th(z_selfinsert)) {
|
|
if(cmd == Th(z_selfinsertunmeta)) {
|
|
fixunmeta();
|
|
} else {
|
|
#ifdef ZLE_UNICODE_SUPPORT
|
|
if (!lastchar_wide_valid)
|
|
getrestchar(lastchar);
|
|
#else
|
|
;
|
|
#endif
|
|
}
|
|
ins:
|
|
if (sptr == ssbuf - 1) {
|
|
ZLE_STRING_T newbuf =
|
|
(ZLE_STRING_T) zhalloc((ssbuf *= 2) * ZLE_CHAR_SIZE);
|
|
ZS_strcpy(newbuf, sbuf);
|
|
statusline = sbuf = newbuf;
|
|
}
|
|
sbuf[sptr++] = LASTFULLCHAR;
|
|
} else {
|
|
feep = 1;
|
|
}
|
|
if (feep)
|
|
handlefeep(zlenoargs);
|
|
feep = 0;
|
|
}
|
|
statusline = NULL;
|
|
selectkeymap(okeymap, 1);
|
|
zsfree(okeymap);
|
|
return ret;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
vihistorysearchforward(char **args)
|
|
{
|
|
if (*args) {
|
|
int ose = visrchsense, ret;
|
|
char *ost = visrchstr;
|
|
|
|
visrchsense = 1;
|
|
visrchstr = *args;
|
|
ret = virepeatsearch(zlenoargs);
|
|
visrchsense = ose;
|
|
visrchstr = ost;
|
|
return ret;
|
|
}
|
|
visrchsense = 1;
|
|
if (getvisrchstr())
|
|
return virepeatsearch(zlenoargs);
|
|
return 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
vihistorysearchbackward(char **args)
|
|
{
|
|
if (*args) {
|
|
int ose = visrchsense, ret;
|
|
char *ost = visrchstr;
|
|
|
|
visrchsense = -1;
|
|
visrchstr = *args;
|
|
ret = virepeatsearch(zlenoargs);
|
|
visrchsense = ose;
|
|
visrchstr = ost;
|
|
return ret;
|
|
}
|
|
visrchsense = -1;
|
|
if (getvisrchstr())
|
|
return virepeatsearch(zlenoargs);
|
|
return 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
virepeatsearch(UNUSED(char **args))
|
|
{
|
|
Histent he;
|
|
ZLE_STRING_T srcstr;
|
|
int srclen;
|
|
int n = zmult;
|
|
struct zle_text zt;
|
|
|
|
if (!visrchstr)
|
|
return 1;
|
|
if (zmult < 0) {
|
|
n = -n;
|
|
visrchsense = -visrchsense;
|
|
}
|
|
srcstr = stringaszleline((unsigned char *)visrchstr, 0,
|
|
&srclen, NULL, NULL);
|
|
if (!(he = quietgethist(histline)))
|
|
return 1;
|
|
while ((he = movehistent(he, visrchsense, hist_skip_flags))) {
|
|
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
|
|
continue;
|
|
zletext(he, &zt);
|
|
if (zlinecmp(zt.text, zt.len, zleline, zlell) &&
|
|
(*visrchstr == '^'?
|
|
(zt.len == srclen - 1 &&
|
|
ZS_memcmp(zt.text, srcstr + 1, zt.len) == 0) :
|
|
zlinefind(zt.text, zt.len, 0, srcstr, srclen, 1, 1) != 0)) {
|
|
if (--n <= 0) {
|
|
zletextfree(&zt);
|
|
zle_setline(he);
|
|
free(srcstr);
|
|
return 0;
|
|
}
|
|
}
|
|
zletextfree(&zt);
|
|
}
|
|
free(srcstr);
|
|
return 1;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
virevrepeatsearch(char **args)
|
|
{
|
|
int ret;
|
|
visrchsense = -visrchsense;
|
|
ret = virepeatsearch(args);
|
|
visrchsense = -visrchsense;
|
|
return ret;
|
|
}
|
|
|
|
/* Extra function added by A.R. Iano-Fletcher. */
|
|
/*The extern variable "zlecs" is the position of the cursor. */
|
|
/* history-beginning-search-backward */
|
|
|
|
/**/
|
|
int
|
|
historybeginningsearchbackward(char **args)
|
|
{
|
|
Histent he;
|
|
int cpos = zlecs; /* save cursor position */
|
|
int n = zmult;
|
|
struct zle_text zt;
|
|
|
|
if (zmult < 0) {
|
|
int ret;
|
|
zmult = -n;
|
|
ret = historybeginningsearchforward(args);
|
|
zmult = n;
|
|
return ret;
|
|
}
|
|
if (!(he = quietgethist(histline)))
|
|
return 1;
|
|
while ((he = movehistent(he, -1, hist_skip_flags))) {
|
|
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
|
|
continue;
|
|
zletext(he, &zt);
|
|
if (zlinecmp(zt.text, zt.len, zleline, zlecs) < 0 &&
|
|
zlinecmp(zt.text, zt.len, zleline, zlell)) {
|
|
if (--n <= 0) {
|
|
zletextfree(&zt);
|
|
zle_setline(he);
|
|
zlecs = cpos;
|
|
return 0;
|
|
}
|
|
}
|
|
zletextfree(&zt);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Extra function added by A.R. Iano-Fletcher. */
|
|
|
|
/* history-beginning-search-forward */
|
|
/**/
|
|
int
|
|
historybeginningsearchforward(char **args)
|
|
{
|
|
Histent he;
|
|
int cpos = zlecs; /* save cursor position */
|
|
int n = zmult;
|
|
struct zle_text zt;
|
|
|
|
if (zmult < 0) {
|
|
int ret;
|
|
zmult = -n;
|
|
ret = historybeginningsearchbackward(args);
|
|
zmult = n;
|
|
return ret;
|
|
}
|
|
if (!(he = quietgethist(histline)))
|
|
return 1;
|
|
while ((he = movehistent(he, 1, hist_skip_flags))) {
|
|
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
|
|
continue;
|
|
zletext(he, &zt);
|
|
if (zlinecmp(zt.text, zt.len, zleline, zlecs) <
|
|
(he->histnum == curhist) &&
|
|
zlinecmp(zt.text, zt.len, zleline, zlell)) {
|
|
if (--n <= 0) {
|
|
zletextfree(&zt);
|
|
zle_setline(he);
|
|
zlecs = cpos;
|
|
return 0;
|
|
}
|
|
}
|
|
zletextfree(&zt);
|
|
}
|
|
return 1;
|
|
}
|