neatvi

[fork] simple vi-type editor with UTF-8 support
git clone git://src.adamsgaard.dk/neatvi # fast
git clone https://src.adamsgaard.dk/neatvi.git # slow
Log | Files | Refs | README Back to index

dir.c (3005B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include "vi.h"
      5 
      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 */
      9 
     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)
     12 {
     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;
     32 	}
     33 	sbuf_free(str);
     34 	return found < 0;
     35 }
     36 
     37 static void dir_reverse(int *ord, int beg, int end)
     38 {
     39 	end--;
     40 	while (beg < end) {
     41 		int tmp = ord[beg];
     42 		ord[beg] = ord[end];
     43 		ord[end] = tmp;
     44 		beg++;
     45 		end--;
     46 	}
     47 }
     48 
     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)
     51 {
     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;
     65 	}
     66 }
     67 
     68 /* return the direction context of the given line */
     69 int dir_context(char *s)
     70 {
     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;
     82 }
     83 
     84 /* reorder the characters in s */
     85 void dir_reorder(char *s, int *ord)
     86 {
     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--;
     93 	}
     94 	dir_fix(chrs, ord, dir, 0, n);
     95 	free(chrs);
     96 }
     97 
     98 void dir_init(void)
     99 {
    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;
    108 	}
    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);
    114 }
    115 
    116 void dir_done(void)
    117 {
    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);
    124 }