# HG changeset patch # User Christian Brabandt # Date 1485709205 -3600 # Node ID 265268ea1adcb273d53d767703afd8f7bd502359 # Parent f49773e0c392e471948e441dfa4ad35370d2f129 patch 8.0.0262: Farsi support is barely tested commit https://github.com/vim/vim/commit/ddf662a1c86ef0b4bd0c55c5f0aa192ebd6d9a5e Author: Bram Moolenaar Date: Sun Jan 29 17:59:12 2017 +0100 patch 8.0.0262: Farsi support is barely tested Problem: Farsi support is barely tested. Solution: Add more tests for Farsi. Clean up the code. diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -6166,6 +6166,9 @@ insertchar( && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1) #endif && i < INPUT_BUFLEN +# ifdef FEAT_FKMAP + && !(p_fkmap && KeyTyped) /* Farsi mode mapping moves cursor */ +# endif && (textwidth == 0 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth) && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) @@ -6174,10 +6177,6 @@ insertchar( c = vgetc(); if (p_hkmap && KeyTyped) c = hkmap(c); /* Hebrew mode mapping */ -# ifdef FEAT_FKMAP - if (p_fkmap && KeyTyped) - c = fkmap(c); /* Farsi mode mapping */ -# endif buf[i++] = c; #else buf[i++] = vgetc(); diff --git a/src/farsi.c b/src/farsi.c --- a/src/farsi.c +++ b/src/farsi.c @@ -15,30 +15,11 @@ #if defined(FEAT_FKMAP) || defined(PROTO) -static int toF_Xor_X_(int c); -static int F_is_TyE(int c); -static int F_is_TyC_TyD(int c); static int F_is_TyB_TyC_TyD(int src, int offset); -static int toF_TyB(int c); -static void put_curr_and_l_to_X(int c); -static void put_and_redo(int c); -static void chg_c_toX_orX(void); -static void chg_c_to_X_orX_(void); -static void chg_c_to_X_or_X(void); -static void chg_l_to_X_orX_(void); -static void chg_l_toXor_X(void); -static void chg_r_to_Xor_X_(void); -static int toF_leading(int c); -static int toF_Rjoin(int c); -static int canF_Ljoin(int c); -static int canF_Rjoin(int c); -static int F_isterm(int c); -static int toF_ending(int c); -static void lrswapbuf(char_u *buf, int len); /* * Convert the given Farsi character into a _X or _X_ type -*/ + */ static int toF_Xor_X_(int c) { @@ -105,7 +86,7 @@ toF_Xor_X_(int c) /* * Convert the given Farsi character into Farsi capital character. -*/ + */ static int toF_TyA(int c) { @@ -156,7 +137,7 @@ toF_TyA(int c) * Is the character under the cursor+offset in the given buffer a join type. * That is a character that is combined with the others. * Note: the offset is used only for command line buffer. -*/ + */ static int F_is_TyB_TyC_TyD(int src, int offset) { @@ -207,7 +188,7 @@ F_is_TyB_TyC_TyD(int src, int offset) /* * Is the Farsi character one of the terminating only type. -*/ + */ static int F_is_TyE(int c) { @@ -230,7 +211,7 @@ F_is_TyE(int c) /* * Is the Farsi character one of the none leading type. -*/ + */ static int F_is_TyC_TyD(int c) { @@ -254,7 +235,7 @@ F_is_TyC_TyD(int c) /* * Convert a none leading Farsi char into a leading type. -*/ + */ static int toF_TyB(int c) { @@ -275,9 +256,18 @@ toF_TyB(int c) return c; } + + static void +put_and_redo(int c) +{ + pchar_cursor(c); + AppendCharToRedobuff(K_BS); + AppendCharToRedobuff(c); +} + /* * Overwrite the current redo and cursor characters + left adjust. -*/ + */ static void put_curr_and_l_to_X(int c) { @@ -312,17 +302,9 @@ put_curr_and_l_to_X(int c) put_and_redo(c); } - static void -put_and_redo(int c) -{ - pchar_cursor(c); - AppendCharToRedobuff(K_BS); - AppendCharToRedobuff(c); -} - /* * Change the char. under the cursor to a X_ or X type -*/ + */ static void chg_c_toX_orX(void) { @@ -446,8 +428,7 @@ chg_c_toX_orX(void) /* * Change the char. under the cursor to a _X_ or X_ type -*/ - + */ static void chg_c_to_X_orX_(void) { @@ -498,9 +479,9 @@ chg_c_to_X_orX_(void) /* * Change the char. under the cursor to a _X_ or _X type -*/ + */ static void -chg_c_to_X_or_X (void) +chg_c_to_X_or_X(void) { int tempc; @@ -529,7 +510,7 @@ chg_c_to_X_or_X (void) /* * Change the character left to the cursor to a _X_ or X_ type -*/ + */ static void chg_l_to_X_orX_(void) { @@ -597,10 +578,9 @@ chg_l_to_X_orX_(void) /* * Change the character left to the cursor to a X or _X type -*/ - + */ static void -chg_l_toXor_X (void) +chg_l_toXor_X(void) { int tempc; @@ -666,8 +646,7 @@ chg_l_toXor_X (void) /* * Change the character right to the cursor to a _X or _X_ type -*/ - + */ static void chg_r_to_Xor_X_(void) { @@ -691,48 +670,50 @@ chg_r_to_Xor_X_(void) /* * Map Farsi keyboard when in fkmap mode. -*/ - + */ int fkmap(int c) { int tempc; - static int revins; + int insert_mode = (State & INSERT); + static int revins = 0; if (IS_SPECIAL(c)) return c; - if (VIM_ISDIGIT(c) || ((c == '.' || c == '+' || c == '-' || - c == '^' || c == '%' || c == '#' || c == '=') && revins)) + if (insert_mode) { - if (!revins) + if (VIM_ISDIGIT(c) || ((c == '.' || c == '+' || c == '-' || + c == '^' || c == '%' || c == '#' || c == '=') && revins)) { - if (curwin->w_cursor.col) + /* Numbers are entered left-to-right. */ + if (!revins) { - if (!p_ri) - dec_cursor(); + if (curwin->w_cursor.col) + { + if (!p_ri) + dec_cursor(); - chg_c_toX_orX (); - chg_l_toXor_X (); + chg_c_toX_orX (); + chg_l_toXor_X (); - if (!p_ri) - inc_cursor(); + if (!p_ri) + inc_cursor(); + } } - } - arrow_used = TRUE; - (void)stop_arrow(); + arrow_used = TRUE; + (void)stop_arrow(); - if (!curwin->w_p_rl && revins) - inc_cursor(); + if (!curwin->w_p_rl && revins) + inc_cursor(); - ++revins; - p_ri=1; - } - else - { - if (revins) + ++revins; + p_ri = 1; + } + else if (revins) { + /* Stop entering number. */ arrow_used = TRUE; (void)stop_arrow(); @@ -773,14 +754,14 @@ fkmap(int c) if (!revins) { if (curwin->w_p_rl) - p_ri=0; + p_ri = 0; if (!curwin->w_p_rl) - p_ri=1; + p_ri = 1; } - if ((c < 0x100) && (isalpha(c) || c == '&' || c == '^' || c == ';' || + if ((c < 0x100) && (isalpha(c) || c == '&' || c == '^' || c == ';' || c == '\''|| c == ',' || c == '[' || - c == ']' || c == '{' || c == '}' )) + c == ']' || c == '{' || c == '}')) chg_r_to_Xor_X_(); tempc = 0; @@ -844,13 +825,12 @@ fkmap(int c) case NL: case TAB: - if (p_ri && c == NL && curwin->w_cursor.col) + if (p_ri && c == NL && curwin->w_cursor.col && insert_mode) { /* * If the char before the cursor is _X_ or X_ do not change * the one under the cursor with X type. - */ - + */ dec_cursor(); if (F_isalpha(gchar_cursor())) @@ -920,215 +900,219 @@ fkmap(int c) } break; } - if (!p_ri) - dec_cursor(); - switch ((tempc = gchar_cursor())) + if (insert_mode) { - case _BE: - case _PE: - case _TE: - case _SE: - case _JIM: - case _CHE: - case _HE_J: - case _XE: - case _SIN: - case _SHIN: - case _SAD: - case _ZAD: - case _FE: - case _GHAF: - case _KAF: - case _KAF_H: - case _GAF: - case _LAM: - case _MIM: - case _NOON: - case _HE: - case _HE_: - case _TA: - case _ZA: - put_curr_and_l_to_X(toF_TyA(tempc)); - break; - case _AYN: - case _AYN_: + if (!p_ri) + dec_cursor(); - if (!p_ri) - if (!curwin->w_cursor.col) - { - put_curr_and_l_to_X(AYN); - break; - } - - if (p_ri) - inc_cursor(); - else - dec_cursor(); + switch ((tempc = gchar_cursor())) + { + case _BE: + case _PE: + case _TE: + case _SE: + case _JIM: + case _CHE: + case _HE_J: + case _XE: + case _SIN: + case _SHIN: + case _SAD: + case _ZAD: + case _FE: + case _GHAF: + case _KAF: + case _KAF_H: + case _GAF: + case _LAM: + case _MIM: + case _NOON: + case _HE: + case _HE_: + case _TA: + case _ZA: + put_curr_and_l_to_X(toF_TyA(tempc)); + break; + case _AYN: + case _AYN_: - if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) - tempc = AYN_; - else - tempc = AYN; + if (!p_ri) + if (!curwin->w_cursor.col) + { + put_curr_and_l_to_X(AYN); + break; + } - if (p_ri) - dec_cursor(); - else - inc_cursor(); + if (p_ri) + inc_cursor(); + else + dec_cursor(); - put_curr_and_l_to_X(tempc); + if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) + tempc = AYN_; + else + tempc = AYN; + + if (p_ri) + dec_cursor(); + else + inc_cursor(); - break; - case _GHAYN: - case _GHAYN_: + put_curr_and_l_to_X(tempc); + + break; + case _GHAYN: + case _GHAYN_: - if (!p_ri) - if (!curwin->w_cursor.col) - { - put_curr_and_l_to_X(GHAYN); - break; - } + if (!p_ri) + if (!curwin->w_cursor.col) + { + put_curr_and_l_to_X(GHAYN); + break; + } - if (p_ri) - inc_cursor(); - else - dec_cursor(); + if (p_ri) + inc_cursor(); + else + dec_cursor(); - if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) - tempc = GHAYN_; - else - tempc = GHAYN; + if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) + tempc = GHAYN_; + else + tempc = GHAYN; - if (p_ri) - dec_cursor(); - else - inc_cursor(); + if (p_ri) + dec_cursor(); + else + inc_cursor(); - put_curr_and_l_to_X(tempc); - break; - case _YE: - case _IE: - case _YEE: - if (!p_ri) - if (!curwin->w_cursor.col) - { - put_curr_and_l_to_X((tempc == _YE ? YE : - (tempc == _IE ? IE : YEE))); - break; - } + put_curr_and_l_to_X(tempc); + break; + case _YE: + case _IE: + case _YEE: + if (!p_ri) + if (!curwin->w_cursor.col) + { + put_curr_and_l_to_X((tempc == _YE ? YE : + (tempc == _IE ? IE : YEE))); + break; + } - if (p_ri) - inc_cursor(); - else - dec_cursor(); + if (p_ri) + inc_cursor(); + else + dec_cursor(); - if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) - tempc = (tempc == _YE ? YE_ : - (tempc == _IE ? IE_ : YEE_)); - else - tempc = (tempc == _YE ? YE : - (tempc == _IE ? IE : YEE)); + if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) + tempc = (tempc == _YE ? YE_ : + (tempc == _IE ? IE_ : YEE_)); + else + tempc = (tempc == _YE ? YE : + (tempc == _IE ? IE : YEE)); - if (p_ri) - dec_cursor(); - else - inc_cursor(); + if (p_ri) + dec_cursor(); + else + inc_cursor(); - put_curr_and_l_to_X(tempc); - break; + put_curr_and_l_to_X(tempc); + break; } if (!p_ri) inc_cursor(); + } - tempc = 0; + tempc = 0; - switch (c) - { - case '0': return FARSI_0; - case '1': return FARSI_1; - case '2': return FARSI_2; - case '3': return FARSI_3; - case '4': return FARSI_4; - case '5': return FARSI_5; - case '6': return FARSI_6; - case '7': return FARSI_7; - case '8': return FARSI_8; - case '9': return FARSI_9; - case 'B': return F_PSP; - case 'E': return JAZR_N; - case 'F': return ALEF_D_H; - case 'H': return ALEF_A; - case 'I': return TASH; - case 'K': return F_LQUOT; - case 'L': return F_RQUOT; - case 'M': return HAMZE; - case 'O': return '['; - case 'P': return ']'; - case 'Q': return OO; - case 'R': return MAD_N; - case 'T': return OW; - case 'U': return MAD; - case 'W': return OW_OW; - case 'Y': return JAZR; - case '`': return F_PCN; - case '!': return F_EXCL; - case '@': return F_COMMA; - case '#': return F_DIVIDE; - case '$': return F_CURRENCY; - case '%': return F_PERCENT; - case '^': return F_MUL; - case '&': return F_BCOMMA; - case '*': return F_STAR; - case '(': return F_LPARENT; - case ')': return F_RPARENT; - case '-': return F_MINUS; - case '_': return F_UNDERLINE; - case '=': return F_EQUALS; - case '+': return F_PLUS; - case '\\': return F_BSLASH; - case '|': return F_PIPE; - case ':': return F_DCOLON; - case '"': return F_SEMICOLON; - case '.': return F_PERIOD; - case '/': return F_SLASH; - case '<': return F_LESS; - case '>': return F_GREATER; - case '?': return F_QUESTION; - case ' ': return F_BLANK; - } - break; + switch (c) + { + case '0': return FARSI_0; + case '1': return FARSI_1; + case '2': return FARSI_2; + case '3': return FARSI_3; + case '4': return FARSI_4; + case '5': return FARSI_5; + case '6': return FARSI_6; + case '7': return FARSI_7; + case '8': return FARSI_8; + case '9': return FARSI_9; + case 'B': return F_PSP; + case 'E': return JAZR_N; + case 'F': return ALEF_D_H; + case 'H': return ALEF_A; + case 'I': return TASH; + case 'K': return F_LQUOT; + case 'L': return F_RQUOT; + case 'M': return HAMZE; + case 'O': return '['; + case 'P': return ']'; + case 'Q': return OO; + case 'R': return MAD_N; + case 'T': return OW; + case 'U': return MAD; + case 'W': return OW_OW; + case 'Y': return JAZR; + case '`': return F_PCN; + case '!': return F_EXCL; + case '@': return F_COMMA; + case '#': return F_DIVIDE; + case '$': return F_CURRENCY; + case '%': return F_PERCENT; + case '^': return F_MUL; + case '&': return F_BCOMMA; + case '*': return F_STAR; + case '(': return F_LPARENT; + case ')': return F_RPARENT; + case '-': return F_MINUS; + case '_': return F_UNDERLINE; + case '=': return F_EQUALS; + case '+': return F_PLUS; + case '\\': return F_BSLASH; + case '|': return F_PIPE; + case ':': return F_DCOLON; + case '"': return F_SEMICOLON; + case '.': return F_PERIOD; + case '/': return F_SLASH; + case '<': return F_LESS; + case '>': return F_GREATER; + case '?': return F_QUESTION; + case ' ': return F_BLANK; + } + break; case 'a': - tempc = _SHIN; - break; + tempc = _SHIN; + break; case 'A': - tempc = WAW_H; - break; + tempc = WAW_H; + break; case 'b': - tempc = ZAL; - break; + tempc = ZAL; + break; case 'c': - tempc = ZE; - break; + tempc = ZE; + break; case 'C': - tempc = JE; - break; + tempc = JE; + break; case 'd': - tempc = _YE; - break; + tempc = _YE; + break; case 'D': - tempc = _YEE; - break; + tempc = _YEE; + break; case 'e': - tempc = _SE; - break; + tempc = _SE; + break; case 'f': - tempc = _BE; - break; + tempc = _BE; + break; case 'g': - tempc = _LAM; - break; + tempc = _LAM; + break; case 'G': if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) { @@ -1230,7 +1214,7 @@ fkmap(int c) inc_cursor(); break; case 'j': - tempc = _TE; + tempc = _TE; break; case 'J': if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) @@ -1260,73 +1244,73 @@ fkmap(int c) return tempc; case 'k': - tempc = _NOON; + tempc = _NOON; break; case 'l': - tempc = _MIM; + tempc = _MIM; break; case 'm': - tempc = _PE; + tempc = _PE; break; case 'n': case 'N': - tempc = DAL; + tempc = DAL; break; case 'o': - tempc = _XE; + tempc = _XE; break; case 'p': - tempc = _HE_J; + tempc = _HE_J; break; case 'q': - tempc = _ZAD; + tempc = _ZAD; break; case 'r': - tempc = _GHAF; + tempc = _GHAF; break; case 's': - tempc = _SIN; + tempc = _SIN; break; case 'S': - tempc = _IE; + tempc = _IE; break; case 't': - tempc = _FE; + tempc = _FE; break; case 'u': - if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) - { - if (!p_ri && !F_is_TyE(tempc)) - chg_c_to_X_orX_ (); - if (p_ri) - chg_c_to_X_or_X (); + if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) + { + if (!p_ri && !F_is_TyE(tempc)) + chg_c_to_X_orX_ (); + if (p_ri) + chg_c_to_X_or_X (); - } + } - if (!p_ri && !curwin->w_cursor.col) - return _AYN; + if (!p_ri && !curwin->w_cursor.col) + return _AYN; - if (!p_ri) - dec_cursor(); + if (!p_ri) + dec_cursor(); - if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) - tempc = _AYN_; - else - tempc = _AYN; + if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) + tempc = _AYN_; + else + tempc = _AYN; - if (!p_ri) - inc_cursor(); + if (!p_ri) + inc_cursor(); break; case 'v': case 'V': - tempc = RE; + tempc = RE; break; case 'w': - tempc = _SAD; + tempc = _SAD; break; case 'x': case 'X': - tempc = _TA; + tempc = _TA; break; case 'y': if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) @@ -1354,36 +1338,36 @@ fkmap(int c) break; case 'z': - tempc = _ZA; + tempc = _ZA; break; case 'Z': - tempc = _KAF_H; + tempc = _KAF_H; break; case ';': - tempc = _KAF; + tempc = _KAF; break; case '\'': - tempc = _GAF; + tempc = _GAF; break; case ',': - tempc = WAW; + tempc = WAW; break; case '[': - tempc = _JIM; + tempc = _JIM; break; case ']': - tempc = _CHE; + tempc = _CHE; break; } - if ((F_isalpha(tempc) || F_isdigit(tempc))) + if (F_isalpha(tempc) || F_isdigit(tempc)) { - if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) + if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) { if (!p_ri && !F_is_TyE(tempc)) - chg_c_to_X_orX_ (); + chg_c_to_X_orX_(); if (p_ri) - chg_c_to_X_or_X (); + chg_c_to_X_or_X(); } if (curwin->w_cursor.col) @@ -1392,9 +1376,9 @@ fkmap(int c) dec_cursor(); if (F_is_TyE(tempc)) - chg_l_toXor_X (); + chg_l_toXor_X(); else - chg_l_to_X_orX_ (); + chg_l_to_X_orX_(); if (!p_ri) inc_cursor(); @@ -1407,7 +1391,7 @@ fkmap(int c) /* * Convert a none leading Farsi char into a leading type. -*/ + */ static int toF_leading(int c) { @@ -1461,7 +1445,7 @@ toF_leading(int c) /* * Convert a given Farsi char into right joining type. -*/ + */ static int toF_Rjoin(int c) { @@ -1517,7 +1501,7 @@ toF_Rjoin(int c) /* * Can a given Farsi character join via its left edj. -*/ + */ static int canF_Ljoin(int c) { @@ -1591,7 +1575,7 @@ canF_Ljoin(int c) /* * Can a given Farsi character join via its right edj. -*/ + */ static int canF_Rjoin(int c) { @@ -1619,7 +1603,7 @@ canF_Rjoin(int c) /* * is a given Farsi character a terminating type. -*/ + */ static int F_isterm(int c) { @@ -1646,7 +1630,7 @@ F_isterm(int c) /* * Convert the given Farsi character into a ending type . -*/ + */ static int toF_ending(int c) { @@ -1691,7 +1675,7 @@ toF_ending(int c) /* * Convert the Farsi 3342 standard into Farsi VIM. -*/ + */ static void conv_to_pvim(void) { diff --git a/src/testdir/test_farsi.vim b/src/testdir/test_farsi.vim --- a/src/testdir/test_farsi.vim +++ b/src/testdir/test_farsi.vim @@ -1,4 +1,5 @@ " Simplistic testing of Farsi mode. +" Note: must be edited with latin1 encoding. if !has('farsi') finish @@ -82,3 +83,21 @@ func Test_farsi_map() set noaltkeymap bwipe! endfunc + +func Test_input_farsi() + new + setlocal rightleft fkmap + " numbers switch input direction + call feedkeys("aabc0123456789.+-^%#=xyz\", 'tx') + call assert_equal("\x8cÌν®¥ª­«¦¹¸·¶µ´³²±°Ô\x93Õ", getline('.')) + + " all non-number special chars + call feedkeys("aB E F H I K L M O P Q R T U W Y ` ! @ # $ % ^ & * () - _ = + \\ | : \" . / < > ? \", 'tx') + call assert_equal("\x8cÌν®¥ª­«¦¹¸·¶µ´³²±°Ô\x93Õ¡ ô ú À ö æ ç Â [ ] ÷ ó ò ð õ ñ ¢ £  § ® ¤ ¥ ª ¬ è ¨© ­ é ½ « ë ê º » ¦  ¯ ¾ ¼ ¿ ", getline('.')) + + " all letter chars + call feedkeys("aa A b c C d D e f g G h i j J k l m n N o p q r s S t u v V w x X y z Z ; \ , [ ] \", 'tx') + call assert_equal("\x8cÌν®¥ª­«¦¹¸·¶µ´³²±°Ô\x93Õ¡ ô ú À ö æ ç Â [ ] ÷ ó ò ð õ ñ ¢ £  § ® ¤ ¥ ª ¬ è ¨© ­ é ½ « ë ê º » ¦  ¯ ¾ ¼ ¿ Ñ ù Ì Î Ï á þ Æ Ã Ü ø Á à Å ü Þ Ý Ä Ë Ë Ê É Ó Ù Ð û Ø Ö Í Í Ò Ô Ô × Õ ý Ú  ß Ç È ", getline('.')) + + bwipe! +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 262, +/**/ 261, /**/ 260,