tex: cm command to change keymap - neatvi - [fork] simple vi-type editor with UTF-8 support
 (HTM) git clone git://src.adamsgaard.dk/neatvi
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 3a4ce478980b560dd436c5fd93e867b1adb35c6a
 (DIR) parent 327a8df78c89d94f7074d6a5881f222287d8fddc
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Thu, 29 Oct 2015 19:40:33 +0330
       
       ex: cm command to change keymap
       
       README explains how to add or switch keymaps.
       
       Diffstat:
         M README                              |      40 ++++++++++++++++++++++----------
         M conf.c                              |      25 ++++++++++++++++++++-----
         M conf.h                              |       3 ---
         M ex.c                                |      29 +++++++++++++++++++++++++++++
         M kmap.h                              |       2 ++
         M led.c                               |      27 ++++++---------------------
         M vi.c                                |       9 ++++-----
         M vi.h                                |       5 ++++-
       
       8 files changed, 93 insertions(+), 47 deletions(-)
       ---
 (DIR) diff --git a/README b/README
       t@@ -3,16 +3,31 @@ NEATVI
        
        Neatvi is a vi/ex editor.  It can edit bidirectional UTF-8 text.
        
       -Edit conf.h to adjust syntax highlighting rules, direction adjustment
       -patterns, and the alternate keymap.  To define a new keymap, create a
       -new array in kmap.h, like kmap_fa, and add it to kmaps array in led.c.
       -When in input mode, ^f switches to the alternate keymap and ^e
       -switches back to the default keymap.
       +Edit conf.h to adjust syntax highlighting rules and text direction
       +patterns.  To define a new keymap, create a new array in kmap.h, like
       +kmap_fa, and add it to kmaps array in the same header (the first entry
       +of the new array specifies its name).  The current keymap may be
       +changed using :cm ex command.  When in input mode, ^e changes to the
       +English kaymap and ^f changes to the alternate keymap (the last keymap
       +specified with :km).
        
       -The following options are supported:
       +Commands not available in ex(1):
       +
       +:cm[ap][!] [kmap]
       +        Without kmap, print the current keymap name.
       +        When kmap is specified, set the alternate keymap to
       +        kmap and, unless ! is given, switch to this keymap.
       +
       +:ft [filetype]
       +        Without filetype, print the current file type.
       +        When filetype is specified, set the file type of the
       +        current ex buffer.
       +
       +Options supported by neatvi:
        
        td, textdirection
       -        Current direction context.  The following values are meaningful:
       +        Current direction context.  The following values are
       +        meaningful:
                
                * +2: always left-to-right.
                * +1: follow conf.h's dircontexts[]; left-to-right for others.
       t@@ -23,7 +38,12 @@ shape
                If set (default), performs Arabic/Farsi letter shaping.
        
        order
       -        If set, reorder characters based on the rules defined in conf.h.
       +        If set, reorder characters based on the rules defined
       +        in conf.h.
       +
       +hl, highlight
       +        If set (default), text will receive syntax highlighting
       +        based on the rules in conf.h.
        
        ai, autoindent
                As in vi(1).
       t@@ -33,7 +53,3 @@ aw, autowrite
        
        ic, ignorecase
                As in vi(1).
       -
       -hl, highlight
       -        If set (default), text will receive syntax highlighting based on the
       -        rules in conf.h.
 (DIR) diff --git a/conf.c b/conf.c
       t@@ -1,11 +1,8 @@
        #include <stdio.h>
       +#include <string.h>
        #include "vi.h"
        #include "conf.h"
       -
       -char *conf_kmapalt(void)
       -{
       -        return KMAPALT;
       -}
       +#include "kmap.h"
        
        int conf_dirmark(int idx, char **pat, int *ctx, int *dir, int *grp)
        {
       t@@ -77,3 +74,21 @@ int conf_highlight_revdir(int *att)
                *att = SYN_REVDIR;
                return 0;
        }
       +
       +char **conf_kmap(char *name)
       +{
       +        int i;
       +        for (i = 0; i < LEN(kmaps); i++)
       +                if (name && kmaps[i][0] && !strcmp(name, kmaps[i][0]))
       +                        return kmaps[i];
       +        return kmap_en;
       +}
       +
       +char *conf_digraph(int c1, int c2)
       +{
       +        int i;
       +        for (i = 0; i < LEN(digraphs); i++)
       +                if (digraphs[i][0][0] == c1 && digraphs[i][0][1] == c2)
       +                        return digraphs[i][1];
       +        return NULL;
       +}
 (DIR) diff --git a/conf.h b/conf.h
       t@@ -61,9 +61,6 @@ static struct highlight {
                {"sh", {4}, "\'[^\']*\'"},
        };
        
       -/* the alternate keymap (^F and ^E in insert mode to switch) */
       -#define KMAPALT                "fa"
       -
        /* how to hightlight text in the reverse direction */
        #define SYN_REVDIR                (SYN_BGMK(255))
        
 (DIR) diff --git a/ex.c b/ex.c
       t@@ -21,6 +21,8 @@ int xshape = 1;                        /* perform letter shaping */
        int xorder = 1;                        /* change the order of characters */
        char xfindkwd[EXLEN];                /* the last searched keyword */
        int xfinddir = +1;                /* the last search direction */
       +static char *xkmap = "en";        /* the current keymap */
       +static char xkmap2[8] = "fa";        /* the alternate keymap */
        
        static struct buf {
                char ft[32];
       t@@ -96,6 +98,16 @@ char *ex_filetype(void)
                return xhl ? bufs[0].ft : "";
        }
        
       +char **ex_kmap(void)
       +{
       +        return &xkmap;
       +}
       +
       +char *ex_kmapalt(void)
       +{
       +        return xkmap2;
       +}
       +
        /* read ex command location */
        static char *ex_loc(char *s, char *loc)
        {
       t@@ -690,6 +702,21 @@ static int ec_ft(char *ec)
                return 0;
        }
        
       +static int ec_cmap(char *ec)
       +{
       +        char cmd[EXLEN];
       +        char arg[EXLEN];
       +        ex_cmd(ec, cmd);
       +        ex_arg(ec, arg);
       +        if (arg[0])
       +                snprintf(xkmap2, sizeof(xkmap2), arg);
       +        else
       +                ex_print(xkmap);
       +        if (arg[0] && !strchr(cmd, '!'))
       +                xkmap = xkmap2;
       +        return 0;
       +}
       +
        static struct option {
                char *abbr;
                char *name;
       t@@ -784,6 +811,8 @@ static struct excmd {
                {"!", "!", ec_exec},
                {"make", "make", ec_make},
                {"ft", "filetype", ec_ft},
       +        {"cm", "cmap", ec_cmap},
       +        {"cm!", "cmap!", ec_cmap},
                {"", "", ec_null},
        };
        
 (DIR) diff --git a/kmap.h b/kmap.h
       t@@ -100,6 +100,8 @@ static char *kmap_fa[256] = {
                ['|'] = "|",
        };
        
       +static char **kmaps[] = {kmap_en, kmap_fa};
       +
        static char *digraphs[][2] = {
                {"cq", "’"},
                {"pl", "+"},
 (DIR) diff --git a/led.c b/led.c
       t@@ -4,23 +4,11 @@
        #include <stdlib.h>
        #include <unistd.h>
        #include "vi.h"
       -#include "kmap.h"
       -
       -static char **kmaps[] = {kmap_en, kmap_fa};
       -
       -static char **kmap_find(char *name)
       -{
       -        int i;
       -        for (i = 0; i < LEN(kmaps); i++)
       -                if (name && kmaps[i][0] && !strcmp(name, kmaps[i][0]))
       -                        return kmaps[i];
       -        return kmap_en;
       -}
        
        static char *kmap_map(char *kmap, int c)
        {
                static char cs[4];
       -        char **keymap = kmap_find(kmap);
       +        char **keymap = conf_kmap(kmap);
                cs[0] = c;
                return keymap[c] ? keymap[c] : cs;
        }
       t@@ -198,10 +186,7 @@ static char *led_readchar(int c, char *kmap)
                        c2 = term_read();
                        if (TK_INT(c2))
                                return NULL;
       -                for (i = 0; i < LEN(digraphs); i++)
       -                        if (digraphs[i][0][0] == c1 && digraphs[i][0][1] == c2)
       -                                return digraphs[i][1];
       -                return NULL;
       +                return conf_digraph(c1, c2);
                }
                if ((c & 0xc0) == 0xc0) {        /* utf-8 character */
                        buf[0] = c;
       t@@ -220,10 +205,10 @@ char *led_read(char **kmap)
                while (!TK_INT(c)) {
                        switch (c) {
                        case TK_CTL('f'):
       -                        *kmap = conf_kmapalt();
       +                        *kmap = ex_kmapalt();
                                break;
                        case TK_CTL('e'):
       -                        *kmap = kmap_en[0];
       +                        *kmap = "en";
                                break;
                        default:
                                return led_readchar(c, *kmap);
       t@@ -249,10 +234,10 @@ static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, ch
                        c = term_read();
                        switch (c) {
                        case TK_CTL('f'):
       -                        *kmap = conf_kmapalt();
       +                        *kmap = ex_kmapalt();
                                continue;
                        case TK_CTL('e'):
       -                        *kmap = kmap_en[0];
       +                        *kmap = "en";
                                continue;
                        case TK_CTL('h'):
                        case 127:
 (DIR) diff --git a/vi.c b/vi.c
       t@@ -17,7 +17,6 @@ static char vi_charlast[8];        /* the last character searched via f, t, F, or T */
        static int vi_charcmd;                /* the character finding command */
        static int vi_arg1, vi_arg2;        /* the first and second arguments */
        static int vi_ybuf;                /* current yank buffer */
       -static char *vi_kmap;                /* current insertion keymap */
        static int vi_pcol;                /* the column requested by | command */
        static int vi_printed;                /* ex_print() calls since the last command */
        static int vi_scroll;                /* scroll amount for ^f and ^d*/
       t@@ -79,7 +78,7 @@ static void vi_back(int c)
        
        static char *vi_char(void)
        {
       -        return led_read(&vi_kmap);
       +        return led_read(ex_kmap());
        }
        
        static char *vi_prompt(char *msg, char **kmap)
       t@@ -101,7 +100,7 @@ char *ex_read(char *msg)
                struct sbuf *sb;
                char c;
                if (xled) {
       -                char *s = led_prompt(msg, "", &vi_kmap);
       +                char *s = led_prompt(msg, "", ex_kmap());
                        if (s)
                                term_chr('\n');
                        return s;
       t@@ -217,7 +216,7 @@ static int vi_search(int cmd, int cnt, int *row, int *off)
                char *soff = "";
                if (cmd == '/' || cmd == '?') {
                        char sign[4] = {cmd};
       -                char *kw = vi_prompt(sign, &vi_kmap);
       +                char *kw = vi_prompt(sign, ex_kmap());
                        if (!kw)
                                return 1;
                        xfinddir = cmd == '/' ? +1 : -1;
       t@@ -618,7 +617,7 @@ static int charcount(char *text, char *post)
        
        static char *vi_input(char *pref, char *post, int *row, int *off)
        {
       -        char *rep = led_input(pref, post, &vi_kmap);
       +        char *rep = led_input(pref, post, ex_kmap());
                if (!rep)
                        return NULL;
                *row = linecount(rep) - 1;
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -141,6 +141,8 @@ int ex_init(char **files);
        void ex_done(void);
        char *ex_path(void);
        char *ex_filetype(void);
       +char **ex_kmap(void);
       +char *ex_kmapalt(void);
        struct lbuf *ex_lbuf(void);
        
        #define xb         ex_lbuf()
       t@@ -169,13 +171,14 @@ void syn_init(void);
        void syn_done(void);
        
        /* configuration variables */
       -char *conf_kmapalt(void);
        int conf_dirmark(int idx, char **pat, int *ctx, int *dir, int *grp);
        int conf_dircontext(int idx, char **pat, int *ctx);
        int conf_placeholder(int idx, char **s, char **d, int *wid);
        int conf_highlight(int idx, char **ft, int **att, char **pat, int *end);
        int conf_filetype(int idx, char **ft, char **pat);
        int conf_highlight_revdir(int *att);
       +char **conf_kmap(char *name);
       +char *conf_digraph(int c1, int c2);
        
        /* global variables */
        extern int xrow;