aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/farsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/farsi.c')
-rw-r--r--src/nvim/farsi.c2994
1 files changed, 2994 insertions, 0 deletions
diff --git a/src/nvim/farsi.c b/src/nvim/farsi.c
new file mode 100644
index 0000000000..ea9432ac8b
--- /dev/null
+++ b/src/nvim/farsi.c
@@ -0,0 +1,2994 @@
+/// @file farsi.c
+///
+/// Functions for Farsi language
+///
+
+
+#include "edit.h"
+#include "ex_docmd.h"
+#include "ex_eval.h"
+#include "ex_getln.h"
+#include "farsi.h"
+#include "getchar.h"
+#include "memline.h"
+#include "message.h"
+#include "misc1.h"
+#include "misc2.h"
+#include "screen.h"
+#include "vim.h"
+
+
+#define SRC_EDT 0
+#define SRC_CMD 1
+
+#define AT_CURSOR 0
+
+// special Farsi text messages
+
+const char_u farsi_text_1[] = {
+ YE_, _SIN, RE, ALEF_, _FE, ' ', 'V', 'I', 'M',
+ ' ', F_HE, _BE, ' ', SHIN, RE, _GAF, DAL, ' ', NOON,
+ ALEF_, _YE, ALEF_, _PE, '\0'
+};
+
+const char_u farsi_text_2[] = {
+ YE_, _SIN, RE, ALEF_, _FE, ' ', FARSI_3, FARSI_3,
+ FARSI_4, FARSI_2, ' ', DAL, RE, ALEF, DAL, _NOON,
+ ALEF_, _TE, _SIN, ALEF, ' ', F_HE, _BE, ' ', SHIN,
+ RE, _GAF, DAL, ' ', NOON, ALEF_, _YE, ALEF_, _PE, '\0'
+};
+
+const char_u farsi_text_3[] = {
+ DAL, WAW, _SHIN, _YE, _MIM, _NOON, ' ', YE_, _NOON,
+ ALEF_, _BE, _YE, _TE, _SHIN, _PE, ' ', 'R', 'E', 'P', 'L',
+ 'A', 'C', 'E', ' ', NOON, ALEF_, _MIM, RE, _FE, ZE, ALEF,
+ ' ', 'R', 'E', 'V', 'E', 'R', 'S', 'E', ' ', 'I', 'N',
+ 'S', 'E', 'R', 'T', ' ', SHIN, WAW, RE, ' ', ALEF_, _BE,
+ ' ', YE_, _SIN, RE, ALEF_, _FE, ' ', RE, DAL, ' ', RE,
+ ALEF_, _KAF, ' ', MIM, ALEF_, _GAF, _NOON, _HE, '\0'
+};
+
+const char_u farsi_text_5[] = {
+ ' ', YE_, _SIN, RE, ALEF_, _FE, '\0'
+};
+
+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
+///
+/// @param c The character to convert.
+///
+/// @return Farsi character converted to a _X or _X_ type.
+static int toF_Xor_X_(int c)
+{
+ int tempc;
+
+ switch (c) {
+ case BE:
+ return _BE;
+
+ case PE:
+ return _PE;
+
+ case TE:
+ return _TE;
+
+ case SE:
+ return _SE;
+
+ case JIM:
+ return _JIM;
+
+ case CHE:
+ return _CHE;
+
+ case HE_J:
+ return _HE_J;
+
+ case XE:
+ return _XE;
+
+ case SIN:
+ return _SIN;
+
+ case SHIN:
+ return _SHIN;
+
+ case SAD:
+ return _SAD;
+
+ case ZAD:
+ return _ZAD;
+
+ case AYN:
+ return _AYN;
+
+ case AYN_:
+ return _AYN_;
+
+ case GHAYN:
+ return _GHAYN;
+
+ case GHAYN_:
+ return _GHAYN_;
+
+ case FE:
+ return _FE;
+
+ case GHAF:
+ return _GHAF;
+
+ case KAF:
+ return _KAF;
+
+ case GAF:
+ return _GAF;
+
+ case LAM:
+ return _LAM;
+
+ case MIM:
+ return _MIM;
+
+ case NOON:
+ return _NOON;
+
+ case YE:
+ case YE_:
+ return _YE;
+
+ case YEE:
+ case YEE_:
+ return _YEE;
+
+ case IE:
+ case IE_:
+ return _IE;
+
+ case F_HE:
+ tempc = _HE;
+
+ if (p_ri &&
+ (curwin->w_cursor.col + 1 < (colnr_T)STRLEN(ml_get_curline()))) {
+ inc_cursor();
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = _HE_;
+ }
+ dec_cursor();
+ }
+
+ if (!p_ri && STRLEN(ml_get_curline())) {
+ dec_cursor();
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = _HE_;
+ }
+ inc_cursor();
+ }
+
+ return tempc;
+ }
+ return 0;
+}
+
+/// Convert the given Farsi character into Farsi capital character.
+///
+/// @param c The character to convert.
+///
+/// @return Character converted to the Farsi capital leter.
+int toF_TyA(int c)
+{
+ switch (c) {
+ case ALEF_:
+ return ALEF;
+
+ case ALEF_U_H_:
+ return ALEF_U_H;
+
+ case _BE:
+ return BE;
+
+ case _PE:
+ return PE;
+
+ case _TE:
+ return TE;
+
+ case _SE:
+ return SE;
+
+ case _JIM:
+ return JIM;
+
+ case _CHE:
+ return CHE;
+
+ case _HE_J:
+ return HE_J;
+
+ case _XE:
+ return XE;
+
+ case _SIN:
+ return SIN;
+
+ case _SHIN:
+ return SHIN;
+
+ case _SAD:
+ return SAD;
+
+ case _ZAD:
+ return ZAD;
+
+ case _AYN:
+ case AYN_:
+ case _AYN_:
+ return AYN;
+
+ case _GHAYN:
+ case GHAYN_:
+ case _GHAYN_:
+ return GHAYN;
+
+ case _FE:
+ return FE;
+
+ case _GHAF:
+ return GHAF;
+
+ // I am not sure what it is !!!
+ // case _KAF_H:
+ case _KAF:
+ return KAF;
+
+ case _GAF:
+ return GAF;
+
+ case _LAM:
+ return LAM;
+
+ case _MIM:
+ return MIM;
+
+ case _NOON:
+ return NOON;
+
+ case _YE:
+ case YE_:
+ return YE;
+
+ case _YEE:
+ case YEE_:
+ return YEE;
+
+ case TEE_:
+ return TEE;
+
+ case _IE:
+ case IE_:
+ return IE;
+
+ case _HE:
+ case _HE_:
+ return F_HE;
+ }
+ return 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.
+///
+/// @param src
+/// @param offset
+///
+/// @return TRUE if the character under the cursor+offset is a join type.
+static int F_is_TyB_TyC_TyD(int src, int offset)
+{
+ int c;
+
+ if (src == SRC_EDT) {
+ c = gchar_cursor();
+ } else {
+ c = cmd_gchar(AT_CURSOR + offset);
+ }
+
+ switch (c) {
+ case _LAM:
+ 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 _TA:
+ case _ZA:
+ case _AYN:
+ case _AYN_:
+ case _GHAYN:
+ case _GHAYN_:
+ case _FE:
+ case _GHAF:
+ case _KAF:
+ case _KAF_H:
+ case _GAF:
+ case _MIM:
+ case _NOON:
+ case _YE:
+ case _YEE:
+ case _IE:
+ case _HE_:
+ case _HE:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/// Is the Farsi character one of the terminating only type.
+///
+/// @param c The character to check.
+///
+/// @return TRUE if the Farsi character is one of the terminating only types.
+static int F_is_TyE(int c)
+{
+ switch (c) {
+ case ALEF_A:
+ case ALEF_D_H:
+ case DAL:
+ case ZAL:
+ case RE:
+ case ZE:
+ case JE:
+ case WAW:
+ case WAW_H:
+ case HAMZE:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/// Is the Farsi character one of the none leading type.
+///
+/// @param c The character to check.
+///
+/// @return TRUE if the Farsi character is one of the none-leading types.
+static int F_is_TyC_TyD(int c)
+{
+ switch (c) {
+ case ALEF_:
+ case ALEF_U_H_:
+ case _AYN_:
+ case AYN_:
+ case _GHAYN_:
+ case GHAYN_:
+ case _HE_:
+ case YE_:
+ case IE_:
+ case TEE_:
+ case YEE_:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/// Convert a none leading Farsi char into a leading type.
+///
+/// @param c The character to convert.
+///
+/// @return The character converted into a leading type.
+static int toF_TyB(int c)
+{
+ switch (c) {
+ case ALEF_:
+ return ALEF;
+
+ case ALEF_U_H_:
+ return ALEF_U_H;
+
+ case _AYN_:
+ return _AYN;
+
+ case AYN_:
+ // exception - there are many of them
+ return AYN;
+
+ case _GHAYN_:
+ return _GHAYN;
+
+ case GHAYN_:
+ // exception - there are many of them
+ return GHAYN;
+
+ case _HE_:
+ return _HE;
+
+ case YE_:
+ return YE;
+
+ case IE_:
+ return IE;
+
+ case TEE_:
+ return TEE;
+
+ case YEE_:
+ return YEE;
+ }
+ return c;
+}
+
+/// Overwrite the current redo and cursor characters + left adjust
+///
+/// @param c
+static void put_curr_and_l_to_X(int c)
+{
+ int tempc;
+
+ if (curwin->w_p_rl && p_ri) {
+ return;
+ }
+
+ if ((curwin->w_cursor.col < (colnr_T)STRLEN(ml_get_curline()))) {
+ if ((p_ri && curwin->w_cursor.col) || !p_ri) {
+ if (p_ri) {
+ dec_cursor();
+ } else {
+ inc_cursor();
+ }
+
+ if (F_is_TyC_TyD((tempc = gchar_cursor()))) {
+ pchar_cursor(toF_TyB(tempc));
+ AppendCharToRedobuff(K_BS);
+ AppendCharToRedobuff(tempc);
+ }
+
+ if (p_ri) {
+ inc_cursor();
+ } else {
+ dec_cursor();
+ }
+ }
+ }
+
+ 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)
+{
+ int tempc, curc;
+
+ switch ((curc = gchar_cursor())) {
+ case _BE:
+ tempc = BE;
+ break;
+
+ case _PE:
+ tempc = PE;
+ break;
+
+ case _TE:
+ tempc = TE;
+ break;
+
+ case _SE:
+ tempc = SE;
+ break;
+
+ case _JIM:
+ tempc = JIM;
+ break;
+
+ case _CHE:
+ tempc = CHE;
+ break;
+
+ case _HE_J:
+ tempc = HE_J;
+ break;
+
+ case _XE:
+ tempc = XE;
+ break;
+
+ case _SIN:
+ tempc = SIN;
+ break;
+
+ case _SHIN:
+ tempc = SHIN;
+ break;
+
+ case _SAD:
+ tempc = SAD;
+ break;
+
+ case _ZAD:
+ tempc = ZAD;
+ break;
+
+ case _FE:
+ tempc = FE;
+ break;
+
+ case _GHAF:
+ tempc = GHAF;
+ break;
+
+ case _KAF_H:
+ case _KAF:
+ tempc = KAF;
+ break;
+
+ case _GAF:
+ tempc = GAF;
+ break;
+
+ case _AYN:
+ tempc = AYN;
+ break;
+
+ case _AYN_:
+ tempc = AYN_;
+ break;
+
+ case _GHAYN:
+ tempc = GHAYN;
+ break;
+
+ case _GHAYN_:
+ tempc = GHAYN_;
+ break;
+
+ case _LAM:
+ tempc = LAM;
+ break;
+
+ case _MIM:
+ tempc = MIM;
+ break;
+
+ case _NOON:
+ tempc = NOON;
+ break;
+
+ case _HE:
+ case _HE_:
+ tempc = F_HE;
+ break;
+
+ case _YE:
+ case _IE:
+ case _YEE:
+ if (p_ri) {
+ inc_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = (curc == _YE ? YE_ :
+ (curc == _IE ? IE_ : YEE_));
+ } else {
+ tempc = (curc == _YE ? YE :
+ (curc == _IE ? IE : YEE));
+ }
+ dec_cursor();
+ } else {
+ if (curwin->w_cursor.col) {
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = (curc == _YE ? YE_ :
+ (curc == _IE ? IE_ : YEE_));
+ } else {
+ tempc = (curc == _YE ? YE :
+ (curc == _IE ? IE : YEE));
+ }
+ inc_cursor();
+ } else {
+ tempc = (curc == _YE ? YE :
+ (curc == _IE ? IE : YEE));
+ }
+ }
+ break;
+
+ default:
+ tempc = 0;
+ }
+
+ if (tempc) {
+ put_and_redo(tempc);
+ }
+}
+
+/// Change the char. under the cursor to a _X_ or X_ type
+static void chg_c_to_X_orX_(void)
+{
+ int tempc;
+
+ switch (gchar_cursor()) {
+ case ALEF:
+ tempc = ALEF_;
+ break;
+
+ case ALEF_U_H:
+ tempc = ALEF_U_H_;
+ break;
+
+ case _AYN:
+ tempc = _AYN_;
+ break;
+
+ case AYN:
+ tempc = AYN_;
+ break;
+
+ case _GHAYN:
+ tempc = _GHAYN_;
+ break;
+
+ case GHAYN:
+ tempc = GHAYN_;
+ break;
+
+ case _HE:
+ tempc = _HE_;
+ break;
+
+ case YE:
+ tempc = YE_;
+ break;
+
+ case IE:
+ tempc = IE_;
+ break;
+
+ case TEE:
+ tempc = TEE_;
+ break;
+
+ case YEE:
+ tempc = YEE_;
+ break;
+
+ default:
+ tempc = 0;
+ }
+
+ if (tempc) {
+ put_and_redo(tempc);
+ }
+}
+
+/// Change the char. under the cursor to a _X_ or _X type
+static void chg_c_to_X_or_X(void)
+{
+ int tempc;
+
+ tempc = gchar_cursor();
+
+ if (curwin->w_cursor.col + 1 < (colnr_T)STRLEN(ml_get_curline())) {
+ inc_cursor();
+ if ((tempc == F_HE) && (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))) {
+ tempc = _HE_;
+ dec_cursor();
+ put_and_redo(tempc);
+ return;
+ }
+
+ dec_cursor();
+ }
+
+ if ((tempc = toF_Xor_X_(tempc)) != 0) {
+ put_and_redo(tempc);
+ }
+}
+
+/// Change the character left to the cursor to a _X_ or X_ type
+static void chg_l_to_X_orX_(void)
+{
+ int tempc;
+
+ if ((curwin->w_cursor.col != 0)
+ && (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(ml_get_curline()))) {
+ return;
+ }
+
+ if (!curwin->w_cursor.col && p_ri) {
+ return;
+ }
+
+ if (p_ri) {
+ dec_cursor();
+ } else {
+ inc_cursor();
+ }
+
+ switch (gchar_cursor()) {
+ case ALEF:
+ tempc = ALEF_;
+ break;
+
+ case ALEF_U_H:
+ tempc = ALEF_U_H_;
+ break;
+
+ case _AYN:
+ tempc = _AYN_;
+ break;
+
+ case AYN:
+ tempc = AYN_;
+ break;
+
+ case _GHAYN:
+ tempc = _GHAYN_;
+ break;
+
+ case GHAYN:
+ tempc = GHAYN_;
+ break;
+
+ case _HE:
+ tempc = _HE_;
+ break;
+
+ case YE:
+ tempc = YE_;
+ break;
+
+ case IE:
+ tempc = IE_;
+ break;
+
+ case TEE:
+ tempc = TEE_;
+ break;
+
+ case YEE:
+ tempc = YEE_;
+ break;
+
+ default:
+ tempc = 0;
+ }
+
+ if (tempc) {
+ put_and_redo(tempc);
+ }
+
+ if (p_ri) {
+ inc_cursor();
+ } else {
+ dec_cursor();
+ }
+}
+
+/// Change the character left to the cursor to a X or _X type
+static void chg_l_toXor_X(void)
+{
+ int tempc;
+
+ if ((curwin->w_cursor.col != 0) &&
+ (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(ml_get_curline()))) {
+ return;
+ }
+
+ if (!curwin->w_cursor.col && p_ri) {
+ return;
+ }
+
+ if (p_ri) {
+ dec_cursor();
+ } else {
+ inc_cursor();
+ }
+
+ switch (gchar_cursor()) {
+ case ALEF_:
+ tempc = ALEF;
+ break;
+
+ case ALEF_U_H_:
+ tempc = ALEF_U_H;
+ break;
+
+ case _AYN_:
+ tempc = _AYN;
+ break;
+
+ case AYN_:
+ tempc = AYN;
+ break;
+
+ case _GHAYN_:
+ tempc = _GHAYN;
+ break;
+
+ case GHAYN_:
+ tempc = GHAYN;
+ break;
+
+ case _HE_:
+ tempc = _HE;
+ break;
+
+ case YE_:
+ tempc = YE;
+ break;
+
+ case IE_:
+ tempc = IE;
+ break;
+
+ case TEE_:
+ tempc = TEE;
+ break;
+
+ case YEE_:
+ tempc = YEE;
+ break;
+
+ default:
+ tempc = 0;
+ }
+
+ if (tempc) {
+ put_and_redo(tempc);
+ }
+
+ if (p_ri) {
+ inc_cursor();
+ } else {
+ dec_cursor();
+ }
+}
+
+/// Change the character right to the cursor to a _X or _X_ type
+static void chg_r_to_Xor_X_(void)
+{
+ int tempc, c;
+
+ if (curwin->w_cursor.col) {
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ tempc = gchar_cursor();
+ if ((c = toF_Xor_X_(tempc)) != 0) {
+ put_and_redo(c);
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+ }
+}
+
+/// Map Farsi keyboard when in fkmap mode.
+int fkmap(int c)
+{
+ int tempc;
+ static int revins;
+
+ if (IS_SPECIAL(c)) {
+ return c;
+ }
+
+ if (VIM_ISDIGIT(c)
+ || (((c == '.')
+ || (c == '+')
+ || (c == '-')
+ || (c == '^')
+ || (c == '%')
+ || (c == '#')
+ || (c == '='))
+ && revins)) {
+ if (!revins) {
+ if (curwin->w_cursor.col) {
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ chg_c_toX_orX();
+ chg_l_toXor_X();
+ if (!p_ri) {
+ inc_cursor();
+ }
+ }
+ }
+
+ arrow_used = TRUE;
+ (void)stop_arrow();
+
+ if (!curwin->w_p_rl && revins) {
+ inc_cursor();
+ }
+
+ revins++;
+ p_ri = 1;
+ } else {
+ if (revins) {
+ arrow_used = TRUE;
+ (void)stop_arrow();
+
+ revins = 0;
+ if (curwin->w_p_rl) {
+ while ((F_isdigit(gchar_cursor())
+ || (gchar_cursor() == F_PERIOD
+ || gchar_cursor() == F_PLUS
+ || gchar_cursor() == F_MINUS
+ || gchar_cursor() == F_MUL
+ || gchar_cursor() == F_DIVIDE
+ || gchar_cursor() == F_PERCENT
+ || gchar_cursor() == F_EQUALS))
+ && gchar_cursor() != NUL) {
+ curwin->w_cursor.col++;
+ }
+ } else {
+ if (curwin->w_cursor.col) {
+ while ((F_isdigit(gchar_cursor())
+ || (gchar_cursor() == F_PERIOD
+ || gchar_cursor() == F_PLUS
+ || gchar_cursor() == F_MINUS
+ || gchar_cursor() == F_MUL
+ || gchar_cursor() == F_DIVIDE
+ || gchar_cursor() == F_PERCENT
+ || gchar_cursor() == F_EQUALS))
+ && --curwin->w_cursor.col) {
+ }
+ }
+
+ if (!F_isdigit(gchar_cursor())) {
+ ++curwin->w_cursor.col;
+ }
+ }
+ }
+ }
+
+ if (!revins) {
+ if (curwin->w_p_rl) {
+ p_ri = 0;
+ }
+
+ if (!curwin->w_p_rl) {
+ p_ri = 1;
+ }
+ }
+
+ if ((c < 0x100) &&
+ (isalpha(c) ||
+ (c == '&') ||
+ (c == '^') ||
+ (c == ';') ||
+ (c == '\'') ||
+ (c == ',') ||
+ (c == '[') ||
+ (c == ']') ||
+ (c == '{') ||
+ (c == '}'))) {
+ chg_r_to_Xor_X_();
+ }
+
+ tempc = 0;
+ switch (c) {
+ case '`':
+ case ' ':
+ case '.':
+ case '!':
+ case '"':
+ case '$':
+ case '%':
+ case '^':
+ case '&':
+ case '/':
+ case '(':
+ case ')':
+ case '=':
+ case '\\':
+ case '?':
+ case '+':
+ case '-':
+ case '_':
+ case '*':
+ case ':':
+ case '#':
+ case '~':
+ case '@':
+ case '<':
+ case '>':
+ case '{':
+ case '}':
+ case '|':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'B':
+ case 'E':
+ case 'F':
+ case 'H':
+ case 'I':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'T':
+ case 'U':
+ case 'W':
+ case 'Y':
+ case NL:
+ case TAB:
+ if (p_ri && (c == NL) && curwin->w_cursor.col) {
+ // 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())) {
+ inc_cursor();
+ return NL;
+ }
+ inc_cursor();
+ }
+
+ if (!p_ri) {
+ if (!curwin->w_cursor.col) {
+ 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;
+ }
+ }
+
+ if (!p_ri) {
+ 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 (!p_ri) {
+ if (!curwin->w_cursor.col) {
+ put_curr_and_l_to_X(AYN);
+ break;
+ }
+ }
+
+ if (p_ri) {
+ inc_cursor();
+ } else {
+ dec_cursor();
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = AYN_;
+ } else {
+ tempc = AYN;
+ }
+
+ if (p_ri) {
+ dec_cursor();
+ } else {
+ inc_cursor();
+ }
+
+ 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) {
+ inc_cursor();
+ } else {
+ dec_cursor();
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = GHAYN_;
+ } else {
+ tempc = GHAYN;
+ }
+
+ 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;
+ }
+ }
+
+ 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 (p_ri) {
+ dec_cursor();
+ } else {
+ inc_cursor();
+ }
+
+ put_curr_and_l_to_X(tempc);
+ break;
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+
+ 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;
+
+ case 'a':
+ tempc = _SHIN;
+ break;
+
+ case 'A':
+ tempc = WAW_H;
+ break;
+
+ case 'b':
+ tempc = ZAL;
+ break;
+
+ case 'c':
+ tempc = ZE;
+ break;
+
+ case 'C':
+ tempc = JE;
+ break;
+
+ case 'd':
+ tempc = _YE;
+ break;
+
+ case 'D':
+ tempc = _YEE;
+ break;
+
+ case 'e':
+ tempc = _SE;
+ break;
+
+ case 'f':
+ tempc = _BE;
+ break;
+
+ case 'g':
+ tempc = _LAM;
+ break;
+
+ case 'G':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
+ if (gchar_cursor() == _LAM) {
+ chg_c_toX_orX();
+ } else if (p_ri) {
+ chg_c_to_X_or_X();
+ }
+ }
+
+ if (!p_ri) {
+ if (!curwin->w_cursor.col) {
+ return ALEF_U_H;
+ }
+ }
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (gchar_cursor() == _LAM) {
+ chg_c_toX_orX();
+ chg_l_toXor_X();
+ tempc = ALEF_U_H;
+ } else if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = ALEF_U_H_;
+ chg_l_toXor_X();
+ } else {
+ tempc = ALEF_U_H;
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+
+ return tempc;
+
+ case 'h':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
+ if (p_ri) {
+ chg_c_to_X_or_X();
+ }
+ }
+
+ if (!p_ri) {
+ if (!curwin->w_cursor.col) {
+ return ALEF;
+ }
+ }
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (gchar_cursor() == _LAM) {
+ chg_l_toXor_X();
+ del_char(FALSE);
+ AppendCharToRedobuff(K_BS);
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ tempc = LA;
+ } else {
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = ALEF_;
+ chg_l_toXor_X();
+ } else {
+ tempc = ALEF;
+ }
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+
+ return tempc;
+
+ case 'i':
+
+ 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 _HE;
+ }
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = _HE_;
+ } else {
+ tempc = _HE;
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+ break;
+
+ case 'j':
+ tempc = _TE;
+ break;
+
+ case 'J':
+
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
+ if (p_ri) {
+ chg_c_to_X_or_X();
+ }
+ }
+
+ if (!p_ri) {
+ if (!curwin->w_cursor.col) {
+ return TEE;
+ }
+ }
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = TEE_;
+ chg_l_toXor_X();
+ } else {
+ tempc = TEE;
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+
+ return tempc;
+
+ case 'k':
+ tempc = _NOON;
+ break;
+
+ case 'l':
+ tempc = _MIM;
+ break;
+
+ case 'm':
+ tempc = _PE;
+ break;
+
+ case 'n':
+ case 'N':
+ tempc = DAL;
+ break;
+
+ case 'o':
+ tempc = _XE;
+ break;
+
+ case 'p':
+ tempc = _HE_J;
+ break;
+
+ case 'q':
+ tempc = _ZAD;
+ break;
+
+ case 'r':
+ tempc = _GHAF;
+ break;
+
+ case 's':
+ tempc = _SIN;
+ break;
+
+ case 'S':
+ tempc = _IE;
+ break;
+
+ case 't':
+ 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 (!p_ri && !curwin->w_cursor.col) {
+ return _AYN;
+ }
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = _AYN_;
+ } else {
+ tempc = _AYN;
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+ break;
+
+ case 'v':
+ case 'V':
+ tempc = RE;
+ break;
+
+ case 'w':
+ tempc = _SAD;
+ break;
+
+ case 'x':
+ case 'X':
+ tempc = _TA;
+ break;
+
+ case 'y':
+ 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 _GHAYN;
+ }
+
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
+ tempc = _GHAYN_;
+ } else {
+ tempc = _GHAYN;
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+
+ break;
+
+ case 'z':
+ tempc = _ZA;
+ break;
+
+ case 'Z':
+ tempc = _KAF_H;
+ break;
+
+ case ';':
+ tempc = _KAF;
+ break;
+
+ case '\'':
+ tempc = _GAF;
+ break;
+
+ case ',':
+ tempc = WAW;
+ break;
+
+ case '[':
+ tempc = _JIM;
+ break;
+
+ case ']':
+ tempc = _CHE;
+ break;
+ }
+
+ if ((F_isalpha(tempc) || F_isdigit(tempc))) {
+ 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) {
+ if (!p_ri) {
+ dec_cursor();
+ }
+
+ if (F_is_TyE(tempc)) {
+ chg_l_toXor_X();
+ } else {
+ chg_l_to_X_orX_();
+ }
+
+ if (!p_ri) {
+ inc_cursor();
+ }
+ }
+ }
+
+ if (tempc) {
+ return tempc;
+ }
+ return c;
+}
+
+/// Convert a none leading Farsi char into a leading type.
+///
+/// @param c The character to convert.
+///
+/// @return The non-leading Farsi character converted to a leading type.
+static int toF_leading(int c)
+{
+ switch (c) {
+ case ALEF_:
+ return ALEF;
+
+ case ALEF_U_H_:
+ return ALEF_U_H;
+
+ case BE:
+ return _BE;
+
+ case PE:
+ return _PE;
+
+ case TE:
+ return _TE;
+
+ case SE:
+ return _SE;
+
+ case JIM:
+ return _JIM;
+
+ case CHE:
+ return _CHE;
+
+ case HE_J:
+ return _HE_J;
+
+ case XE:
+ return _XE;
+
+ case SIN:
+ return _SIN;
+
+ case SHIN:
+ return _SHIN;
+
+ case SAD:
+ return _SAD;
+
+ case ZAD:
+ return _ZAD;
+
+ case AYN:
+ case AYN_:
+ case _AYN_:
+ return _AYN;
+
+ case GHAYN:
+ case GHAYN_:
+ case _GHAYN_:
+ return _GHAYN;
+
+ case FE:
+ return _FE;
+
+ case GHAF:
+ return _GHAF;
+
+ case KAF:
+ return _KAF;
+
+ case GAF:
+ return _GAF;
+
+ case LAM:
+ return _LAM;
+
+ case MIM:
+ return _MIM;
+
+ case NOON:
+ return _NOON;
+
+ case _HE_:
+ case F_HE:
+ return _HE;
+
+ case YE:
+ case YE_:
+ return _YE;
+
+ case IE_:
+ case IE:
+ return _IE;
+
+ case YEE:
+ case YEE_:
+ return _YEE;
+ }
+ return c;
+}
+
+/// Convert a given Farsi char into right joining type.
+///
+/// @param c The character to convert.
+///
+/// @return The Farsi character converted into a right joining type
+static int toF_Rjoin(int c)
+{
+ switch (c) {
+ case ALEF:
+ return ALEF_;
+
+ case ALEF_U_H:
+ return ALEF_U_H_;
+
+ case BE:
+ return _BE;
+
+ case PE:
+ return _PE;
+
+ case TE:
+ return _TE;
+
+ case SE:
+ return _SE;
+
+ case JIM:
+ return _JIM;
+
+ case CHE:
+ return _CHE;
+
+ case HE_J:
+ return _HE_J;
+
+ case XE:
+ return _XE;
+
+ case SIN:
+ return _SIN;
+
+ case SHIN:
+ return _SHIN;
+
+ case SAD:
+ return _SAD;
+
+ case ZAD:
+ return _ZAD;
+
+ case AYN:
+ case AYN_:
+ case _AYN:
+ return _AYN_;
+
+ case GHAYN:
+ case GHAYN_:
+ case _GHAYN_:
+ return _GHAYN_;
+
+ case FE:
+ return _FE;
+
+ case GHAF:
+ return _GHAF;
+
+ case KAF:
+ return _KAF;
+
+ case GAF:
+ return _GAF;
+
+ case LAM:
+ return _LAM;
+
+ case MIM:
+ return _MIM;
+
+ case NOON:
+ return _NOON;
+
+ case _HE:
+ case F_HE:
+ return _HE_;
+
+ case YE:
+ case YE_:
+ return _YE;
+
+ case IE_:
+ case IE:
+ return _IE;
+
+ case TEE:
+ return TEE_;
+
+ case YEE:
+ case YEE_:
+ return _YEE;
+ }
+ return c;
+}
+
+/// Can a given Farsi character join via its left edj.
+///
+/// @param c The character to check.
+///
+/// @return TRUE if the character can join via its left edj.
+static int canF_Ljoin(int c)
+{
+ switch (c) {
+ case _BE:
+ case BE:
+ case PE:
+ case _PE:
+ case TE:
+ case _TE:
+ case SE:
+ case _SE:
+ case JIM:
+ case _JIM:
+ case CHE:
+ case _CHE:
+ case HE_J:
+ case _HE_J:
+ case XE:
+ case _XE:
+ case SIN:
+ case _SIN:
+ case SHIN:
+ case _SHIN:
+ case SAD:
+ case _SAD:
+ case ZAD:
+ case _ZAD:
+ case _TA:
+ case _ZA:
+ case AYN:
+ case _AYN:
+ case _AYN_:
+ case AYN_:
+ case GHAYN:
+ case GHAYN_:
+ case _GHAYN_:
+ case _GHAYN:
+ case FE:
+ case _FE:
+ case GHAF:
+ case _GHAF:
+ case _KAF_H:
+ case KAF:
+ case _KAF:
+ case GAF:
+ case _GAF:
+ case LAM:
+ case _LAM:
+ case MIM:
+ case _MIM:
+ case NOON:
+ case _NOON:
+ case IE:
+ case _IE:
+ case IE_:
+ case YE:
+ case _YE:
+ case YE_:
+ case YEE:
+ case _YEE:
+ case YEE_:
+ case F_HE:
+ case _HE:
+ case _HE_:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/// Can a given Farsi character join via its right edj.
+///
+/// @param c
+///
+/// @return TRUE if the character can join via its right edj.
+static int canF_Rjoin(int c)
+{
+ switch (c) {
+ case ALEF:
+ case ALEF_:
+ case ALEF_U_H:
+ case ALEF_U_H_:
+ case DAL:
+ case ZAL:
+ case RE:
+ case JE:
+ case ZE:
+ case TEE:
+ case TEE_:
+ case WAW:
+ case WAW_H:
+ return TRUE;
+ }
+
+ return canF_Ljoin(c);
+}
+
+/// Is a given Farsi character a terminating type.
+///
+/// @param c
+///
+/// @return TRUE if the character is a terminating type.
+static int F_isterm(int c)
+{
+ switch (c) {
+ case ALEF:
+ case ALEF_:
+ case ALEF_U_H:
+ case ALEF_U_H_:
+ case DAL:
+ case ZAL:
+ case RE:
+ case JE:
+ case ZE:
+ case WAW:
+ case WAW_H:
+ case TEE:
+ case TEE_:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/// Convert the given Farsi character into a ending type.
+///
+/// @param c The character to convert.
+///
+/// @return The character converted into an ending type.
+static int toF_ending(int c)
+{
+ switch (c) {
+ case _BE:
+ return BE;
+
+ case _PE:
+ return PE;
+
+ case _TE:
+ return TE;
+
+ case _SE:
+ return SE;
+
+ case _JIM:
+ return JIM;
+
+ case _CHE:
+ return CHE;
+
+ case _HE_J:
+ return HE_J;
+
+ case _XE:
+ return XE;
+
+ case _SIN:
+ return SIN;
+
+ case _SHIN:
+ return SHIN;
+
+ case _SAD:
+ return SAD;
+
+ case _ZAD:
+ return ZAD;
+
+ case _AYN:
+ return AYN;
+
+ case _AYN_:
+ return AYN_;
+
+ case _GHAYN:
+ return GHAYN;
+
+ case _GHAYN_:
+ return GHAYN_;
+
+ case _FE:
+ return FE;
+
+ case _GHAF:
+ return GHAF;
+
+ case _KAF_H:
+ case _KAF:
+ return KAF;
+
+ case _GAF:
+ return GAF;
+
+ case _LAM:
+ return LAM;
+
+ case _MIM:
+ return MIM;
+
+ case _NOON:
+ return NOON;
+
+ case _YE:
+ return YE_;
+
+ case YE_:
+ return YE;
+
+ case _YEE:
+ return YEE_;
+
+ case YEE_:
+ return YEE;
+
+ case TEE:
+ return TEE_;
+
+ case _IE:
+ return IE_;
+
+ case IE_:
+ return IE;
+
+ case _HE:
+ case _HE_:
+ return F_HE;
+ }
+ return c;
+}
+
+/// Convert the Farsi 3342 standard into Farsi VIM.
+void conv_to_pvim(void)
+{
+ char_u *ptr;
+ int lnum, llen, i;
+
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
+ ptr = ml_get((linenr_T)lnum);
+ llen = (int)STRLEN(ptr);
+ for (i = 0; i < llen - 1; i++) {
+ if (canF_Ljoin(ptr[i]) && canF_Rjoin(ptr[i + 1])) {
+ ptr[i] = toF_leading(ptr[i]);
+ i++;
+
+ while (canF_Rjoin(ptr[i]) && i < llen) {
+ ptr[i] = toF_Rjoin(ptr[i]);
+ if (F_isterm(ptr[i]) || !F_isalpha(ptr[i])) {
+ break;
+ }
+ i++;
+ }
+
+ if (!F_isalpha(ptr[i]) || !canF_Rjoin(ptr[i])) {
+ ptr[i - 1] = toF_ending(ptr[i - 1]);
+ }
+ } else {
+ ptr[i] = toF_TyA(ptr[i]);
+ }
+ }
+ }
+
+ // Following lines contains Farsi encoded character.
+ do_cmdline_cmd((char_u *)"%s/\202\231/\232/g");
+ do_cmdline_cmd((char_u *)"%s/\201\231/\370\334/g");
+
+ // Assume the screen has been messed up: clear it and redraw.
+ redraw_later(CLEAR);
+ MSG_ATTR(farsi_text_1, hl_attr(HLF_S));
+}
+
+/// Convert the Farsi VIM into Farsi 3342 standard.
+void conv_to_pstd(void)
+{
+ char_u *ptr;
+ int lnum, llen, i;
+
+ // Following line contains Farsi encoded character.
+ do_cmdline_cmd((char_u *)"%s/\232/\202\231/g");
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
+ ptr = ml_get((linenr_T)lnum);
+ llen = (int)STRLEN(ptr);
+ for (i = 0; i < llen; i++) {
+ ptr[i] = toF_TyA(ptr[i]);
+ }
+ }
+
+ // Assume the screen has been messed up: clear it and redraw.
+ redraw_later(CLEAR);
+ MSG_ATTR(farsi_text_2, hl_attr(HLF_S));
+}
+
+/// left-right swap the characters in buf[len].
+///
+/// @param buf
+/// @param len
+static void lrswapbuf(char_u *buf, int len)
+{
+ char_u *s, *e;
+ int c;
+
+ s = buf;
+ e = buf + len - 1;
+ while (e > s) {
+ c = *s;
+ *s = *e;
+ *e = c;
+ ++s;
+ --e;
+ }
+}
+
+/// swap all the characters in reverse direction
+///
+/// @param ibuf
+///
+/// @return The buffer with the characters swapped.
+char_u* lrswap(char_u *ibuf)
+{
+ if ((ibuf != NULL) && (*ibuf != NUL)) {
+ lrswapbuf(ibuf, (int)STRLEN(ibuf));
+ }
+ return ibuf;
+}
+
+/// swap all the Farsi characters in reverse direction
+///
+/// @param cmdbuf
+/// @param .
+///
+/// @return The buffer with all Farsi characters swapped.
+char_u* lrFswap(char_u *cmdbuf, int len)
+{
+ int i, cnt;
+ if (cmdbuf == NULL) {
+ return cmdbuf;
+ }
+
+ if ((len == 0) && ((len = (int)STRLEN(cmdbuf)) == 0)) {
+ return cmdbuf;
+ }
+
+ for (i = 0; i < len; i++) {
+ for (cnt = 0; i + cnt < len
+ && (F_isalpha(cmdbuf[i + cnt])
+ || F_isdigit(cmdbuf[i + cnt])
+ || cmdbuf[i + cnt] == ' '); ++cnt) {
+ }
+
+ lrswapbuf(cmdbuf + i, cnt);
+ i += cnt;
+ }
+ return cmdbuf;
+}
+
+/// Reverse the characters in the search path and substitute section
+/// accordingly.
+/// TODO: handle different separator characters. Use skip_regexp().
+///
+/// @param ibuf
+///
+/// @return The buffer with the characters in the search path and substitute
+/// section reversed.
+char_u* lrF_sub(char_u *ibuf)
+{
+ char_u *p, *ep;
+ int i, cnt;
+
+ p = ibuf;
+
+ // Find the boundary of the search path
+ while (((p = vim_strchr(p + 1, '/')) != NULL) && p[-1] == '\\') {
+ }
+
+ if (p == NULL) {
+ return ibuf;
+ }
+
+ // Reverse the Farsi characters in the search path.
+ lrFswap(ibuf, (int)(p - ibuf));
+
+ // Now find the boundary of the substitute section
+ if ((ep = (char_u *)strrchr((char *)++p, '/')) != NULL) {
+ cnt = (int)(ep - p);
+ } else {
+ cnt = (int)STRLEN(p);
+ }
+
+ // Reverse the characters in the substitute section and take care of '\'
+ for (i = 0; i < cnt - 1; i++) {
+ if (p[i] == '\\') {
+ p[i] = p[i + 1];
+ p[++i] = '\\';
+ }
+ }
+
+ lrswapbuf(p, cnt);
+ return ibuf;
+}
+
+/// Map Farsi keyboard when in cmd_fkmap mode.
+///
+/// @param c
+///
+/// @return The mapped character.
+int cmdl_fkmap(int c)
+{
+ int tempc;
+
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '`':
+ case ' ':
+ case '.':
+ case '!':
+ case '"':
+ case '$':
+ case '%':
+ case '^':
+ case '&':
+ case '/':
+ case '(':
+ case ')':
+ case '=':
+ case '\\':
+ case '?':
+ case '+':
+ case '-':
+ case '_':
+ case '*':
+ case ':':
+ case '#':
+ case '~':
+ case '@':
+ case '<':
+ case '>':
+ case '{':
+ case '}':
+ case '|':
+ case 'B':
+ case 'E':
+ case 'F':
+ case 'H':
+ case 'I':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'T':
+ case 'U':
+ case 'W':
+ case 'Y':
+ case NL:
+ case TAB:
+ switch ((tempc = cmd_gchar(AT_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 _AYN:
+ case _GHAYN:
+ case _FE:
+ case _GHAF:
+ case _KAF:
+ case _GAF:
+ case _LAM:
+ case _MIM:
+ case _NOON:
+ case _HE:
+ case _HE_:
+ cmd_pchar(toF_TyA(tempc), AT_CURSOR);
+ break;
+
+ case _AYN_:
+ cmd_pchar(AYN_, AT_CURSOR);
+ break;
+
+ case _GHAYN_:
+ cmd_pchar(GHAYN_, AT_CURSOR);
+ break;
+
+ case _IE:
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR + 1)) {
+ cmd_pchar(IE_, AT_CURSOR);
+ } else {
+ cmd_pchar(IE, AT_CURSOR);
+ }
+ break;
+
+ case _YEE:
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR + 1)) {
+ cmd_pchar(YEE_, AT_CURSOR);
+ } else {
+ cmd_pchar(YEE, AT_CURSOR);
+ }
+ break;
+
+ case _YE:
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR + 1)) {
+ cmd_pchar(YE_, AT_CURSOR);
+ } else {
+ cmd_pchar(YE, AT_CURSOR);
+ }
+ }
+
+ 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':
+ return _SHIN;
+
+ case 'A':
+ return WAW_H;
+
+ case 'b':
+ return ZAL;
+
+ case 'c':
+ return ZE;
+
+ case 'C':
+ return JE;
+
+ case 'd':
+ return _YE;
+
+ case 'D':
+ return _YEE;
+
+ case 'e':
+ return _SE;
+
+ case 'f':
+ return _BE;
+
+ case 'g':
+ return _LAM;
+
+ case 'G':
+ if (cmd_gchar(AT_CURSOR) == _LAM) {
+ cmd_pchar(LAM, AT_CURSOR);
+ return ALEF_U_H;
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR)) {
+ return ALEF_U_H_;
+ } else {
+ return ALEF_U_H;
+ }
+
+ case 'h':
+ if (cmd_gchar(AT_CURSOR) == _LAM) {
+ cmd_pchar(LA, AT_CURSOR);
+ redrawcmdline();
+ return K_IGNORE;
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR)) {
+ return ALEF_;
+ } else {
+ return ALEF;
+ }
+
+ case 'i':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR)) {
+ return _HE_;
+ } else {
+ return _HE;
+ }
+
+ case 'j':
+ return _TE;
+
+ case 'J':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR)) {
+ return TEE_;
+ } else {
+ return TEE;
+ }
+
+ case 'k':
+ return _NOON;
+
+ case 'l':
+ return _MIM;
+
+ case 'm':
+ return _PE;
+
+ case 'n':
+ case 'N':
+ return DAL;
+
+ case 'o':
+ return _XE;
+
+ case 'p':
+ return _HE_J;
+
+ case 'q':
+ return _ZAD;
+
+ case 'r':
+ return _GHAF;
+
+ case 's':
+ return _SIN;
+
+ case 'S':
+ return _IE;
+
+ case 't':
+ return _FE;
+
+ case 'u':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR)) {
+ return _AYN_;
+ } else {
+ return _AYN;
+ }
+
+ case 'v':
+ case 'V':
+ return RE;
+
+ case 'w':
+ return _SAD;
+
+ case 'x':
+ case 'X':
+ return _TA;
+
+ case 'y':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR)) {
+ return _GHAYN_;
+ } else {
+ return _GHAYN;
+ }
+
+ case 'z':
+ case 'Z':
+ return _ZA;
+
+ case ';':
+ return _KAF;
+
+ case '\'':
+ return _GAF;
+
+ case ',':
+ return WAW;
+
+ case '[':
+ return _JIM;
+
+ case ']':
+ return _CHE;
+ }
+
+ return c;
+}
+
+/// F_isalpha returns TRUE if 'c' is a Farsi alphabet
+///
+/// @param c The character to check.
+///
+/// @return TRUE if 'c' is a Farsi alphabet character.
+int F_isalpha(int c)
+{
+ return (c >= TEE_ && c <= _YE)
+ || (c >= ALEF_A && c <= YE)
+ || (c >= _IE && c <= YE_);
+}
+
+/// F_isdigit returns TRUE if 'c' is a Farsi digit
+///
+/// @param c The character to check.
+///
+/// @return TRUE if 'c' is a Farsi digit.
+int F_isdigit(int c)
+{
+ return c >= FARSI_0 && c <= FARSI_9;
+}
+
+/// F_ischar returns TRUE if 'c' is a Farsi character.
+///
+/// @param c The character to check.
+///
+/// @return TRUE if 'c' is a Farsi character.
+int F_ischar(int c)
+{
+ return c >= TEE_ && c <= YE_;
+}
+
+void farsi_fkey(cmdarg_T *cap)
+{
+ int c = cap->cmdchar;
+
+ if (c == K_F8) {
+ if (p_altkeymap) {
+ if (curwin->w_farsi & W_R_L) {
+ p_fkmap = 0;
+ do_cmdline_cmd((char_u *)"set norl");
+ MSG("");
+ } else {
+ p_fkmap = 1;
+ do_cmdline_cmd((char_u *)"set rl");
+ MSG("");
+ }
+
+ curwin->w_farsi = curwin->w_farsi ^ W_R_L;
+ }
+ }
+
+ if (c == K_F9) {
+ if (p_altkeymap && curwin->w_p_rl) {
+ curwin->w_farsi = curwin->w_farsi ^ W_CONV;
+ if (curwin->w_farsi & W_CONV) {
+ conv_to_pvim();
+ } else {
+ conv_to_pstd();
+ }
+ }
+ }
+}