/* 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(); }