refactor: move some mapping-related code to a separate file (#19061)

This marks the following Vim patches as ported:

vim-patch:8.1.1785: map functionality mixed with character input

Problem:    Map functionality mixed with character input.
Solution:   Move the map functionality to a separate file. (Yegappan
            Lakshmanan, closes vim/vim#4740)  Graduate the +localmap feature.
b66bab381c

vim-patch:8.2.3643: header for source file is outdated

Problem:    Header for source file is outdated.
Solution:   Make the header more accurate. (closes vim/vim#9186)
a3f83feb63

Also cherry-pick a change for <unique> mappings from patch 8.2.0807.
Rename map_clear_mode() to do_mapclear().
This commit is contained in:
zeertzjq
2022-06-23 21:17:11 +08:00
committed by GitHub
parent 05ca14a881
commit 7718b75846
21 changed files with 2705 additions and 2659 deletions

View File

@@ -51,6 +51,7 @@
#include "nvim/indent_c.h"
#include "nvim/keycodes.h"
#include "nvim/macros.h"
#include "nvim/mapping.h"
#include "nvim/mbyte.h"
#include "nvim/memfile.h"
#include "nvim/memline.h"
@@ -7062,175 +7063,6 @@ static int wc_use_keyname(char_u *varp, long *wcp)
return false;
}
/// 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.
///
/// With multi-byte support use growarray for 'langmap' chars >= 256
typedef struct {
int from;
int to;
} langmap_entry_T;
static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE;
/// 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);
unsigned int a = 0;
assert(langmap_mapga.ga_len >= 0);
unsigned int b = (unsigned int)langmap_mapga.ga_len;
// Do a binary search for an existing entry.
while (a != b) {
unsigned 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;
}
}
ga_grow(&langmap_mapga, 1);
// insert new entry at position "a"
entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
memmove(entries + 1, entries,
((unsigned int)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
}
static void langmap_init(void)
{
for (int i = 0; i < 256; i++) {
langmap_mapchar[i] = (char_u)i; // we init with a one-to-one map
}
ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8);
}
/// Called when langmap option is set; the language map can be
/// changed at any time!
static 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 = utf_ptr2char((char *)p);
to = NUL;
if (p2 == NULL) {
MB_PTR_ADV(p);
if (p[0] != ',') {
if (p[0] == '\\') {
p++;
}
to = utf_ptr2char((char *)p);
}
} else {
if (p2[0] != ',') {
if (p2[0] == '\\') {
p2++;
}
to = utf_ptr2char((char *)p2);
}
}
if (to == NUL) {
semsg(_("E357: 'langmap': Matching character missing for %s"),
transchar(from));
return;
}
if (from >= 256) {
langmap_set_entry(from, to);
} else {
assert(to <= UCHAR_MAX);
langmap_mapchar[from & 255] = (char_u)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;
}
}
}
}
}
/// Return true if format option 'x' is in effect.
/// Take care of no formatting when 'paste' is set.
bool has_format_option(int x)