vi: redraw if commands like x change visible columns
[neatvi.git] / dir.c
blob56cc30ae54af36172b38239bfeb46b0bd1ab5ed6
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "vi.h"
6 static struct rset *dir_rslr; /* pattern of marks for left-to-right strings */
7 static struct rset *dir_rsrl; /* pattern of marks for right-to-left strings */
8 static struct rset *dir_rsctx; /* direction context patterns */
10 static int dir_match(char **chrs, int beg, int end, int ctx, int *rec,
11 int *r_beg, int *r_end, int *c_beg, int *c_end, int *dir)
13 int subs[16 * 2];
14 struct rset *rs = ctx < 0 ? dir_rsrl : dir_rslr;
15 struct sbuf *str = sbuf_make();
16 int grp;
17 int flg = (beg ? RE_NOTBOL : 0) | (chrs[end][0] ? RE_NOTEOL : 0);
18 int found = -1;
19 sbuf_mem(str, chrs[beg], chrs[end] - chrs[beg]);
20 if (rs)
21 found = rset_find(rs, sbuf_buf(str), LEN(subs) / 2, subs, flg);
22 if (found >= 0 && r_beg && r_end && c_beg && c_end) {
23 char *s = sbuf_buf(str);
24 conf_dirmark(found, NULL, NULL, dir, &grp);
25 *r_beg = beg + uc_off(s, subs[0]);
26 *r_end = beg + uc_off(s, subs[1]);
27 *c_beg = subs[grp * 2 + 0] >= 0 ?
28 beg + uc_off(s, subs[grp * 2 + 0]) : *r_beg;
29 *c_end = subs[grp * 2 + 1] >= 0 ?
30 beg + uc_off(s, subs[grp * 2 + 1]) : *r_end;
31 *rec = grp > 0;
33 sbuf_free(str);
34 return found < 0;
37 static void dir_reverse(int *ord, int beg, int end)
39 end--;
40 while (beg < end) {
41 int tmp = ord[beg];
42 ord[beg] = ord[end];
43 ord[end] = tmp;
44 beg++;
45 end--;
49 /* reorder the characters based on direction marks and characters */
50 static void dir_fix(char **chrs, int *ord, int dir, int beg, int end)
52 int r_beg, r_end, c_beg, c_end;
53 int c_dir, c_rec;
54 while (beg < end && !dir_match(chrs, beg, end, dir, &c_rec,
55 &r_beg, &r_end, &c_beg, &c_end, &c_dir)) {
56 if (dir < 0)
57 dir_reverse(ord, r_beg, r_end);
58 if (c_dir < 0)
59 dir_reverse(ord, c_beg, c_end);
60 if (c_beg == r_beg)
61 c_beg++;
62 if (c_rec)
63 dir_fix(chrs, ord, c_dir, c_beg, c_end);
64 beg = r_end;
68 int dir_context(char *s)
70 int found = -1;
71 int dir;
72 if (xdir > +1)
73 return +1;
74 if (xdir < -1)
75 return -1;
76 if (dir_rsctx)
77 found = rset_find(dir_rsctx, s ? s : "", 0, NULL, 0);
78 if (!conf_dircontext(found, NULL, &dir))
79 return dir;
80 return xdir < 0 ? -1 : +1;
83 /* reorder the characters in s */
84 void dir_reorder(char *s, int *ord)
86 int n;
87 char **chrs = uc_chop(s, &n);
88 int dir = dir_context(s);
89 if (n && chrs[n - 1][0] == '\n') {
90 ord[n - 1] = n - 1;
91 n--;
93 dir_fix(chrs, ord, dir, 0, n);
94 free(chrs);
97 void dir_init(void)
99 char *relr[128];
100 char *rerl[128];
101 char *ctx[128];
102 int curctx, i;
103 char *pat;
104 for (i = 0; !conf_dirmark(i, &pat, &curctx, NULL, NULL); i++) {
105 relr[i] = curctx >= 0 ? pat : NULL;
106 rerl[i] = curctx <= 0 ? pat : NULL;
108 dir_rslr = rset_make(i, relr, 0);
109 dir_rsrl = rset_make(i, rerl, 0);
110 for (i = 0; !conf_dircontext(i, &pat, NULL); i++)
111 ctx[i] = pat;
112 dir_rsctx = rset_make(i, ctx, 0);
115 void dir_done(void)
117 if (dir_rslr)
118 rset_free(dir_rslr);
119 if (dir_rsrl)
120 rset_free(dir_rsrl);
121 if (dir_rsctx)
122 rset_free(dir_rsctx);