mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			933 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			933 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * zle_move.c - editor movement
 | |
|  *
 | |
|  * 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_move.pro"
 | |
| 
 | |
| static int vimarkcs[27], vimarkline[27];
 | |
| 
 | |
| #ifdef MULTIBYTE_SUPPORT
 | |
| /*
 | |
|  * Take account of combining characters when moving left.  If
 | |
|  * we are on a zero-width printable wide character and are
 | |
|  * treating these as part of the base character for display purposes,
 | |
|  * move left until we reach a non-zero-width printable character
 | |
|  * (the base character).  If we reach something else first, stay where we
 | |
|  * were.
 | |
|  *
 | |
|  * If setpos is non-zero, update zlecs on success.
 | |
|  * Return 1 if we were on a combining char and could move, else 0.
 | |
|  */
 | |
| /**/
 | |
| int
 | |
| alignmultiwordleft(int *pos, int setpos)
 | |
| {
 | |
|     int loccs = *pos;
 | |
| 
 | |
|     /* generic nothing to do test */
 | |
|     if (!isset(COMBININGCHARS) || loccs == zlell || loccs == 0)
 | |
| 	return 0;
 | |
| 
 | |
|     /* need to be on combining character */
 | |
|     if (!IS_COMBINING(zleline[loccs]))
 | |
| 	 return 0;
 | |
| 
 | |
|     /* yes, go left */
 | |
|     loccs--;
 | |
| 
 | |
|     for (;;) {
 | |
| 	if (IS_BASECHAR(zleline[loccs])) {
 | |
| 	    /* found start position */
 | |
| 	    if (setpos)
 | |
| 		*pos = loccs;
 | |
| 	    return 1;
 | |
| 	} else if (!IS_COMBINING(zleline[loccs])) {
 | |
| 	    /* no go */
 | |
| 	    return 0;
 | |
| 	}
 | |
| 	/* combining char, keep going */
 | |
| 	if (loccs-- == 0)
 | |
| 	    return 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Same principle when moving right.  We need to check if
 | |
|  * alignmultiwordleft() would be successful in order to decide
 | |
|  * if we're on a combining character, and if so we move right to
 | |
|  * anything that isn't one.
 | |
|  */
 | |
| /**/
 | |
| int
 | |
| alignmultiwordright(int *pos, int setpos)
 | |
| {
 | |
|     int loccs;
 | |
| 
 | |
|     /*
 | |
|      * Are we on a suitable character?
 | |
|      */
 | |
|     if (!alignmultiwordleft(pos, 0))
 | |
| 	return 0;
 | |
| 
 | |
|     /* yes, go right */
 | |
|     loccs = *pos + 1;
 | |
| 
 | |
|     while (loccs < zlell) {
 | |
| 	/* Anything other than a combining char will do here */
 | |
| 	if (!IS_COMBINING(zleline[loccs])) {
 | |
| 	    if (setpos)
 | |
| 		*pos = loccs;
 | |
| 	    return 1;
 | |
| 	}
 | |
| 	loccs++;
 | |
|     }
 | |
| 
 | |
|     if (setpos)
 | |
| 	*pos = loccs;
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Move cursor right, checking for combining characters */
 | |
| 
 | |
| /**/
 | |
| mod_export void
 | |
| inccs(void)
 | |
| {
 | |
|     zlecs++;
 | |
|     alignmultiwordright(&zlecs, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Move cursor left, checking for combining characters */
 | |
| 
 | |
| /**/
 | |
| mod_export void
 | |
| deccs(void)
 | |
| {
 | |
|     zlecs--;
 | |
|     alignmultiwordleft(&zlecs, 1);
 | |
| }
 | |
| 
 | |
| /* Same utilities for general position */
 | |
| 
 | |
| /**/
 | |
| mod_export void
 | |
| incpos(int *pos)
 | |
| {
 | |
|     (*pos)++;
 | |
|     alignmultiwordright(pos, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**/
 | |
| mod_export void
 | |
| decpos(int *pos)
 | |
| {
 | |
|     (*pos)--;
 | |
|     alignmultiwordleft(pos, 1);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /* Size of buffer in the following function */
 | |
| #define BMC_BUFSIZE MB_CUR_MAX
 | |
| /*
 | |
|  * For a metafied string that starts at "start" and where the
 | |
|  * current position is "ptr", go back one full character,
 | |
|  * taking account of combining characters if necessary.
 | |
|  */
 | |
| 
 | |
| /**/
 | |
| mod_export char *
 | |
| backwardmetafiedchar(char *start, char *endptr, convchar_t *retchr)
 | |
| {
 | |
| #ifdef MULTIBYTE_SUPPORT
 | |
|     int charlen = 0;
 | |
|     char *last = NULL, *bufptr, *ptr = endptr;
 | |
|     convchar_t lastc = (convchar_t)0; /* not used, silence compiler */
 | |
|     mbstate_t mbs;
 | |
|     size_t ret;
 | |
|     wchar_t wc;
 | |
|     VARARR(char, buf, BMC_BUFSIZE);
 | |
| 
 | |
|     bufptr = buf + BMC_BUFSIZE;
 | |
|     while (ptr > start) {
 | |
| 	ptr--;
 | |
| 	/*
 | |
| 	 * Scanning backwards we're not guaranteed ever to find a
 | |
| 	 * valid character.  If we've looked as far as we should
 | |
| 	 * need to, give up.
 | |
| 	 */
 | |
| 	if (bufptr-- == buf)
 | |
| 	    break;
 | |
| 	charlen++;
 | |
| 	if (ptr > start && ptr[-1] == Meta)
 | |
| 	    *bufptr = *ptr-- ^ 32;
 | |
| 	else
 | |
| 	    *bufptr = *ptr;
 | |
| 
 | |
| 	/* we always need to restart the character from scratch */
 | |
| 	memset(&mbs, 0, sizeof(mbs));
 | |
| 	ret = mbrtowc(&wc, bufptr, charlen, &mbs);
 | |
| 	if (ret == 0) {
 | |
| 	    /* NULL: unlikely, but handle anyway. */
 | |
| 	    if (last) {
 | |
| 		if (retchr)
 | |
| 		    *retchr = lastc;
 | |
| 		return last;
 | |
| 	    } else {
 | |
| 		if (retchr)
 | |
| 		    *retchr = wc;
 | |
| 		return ptr;
 | |
| 	    }
 | |
| 	}
 | |
| 	if (ret != (size_t)-1) {
 | |
| 	    if (ret < (size_t)charlen) {
 | |
| 		/* The last character didn't convert, so use it raw. */
 | |
| 		break;
 | |
| 	    }
 | |
| 	    if (!isset(COMBININGCHARS)) {
 | |
| 		if (retchr)
 | |
| 		    *retchr = wc;
 | |
| 		return ptr;
 | |
| 	    }
 | |
| 	    if (!IS_COMBINING(wc)) {
 | |
| 		/* not a combining character... */
 | |
| 		if (last) {
 | |
| 		    /*
 | |
| 		     * ... but we were looking for a suitable base character,
 | |
| 		     * test it.
 | |
| 		     */
 | |
| 		    if (IS_BASECHAR(wc)) {
 | |
| 			/*
 | |
| 			 * Yes, this will do.
 | |
| 			 */
 | |
| 			if (retchr)
 | |
| 			    *retchr = wc;
 | |
| 			return ptr;
 | |
| 		    } else {
 | |
| 			/* No, just return the first character we found */
 | |
| 			if (retchr)
 | |
| 			    *retchr = lastc;
 | |
| 			return last;
 | |
| 		    }
 | |
| 		}
 | |
| 		/* This is the first character, so just return it. */
 | |
| 		if (retchr)
 | |
| 		    *retchr = wc;
 | |
| 		return ptr;
 | |
| 	    }
 | |
| 	    if (!last) {
 | |
| 		/* still looking for the character immediately before ptr */
 | |
| 		last = ptr;
 | |
| 		lastc = wc;
 | |
| 	    }
 | |
| 	    /* searching for base character of combining character */
 | |
| 	    charlen = 0;
 | |
| 	    bufptr = buf + BMC_BUFSIZE;
 | |
| 	}
 | |
| 	/*
 | |
| 	 * Else keep scanning this character even if MB_INVALID:  we can't
 | |
| 	 * expect MB_INCOMPLETE to work when moving backwards.
 | |
| 	 */
 | |
|     }
 | |
|     /*
 | |
|      * Found something we didn't like, was there a good character
 | |
|      * immediately before ptr?
 | |
|      */
 | |
|     if (last) {
 | |
| 	if (retchr)
 | |
| 	    *retchr = lastc;
 | |
| 	return last;
 | |
|     }
 | |
|     /*
 | |
|      * No, we couldn't find any good character, so just treat
 | |
|      * the last unmetafied byte we found as a character.
 | |
|      */
 | |
| #endif
 | |
|     if (endptr > start) {
 | |
| 	if (endptr > start - 1 && endptr[-2] == Meta)
 | |
| 	{
 | |
| 	    if (retchr)
 | |
| 		*retchr = (convchar_t)(endptr[-1] ^ 32);
 | |
| 	    return endptr - 2;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    if (retchr)
 | |
| 		*retchr = (convchar_t)endptr[-1];
 | |
| 	    return endptr - 1;
 | |
| 	}
 | |
|     }
 | |
|     if (retchr)
 | |
| 	*retchr = (convchar_t)0;
 | |
|     return endptr;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**/
 | |
| int
 | |
| beginningofline(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = endofline(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     while (n--) {
 | |
| 	int pos;
 | |
| 
 | |
| 	if (zlecs == 0)
 | |
| 	    return 0;
 | |
| 	pos = zlecs;
 | |
| 	DECPOS(pos);
 | |
| 	if (zleline[pos] == '\n') {
 | |
| 	    zlecs = pos;
 | |
| 	    if (!zlecs)
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	/* works OK with combining chars since '\n' must be on its own */
 | |
| 	while (zlecs && zleline[zlecs - 1] != '\n')
 | |
| 	    zlecs--;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| endofline(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = beginningofline(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     while (n--) {
 | |
| 	if (zlecs >= zlell) {
 | |
| 	    zlecs = zlell;
 | |
| 	    return 0;
 | |
| 	}
 | |
| 	if ((zlecs += invicmdmode()) == zlell)
 | |
| 	    break;
 | |
| 	if (zleline[zlecs] == '\n')
 | |
| 	    if (++zlecs == zlell)
 | |
| 		return 0;
 | |
| 	while (zlecs != zlell && zleline[zlecs] != '\n')
 | |
| 	    zlecs++;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| beginningoflinehist(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = endoflinehist(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     while (n) {
 | |
| 	int pos;
 | |
| 
 | |
| 	if (zlecs == 0)
 | |
| 	    break;
 | |
| 	pos = zlecs;
 | |
| 	DECPOS(pos);
 | |
| 	if (zleline[pos] == '\n') {
 | |
| 	    zlecs = pos;
 | |
| 	    if (!pos)
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	/* works OK with combining chars since '\n' must be on its own */
 | |
| 	while (zlecs && zleline[zlecs - 1] != '\n')
 | |
| 	    zlecs--;
 | |
| 	n--;
 | |
|     }
 | |
|     if (n) {
 | |
| 	int m = zmult, ret;
 | |
| 
 | |
| 	zmult = n;
 | |
| 	ret = uphistory(args);
 | |
| 	zmult = m;
 | |
| 	zlecs = 0;
 | |
| 	return ret;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| endoflinehist(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = beginningoflinehist(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     while (n) {
 | |
| 	if (zlecs >= zlell) {
 | |
| 	    zlecs = zlell;
 | |
| 	    break;
 | |
| 	}
 | |
| 	if ((zlecs += invicmdmode()) == zlell)
 | |
| 	    break;
 | |
| 	if (zleline[zlecs] == '\n')
 | |
| 	    if (++zlecs == zlell)
 | |
| 		break;
 | |
| 	while (zlecs != zlell && zleline[zlecs] != '\n')
 | |
| 	    zlecs++;
 | |
| 	n--;
 | |
|     }
 | |
|     if (n) {
 | |
| 	int m = zmult, ret;
 | |
| 
 | |
| 	zmult = n;
 | |
| 	ret = downhistory(args);
 | |
| 	zmult = m;
 | |
| 	return ret;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| forwardchar(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = backwardchar(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * If handling combining characters with the base character,
 | |
|      * we skip over the whole set in one go, so need to check.
 | |
|      */
 | |
|     while (zlecs < zlell && n--)
 | |
| 	INCCS();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| backwardchar(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = forwardchar(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
| 
 | |
|     while (zlecs > 0 && n--)
 | |
| 	DECCS();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| setmarkcommand(UNUSED(char **args))
 | |
| {
 | |
|     if (zmult < 0) {
 | |
| 	region_active = 0;
 | |
| 	return 0;
 | |
|     }
 | |
|     mark = zlecs;
 | |
|     region_active = 1;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| exchangepointandmark(UNUSED(char **args))
 | |
| {
 | |
|     int x;
 | |
| 
 | |
|     if (zmult == 0) {
 | |
| 	region_active = 1;
 | |
| 	return 0;
 | |
|     }
 | |
|     x = mark;
 | |
|     mark = zlecs;
 | |
|     zlecs = x;
 | |
|     if (zlecs > zlell)
 | |
| 	zlecs = zlell;
 | |
|     if (zmult > 0)
 | |
| 	region_active = 1;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| visualmode(UNUSED(char **args))
 | |
| {
 | |
|     if (virangeflag) {
 | |
| 	prefixflag = 1;
 | |
| 	zmod.flags &= ~MOD_LINE;
 | |
| 	zmod.flags |= MOD_CHAR;
 | |
| 	return 0;
 | |
|     }
 | |
|     switch (region_active) {
 | |
|     case 1:
 | |
| 	region_active = 0;
 | |
| 	break;
 | |
|     case 0:
 | |
| 	mark = zlecs;
 | |
| 	/* fall through */
 | |
|     case 2:
 | |
| 	region_active = 1;
 | |
| 	break;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| visuallinemode(UNUSED(char **args))
 | |
| {
 | |
|     if (virangeflag) {
 | |
| 	prefixflag = 1;
 | |
| 	zmod.flags &= ~MOD_CHAR;
 | |
| 	zmod.flags |= MOD_LINE;
 | |
| 	return 0;
 | |
|     }
 | |
|     switch (region_active) {
 | |
|     case 2:
 | |
| 	region_active = 0;
 | |
| 	break;
 | |
|     case 0:
 | |
| 	mark = zlecs;
 | |
| 	/* fall through */
 | |
|     case 1:
 | |
| 	region_active = 2;
 | |
| 	break;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| deactivateregion(UNUSED(char **args))
 | |
| {
 | |
|     region_active = 0;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vigotocolumn(UNUSED(char **args))
 | |
| {
 | |
|     int x, y, n = zmult;
 | |
| 
 | |
|     findline(&x, &y);
 | |
|     if (n >= 0) {
 | |
| 	if (n)
 | |
| 	    n--;
 | |
| 	zlecs = x;
 | |
| 	while (zlecs < y && n--)
 | |
| 	    INCCS();
 | |
|     } else {
 | |
| 	zlecs = y;
 | |
| 	n = -n;
 | |
| 	while (zlecs > x && n--)
 | |
| 	    DECCS();
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vimatchbracket(UNUSED(char **args))
 | |
| {
 | |
|     int ocs = zlecs, dir, ct;
 | |
|     unsigned char oth, me;
 | |
| 
 | |
|     if ((zlecs == zlell || zleline[zlecs] == '\n') && zlecs > 0)
 | |
| 	DECCS();
 | |
|     if (virangeflag)
 | |
| 	mark = zlecs;
 | |
|   otog:
 | |
|     if (zlecs == zlell || zleline[zlecs] == '\n') {
 | |
| 	zlecs = ocs;
 | |
| 	return 1;
 | |
|     }
 | |
|     switch (me = zleline[zlecs]) {
 | |
|     case '{':
 | |
| 	dir = 1;
 | |
| 	oth = '}';
 | |
| 	break;
 | |
|     case /*{*/ '}':
 | |
| 	dir = -1;
 | |
| 	oth = '{'; /*}*/
 | |
| 	break;
 | |
|     case '(':
 | |
| 	dir = 1;
 | |
| 	oth = ')';
 | |
| 	break;
 | |
|     case ')':
 | |
| 	dir = -1;
 | |
| 	oth = '(';
 | |
| 	break;
 | |
|     case '[':
 | |
| 	dir = 1;
 | |
| 	oth = ']';
 | |
| 	break;
 | |
|     case ']':
 | |
| 	dir = -1;
 | |
| 	oth = '[';
 | |
| 	break;
 | |
|     default:
 | |
| 	INCCS();
 | |
| 	goto otog;
 | |
|     }
 | |
|     if (virangeflag && dir < 0)
 | |
| 	INCPOS(mark); /* include starting position when going backwards */
 | |
|     ct = 1;
 | |
|     while (zlecs >= 0 && zlecs < zlell && ct) {
 | |
| 	if (dir < 0)
 | |
| 	    DECCS();
 | |
| 	else
 | |
| 	    INCCS();
 | |
| 	if (zleline[zlecs] == oth)
 | |
| 	    ct--;
 | |
| 	else if (zleline[zlecs] == me)
 | |
| 	    ct++;
 | |
|     }
 | |
|     if (zlecs < 0 || zlecs >= zlell) {
 | |
| 	zlecs = ocs;
 | |
| 	return 1;
 | |
|     } else if(dir > 0 && virangeflag)
 | |
| 	INCCS();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| viforwardchar(char **args)
 | |
| {
 | |
|     int lim = findeol();
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = vibackwardchar(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     if (invicmdmode() && !virangeflag)
 | |
| 	DECPOS(lim);
 | |
|     if (zlecs >= lim)
 | |
| 	return 1;
 | |
|     while (n-- && zlecs < lim)
 | |
| 	INCCS();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vibackwardchar(char **args)
 | |
| {
 | |
|     int n = zmult;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = viforwardchar(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     if (zlecs == findbol())
 | |
| 	return 1;
 | |
|     while (n-- && zlecs > 0) {
 | |
| 	DECCS();
 | |
| 	if (zleline[zlecs] == '\n') {
 | |
| 	    zlecs++;
 | |
| 	    break;
 | |
| 	}
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| viendofline(UNUSED(char **args))
 | |
| {
 | |
|     int oldcs = zlecs, n = zmult;
 | |
| 
 | |
|     if (n < 1)
 | |
| 	return 1;
 | |
|     while(n--) {
 | |
| 	if (zlecs > zlell) {
 | |
| 	    zlecs = oldcs;
 | |
| 	    return 1;
 | |
| 	}
 | |
| 	zlecs = findeol() + 1;
 | |
|     }
 | |
|     DECCS();
 | |
|     lastcol = 1<<30;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vibeginningofline(UNUSED(char **args))
 | |
| {
 | |
|     zlecs = findbol();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static ZLE_INT_T vfindchar;
 | |
| static int vfinddir, tailadd;
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vifindnextchar(char **args)
 | |
| {
 | |
|     if ((vfindchar = vigetkey()) != ZLEEOF) {
 | |
| 	vfinddir = 1;
 | |
| 	tailadd = 0;
 | |
| 	return vifindchar(0, args);
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vifindprevchar(char **args)
 | |
| {
 | |
|     if ((vfindchar = vigetkey()) != ZLEEOF) {
 | |
| 	vfinddir = -1;
 | |
| 	tailadd = 0;
 | |
| 	return vifindchar(0, args);
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vifindnextcharskip(char **args)
 | |
| {
 | |
|     if ((vfindchar = vigetkey()) != ZLEEOF) {
 | |
| 	vfinddir = 1;
 | |
| 	tailadd = -1;
 | |
| 	return vifindchar(0, args);
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vifindprevcharskip(char **args)
 | |
| {
 | |
|     if ((vfindchar = vigetkey()) != ZLEEOF) {
 | |
| 	vfinddir = -1;
 | |
| 	tailadd = 1;
 | |
| 	return vifindchar(0, args);
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vifindchar(int repeat, char **args)
 | |
| {
 | |
|     int ocs = zlecs, n = zmult;
 | |
| 
 | |
|     if (!vfinddir)
 | |
| 	return 1;
 | |
|     if (n < 0) {
 | |
| 	int ret;
 | |
| 	zmult = -n;
 | |
| 	ret = virevrepeatfind(args);
 | |
| 	zmult = n;
 | |
| 	return ret;
 | |
|     }
 | |
|     if (repeat && tailadd != 0) {
 | |
| 	if (vfinddir > 0) {
 | |
| 	    if(zlecs < zlell && (ZLE_INT_T)zleline[zlecs+1] == vfindchar)
 | |
| 		INCCS();
 | |
| 	}
 | |
| 	else {
 | |
| 	    if(zlecs > 0 && (ZLE_INT_T)zleline[zlecs-1] == vfindchar)
 | |
| 		DECCS();
 | |
| 	}
 | |
|     }
 | |
|     while (n--) {
 | |
| 	do {
 | |
| 	    if (vfinddir > 0)
 | |
| 		INCCS();
 | |
| 	    else
 | |
| 		DECCS();
 | |
| 	} while (zlecs >= 0 && zlecs < zlell
 | |
| 	    && (ZLE_INT_T)zleline[zlecs] != vfindchar
 | |
| 	    && zleline[zlecs] != ZWC('\n'));
 | |
| 	if (zlecs < 0 || zlecs >= zlell || zleline[zlecs] == ZWC('\n')) {
 | |
| 	    zlecs = ocs;
 | |
| 	    return 1;
 | |
| 	}
 | |
|     }
 | |
|     if (tailadd > 0)
 | |
| 	INCCS();
 | |
|     else if (tailadd < 0)
 | |
| 	DECCS();
 | |
|     if (vfinddir == 1 && virangeflag)
 | |
| 	INCCS();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| virepeatfind(char **args)
 | |
| {
 | |
|     return vifindchar(1, args);
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| virevrepeatfind(char **args)
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     if (zmult < 0) {
 | |
| 	zmult = -zmult;
 | |
| 	ret = vifindchar(1, args);
 | |
| 	zmult = -zmult;
 | |
| 	return ret;
 | |
|     }
 | |
|     tailadd = -tailadd;
 | |
|     vfinddir = -vfinddir;
 | |
|     ret = vifindchar(1, args);
 | |
|     vfinddir = -vfinddir;
 | |
|     tailadd = -tailadd;
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vifirstnonblank(UNUSED(char **args))
 | |
| {
 | |
|     zlecs = findbol();
 | |
|     while (zlecs != zlell && ZC_iblank(zleline[zlecs]))
 | |
| 	INCCS();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| visetmark(UNUSED(char **args))
 | |
| {
 | |
|     ZLE_INT_T ch;
 | |
| 
 | |
|     ch = getfullchar(0);
 | |
|     if (ch < ZWC('a') || ch > ZWC('z'))
 | |
| 	return 1;
 | |
|     ch -= ZWC('a');
 | |
|     vimarkcs[ch] = zlecs;
 | |
|     vimarkline[ch] = histline;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vigotomark(UNUSED(char **args))
 | |
| {
 | |
|     ZLE_INT_T ch;
 | |
|     int *markcs, *markhist = 0;
 | |
|     int oldcs = zlecs;
 | |
|     int oldline = histline;
 | |
|     int tmpcs, tmphist;
 | |
| 
 | |
|     ch = getfullchar(0);
 | |
|     if (ch == ZWC('\'') || ch == ZWC('`')) {
 | |
| 	markhist = vimarkline + 26;
 | |
| 	markcs = vimarkcs + 26;
 | |
|     } else if (ch == ZWC('.') && curchange->prev) {
 | |
| 	/* position cursor where it was after the last change. not exactly
 | |
| 	 * what vim does but close enough */
 | |
| 	tmpcs = curchange->prev->new_cs;
 | |
| 	tmphist = curchange->prev->hist;
 | |
| 	markcs = &tmpcs;
 | |
| 	markhist = &tmphist;
 | |
|     } else if (ch >= ZWC('a') && ch <= ZWC('z')) {
 | |
| 	markhist = vimarkline + (ch - ZWC('a'));
 | |
| 	markcs = vimarkcs + (ch - ZWC('a'));
 | |
|     } else
 | |
| 	return 1;
 | |
|     if (markhist) {
 | |
| 	if (!*markhist)
 | |
| 	    return 1;
 | |
| 	if (histline != *markhist && !zle_goto_hist(*markhist, 0, 0)) {
 | |
| 	    *markhist = 0;
 | |
| 	    return 1;
 | |
| 	}
 | |
|     }
 | |
|     zlecs = *markcs;
 | |
|     vimarkcs[26] = oldcs;
 | |
|     vimarkline[26] = oldline;
 | |
|     if (zlecs > zlell)
 | |
| 	zlecs = zlell;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| vigotomarkline(char **args)
 | |
| {
 | |
|     vigotomark(args);
 | |
|     return vifirstnonblank(zlenoargs);
 | |
| }
 |