sandy

text editor
git clone git://git.suckless.org/sandy
Log | Files | Refs | README | LICENSE

config.def.h (27156B)


      1 /* A simplified way to customize */
      2 #define USE_TERM_STATUS 1
      3 #define BOTTOM_TITLE    0
      4 #define HILIGHT_CURRENT 1
      5 #define HILIGHT_SYNTAX  1
      6 #define SHOW_NONPRINT   0
      7 #define HANDLE_MOUSE    1
      8 #define VIM_BINDINGS    1
      9 
     10 /* Things unlikely to be changed, yet still in the config.h file */
     11 static const bool   isutf8     = TRUE;
     12 static const char   fifobase[] = "/tmp/sandyfifo.";
     13 static       int    tabstop    = 8; /* Not const, as it may be changed via param */
     14 /* static const char   systempath[]  = "/etc/sandy"; */
     15 /* static const char   userpath[]    = ".sandy"; */ /* Relative to $HOME */
     16 
     17 #if SHOW_NONPRINT /* TODO: show newline character too (as $) */
     18 static const char   tabstr[3]  = { (char)0xC2, (char)0xBB, 0x00 }; /* Double right arrow */
     19 static const char   spcstr[3]  = { (char)0xC2, (char)0xB7, 0x00 }; /* Middle dot */
     20 static const char   nlstr[2]   = { '$', 0x00 }; /* '$' is tradition for EOL */
     21 #else
     22 static const char   tabstr[2]  = { ' ', 0 };
     23 static const char   spcstr[2]  = { ' ', 0 };
     24 static const char   nlstr[1]   = { 0 };
     25 #endif
     26 
     27 /* Helper config functions, not used in main code */
     28 static void f_pipeai(const Arg*);
     29 static void f_pipeline(const Arg*);
     30 static void f_pipenull(const Arg*);
     31 
     32 /* Args to f_spawn */
     33 #define PROMPT(prompt, default, cmd) { .v = (const char *[]){ "/bin/sh", "-c", \
     34 	"dmenu -v >/dev/null 2>&1 || DISPLAY=\"\";"\
     35 	"if [ -n \"$DISPLAY\" ]; then arg=\"`echo \\\"" default "\\\" | dmenu $DMENU_OPTS -p '" prompt "'`\";" \
     36 	"else if slmenu -v >/dev/null 2>&1; then arg=\"`echo \\\"" default "\\\" | slmenu -t -p '" prompt "'`\";" \
     37 	"else printf \"\033[0;0H\033[7m"prompt"\033[K\033[0m \" >&2; read -r arg; fi; fi &&" \
     38 	"echo " cmd "\"$arg\" > ${SANDY_FIFO}", NULL } }
     39 
     40 #define FIND    PROMPT("Find:",        "${SANDY_FIND}",   "/")
     41 #define FINDBW  PROMPT("Find (back):", "${SANDY_FIND}",   "?")
     42 #define PIPE    PROMPT("Pipe:",        "${SANDY_PIPE}",   "!")
     43 #define SAVEAS  PROMPT("Save as:",     "${SANDY_FILE}",   "w")
     44 #define REPLACE PROMPT("Replace:",     "",                "!echo -n ")
     45 #define SED     PROMPT("Sed:",         "",                "!sed ")
     46 #define CMD_P   PROMPT("Command:",     "/\n?\nw\nq\n!\nsyntax\noffset\nicase\nro\nai\ndump", "")
     47 
     48 /* Args to f_pipe and friends, simple examples are inlined instead */
     49 #define TOCLIP     "tee /tmp/.sandy.clipboard.$USER | xsel -ib 2>/dev/null"
     50 #define FROMCLIP   "xsel -ob 2>/dev/null || cat /tmp/.sandy.clipboard.$USER"
     51 #define TOSEL      "tee /tmp/.sandy.selection.$USER | xsel -i 2>/dev/null"
     52 #define FROMSEL    "xsel -o 2>/dev/null || cat /tmp/.sandy.selection.$USER"
     53 #define AUTOINDENT "awk 'BEGIN{ l=\"\\n\" }; \
     54 				{ if(match($0, \"^[\t ]+[^\t ]\")) l=substr($0, RSTART, RLENGTH-1); \
     55 				  else l=\"\"; \
     56 				  if(FNR==NR && $0 ~ /^[\t ]+$/) print \"\"; \
     57 				  else print }; \
     58 				END{ ORS=\"\"; print l }' 2>/dev/null"
     59 #define CAPITALIZE "awk 'BEGIN{ ORS=\"\" }; \
     60 				{ for ( i=1; i <= NF; i++) { $i=tolower($i) ; sub(\".\", substr(toupper($i),1,1) , $i) } \
     61 				if(FNR==NF) print $0; \
     62 				else print $0\"\\n\" }' 2>/dev/null"
     63 
     64 /* Hooks are launched from the main code */
     65 #define HOOK_SAVE_NO_FILE f_spawn (&(const Arg)SAVEAS)
     66 #undef  HOOK_DELETE_ALL   /* This affects every delete */
     67 #undef  HOOK_SELECT_ALL   /* This affects every selection */
     68 
     69 /* Key-bindings and stuff */
     70 /* WARNING: use CONTROL(ch) ONLY with '@', (caps)A-Z, '[', '\', ']', '^', '_' or '?' */
     71 /*          otherwise it may not mean what you think. See man 7 ascii for more info */
     72 #define CONTROL(ch)   {(ch ^ 0x40)}
     73 #define META(ch)      { 0x1B, ch }
     74 
     75 static const Key curskeys[] = { /* Plain keys here, no CONTROL or META */
     76 /* keyv.i,                  tests,                     func,       arg */
     77 { .keyv.i = KEY_BACKSPACE,  { t_rw,  t_ins,0,   0 },   f_delete,    { .m = m_prevchar } },
     78 { .keyv.i = KEY_BACKSPACE,  { 0,     0,    0,   0 },   f_move,      { .m = m_prevchar } },
     79 { .keyv.i = KEY_DC,         { t_sel, t_rw, 0,   0 },   f_delete,    { .m = m_tosel    } },
     80 { .keyv.i = KEY_DC,         { t_rw,  0,    0,   0 },   f_delete,    { .m = m_nextchar } },
     81 { .keyv.i = KEY_SDC,        { t_sel, t_rw, 0,   0 },   f_delete,    { .m = m_tosel    } },
     82 { .keyv.i = KEY_SDC,        { t_rw,  0,    0,   0 },   f_delete,    { .m = m_nextchar } },
     83 { .keyv.i = KEY_IC,         { t_sel, 0,    0,   0 },   f_pipero,    { .v = TOCLIP     } },
     84 { .keyv.i = KEY_SIC,        { t_rw,  0,    0,   0 },   f_pipenull,  { .v = FROMCLIP   } },
     85 { .keyv.i = KEY_HOME,       { t_ai,  0,    0,   0 },   f_move,      { .m = m_smartbol } },
     86 { .keyv.i = KEY_HOME,       { 0,     0,    0,   0 },   f_move,      { .m = m_bol      } },
     87 { .keyv.i = KEY_END,        { 0,     0,    0,   0 },   f_move,      { .m = m_eol      } },
     88 { .keyv.i = KEY_SHOME,      { 0,     0,    0,   0 },   f_move,      { .m = m_bof      } },
     89 { .keyv.i = KEY_SEND,       { 0,     0,    0,   0 },   f_move,      { .m = m_eof      } },
     90 { .keyv.i = KEY_PPAGE,      { 0,     0,    0,   0 },   f_move,      { .m = m_prevscr  } },
     91 { .keyv.i = KEY_NPAGE,      { 0,     0,    0,   0 },   f_move,      { .m = m_nextscr  } },
     92 { .keyv.i = KEY_UP,         { t_sent,0,    0,   0 },   f_adjective, { .m = m_prevline } },
     93 { .keyv.i = KEY_UP,         { 0,     0,    0,   0 },   f_move,      { .m = m_prevline } },
     94 { .keyv.i = KEY_DOWN,       { t_sent,0,    0,   0 },   f_adjective, { .m = m_nextline } },
     95 { .keyv.i = KEY_DOWN,       { 0,     0,    0,   0 },   f_move,      { .m = m_nextline } },
     96 { .keyv.i = KEY_LEFT,       { t_sent,0,    0,   0 },   f_adjective, { .m = m_prevchar } },
     97 { .keyv.i = KEY_LEFT,       { 0,     0,    0,   0 },   f_move,      { .m = m_prevchar } },
     98 { .keyv.i = KEY_RIGHT,      { t_sent,0,    0,   0 },   f_adjective, { .m = m_nextchar } },
     99 { .keyv.i = KEY_RIGHT,      { 0,     0,    0,   0 },   f_move,      { .m = m_nextchar } },
    100 { .keyv.i = KEY_SLEFT,      { 0,     0,    0,   0 },   f_move,      { .m = m_prevword } },
    101 { .keyv.i = KEY_SRIGHT,     { 0,     0,    0,   0 },   f_move,      { .m = m_nextword } },
    102 };
    103 
    104 static const Key stdkeys[] = {
    105 /* keyv.c,                test,                     func,        arg */
    106 { .keyv.c = CONTROL('@'), { 0,     0,    0,   0 },  f_move,      { .m = m_tomark } },
    107 { .keyv.c = META(' '),    { 0,     0,    0,   0 },  f_mark,      { 0 } },
    108 { .keyv.c = META('`'),    { 0,     0,    0,   0 },  f_mark,      { 0 } },
    109 { .keyv.c = CONTROL('A'), { t_ai,  0,    0,   0 },  f_move,      { .m = m_smartbol } },
    110 { .keyv.c = CONTROL('A'), { 0,     0,    0,   0 },  f_move,      { .m = m_bol } },
    111 { .keyv.c = CONTROL('B'), { 0,     0,    0,   0 },  f_move,      { .m = m_prevchar } },
    112 { .keyv.c = META('b'),    { 0,     0,    0,   0 },  f_move,      { .m = m_prevword } },
    113 { .keyv.c = CONTROL('C'), { t_warn,t_mod,0,   0 },  f_toggle,    { .i = S_Running     } },
    114 { .keyv.c = CONTROL('C'), { t_mod, 0,    0,   0 },  f_toggle,    { .i = S_Warned      } },
    115 { .keyv.c = CONTROL('C'), { 0,     0,    0,   0 },  f_toggle,    { .i = S_Running     } },
    116 { .keyv.c = META('c'),    { t_sel, t_rw, 0,   0 },  f_pipe,      { .v = CAPITALIZE    } },
    117 { .keyv.c = CONTROL('D'), { t_sel, t_rw, 0,   0 },  f_pipe,      { .v = TOCLIP        } },
    118 { .keyv.c = CONTROL('D'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_nextchar    } },
    119 { .keyv.c = META('d'),    { t_rw,  0,    0,   0 },  f_delete,    { .m = m_nextword    } },
    120 { .keyv.c = CONTROL('E'), { 0,     0,    0,   0 },  f_move,      { .m = m_eol         } },
    121 { .keyv.c = CONTROL('F'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextchar    } },
    122 { .keyv.c = META('f'),    { 0,     0,    0,   0 },  f_move,      { .m = m_nextword    } },
    123 { .keyv.c = CONTROL('G'), { t_sel, 0,    0,   0 },  f_select,    { .m = m_stay        } },
    124 { .keyv.c = CONTROL('H'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_prevchar    } },
    125 { .keyv.c = CONTROL('I'), { t_rw,  t_ins,0,   0 },  f_insert,    { .v = "\t"          } },
    126 { .keyv.c = CONTROL('J'), { t_rw,  t_ai, 0,   0 },  f_pipeai,    { .v = AUTOINDENT    } },
    127 { .keyv.c = CONTROL('J'), { t_rw,  t_ins,0,   0 },  f_insert,    { .v = "\n"          } },
    128 { .keyv.c = CONTROL('J'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextline    } },
    129 { .keyv.c = CONTROL('K'), { t_eol, t_rw, 0,   0 },  f_delete,    { .m = m_nextchar    } },
    130 { .keyv.c = CONTROL('K'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_eol         } },
    131 { .keyv.c = CONTROL('L'), { 0,     0,    0,   0 },  f_center,    { 0                  } },
    132 { .keyv.c = META('l'),    { t_sel, t_rw, 0,   0 },  f_pipe,      { .v = "tr [A-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ] [a-zàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ]" } }, /* Lowercase */
    133 { .keyv.c = CONTROL('M'), { t_rw,  t_ai, 0,   0 },  f_pipeai,    { .v = AUTOINDENT    } } ,
    134 { .keyv.c = CONTROL('M'), { t_rw,  t_ins,0,   0 },  f_insert,    { .v = "\n"          } },
    135 { .keyv.c = CONTROL('M'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextline    } },
    136 { .keyv.c = CONTROL('N'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextline    } },
    137 { .keyv.c = CONTROL('O'), { t_sel, 0,    0,   0 },  f_select,    { .m = m_tosel       } }, /* Swap fsel and fcur */
    138 { .keyv.c = CONTROL('P'), { 0,     0,    0,   0 },  f_move,      { .m = m_prevline    } },
    139 { .keyv.c = CONTROL('Q'), { t_rw,  0,    0,   0 },  f_toggle,    { .i = S_InsEsc      } },
    140 { .keyv.c = CONTROL('R'), { t_redo,t_rw, 0,   0 },  f_undo,      { .i = -1            } },
    141 { .keyv.c = META('r'),    { 0,     0,    0,   0 },  f_findbw,    { 0                  } },
    142 { .keyv.c = CONTROL('S'), { t_sel, 0,    0,   0 },  f_findfw,    { 0                  } },
    143 { .keyv.c = CONTROL('S'), { 0,     0,    0,   0 },  f_spawn,     FIND },
    144 { .keyv.c = META('s'),    { 0,     0,    0,   0 },  f_findfw,    { 0                  } },
    145 { .keyv.c = CONTROL('T'), { 0,     0,    0,   0 },  f_pipero ,   { .v = TOCLIP        } },
    146 { .keyv.c = CONTROL('U'), { t_bol, t_rw, 0,   0 },  f_delete,    { .m = m_prevchar    } },
    147 { .keyv.c = CONTROL('U'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_bol         } },
    148 { .keyv.c = META('u'),    { t_sel, t_rw, 0,   0 },  f_pipe,      { .v = "tr [a-zàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ] [A-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ] | sed 's/ß/SS/g'" } }, /* Uppercase */
    149 { .keyv.c = CONTROL('V'), { 0,     0,    0,   0 },  f_move,      { .m = m_prevscr     } },
    150 { .keyv.c = META('v'),    { 0,     0,    0,   0 },  f_move,      { .m = m_nextscr     } },
    151 { .keyv.c = CONTROL('W'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_prevword    } },
    152 { .keyv.c = CONTROL('X'), { t_mod, t_rw, 0,   0 },  f_save,      { 0 } },
    153 { .keyv.c = CONTROL('X'), { 0,     0,    0,   0 },  f_toggle,    { .i = S_Running } },
    154 { .keyv.c = META('x'),    { 0,     0,    0,   0 },  f_spawn,     CMD_P },
    155 { .keyv.c = CONTROL('Y'), { t_rw,  0,    0,   0 },  f_pipenull,  { .v = FROMCLIP } },
    156 { .keyv.c = CONTROL('Z'), { 0,     0,    0,   0 },  f_suspend,   { 0                  } },
    157 { .keyv.c = CONTROL('['), { t_vis, 0,    0,   0 },  f_toggle,    { .i = S_Visual      } },
    158 #if VIM_BINDINGS
    159 { .keyv.c = CONTROL('['), { t_ins, 0,  0,   0 },  f_toggle,    { .i = S_Command     } },
    160 #else
    161 { .keyv.c = CONTROL('['), { 0,     0,    0,   0 },  f_spawn,     CMD_P },
    162 #endif
    163 { .keyv.c = CONTROL('\\'),{ t_rw,  0,    0,   0 },  f_spawn,     PIPE                   },
    164 { .keyv.c = META('\\'),   { t_rw,  0,    0,   0 },  f_spawn,     SED                    },
    165 { .keyv.c = CONTROL(']'), { 0,     0,    0,   0 },  f_extsel,    { .i = ExtDefault    } },
    166 { .keyv.c = CONTROL('^'), { t_redo,t_rw, 0,   0 },  f_undo,      { .i = -1 } },
    167 { .keyv.c = CONTROL('^'), { t_rw,  0,    0,   0 },  f_repeat,    { 0 } },
    168 { .keyv.c = META('6'),    { t_rw,  0,    0,   0 },  f_pipeline,  { .v = "tr '\n' ' '" } }, /* Join lines */
    169 { .keyv.c = META('5'),    { t_sel, t_rw, 0,   0 },  f_spawn,     REPLACE },
    170 { .keyv.c = CONTROL('?'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_prevchar    } },
    171 { .keyv.c = META(','),    { 0,     0,    0,   0 },  f_move,      { .m = m_bof         } },
    172 { .keyv.c = META('.'),    { 0,     0,    0,   0 },  f_move,      { .m = m_eof         } },
    173 };
    174 
    175 #if VIM_BINDINGS
    176 /* TODO: add better paste support (if whole line was yanked, append above,
    177  *       not where you are) */
    178 static const Key commkeys[] = { /* Command mode keys here */
    179 /* keyv.c,                  tests,                     func,       arg */
    180 { .keyv.c = { '$' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_eol          } },
    181 { .keyv.c = { '$' },      { 0,     0,    0,   0 },  f_move,      { .m = m_eol          } },
    182 { .keyv.c = { '^' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_bol          } },
    183 { .keyv.c = { '^' },      { 0,     0,    0,   0 },  f_move,      { .m = m_bol          } },
    184 { .keyv.c = { 'A' },      { 0,     0,    0,   0 },  f_move,      { .m = m_eol          } },
    185 { .keyv.c = { 'A' },      { 0,     0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    186 { .keyv.c = { 'a' },      { t_eol, 0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    187 { .keyv.c = { 'a' },      { 0,     0,    0,   0 },  f_move,      { .m = m_nextchar     } },
    188 { .keyv.c = { 'a' },      { 0,     0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    189 { .keyv.c = { 'b' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_prevword     } },
    190 { .keyv.c = { 'b' },      { 0,     0,    0,   0 },  f_move,      { .m = m_prevword     } },
    191 { .keyv.c = { 'c' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_sentence     } },
    192 { .keyv.c = { 'c' },      { t_rw,  0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    193 { .keyv.c = { 'C' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_eol          } },
    194 { .keyv.c = { 'C' },      { t_rw,  0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    195 { .keyv.c = { 'd' },      { t_sel, t_rw, 0,   0 },  f_delete,    { .m = m_tosel        } },
    196 { .keyv.c = { 'd' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_sentence     } },
    197 /*{ .keyv.c = { 'd' },      { t_rw,  0,    0,   0 },  f_pipe,      { .m = m_sentence, .v = TOCLIP } }, */
    198 { .keyv.c = { 'D' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_eol          } },
    199 { .keyv.c = { 'g' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_bof          } },
    200 { .keyv.c = { 'g' },      { 0,     0,    0,   0 },  f_move,      { .m = m_bof          } },
    201 { .keyv.c = { 'G' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_eof          } },
    202 { .keyv.c = { 'G' },      { 0,     0,    0,   0 },  f_move,      { .m = m_eof          } },
    203 { .keyv.c = { 'h' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_prevchar     } },
    204 { .keyv.c = { 'h' },      { 0,     0,    0,   0 },  f_move,      { .m = m_prevchar     } },
    205 { .keyv.c = { 'i' },      { 0,     0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    206 { .keyv.c = { 'j' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_nextline     } },
    207 { .keyv.c = { 'j' },      { 0,     0,    0,   0 },  f_move,      { .m = m_nextline     } },
    208 { .keyv.c = { 'k' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_prevline     } },
    209 { .keyv.c = { 'k' },      { 0,     0,    0,   0 },  f_move,      { .m = m_prevline     } },
    210 { .keyv.c = { 'l' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_nextchar     } },
    211 { .keyv.c = { 'l' },      { 0,     0,    0,   0 },  f_move,      { .m = m_nextchar     } },
    212 { .keyv.c = { 'm' },      { 0,     0,    0,   0 },  f_mark,      { .i = 0              } },
    213 { .keyv.c = { 'n' },      { 0,     0,    0,   0 },  f_findfw,    { .i = 0              } },
    214 { .keyv.c = { 'N' },      { 0,     0,    0,   0 },  f_findbw,    { .i = 0              } },
    215 { .keyv.c = { 'o' },      { t_rw,  t_ai, 0,   0 },  f_move,      { .m = m_eol          } },
    216 { .keyv.c = { 'o' },      { t_rw,  t_ai, 0,   0 },  f_pipeai,    { .v = AUTOINDENT     } },
    217 { .keyv.c = { 'o' },      { t_rw,  t_ai, 0,   0 },  f_toggle,    { .i = S_Command      } },
    218 { .keyv.c = { 'o' },      { t_rw,  0,    0,   0 },  f_move,      { .m = m_eol          } },
    219 { .keyv.c = { 'o' },      { t_rw,  0,    0,   0 },  f_insert,    { .v = "\n"           } },
    220 { .keyv.c = { 'o' },      { t_rw,  0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    221 { .keyv.c = { 'O' },      { t_rw,  t_ai, 0,   0 },  f_move,      { .m = m_bol          } },
    222 { .keyv.c = { 'O' },      { t_rw,  t_ai, 0,   0 },  f_pipeai,    { .v = AUTOINDENT     } },
    223 { .keyv.c = { 'O' },      { t_rw,  t_ai, 0,   0 },  f_move,      { .m = m_prevline     } },
    224 { .keyv.c = { 'O' },      { t_rw,  t_ai, 0,   0 },  f_toggle,    { .i = S_Command      } },
    225 { .keyv.c = { 'O' },      { t_rw,  0,    0,   0 },  f_move,      { .m = m_bol          } },
    226 { .keyv.c = { 'O' },      { t_rw,  0,    0,   0 },  f_insert,    { .v = "\n"           } },
    227 { .keyv.c = { 'O' },      { t_rw,  0,    0,   0 },  f_move,      { .m = m_prevline     } },
    228 { .keyv.c = { 'O' },      { t_rw,  0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    229 { .keyv.c = { 'p' },      { t_rw,  0,    0,   0 },  f_pipenull,  { .v = FROMCLIP       } },
    230 { .keyv.c = { 's' },      { t_sel, t_rw, 0,   0 },  f_delete,    { .m = m_tosel        } },
    231 { .keyv.c = { 's' },      { t_sel, t_rw, 0,   0 },  f_toggle,    { .i = S_Command      } },
    232 { .keyv.c = { 's' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_nextchar     } },
    233 { .keyv.c = { 's' },      { t_rw,  0,    0,   0 },  f_toggle,    { .i = S_Command      } },
    234 { .keyv.c = { 'u' },      { t_undo,t_rw, 0,   0 },  f_undo,      { .i = 1              } },
    235 { .keyv.c = { 'v' },      { 0,     0,    0,   0 },  f_toggle,    { .i = S_Visual       } },
    236 { .keyv.c = { 'w' },      { t_sent,0,    0,   0 },  f_adjective, { .m = m_nextword     } },
    237 { .keyv.c = { 'w' },      { 0,     0,    0,   0 },  f_move,      { .m = m_nextword     } },
    238 { .keyv.c = { 'x' },      { t_sel, t_rw, 0,   0 },  f_delete,    { .m = m_tosel        } },
    239 { .keyv.c = { 'x' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_nextchar     } },
    240 { .keyv.c = { 'X' },      { t_sel, t_rw, 0,   0 },  f_delete,    { .m = m_tosel        } },
    241 { .keyv.c = { 'X' },      { t_rw,  0,    0,   0 },  f_delete,    { .m = m_prevchar     } },
    242 /* TODO: won't work since Arg is a union */
    243 /*{ .keyv.c = { 'y' },      { t_rw,  0,    0,   0 },  f_pipero,    { .m = m_sentence, .v = TOCLIP } },*/
    244 { .keyv.c = { 'y' },      { t_rw,  0,    0,   0 },  f_pipero,    { .v = TOCLIP         } },
    245 { .keyv.c = { ';' },      { 0,     0,    0,   0 },  f_spawn,     CMD_P                   },
    246 { .keyv.c = { ':' },      { 0,     0,    0,   0 },  f_spawn,     CMD_P                   },
    247 { .keyv.c = { '\'' },     { 0,     0,    0,   0 },  f_move,      { .m = m_tomark       } },
    248 { .keyv.c = { '.' },      { t_rw,  0,    0,   0 },  f_repeat,    { 0                   } },
    249 { .keyv.c = { '/' },      { 0,     0,    0,   0 },  f_spawn,     FIND                    },
    250 { .keyv.c = { ' ' },      { 0,     0,    0,   0 },  f_move,      { .m = m_nextchar     } },
    251 /* TODO: Keybindings left:
    252  * e/E go to the end of the word (adj) (?)
    253  * r replace char (verb)
    254  * t/T do until char (adj)
    255  * i do inside (adj) (ex. diw deletes current word)
    256  * </> ident
    257  */
    258 };
    259 #endif
    260 
    261 #if HANDLE_MOUSE
    262 /*Mouse clicks */
    263 static const Click clks[] = {
    264 /* mouse mask,           fcur / fsel,      tests,               func,       arg */
    265 {BUTTON1_CLICKED,        { TRUE , TRUE  }, { 0,     0,     0 }, 0,          { 0 } },
    266 {BUTTON3_CLICKED,        { TRUE , FALSE }, { t_sel, 0,     0 }, f_pipero,   { .v = TOSEL } },
    267 {BUTTON2_CLICKED,        { FALSE, FALSE }, { t_rw,  0,     0 }, f_pipenull, { .v = FROMSEL } },
    268 {BUTTON4_CLICKED,        { FALSE, FALSE }, { 0,     0,     0 }, f_move,     { .m = m_prevscr } },
    269 #ifdef BUTTON5_CLICKED
    270 {BUTTON5_CLICKED,        { FALSE, FALSE }, { 0,     0,     0 }, f_move,     { .m = m_nextscr } },
    271 #endif
    272 /* ^^ NCurses is a sad old library.... it does not include button 5 nor
    273  *    cursor movement in its mouse declaration by default */
    274 {BUTTON1_DOUBLE_CLICKED, { TRUE , TRUE  }, { 0,     0,     0 }, f_extsel,   { .i = ExtWord }  },
    275 {BUTTON1_TRIPLE_CLICKED, { TRUE , TRUE  }, { 0,     0,     0 }, f_extsel,   { .i = ExtLines }  },
    276 };
    277 #endif /* HANDLE_MOUSE */
    278 
    279 /* Commands read at the fifo */
    280 static const Command cmds[] = { /* REMEMBER: if(arg == 0) arg.v=regex_match */
    281 /* regex,           tests,              func      arg */
    282 {"^([0-9]+)$",      { 0,     0,    0 }, f_line ,  { 0 } },
    283 {"^/(.*)$",         { 0,     0,    0 }, f_findfw, { 0 } },
    284 {"^\\?(.*)$",       { 0,     0,    0 }, f_findbw, { 0 } },
    285 {"^![ \t]*(.*)$",   { t_rw,  0,    0 }, f_pipe,   { 0 } },
    286 {"^![ /t]*(.*)$",   { 0,     0,    0 }, f_pipero, { 0 } },
    287 {"^w[ \t]*(.*)$",   { t_mod, t_rw, 0 }, f_save,   { 0 } },
    288 {"^syntax (.*)$",   { 0,     0,    0 }, f_syntax, { 0 } },
    289 {"^offset (.*)$",   { 0,     0,    0 }, f_offset, { 0 } },
    290 {"^icase$",         { 0,     0,    0 }, f_toggle, { .i = S_CaseIns } },
    291 {"^ro$",            { 0,     0,    0 }, f_toggle, { .i = S_Readonly } },
    292 {"^ai$",            { 0,     0,    0 }, f_toggle, { .i = S_AutoIndent } },
    293 {"^dump$",          { 0,     0,    0 }, f_toggle, { .i = S_DumpStdout } },
    294 {"^q$",             { t_mod, 0,    0 }, f_toggle, { .i = S_Warned } },
    295 {"^q$",             { 0,     0,    0 }, f_toggle, { .i = S_Running } },
    296 {"^q!$",            { 0,     0,    0 }, f_toggle, { .i = S_Running } },
    297 };
    298 
    299 /* Syntax color definition */
    300 #define B "\\b"
    301 /* #define B "^| |\t|\\(|\\)|\\[|\\]|\\{|\\}|\\||$"  -- Use this if \b is not in your libc's regex implementation */
    302 
    303 static const Syntax syntaxes[] = {
    304 #if HILIGHT_SYNTAX
    305 {"c", "\\.([ch](pp|xx)?|cc)$", {
    306 	/* HiRed   */  "$^",
    307 	/* HiGreen */  B"(for|if|while|do|else|case|default|switch|try|throw|catch|operator|new|delete)"B,
    308 	/* LoGreen */  B"(float|double|bool|char|int|short|long|sizeof|enum|void|static|const|struct|union|typedef|extern|(un)?signed|inline|((s?size)|((u_?)?int(8|16|32|64|ptr)))_t|class|namespace|template|public|protected|private|typename|this|friend|virtual|using|mutable|volatile|register|explicit)"B,
    309 	/* HiMag   */  B"(goto|continue|break|return)"B,
    310 	/* LoMag   */  "(^#(define|include(_next)?|(un|ifn?)def|endif|el(if|se)|if|warning|error|pragma))|"B"[A-Z_][0-9A-Z_]+"B"",
    311 	/* HiBlue  */  "(\\(|\\)|\\{|\\}|\\[|\\])",
    312 	/* LoRed   */  "(\"(\\\\.|[^\"])*\")",
    313 	/* LoBlue  */  "(//.*|/\\*([^*]|\\*[^/])*\\*/|/\\*([^*]|\\*[^/])*$|^([^/]|/[^*])*\\*/)",
    314 	} },
    315 
    316 {"sh", "\\.sh$", {
    317 	/* HiRed   */  "$^",
    318 	/* HiGreen */  "^[0-9A-Z_]+\\(\\)",
    319 	/* LoGreen */  B"(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)"B,
    320 	/* HiMag   */  "$^",
    321 	/* LoMag   */  "\"(\\\\.|[^\"])*\"",
    322 	/* HiBlue  */  "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)",
    323 	/* LoRed   */  "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?",
    324 	/* LoBlue  */  "#.*$",
    325 	} },
    326 
    327 {"makefile", "(Makefile[^/]*|\\.mk)$", {
    328 	/* HiRed   */  "$^",
    329 	/* HiGreen */  "$^",
    330 	/* LoGreen */  "\\$+[{(][a-zA-Z0-9_-]+[})]",
    331 	/* HiMag   */  B"(if|ifeq|else|endif)"B,
    332 	/* LoMag   */  "$^",
    333 	/* HiBlue  */  "^[^ 	]+:",
    334 	/* LoRed   */  "[:=]",
    335 	/* LoBlue  */  "#.*$",
    336 	} },
    337 
    338 {"man", "\\.[1-9]x?$", {
    339 	/* HiRed   */  "\\.(BR?|I[PR]?).*$",
    340 	/* HiGreen */  "$^",
    341 	/* LoGreen */  "\\.(S|T)H.*$",
    342 	/* HiMag   */  "\\.(br|DS|RS|RE|PD)",
    343 	/* LoMag   */  "(\\.(S|T)H|\\.TP)",
    344 	/* HiBlue  */  "\\.(BR?|I[PR]?|PP)",
    345 	/* LoRed   */  "$^",
    346 	/* LoBlue  */  "\\\\f[BIPR]",
    347 	} },
    348 
    349 {"vala", "\\.(vapi|vala)$", {
    350 	/* HiRed   */  B"[A-Z_][0-9A-Z_]+"B,
    351 	/* HiGreen */  B"(for|if|while|do|else|case|default|switch|get|set|value|out|ref|enum)"B,
    352 	/* LoGreen */  B"(uint|uint8|uint16|uint32|uint64|bool|byte|ssize_t|size_t|char|double|string|float|int|long|short|this|base|transient|void|true|false|null|unowned|owned)"B,
    353 	/* HiMag   */  B"(try|catch|throw|finally|continue|break|return|new|sizeof|signal|delegate)"B,
    354 	/* LoMag   */  B"(abstract|class|final|implements|import|instanceof|interface|using|private|public|static|strictfp|super|throws)"B,
    355 	/* HiBlue  */  "(\\(|\\)|\\{|\\}|\\[|\\])",
    356 	/* LoRed   */  "\"(\\\\.|[^\"])*\"",
    357 	/* LoBlue  */  "(//.*|/\\*([^*]|\\*[^/])*\\*/|/\\*([^*]|\\*[^/])*$|^([^/]|/[^*])*\\*/)",
    358 	} },
    359 {"java", "\\.java$", {
    360 	/* HiRed   */  B"[A-Z_][0-9A-Z_]+"B,
    361 	/* HiGreen */  B"(for|if|while|do|else|case|default|switch)"B,
    362 	/* LoGreen */  B"(boolean|byte|char|double|float|int|long|short|transient|void|true|false|null)"B,
    363 	/* HiMag   */  B"(try|catch|throw|finally|continue|break|return|new)"B,
    364 	/* LoMag   */  B"(abstract|class|extends|final|implements|import|instanceof|interface|native|package|private|protected|public|static|strictfp|this|super|synchronized|throws|volatile)"B,
    365 	/* HiBlue  */  "(\\(|\\)|\\{|\\}|\\[|\\])",
    366 	/* LoRed   */  "\"(\\\\.|[^\"])*\"",
    367 	/* LoBlue  */  "(//.*|/\\*([^*]|\\*[^/])*\\*/|/\\*([^*]|\\*[^/])*$|^([^/]|/[^*])*\\*/)",
    368 	} },
    369 {"ruby", "\\.rb$", {
    370 	/* HiRed   */  "(\\$|@|@@)?"B"[A-Z]+[0-9A-Z_a-z]*",
    371 	/* HiGreen */  B"(__FILE__|__LINE__|BEGIN|END|alias|and|begin|break|case|class|def|defined\?|do|else|elsif|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)"B,
    372 	/* LoGreen */  "([ 	]|^):[0-9A-Z_]+"B,
    373 	/* HiMag   */  "(/([^/]|(\\/))*/[iomx]*|%r\\{([^}]|(\\}))*\\}[iomx]*)",
    374 	/* LoMag   */  "(`[^`]*`|%x\\{[^}]*\\})",
    375 	/* HiBlue  */  "(\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!|\'([^\']|(\\\\\'))*\'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!)",
    376 	/* LoRed   */  "#\\{[^}]*\\}",
    377 	/* LoBlue  */  "(#[^{].*$|#$)",
    378 	} },
    379 #else  /* HILIGHT_SYNTAX */
    380 {"", "\0", { "\0", "\0", "\0", "\0", "\0", "\0", "\0", "\0" } }
    381 #endif /* HILIGHT_SYNTAX */
    382 };
    383 
    384 /* Colors */
    385 static const short  fgcolors[LastFG] = {
    386 	[DefFG]  = -1,
    387 	[CurFG]  = (HILIGHT_CURRENT?COLOR_BLACK : -1),
    388 	[SelFG]  = COLOR_BLACK,
    389 	[SpcFG]  = COLOR_WHITE,
    390 	[CtrlFG] = COLOR_RED,
    391 	[Syn0FG] = COLOR_RED,
    392 	[Syn1FG] = COLOR_GREEN,
    393 	[Syn2FG] = COLOR_GREEN,
    394 	[Syn3FG] = COLOR_MAGENTA,
    395 	[Syn4FG] = COLOR_MAGENTA,
    396 	[Syn5FG] = COLOR_BLUE,
    397 	[Syn6FG] = COLOR_RED,
    398 	[Syn7FG] = COLOR_BLUE,
    399 };
    400 
    401 static const int colorattrs[LastFG] = {
    402 	[DefFG]  = 0,
    403 	[CurFG]  = 0,
    404 	[SelFG]  = 0,
    405 	[SpcFG]  = A_DIM,
    406 	[CtrlFG] = A_DIM,
    407 	[Syn0FG] = A_BOLD,
    408 	[Syn1FG] = A_BOLD,
    409 	[Syn2FG] = 0,
    410 	[Syn3FG] = A_BOLD,
    411 	[Syn4FG] = 0,
    412 	[Syn5FG] = A_BOLD,
    413 	[Syn6FG] = 0,
    414 	[Syn7FG] = 0,
    415 };
    416 
    417 static const int bwattrs[LastFG] = {
    418 	[DefFG]  = 0,
    419 	[CurFG]  = 0,
    420 	[SelFG]  = A_REVERSE,
    421 	[SpcFG]  = A_DIM,
    422 	[CtrlFG] = A_DIM,
    423 	[Syn0FG] = A_BOLD,
    424 	[Syn1FG] = A_BOLD,
    425 	[Syn2FG] = A_BOLD,
    426 	[Syn3FG] = A_BOLD,
    427 	[Syn4FG] = A_BOLD,
    428 	[Syn5FG] = A_BOLD,
    429 	[Syn6FG] = A_BOLD,
    430 	[Syn7FG] = A_BOLD,
    431 };
    432 
    433 static const short bgcolors[LastBG] = {
    434 	[DefBG] = -1,
    435 	[CurBG] = (HILIGHT_CURRENT ? COLOR_CYAN : -1),
    436 	[SelBG] = COLOR_YELLOW,
    437 };
    438 
    439 /* Helper config functions implementation */
    440 void /* Pipe selection from bol, then select last line only, special for autoindenting */
    441 f_pipeai(const Arg *arg) {
    442 	i_sortpos(&fsel, &fcur);
    443 	fsel.o = 0;
    444 	f_pipe(arg);
    445 	fsel = fcur;
    446 }
    447 
    448 void /* Pipe full lines including the selection */
    449 f_pipeline(const Arg *arg) {
    450 	f_extsel(&(const Arg){ .i = ExtLines });
    451 	f_pipe(arg);
    452 }
    453 
    454 void /* Pipe empty text */
    455 f_pipenull(const Arg *arg) {
    456 	fsel = fcur;
    457 	f_pipe(arg);
    458 }