/*
 *
 * zle_move.c - editor movement
 *
 * This file is part of zsh, the Z shell.
 *
 * This software is Copyright 1992 by Paul Falstad
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made.
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk.
 *
 */

#define ZLE
#include "zsh.h"

static vimarkcs[27], vimarkline[27];

void beginningofline()
{				/**/
    if (mult < 0) {
	mult = -mult;
	endofline();
	return;
    }
    while (mult--) {
	if (cs == 0)
	    return;
	if (line[cs - 1] == '\n')
	    if (!--cs)
		return;
	while (cs && line[cs - 1] != '\n')
	    cs--;
    }
}

void endofline()
{				/**/
    if (mult < 0) {
	mult = -mult;
	beginningofline();
	return;
    }
    while (mult--) {
	if (cs >= ll) {
	    cs = ll;
	    return;
	}
	if (line[cs] == '\n')
	    if (++cs == ll)
		return;
	while (cs != ll && line[cs] != '\n')
	    cs++;
    }
}

void beginningoflinehist()
{				/**/
    if (mult < 0) {
	mult = -mult;
	endoflinehist();
	return;
    }
    while (mult) {
	if (cs == 0)
	    break;
	if (line[cs - 1] == '\n')
	    if (!--cs)
		break;
	while (cs && line[cs - 1] != '\n')
	    cs--;
	mult--;
    }
    if (mult) {
	uphistory();
	cs = 0;
    }
}

void endoflinehist()
{				/**/
    if (mult < 0) {
	mult = -mult;
	beginningoflinehist();
	return;
    }
    while (mult) {
	if (cs >= ll) {
	    cs = ll;
	    break;
	}
	if (line[cs] == '\n')
	    if (++cs == ll)
		break;
	while (cs != ll && line[cs] != '\n')
	    cs++;
	mult--;
    }
    if (mult)
	downhistory();
}

void forwardchar()
{				/**/
    cs += mult;
    if (cs > ll)
	cs = ll;
    if (cs < 0)
	cs = 0;
}

void backwardchar()
{				/**/
    cs -= mult;
    if (cs > ll)
	cs = ll;
    if (cs < 0)
	cs = 0;
}

void setmarkcommand()
{				/**/
    mark = cs;
}

void exchangepointandmark()
{				/**/
    int x;

    x = mark;
    mark = cs;
    cs = x;
    if (cs > ll)
	cs = ll;
}

void vigotocolumn()
{				/**/
    int x, y, ocs = cs;

    if (mult > 0)
	mult--;
    findline(&x, &y);
    if (mult >= 0)
	cs = x + mult;
    else
	cs = y + mult;
    if (cs < x || cs > y) {
	feep();
	cs = ocs;
    }
}

void vimatchbracket()
{				/**/
    int ocs = cs, dir, ct;
    unsigned char oth, me;

  otog:
    if (cs == ll) {
	feep();
	cs = ocs;
	return;
    }
    switch (me = line[cs]) {
    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:
	cs++;
	goto otog;
    }
    ct = 1;
    while (cs >= 0 && cs < ll && ct) {
	cs += dir;
	if (line[cs] == oth)
	    ct--;
	else if (line[cs] == me)
	    ct++;
    }
    if (cs < 0 || cs >= ll) {
	feep();
	cs = ocs;
    }
}

void viforwardchar()
{				/**/
    if (mult < 0) {
	mult = -mult;
	vibackwardchar();
	return;
    }
    while (mult--) {
	cs++;
	if (cs >= ll || line[cs] == '\n') {
	    cs--;
	    break;
	}
    }
}

void vibackwardchar()
{				/**/
    if (mult < 0) {
	mult = -mult;
	viforwardchar();
	return;
    }
    while (mult--) {
	cs--;
	if (cs < 0 || line[cs] == '\n') {
	    cs++;
	    break;
	}
    }
}

void viendofline()
{				/**/
    cs = findeol();
    if (!virangeflag && cs != 0 && line[cs - 1] != '\n')
	cs--;
}

void vibeginningofline()
{				/**/
    cs = findbol();
}

static int vfindchar, vfinddir, tailadd;

void vifindnextchar()
{				/**/
    if ((vfindchar = vigetkey())) {
	vfinddir = 1;
	tailadd = 0;
	virepeatfind();
    }
}

void vifindprevchar()
{				/**/
    if ((vfindchar = vigetkey())) {
	vfinddir = -1;
	tailadd = 0;
	virepeatfind();
    }
}

void vifindnextcharskip()
{				/**/
    if ((vfindchar = vigetkey())) {
	vfinddir = 1;
	tailadd = -1;
	virepeatfind();
    }
}

void vifindprevcharskip()
{				/**/
    if ((vfindchar = vigetkey())) {
	vfinddir = -1;
	tailadd = 1;
	virepeatfind();
    }
}

void virepeatfind()
{				/**/
    int ocs = cs;

    if (!vfinddir) {
	feep();
	return;
    }
    if (mult < 0) {
	mult = -mult;
	virevrepeatfind();
	return;
    }
    while (mult--) {
	do
	    cs += vfinddir;
	while (cs >= 0 && cs < ll && line[cs] != vfindchar && line[cs] != '\n');
	if (cs < 0 || cs >= ll || line[cs] == '\n') {
	    feep();
	    cs = ocs;
	    return;
	}
    }
    cs += tailadd;
    if (vfinddir == 1 && virangeflag)
	cs++;
}

void virevrepeatfind()
{				/**/
    if (mult < 0) {
	mult = -mult;
	virepeatfind();
	return;
    }
    vfinddir = -vfinddir;
    virepeatfind();
    vfinddir = -vfinddir;
}

void vifirstnonblank()
{				/**/
    cs = findbol();
    while (cs != ll && iblank(line[cs]))
	cs++;
}

void visetmark()
{				/**/
    int ch;

    ch = getkey(0);
    if (ch < 'a' || ch > 'z') {
	feep();
	return;
    }
    ch -= 'a';
    vimarkcs[ch] = cs;
    vimarkline[ch] = histline;
}

void vigotomark()
{				/**/
    int ch;

    ch = getkey(0);
    if (ch == c)
	ch = 26;
    else {
	if (ch < 'a' || ch > 'z') {
	    feep();
	    return;
	}
	ch -= 'a';
    }
    if (!vimarkline[ch]) {
	feep();
	return;
    }
    if (curhist != vimarkline[ch]) {
	mult = vimarkline[ch];
	lastcmd |= ZLE_ARG;
	vifetchhistory();
	if (histline != vimarkline[ch])
	    return;
    }
    cs = vimarkcs[ch];
}

void vigotomarkline()
{				/**/
    vigotomark();
    cs = findbol();
}
