diff src/map.c @ 17940:079e10a49ea1 v8.1.1966

patch 8.1.1966: some code in options.c fits better elsewhere Commit: https://github.com/vim/vim/commit/e677df8d93772a705f40a94f3c871aee78fe4d99 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Sep 2 22:31:11 2019 +0200 patch 8.1.1966: some code in options.c fits better elsewhere Problem: Some code in options.c fits better elsewhere. Solution: Move functions from options.c to other files. (Yegappan Lakshmanan, closes #4889)
author Bram Moolenaar <Bram@vim.org>
date Mon, 02 Sep 2019 22:45:05 +0200
parents 04245f071792
children ec4248c4b92c
line wrap: on
line diff
--- a/src/map.c
+++ b/src/map.c
@@ -2193,6 +2193,197 @@ add_map(char_u *map, int mode)
 }
 #endif
 
+#if defined(FEAT_LANGMAP) || defined(PROTO)
+/*
+ * Any character has an equivalent 'langmap' character.  This is used for
+ * keyboards that have a special language mode that sends characters above
+ * 128 (although other characters can be translated too).  The "to" field is a
+ * Vim command character.  This avoids having to switch the keyboard back to
+ * ASCII mode when leaving Insert mode.
+ *
+ * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
+ * commands.
+ * langmap_mapga.ga_data is a sorted table of langmap_entry_T.  This does the
+ * same as langmap_mapchar[] for characters >= 256.
+ *
+ * Use growarray for 'langmap' chars >= 256
+ */
+typedef struct
+{
+    int	    from;
+    int     to;
+} langmap_entry_T;
+
+static garray_T langmap_mapga;
+
+/*
+ * Search for an entry in "langmap_mapga" for "from".  If found set the "to"
+ * field.  If not found insert a new entry at the appropriate location.
+ */
+    static void
+langmap_set_entry(int from, int to)
+{
+    langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
+    int		    a = 0;
+    int		    b = langmap_mapga.ga_len;
+
+    // Do a binary search for an existing entry.
+    while (a != b)
+    {
+	int i = (a + b) / 2;
+	int d = entries[i].from - from;
+
+	if (d == 0)
+	{
+	    entries[i].to = to;
+	    return;
+	}
+	if (d < 0)
+	    a = i + 1;
+	else
+	    b = i;
+    }
+
+    if (ga_grow(&langmap_mapga, 1) != OK)
+	return;  // out of memory
+
+    // insert new entry at position "a"
+    entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
+    mch_memmove(entries + 1, entries,
+			(langmap_mapga.ga_len - a) * sizeof(langmap_entry_T));
+    ++langmap_mapga.ga_len;
+    entries[0].from = from;
+    entries[0].to = to;
+}
+
+/*
+ * Apply 'langmap' to multi-byte character "c" and return the result.
+ */
+    int
+langmap_adjust_mb(int c)
+{
+    langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
+    int a = 0;
+    int b = langmap_mapga.ga_len;
+
+    while (a != b)
+    {
+	int i = (a + b) / 2;
+	int d = entries[i].from - c;
+
+	if (d == 0)
+	    return entries[i].to;  // found matching entry
+	if (d < 0)
+	    a = i + 1;
+	else
+	    b = i;
+    }
+    return c;  // no entry found, return "c" unmodified
+}
+
+    void
+langmap_init(void)
+{
+    int i;
+
+    for (i = 0; i < 256; i++)
+	langmap_mapchar[i] = i;	 // we init with a one-to-one map
+    ga_init2(&langmap_mapga, sizeof(langmap_entry_T), 8);
+}
+
+/*
+ * Called when langmap option is set; the language map can be
+ * changed at any time!
+ */
+    void
+langmap_set(void)
+{
+    char_u  *p;
+    char_u  *p2;
+    int	    from, to;
+
+    ga_clear(&langmap_mapga);		    // clear the previous map first
+    langmap_init();			    // back to one-to-one map
+
+    for (p = p_langmap; p[0] != NUL; )
+    {
+	for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
+							       MB_PTR_ADV(p2))
+	{
+	    if (p2[0] == '\\' && p2[1] != NUL)
+		++p2;
+	}
+	if (p2[0] == ';')
+	    ++p2;	    // abcd;ABCD form, p2 points to A
+	else
+	    p2 = NULL;	    // aAbBcCdD form, p2 is NULL
+	while (p[0])
+	{
+	    if (p[0] == ',')
+	    {
+		++p;
+		break;
+	    }
+	    if (p[0] == '\\' && p[1] != NUL)
+		++p;
+	    from = (*mb_ptr2char)(p);
+	    to = NUL;
+	    if (p2 == NULL)
+	    {
+		MB_PTR_ADV(p);
+		if (p[0] != ',')
+		{
+		    if (p[0] == '\\')
+			++p;
+		    to = (*mb_ptr2char)(p);
+		}
+	    }
+	    else
+	    {
+		if (p2[0] != ',')
+		{
+		    if (p2[0] == '\\')
+			++p2;
+		    to = (*mb_ptr2char)(p2);
+		}
+	    }
+	    if (to == NUL)
+	    {
+		semsg(_("E357: 'langmap': Matching character missing for %s"),
+							     transchar(from));
+		return;
+	    }
+
+	    if (from >= 256)
+		langmap_set_entry(from, to);
+	    else
+		langmap_mapchar[from & 255] = to;
+
+	    // Advance to next pair
+	    MB_PTR_ADV(p);
+	    if (p2 != NULL)
+	    {
+		MB_PTR_ADV(p2);
+		if (*p == ';')
+		{
+		    p = p2;
+		    if (p[0] != NUL)
+		    {
+			if (p[0] != ',')
+			{
+			    semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p);
+			    return;
+			}
+			++p;
+		    }
+		    break;
+		}
+	    }
+	}
+    }
+}
+#endif
+
     static void
 do_exmap(exarg_T *eap, int isabbrev)
 {