vi: specifying yank buffer for d, c, y, and p
[neatvi.git] / dir.c
blob8da422884c687745a6829997d499ae631f222c71
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "vi.h"
6 #define CR2L "ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوىييپچژکگی‌‍؛،»«؟"
7 #define CNEUT "-!\"#$%&'()*+,./:;<=>?@^_`{|}~ "
9 /* direction context patterns */
10 static struct dcontext {
11 int dir;
12 char *pat;
13 } dcontexts[] = {
14 {-1, "^[" CR2L "]"},
15 {+1, "^[a-zA-Z_0-9]"},
18 /* direction marks */
19 static struct dmark {
20 int ctx; /* the direction context for this mark; 0 means any */
21 int dir; /* the direction of matched text */
22 int grp; /* the nested subgroup; 0 means no groups */
23 char *pat;
24 } dmarks[] = {
25 {+0, +1, 0, "$([^$]+)\\$"},
26 {+0, +1, 1, "\\\\\\*\\[([^]]+)\\]"},
27 {+1, -1, 0, "[" CR2L "][" CNEUT CR2L "]*[" CR2L "]"},
28 {-1, +1, 0, "[a-zA-Z0-9_][^" CR2L "\\\\`$']*[a-zA-Z0-9_]"},
31 static struct rset *dir_rslr; /* pattern of marks for left-to-right strings */
32 static struct rset *dir_rsrl; /* pattern of marks for right-to-left strings */
33 static struct rset *dir_rsctx; /* direction context patterns */
35 static int dir_match(char **chrs, int beg, int end, int ctx, int *rec,
36 int *r_beg, int *r_end, int *c_beg, int *c_end, int *dir)
38 int subs[16 * 2];
39 struct rset *rs = ctx < 0 ? dir_rsrl : dir_rslr;
40 struct sbuf *str = sbuf_make();
41 int flg = (beg ? RE_NOTBOL : 0) | (chrs[end][0] ? RE_NOTEOL : 0);
42 int found;
43 sbuf_mem(str, chrs[beg], chrs[end] - chrs[beg]);
44 found = rset_find(rs, sbuf_buf(str), LEN(subs) / 2, subs, flg);
45 if (found >= 0 && r_beg && r_end && c_beg && c_end) {
46 struct dmark *dm = &dmarks[found];
47 char *s = sbuf_buf(str);
48 int grp = dm->grp;
49 *r_beg = beg + uc_off(s, subs[0]);
50 *r_end = beg + uc_off(s, subs[1]);
51 *c_beg = subs[grp * 2 + 0] >= 0 ?
52 beg + uc_off(s, subs[grp * 2 + 0]) : *r_beg;
53 *c_end = subs[grp * 2 + 1] >= 0 ?
54 beg + uc_off(s, subs[grp * 2 + 1]) : *r_end;
55 *dir = dm->dir;
56 *rec = grp > 0;
58 sbuf_free(str);
59 return found < 0;
62 static void dir_reverse(int *ord, int beg, int end)
64 end--;
65 while (beg < end) {
66 int tmp = ord[beg];
67 ord[beg] = ord[end];
68 ord[end] = tmp;
69 beg++;
70 end--;
74 /* reorder the characters based on direction marks and characters */
75 static void dir_fix(char **chrs, int *ord, int dir, int beg, int end)
77 int r_beg, r_end, c_beg, c_end;
78 int c_dir, c_rec;
79 while (beg < end && !dir_match(chrs, beg, end, dir, &c_rec,
80 &r_beg, &r_end, &c_beg, &c_end, &c_dir)) {
81 if (dir < 0)
82 dir_reverse(ord, r_beg, r_end);
83 if (c_dir < 0)
84 dir_reverse(ord, c_beg, c_end);
85 if (c_beg == r_beg)
86 c_beg++;
87 if (c_rec)
88 dir_fix(chrs, ord, c_dir, c_beg, c_end);
89 beg = r_end;
93 int dir_context(char *s)
95 int found;
96 if (xdir == 'L')
97 return +1;
98 if (xdir == 'R')
99 return -1;
100 found = rset_find(dir_rsctx, s ? s : "", 0, NULL, 0);
101 if (found >= 0)
102 return dcontexts[found].dir;
103 return xdir == 'r' ? -1 : +1;
106 /* reorder the characters in s */
107 void dir_reorder(char *s, int *ord)
109 int n;
110 char **chrs = uc_chop(s, &n);
111 int dir = dir_context(s);
112 if (n && chrs[n - 1][0] == '\n') {
113 ord[n - 1] = n - 1;
114 n--;
116 dir_fix(chrs, ord, dir, 0, n);
117 free(chrs);
120 void dir_init(void)
122 char *relr[128];
123 char *rerl[128];
124 char *ctx[128];
125 int i;
126 for (i = 0; i < LEN(dmarks); i++) {
127 relr[i] = dmarks[i].ctx >= 0 ? dmarks[i].pat : NULL;
128 rerl[i] = dmarks[i].ctx <= 0 ? dmarks[i].pat : NULL;
130 dir_rslr = rset_make(LEN(dmarks), relr, 0);
131 dir_rsrl = rset_make(LEN(dmarks), rerl, 0);
132 for (i = 0; i < LEN(dcontexts); i++)
133 ctx[i] = dcontexts[i].pat;
134 dir_rsctx = rset_make(LEN(dcontexts), ctx, 0);
137 void dir_done(void)
139 rset_free(dir_rslr);
140 rset_free(dir_rsrl);
141 rset_free(dir_rsctx);