/* vi:ts=4:sw=4
*
* VIM - Vi IMproved
*
* Code Contributions By: Atsushi Nakamura anaka@mrit.mei.co.jp
*/
/*
* track.c: functions for draw tracks.
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#ifdef JP
#include "jp.h"
#endif
extern u_char *get_inserted();
/*
* directions where a line exists.
* 1 : up
* 2 : down
* 4 : left
* 8 : right
*/
#define TK_U 1
#define TK_D 2
#define TK_L 4
#define TK_R 8
struct tracktab
{
char *name;
int vw;
char **ch;
};
#ifdef JP
#define JP_TRACKTAB
#include "jptab.h"
#undef JP_TRACKTAB
#endif
char *
tracktab_as[] =
{
" ", "V", "A", "|", ">", "+", "+", "+",
"<", "+", "+", "+", "-", "+", "+", "+"
};
static struct tracktab
tracktabs[] =
{
{ "as", 1, tracktab_as },
#ifdef JP
{ "jp", 2, tracktab_jp },
{ "bj", 2, tracktab_bj },
{ "hj", 2, tracktab_hj },
{ "vj", 2, tracktab_vj },
# ifdef DOSGEN
{ "pc98", 2, tracktab_pc98 },
{ "pc98b", 2, tracktab_pc98b },
# endif
#endif
{ NULL, 0, NULL }
},
*tracktab = &tracktabs[0];
static void
tracktab_sw(tname)
char *tname;
{
struct tracktab *tp;
if (tname && !strcmp(tracktab->name, tname))
return;
for(tp = &tracktabs[0]; tp->name; tp++)
if (!strcmp(tp->name, tname))
{
tracktab = tp;
break;
}
if (!(tp->name))
smsg("%s unknown track character set.", tname);
}
char *
tracktab_next(tset)
char *tset;
{
struct tracktab *tp;
for(tp = &tracktabs[0]; tp->name; tp++)
if (!strcmp(tp->name, tset))
{
tp++;
break;
}
if (!tp->name)
tp = &tracktabs[0];
tracktab = tp;
return tp->name;
}
char *
tracktab_prev(tset)
char *tset;
{
struct tracktab *tp;
tp = &tracktabs[0];
if (strcmp(tp->name, tset))
for(tp++; tp->name; tp++)
if (!strcmp(tp->name, tset))
return (tp-1)->name;
for(tp = &tracktabs[0]; tp->name; tp++);
return (tp-1)->name;
}
#define TV_JUST 1
#define TV_NEXT 2
#define TV_PREV 3
#define TV_FPAD -1
#define TV_BPAD -2
static char *
track_vcol(line, cvcol, mode)
char *line;
int cvcol, mode;
{
int vcol, pcol;
char *ctop = line;
vcol = pcol = 0;
while(*line && vcol < cvcol)
{
pcol = vcol;
ctop = line;
#ifdef JP
if (IsKanji(*line))
{
vcol += 2;
line += 2;
}
else
#endif
vcol += chartabsize(* line++, vcol);
}
switch(mode)
{
case TV_JUST:
if (vcol != cvcol)
return NULL;
case TV_NEXT:
return line;
case TV_PREV: /* tail byte of the previous char */
return vcol == cvcol ? line: ctop;
case TV_FPAD:
if (!*line)
return (char *)(long)(cvcol - vcol);
return (char *)(long)((vcol == cvcol ? 0 : cvcol - pcol));
case TV_BPAD:
return (char *)(long)((vcol - cvcol));
default: /* error */
return NULL;
}
}
static int
track_has_arc(ptr, tc, dir)
char *ptr, *tc[];
int dir;
{
int i;
for(i = 1; i < 16; i++)
if (i & dir && !strncmp(ptr, tc[i], strlen(tc[i])))
return TRUE;
return FALSE;
}
static int
track_code(move, vstart, vend)
int move, vstart, vend;
{
int len;
long i;
char *line, *ptr;
char **tc;
int code;
line = nr2ptr(Curpos.lnum);
tc = tracktab->ch ;
len = tracktab->vw;
code = move;
/* left char. */
if (!(code & TK_L) && (ptr = track_vcol(line, vstart, TV_PREV)))
{
if (p_tt)
while(ptr - line >= len && strchr(" \t", *(ptr - 1)))
ptr --;
if (ptr - line >= len && track_has_arc(ptr - len, tc, TK_R))
code |= TK_L;
}
/* right char. */
if (!(code & TK_R) && (ptr = track_vcol(line, vend, TV_NEXT)))
{
if (p_tt)
while(*ptr && strchr(" \t", *ptr))
ptr ++;
if (track_has_arc(ptr, tc, TK_L))
code |= TK_R;
}
/* up char. */
if (!(code & TK_U))
for(i = Curpos.lnum - 1; i > 0; i --)
{
ptr = track_vcol(nr2ptr(i), vstart, TV_JUST);
if (p_tt && (!ptr || (*ptr && strchr(" \t", *ptr))))
continue;
if (track_has_arc(ptr, tc, TK_D))
code |= TK_U;
break;
}
/* down char. */
if (!(code & TK_D))
for(i = Curpos.lnum + 1; i <= line_count; i ++)
{
ptr = track_vcol(nr2ptr(i), vstart, TV_JUST);
if (p_tt && (!ptr || (*ptr && strchr(" \t", *ptr))))
continue;
if (track_has_arc(ptr, tc, TK_U))
code |= TK_D;
break;
}
return code;
}
static void
track_ins(dir)
int dir;
{
FPOS cpos;
char *line, *ins, *nextp, *prevp;
int oldState;
int ndel, fpad, bpad;
int vstart, vend;
int ralign;
int rvstart, rvend;
int rcode, lcode;
if (Curswant == MAXCOL)
Curswant = Cursvcol;
if (!u_save(Curpos.lnum - 1, Curpos.lnum + 1))
return;
tracktab_sw(p_trs);
line = nr2ptr(Curpos.lnum);
vstart = vend = Curswant;
vend += tracktab->vw;
rvstart = rvend = Curswant + 1;
rvstart -= tracktab->vw;
if (rvstart < 0)
{
rvstart = 0;
rvend = tracktab->vw;
}
/* determine alignment */
/* vertical matching (matched lines.) */
rcode = track_code(0, rvstart, rvend) & (TK_U | TK_D);
lcode = track_code(0, vstart, vend) & (TK_U | TK_D);
if ((lcode && !rcode) || (lcode & (TK_U | TK_D)) == (TK_U | TK_D))
ralign = FALSE;
else if ((!lcode && rcode) || (rcode & (TK_U | TK_D)) == (TK_U | TK_D))
ralign = TRUE;
else if (lcode & dir)
ralign = FALSE;
else if (rcode & dir)
ralign = TRUE;
else
{ /* holizontal matching (padding chars.) */
lcode = rcode = 0;
if (track_vcol(line, vstart, TV_FPAD))
lcode |= TK_L;
if (track_vcol(line, vend, TV_BPAD))
lcode |= TK_R;
if (track_vcol(line, rvstart, TV_FPAD))
rcode |= TK_L;
if (track_vcol(line, rvend, TV_BPAD))
rcode |= TK_R;
if (!rcode && lcode)
ralign = TRUE;
else if (rcode && !lcode)
ralign = FALSE;
else
{
rcode &= ~dir;
lcode &= ~dir;
if (!rcode && lcode)
ralign = TRUE;
else if (rcode && !lcode)
ralign = FALSE;
else if (dir & TK_L)
ralign = TRUE;
else if (dir & TK_R)
ralign = FALSE;
else
ralign = FALSE;
}
}
/* */
if (ralign)
{
vstart = rvstart;
vend = rvend;
}
oldState = State;
if (State == NORMAL)
State = INSERT;
/* find suitable track character */
ins = tracktab->ch[track_code(dir, vstart, vend)];
nextp = track_vcol(line, vend, TV_NEXT);
prevp = track_vcol(line, vstart, TV_PREV);
ndel = nextp - prevp;
fpad = (long) track_vcol(line, vstart, TV_FPAD);
bpad = (long) track_vcol(line, vend, TV_BPAD);
if (ralign && (Curpos.col = prevp - line) <= 0)
Curpos.col = 0;
if (- bpad > tracktab->vw)
{
Curpos.col = strlen(line);
ndel = 0;
}
/* remove old characters */
for(;ndel > 0; ndel--)
delchar(FALSE);
/* padd preceeding space */
for(; fpad > 0; fpad--)
inschar(' ', NUL);
/* insert track */
cpos = Curpos;
#ifdef JP
for(; *ins; ins += IsKanji(*ins)? 2 : 1)
inschar(*ins, *(ins + 1));
#else
for(; *ins; ins ++)
inschar(*ins, 0);
#endif
/* padd tailing space */
for(; bpad > 0; bpad--)
inschar(' ', NUL);
if (dir == TK_R)
{
line = Curpos2ptr();
if (!*line)
inschar('X', NUL);
}
/* recover saved states */
Curpos = cpos;
updateline();
State = oldState;
}
void
track_right()
{
track_ins(TK_R);
}
void
track_left()
{
track_ins(TK_L);
}
void
track_up()
{
track_ins(TK_U);
}
void
track_down()
{
track_ins(TK_D);
}
void
showtrack()
{
if (!Track)
return;
gotocmdline(TRUE, NUL);
outstrn("[TRACK]");
outstrn(p_trs);
setcursor();
}
syntax highlighted by Code2HTML, v. 0.9.1