vi: explain when the screen is updated in vi()
[neatvi.git] / dir.c
blob051b90aa2304499bfb83128affe71002552f14d4
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 /* return the direction context of the given line */
69 int dir_context(char *s)
71 int found = -1;
72 int dir;
73 if (xtd > +1)
74 return +1;
75 if (xtd < -1)
76 return -1;
77 if (dir_rsctx)
78 found = rset_find(dir_rsctx, s ? s : "", 0, NULL, 0);
79 if (!conf_dircontext(found, NULL, &dir))
80 return dir;
81 return xtd < 0 ? -1 : +1;
84 /* reorder the characters in s */
85 void dir_reorder(char *s, int *ord)
87 int n;
88 char **chrs = uc_chop(s, &n);
89 int dir = dir_context(s);
90 if (n && chrs[n - 1][0] == '\n') {
91 ord[n - 1] = n - 1;
92 n--;
94 dir_fix(chrs, ord, dir, 0, n);
95 free(chrs);
98 void dir_init(void)
100 char *relr[128];
101 char *rerl[128];
102 char *ctx[128];
103 int curctx, i;
104 char *pat;
105 for (i = 0; !conf_dirmark(i, &pat, &curctx, NULL, NULL); i++) {
106 relr[i] = curctx >= 0 ? pat : NULL;
107 rerl[i] = curctx <= 0 ? pat : NULL;
109 dir_rslr = rset_make(i, relr, 0);
110 dir_rsrl = rset_make(i, rerl, 0);
111 for (i = 0; !conf_dircontext(i, &pat, NULL); i++)
112 ctx[i] = pat;
113 dir_rsctx = rset_make(i, ctx, 0);
116 void dir_done(void)
118 if (dir_rslr)
119 rset_free(dir_rslr);
120 if (dir_rsrl)
121 rset_free(dir_rsrl);
122 if (dir_rsctx)
123 rset_free(dir_rsctx);