input.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. /*
  2. Widgets for the Midnight Commander
  3. Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
  4. 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2013
  5. The Free Software Foundation, Inc.
  6. Authors:
  7. Radek Doulik, 1994, 1995
  8. Miguel de Icaza, 1994, 1995
  9. Jakub Jelinek, 1995
  10. Andrej Borsenkow, 1996
  11. Norbert Warmuth, 1997
  12. Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2013
  13. This file is part of the Midnight Commander.
  14. The Midnight Commander is free software: you can redistribute it
  15. and/or modify it under the terms of the GNU General Public License as
  16. published by the Free Software Foundation, either version 3 of the License,
  17. or (at your option) any later version.
  18. The Midnight Commander is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. GNU General Public License for more details.
  22. You should have received a copy of the GNU General Public License
  23. along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. /** \file input.c
  26. * \brief Source: WInput widget
  27. */
  28. #include <config.h>
  29. #include <stdlib.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #include "lib/global.h"
  34. #include "lib/tty/tty.h"
  35. #include "lib/tty/mouse.h"
  36. #include "lib/tty/key.h" /* XCTRL and ALT macros */
  37. #include "lib/fileloc.h"
  38. #include "lib/skin.h"
  39. #include "lib/strutil.h"
  40. #include "lib/util.h"
  41. #include "lib/keybind.h" /* global_keymap_t */
  42. #include "lib/widget.h"
  43. #include "lib/event.h" /* mc_event_raise() */
  44. #include "input_complete.h"
  45. /*** global variables ****************************************************************************/
  46. int quote = 0;
  47. const global_keymap_t *input_map = NULL;
  48. /*** file scope macro definitions ****************************************************************/
  49. #define LARGE_HISTORY_BUTTON 1
  50. #ifdef LARGE_HISTORY_BUTTON
  51. #define HISTORY_BUTTON_WIDTH 3
  52. #else
  53. #define HISTORY_BUTTON_WIDTH 1
  54. #endif
  55. #define should_show_history_button(in) \
  56. (in->history.list != NULL && WIDGET (in)->cols > HISTORY_BUTTON_WIDTH * 2 + 1 \
  57. && WIDGET (in)->owner != NULL)
  58. /*** file scope type declarations ****************************************************************/
  59. /*** file scope variables ************************************************************************/
  60. /* Input widgets have a global kill ring */
  61. /* Pointer to killed data */
  62. static char *kill_buffer = NULL;
  63. /*** file scope functions ************************************************************************/
  64. /* --------------------------------------------------------------------------------------------- */
  65. static size_t
  66. get_history_length (const GList * history)
  67. {
  68. size_t len = 0;
  69. for (; history != NULL; history = g_list_previous (history))
  70. len++;
  71. return len;
  72. }
  73. /* --------------------------------------------------------------------------------------------- */
  74. static void
  75. draw_history_button (WInput * in)
  76. {
  77. char c;
  78. gboolean disabled = (WIDGET (in)->options & W_DISABLED) != 0;
  79. if (g_list_next (in->history.current) == NULL)
  80. c = '^';
  81. else if (g_list_previous (in->history.current) == NULL)
  82. c = 'v';
  83. else
  84. c = '|';
  85. widget_move (in, 0, WIDGET (in)->cols - HISTORY_BUTTON_WIDTH);
  86. tty_setcolor (disabled ? DISABLED_COLOR : in->color[WINPUTC_HISTORY]);
  87. #ifdef LARGE_HISTORY_BUTTON
  88. tty_print_string ("[ ]");
  89. widget_move (in, 0, WIDGET (in)->cols - HISTORY_BUTTON_WIDTH + 1);
  90. #endif
  91. tty_print_char (c);
  92. }
  93. /* --------------------------------------------------------------------------------------------- */
  94. static void
  95. input_set_markers (WInput * in, long m1)
  96. {
  97. in->mark = m1;
  98. }
  99. /* --------------------------------------------------------------------------------------------- */
  100. static void
  101. input_mark_cmd (WInput * in, gboolean mark)
  102. {
  103. if (mark == 0)
  104. {
  105. in->highlight = FALSE;
  106. input_set_markers (in, 0);
  107. }
  108. else
  109. {
  110. in->highlight = TRUE;
  111. input_set_markers (in, in->point);
  112. }
  113. }
  114. /* --------------------------------------------------------------------------------------------- */
  115. static gboolean
  116. input_eval_marks (WInput * in, long *start_mark, long *end_mark)
  117. {
  118. if (in->highlight)
  119. {
  120. *start_mark = min (in->mark, in->point);
  121. *end_mark = max (in->mark, in->point);
  122. return TRUE;
  123. }
  124. else
  125. {
  126. *start_mark = *end_mark = 0;
  127. return FALSE;
  128. }
  129. }
  130. /* --------------------------------------------------------------------------------------------- */
  131. static void
  132. delete_region (WInput * in, int x_first, int x_last)
  133. {
  134. int first = min (x_first, x_last);
  135. int last = max (x_first, x_last);
  136. size_t len;
  137. input_mark_cmd (in, FALSE);
  138. in->point = first;
  139. last = str_offset_to_pos (in->buffer, last);
  140. first = str_offset_to_pos (in->buffer, first);
  141. len = strlen (&in->buffer[last]) + 1;
  142. memmove (&in->buffer[first], &in->buffer[last], len);
  143. in->charpoint = 0;
  144. in->need_push = TRUE;
  145. }
  146. /* --------------------------------------------------------------------------------------------- */
  147. static void
  148. do_show_hist (WInput * in)
  149. {
  150. size_t len;
  151. char *r;
  152. len = get_history_length (in->history.list);
  153. r = history_show (&in->history.list, WIDGET (in),
  154. g_list_position (in->history.list, in->history.list));
  155. if (r != NULL)
  156. {
  157. input_assign_text (in, r);
  158. g_free (r);
  159. }
  160. /* Has history cleaned up or not? */
  161. if (len != get_history_length (in->history.list))
  162. in->history.changed = TRUE;
  163. }
  164. /* --------------------------------------------------------------------------------------------- */
  165. /**
  166. * Strip password from incomplete url (just user:pass@host without VFS prefix).
  167. *
  168. * @param url partial URL
  169. * @return newly allocated string without password
  170. */
  171. static char *
  172. input_history_strip_password (char *url)
  173. {
  174. char *at, *delim, *colon;
  175. at = strrchr (url, '@');
  176. if (at == NULL)
  177. return g_strdup (url);
  178. /* TODO: handle ':' and '@' in password */
  179. delim = strstr (url, VFS_PATH_URL_DELIMITER);
  180. if (delim != NULL)
  181. colon = strchr (delim + strlen (VFS_PATH_URL_DELIMITER), ':');
  182. else
  183. colon = strchr (url, ':');
  184. /* if 'colon' before 'at', 'colon' delimits user and password: user:password@host */
  185. /* if 'colon' after 'at', 'colon' delimits host and port: user@host:port */
  186. if (colon != NULL && colon > at)
  187. colon = NULL;
  188. if (colon == NULL)
  189. return g_strdup (url);
  190. *colon = '\0';
  191. return g_strconcat (url, at, NULL);
  192. }
  193. /* --------------------------------------------------------------------------------------------- */
  194. static void
  195. push_history (WInput * in, const char *text)
  196. {
  197. char *t;
  198. gboolean empty;
  199. if (text == NULL)
  200. return;
  201. t = g_strstrip (g_strdup (text));
  202. empty = *t == '\0';
  203. g_free (t);
  204. t = g_strdup (empty ? "" : text);
  205. if (!empty && in->history.name != NULL && in->strip_password)
  206. {
  207. /*
  208. We got string user:pass@host without any VFS prefixes
  209. and vfs_path_to_str_flags (t, VPF_STRIP_PASSWORD) doesn't work.
  210. Therefore we want to strip password in separate algorithm
  211. */
  212. char *url_with_stripped_password;
  213. url_with_stripped_password = input_history_strip_password (t);
  214. g_free (t);
  215. t = url_with_stripped_password;
  216. }
  217. if (in->history.list == NULL || in->history.list->data == NULL
  218. || strcmp (in->history.list->data, t) != 0 || in->history.changed)
  219. {
  220. in->history.list = list_append_unique (in->history.list, t);
  221. in->history.current = in->history.list;
  222. in->history.changed = TRUE;
  223. }
  224. else
  225. g_free (t);
  226. in->need_push = FALSE;
  227. }
  228. /* --------------------------------------------------------------------------------------------- */
  229. static void
  230. move_buffer_backward (WInput * in, int start, int end)
  231. {
  232. int i, pos, len;
  233. int str_len;
  234. str_len = str_length (in->buffer);
  235. if (start >= str_len || end > str_len + 1)
  236. return;
  237. pos = str_offset_to_pos (in->buffer, start);
  238. len = str_offset_to_pos (in->buffer, end) - pos;
  239. for (i = pos; in->buffer[i + len - 1]; i++)
  240. in->buffer[i] = in->buffer[i + len];
  241. }
  242. /* --------------------------------------------------------------------------------------------- */
  243. static cb_ret_t
  244. insert_char (WInput * in, int c_code)
  245. {
  246. size_t i;
  247. int res;
  248. if (in->highlight)
  249. {
  250. long m1, m2;
  251. if (input_eval_marks (in, &m1, &m2))
  252. delete_region (in, m1, m2);
  253. }
  254. if (c_code == -1)
  255. return MSG_NOT_HANDLED;
  256. if (in->charpoint >= MB_LEN_MAX)
  257. return MSG_HANDLED;
  258. in->charbuf[in->charpoint] = c_code;
  259. in->charpoint++;
  260. res = str_is_valid_char (in->charbuf, in->charpoint);
  261. if (res < 0)
  262. {
  263. if (res != -2)
  264. in->charpoint = 0; /* broken multibyte char, skip */
  265. return MSG_HANDLED;
  266. }
  267. in->need_push = TRUE;
  268. if (strlen (in->buffer) + 1 + in->charpoint >= in->current_max_size)
  269. {
  270. /* Expand the buffer */
  271. size_t new_length;
  272. char *narea;
  273. new_length = in->current_max_size + WIDGET (in)->cols + in->charpoint;
  274. narea = g_try_renew (char, in->buffer, new_length);
  275. if (narea != NULL)
  276. {
  277. in->buffer = narea;
  278. in->current_max_size = new_length;
  279. }
  280. }
  281. if (strlen (in->buffer) + in->charpoint < in->current_max_size)
  282. {
  283. /* bytes from begin */
  284. size_t ins_point = str_offset_to_pos (in->buffer, in->point);
  285. /* move chars */
  286. size_t rest_bytes = strlen (in->buffer + ins_point);
  287. for (i = rest_bytes + 1; i > 0; i--)
  288. in->buffer[ins_point + i + in->charpoint - 1] = in->buffer[ins_point + i - 1];
  289. memcpy (in->buffer + ins_point, in->charbuf, in->charpoint);
  290. in->point++;
  291. }
  292. in->charpoint = 0;
  293. return MSG_HANDLED;
  294. }
  295. /* --------------------------------------------------------------------------------------------- */
  296. static void
  297. beginning_of_line (WInput * in)
  298. {
  299. in->point = 0;
  300. in->charpoint = 0;
  301. }
  302. /* --------------------------------------------------------------------------------------------- */
  303. static void
  304. end_of_line (WInput * in)
  305. {
  306. in->point = str_length (in->buffer);
  307. in->charpoint = 0;
  308. }
  309. /* --------------------------------------------------------------------------------------------- */
  310. static void
  311. backward_char (WInput * in)
  312. {
  313. const char *act;
  314. act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  315. if (in->point > 0)
  316. in->point -= str_cprev_noncomb_char (&act, in->buffer);
  317. in->charpoint = 0;
  318. }
  319. /* --------------------------------------------------------------------------------------------- */
  320. static void
  321. forward_char (WInput * in)
  322. {
  323. const char *act;
  324. act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  325. if (act[0] != '\0')
  326. in->point += str_cnext_noncomb_char (&act);
  327. in->charpoint = 0;
  328. }
  329. /* --------------------------------------------------------------------------------------------- */
  330. static void
  331. forward_word (WInput * in)
  332. {
  333. const char *p;
  334. p = in->buffer + str_offset_to_pos (in->buffer, in->point);
  335. while (p[0] != '\0' && (str_isspace (p) || str_ispunct (p)))
  336. {
  337. str_cnext_char (&p);
  338. in->point++;
  339. }
  340. while (p[0] != '\0' && !str_isspace (p) && !str_ispunct (p))
  341. {
  342. str_cnext_char (&p);
  343. in->point++;
  344. }
  345. }
  346. /* --------------------------------------------------------------------------------------------- */
  347. static void
  348. backward_word (WInput * in)
  349. {
  350. const char *p, *p_tmp;
  351. for (p = in->buffer + str_offset_to_pos (in->buffer, in->point);
  352. (p != in->buffer) && (p[0] == '\0'); str_cprev_char (&p), in->point--);
  353. while (p != in->buffer)
  354. {
  355. p_tmp = p;
  356. str_cprev_char (&p);
  357. if (!str_isspace (p) && !str_ispunct (p))
  358. {
  359. p = p_tmp;
  360. break;
  361. }
  362. in->point--;
  363. }
  364. while (p != in->buffer)
  365. {
  366. str_cprev_char (&p);
  367. if (str_isspace (p) || str_ispunct (p))
  368. break;
  369. in->point--;
  370. }
  371. }
  372. /* --------------------------------------------------------------------------------------------- */
  373. static void
  374. backward_delete (WInput * in)
  375. {
  376. const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  377. int start;
  378. if (in->point == 0)
  379. return;
  380. start = in->point - str_cprev_noncomb_char (&act, in->buffer);
  381. move_buffer_backward (in, start, in->point);
  382. in->charpoint = 0;
  383. in->need_push = TRUE;
  384. in->point = start;
  385. }
  386. /* --------------------------------------------------------------------------------------------- */
  387. static void
  388. delete_char (WInput * in)
  389. {
  390. const char *act;
  391. int end = in->point;
  392. act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  393. end += str_cnext_noncomb_char (&act);
  394. move_buffer_backward (in, in->point, end);
  395. in->charpoint = 0;
  396. in->need_push = TRUE;
  397. }
  398. /* --------------------------------------------------------------------------------------------- */
  399. static void
  400. copy_region (WInput * in, int x_first, int x_last)
  401. {
  402. int first = min (x_first, x_last);
  403. int last = max (x_first, x_last);
  404. if (last == first)
  405. {
  406. /* Copy selected files to clipboard */
  407. mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "panel_save_current_file_to_clip_file", NULL);
  408. /* try use external clipboard utility */
  409. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
  410. return;
  411. }
  412. g_free (kill_buffer);
  413. first = str_offset_to_pos (in->buffer, first);
  414. last = str_offset_to_pos (in->buffer, last);
  415. kill_buffer = g_strndup (in->buffer + first, last - first);
  416. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_text_to_file", kill_buffer);
  417. /* try use external clipboard utility */
  418. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
  419. }
  420. /* --------------------------------------------------------------------------------------------- */
  421. static void
  422. kill_word (WInput * in)
  423. {
  424. int old_point = in->point;
  425. int new_point;
  426. forward_word (in);
  427. new_point = in->point;
  428. in->point = old_point;
  429. delete_region (in, old_point, new_point);
  430. in->need_push = TRUE;
  431. in->charpoint = 0;
  432. }
  433. /* --------------------------------------------------------------------------------------------- */
  434. static void
  435. back_kill_word (WInput * in)
  436. {
  437. int old_point = in->point;
  438. int new_point;
  439. backward_word (in);
  440. new_point = in->point;
  441. in->point = old_point;
  442. delete_region (in, old_point, new_point);
  443. in->need_push = TRUE;
  444. }
  445. /* --------------------------------------------------------------------------------------------- */
  446. static void
  447. yank (WInput * in)
  448. {
  449. if (kill_buffer != NULL)
  450. {
  451. char *p;
  452. in->charpoint = 0;
  453. for (p = kill_buffer; *p != '\0'; p++)
  454. insert_char (in, *p);
  455. in->charpoint = 0;
  456. }
  457. }
  458. /* --------------------------------------------------------------------------------------------- */
  459. static void
  460. kill_line (WInput * in)
  461. {
  462. int chp;
  463. chp = str_offset_to_pos (in->buffer, in->point);
  464. g_free (kill_buffer);
  465. kill_buffer = g_strdup (&in->buffer[chp]);
  466. in->buffer[chp] = '\0';
  467. in->charpoint = 0;
  468. }
  469. /* --------------------------------------------------------------------------------------------- */
  470. static void
  471. clear_line (WInput * in)
  472. {
  473. in->need_push = TRUE;
  474. in->buffer[0] = '\0';
  475. in->point = 0;
  476. in->mark = 0;
  477. in->highlight = FALSE;
  478. in->charpoint = 0;
  479. }
  480. /* --------------------------------------------------------------------------------------------- */
  481. static void
  482. ins_from_clip (WInput * in)
  483. {
  484. char *p = NULL;
  485. ev_clipboard_text_from_file_t event_data;
  486. /* try use external clipboard utility */
  487. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
  488. event_data.text = &p;
  489. mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_text_from_file", &event_data);
  490. if (event_data.ret)
  491. {
  492. char *pp;
  493. for (pp = p; *pp != '\0'; pp++)
  494. insert_char (in, *pp);
  495. g_free (p);
  496. }
  497. }
  498. /* --------------------------------------------------------------------------------------------- */
  499. static void
  500. hist_prev (WInput * in)
  501. {
  502. GList *prev;
  503. if (in->history.list == NULL)
  504. return;
  505. if (in->need_push)
  506. push_history (in, in->buffer);
  507. prev = g_list_previous (in->history.current);
  508. if (prev != NULL)
  509. {
  510. input_assign_text (in, (char *) prev->data);
  511. in->history.current = prev;
  512. in->history.changed = TRUE;
  513. in->need_push = FALSE;
  514. }
  515. }
  516. /* --------------------------------------------------------------------------------------------- */
  517. static void
  518. hist_next (WInput * in)
  519. {
  520. GList *next;
  521. if (in->need_push)
  522. {
  523. push_history (in, in->buffer);
  524. input_assign_text (in, "");
  525. return;
  526. }
  527. if (in->history.list == NULL)
  528. return;
  529. next = g_list_next (in->history.current);
  530. if (next == NULL)
  531. {
  532. input_assign_text (in, "");
  533. in->history.current = in->history.list;
  534. }
  535. else
  536. {
  537. input_assign_text (in, (char *) next->data);
  538. in->history.current = next;
  539. in->history.changed = TRUE;
  540. in->need_push = FALSE;
  541. }
  542. }
  543. /* --------------------------------------------------------------------------------------------- */
  544. static void
  545. port_region_marked_for_delete (WInput * in)
  546. {
  547. in->buffer[0] = '\0';
  548. in->point = 0;
  549. in->first = FALSE;
  550. in->charpoint = 0;
  551. }
  552. /* --------------------------------------------------------------------------------------------- */
  553. static cb_ret_t
  554. input_execute_cmd (WInput * in, unsigned long command)
  555. {
  556. cb_ret_t res = MSG_HANDLED;
  557. /* a highlight command like shift-arrow */
  558. if (command == CK_MarkLeft || command == CK_MarkRight ||
  559. command == CK_MarkToWordBegin || command == CK_MarkToWordEnd ||
  560. command == CK_MarkToHome || command == CK_MarkToEnd)
  561. {
  562. if (!in->highlight)
  563. {
  564. input_mark_cmd (in, FALSE); /* clear */
  565. input_mark_cmd (in, TRUE); /* marking on */
  566. }
  567. }
  568. switch (command)
  569. {
  570. case CK_WordRight:
  571. case CK_WordLeft:
  572. case CK_Right:
  573. case CK_Left:
  574. if (in->highlight)
  575. input_mark_cmd (in, FALSE);
  576. }
  577. switch (command)
  578. {
  579. case CK_Home:
  580. case CK_MarkToHome:
  581. beginning_of_line (in);
  582. break;
  583. case CK_End:
  584. case CK_MarkToEnd:
  585. end_of_line (in);
  586. break;
  587. case CK_Left:
  588. case CK_MarkLeft:
  589. backward_char (in);
  590. break;
  591. case CK_WordLeft:
  592. case CK_MarkToWordBegin:
  593. backward_word (in);
  594. break;
  595. case CK_Right:
  596. case CK_MarkRight:
  597. forward_char (in);
  598. break;
  599. case CK_WordRight:
  600. case CK_MarkToWordEnd:
  601. forward_word (in);
  602. break;
  603. case CK_BackSpace:
  604. if (in->highlight)
  605. {
  606. long m1, m2;
  607. if (input_eval_marks (in, &m1, &m2))
  608. delete_region (in, m1, m2);
  609. }
  610. else
  611. backward_delete (in);
  612. break;
  613. case CK_Delete:
  614. if (in->first)
  615. port_region_marked_for_delete (in);
  616. else if (in->highlight)
  617. {
  618. long m1, m2;
  619. if (input_eval_marks (in, &m1, &m2))
  620. delete_region (in, m1, m2);
  621. }
  622. else
  623. delete_char (in);
  624. break;
  625. case CK_DeleteToWordEnd:
  626. kill_word (in);
  627. break;
  628. case CK_DeleteToWordBegin:
  629. back_kill_word (in);
  630. break;
  631. case CK_Mark:
  632. input_mark_cmd (in, TRUE);
  633. break;
  634. case CK_Remove:
  635. delete_region (in, in->point, in->mark);
  636. break;
  637. case CK_DeleteToEnd:
  638. kill_line (in);
  639. break;
  640. case CK_Clear:
  641. clear_line (in);
  642. break;
  643. case CK_Store:
  644. copy_region (in, in->mark, in->point);
  645. break;
  646. case CK_Cut:
  647. copy_region (in, in->mark, in->point);
  648. delete_region (in, in->point, in->mark);
  649. break;
  650. case CK_Yank:
  651. yank (in);
  652. break;
  653. case CK_Paste:
  654. ins_from_clip (in);
  655. break;
  656. case CK_HistoryPrev:
  657. hist_prev (in);
  658. break;
  659. case CK_HistoryNext:
  660. hist_next (in);
  661. break;
  662. case CK_History:
  663. do_show_hist (in);
  664. break;
  665. case CK_Complete:
  666. complete (in);
  667. break;
  668. default:
  669. res = MSG_NOT_HANDLED;
  670. }
  671. if (command != CK_MarkLeft && command != CK_MarkRight &&
  672. command != CK_MarkToWordBegin && command != CK_MarkToWordEnd &&
  673. command != CK_MarkToHome && command != CK_MarkToEnd)
  674. in->highlight = FALSE;
  675. return res;
  676. }
  677. /* --------------------------------------------------------------------------------------------- */
  678. /* "history_load" event handler */
  679. static gboolean
  680. input_load_history (const gchar * event_group_name, const gchar * event_name,
  681. gpointer init_data, gpointer data)
  682. {
  683. WInput *in = INPUT (init_data);
  684. ev_history_load_save_t *ev = (ev_history_load_save_t *) data;
  685. (void) event_group_name;
  686. (void) event_name;
  687. in->history.list = history_load (ev->cfg, in->history.name);
  688. in->history.current = in->history.list;
  689. if (in->init_from_history)
  690. {
  691. const char *def_text = "";
  692. if (in->history.list != NULL && in->history.list->data != NULL)
  693. def_text = (const char *) in->history.list->data;
  694. input_assign_text (in, def_text);
  695. }
  696. return TRUE;
  697. }
  698. /* --------------------------------------------------------------------------------------------- */
  699. /* "history_save" event handler */
  700. static gboolean
  701. input_save_history (const gchar * event_group_name, const gchar * event_name,
  702. gpointer init_data, gpointer data)
  703. {
  704. WInput *in = INPUT (init_data);
  705. (void) event_group_name;
  706. (void) event_name;
  707. if (!in->is_password && (WIDGET (in)->owner->ret_value != B_CANCEL))
  708. {
  709. ev_history_load_save_t *ev = (ev_history_load_save_t *) data;
  710. push_history (in, in->buffer);
  711. if (in->history.changed)
  712. history_save (ev->cfg, in->history.name, in->history.list);
  713. in->history.changed = FALSE;
  714. }
  715. return TRUE;
  716. }
  717. /* --------------------------------------------------------------------------------------------- */
  718. static void
  719. input_destroy (WInput * in)
  720. {
  721. if (in == NULL)
  722. {
  723. fprintf (stderr, "Internal error: null Input *\n");
  724. exit (EXIT_FAILURE);
  725. }
  726. input_free_completions (in);
  727. /* clean history */
  728. if (in->history.list != NULL)
  729. {
  730. /* history is already saved before this moment */
  731. in->history.list = g_list_first (in->history.list);
  732. g_list_foreach (in->history.list, (GFunc) g_free, NULL);
  733. g_list_free (in->history.list);
  734. }
  735. g_free (in->history.name);
  736. g_free (in->buffer);
  737. g_free (kill_buffer);
  738. kill_buffer = NULL;
  739. }
  740. /* --------------------------------------------------------------------------------------------- */
  741. static int
  742. input_event (Gpm_Event * event, void *data)
  743. {
  744. WInput *in = INPUT (data);
  745. Widget *w = WIDGET (data);
  746. if (!mouse_global_in_widget (event, w))
  747. return MOU_UNHANDLED;
  748. if ((event->type & GPM_DOWN) != 0)
  749. {
  750. in->first = FALSE;
  751. input_mark_cmd (in, FALSE);
  752. }
  753. if ((event->type & (GPM_DOWN | GPM_DRAG)) != 0)
  754. {
  755. Gpm_Event local;
  756. local = mouse_get_local (event, w);
  757. dlg_select_widget (w);
  758. if (local.x >= w->cols - HISTORY_BUTTON_WIDTH + 1 && should_show_history_button (in))
  759. do_show_hist (in);
  760. else
  761. {
  762. in->point = str_length (in->buffer);
  763. if (local.x + in->term_first_shown - 1 < str_term_width1 (in->buffer))
  764. in->point = str_column_to_pos (in->buffer, local.x + in->term_first_shown - 1);
  765. }
  766. input_update (in, TRUE);
  767. }
  768. /* A lone up mustn't do anything */
  769. if (in->highlight && (event->type & (GPM_UP | GPM_DRAG)) != 0)
  770. return MOU_NORMAL;
  771. if ((event->type & GPM_DRAG) == 0)
  772. input_mark_cmd (in, TRUE);
  773. return MOU_NORMAL;
  774. }
  775. /* --------------------------------------------------------------------------------------------- */
  776. /**
  777. * Callback for applying new options to input widget.
  778. *
  779. * @param w widget
  780. * @param options options set
  781. * @param enable TRUE if specified options should be added, FALSE if options should be removed
  782. */
  783. static void
  784. input_set_options_callback (Widget * w, widget_options_t options, gboolean enable)
  785. {
  786. WInput *in = INPUT (w);
  787. widget_default_set_options_callback (w, options, enable);
  788. if (in->label != NULL)
  789. widget_set_options (WIDGET (in->label), options, enable);
  790. }
  791. /* --------------------------------------------------------------------------------------------- */
  792. /*** public functions ****************************************************************************/
  793. /* --------------------------------------------------------------------------------------------- */
  794. /** Create new instance of WInput object.
  795. * @param y Y coordinate
  796. * @param x X coordinate
  797. * @param input_colors Array of used colors
  798. * @param width Widget width
  799. * @param def_text Default text filled in widget
  800. * @param histname Name of history
  801. * @param completion_flags Flags for specify type of completions
  802. * @return WInput object
  803. */
  804. WInput *
  805. input_new (int y, int x, const int *input_colors, int width, const char *def_text,
  806. const char *histname, input_complete_t completion_flags)
  807. {
  808. WInput *in;
  809. Widget *w;
  810. in = g_new (WInput, 1);
  811. w = WIDGET (in);
  812. widget_init (w, y, x, 1, width, input_callback, input_event);
  813. w->options |= W_IS_INPUT;
  814. w->set_options = input_set_options_callback;
  815. memmove (in->color, input_colors, sizeof (input_colors_t));
  816. in->first = TRUE;
  817. in->highlight = FALSE;
  818. in->term_first_shown = 0;
  819. in->disable_update = 0;
  820. in->is_password = FALSE;
  821. in->strip_password = FALSE;
  822. /* in->buffer will be corrected in "history_load" event handler */
  823. in->current_max_size = width + 1;
  824. in->buffer = g_new0 (char, in->current_max_size);
  825. /* init completions before input_assign_text() call */
  826. in->completions = NULL;
  827. in->completion_flags = completion_flags;
  828. in->init_from_history = (def_text == INPUT_LAST_TEXT);
  829. if (in->init_from_history || def_text == NULL)
  830. def_text = "";
  831. input_assign_text (in, def_text);
  832. /* prepare to history setup */
  833. in->history.list = NULL;
  834. in->history.current = NULL;
  835. in->history.changed = FALSE;
  836. in->history.name = NULL;
  837. if ((histname != NULL) && (*histname != '\0'))
  838. in->history.name = g_strdup (histname);
  839. /* history will be loaded later */
  840. in->label = NULL;
  841. return in;
  842. }
  843. /* --------------------------------------------------------------------------------------------- */
  844. cb_ret_t
  845. input_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
  846. {
  847. WInput *in = INPUT (w);
  848. cb_ret_t v;
  849. switch (msg)
  850. {
  851. case MSG_INIT:
  852. /* subscribe to "history_load" event */
  853. mc_event_add (w->owner->event_group, MCEVENT_HISTORY_LOAD, input_load_history, w, NULL);
  854. /* subscribe to "history_save" event */
  855. mc_event_add (w->owner->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w, NULL);
  856. return MSG_HANDLED;
  857. case MSG_KEY:
  858. if (parm == XCTRL ('q'))
  859. {
  860. quote = 1;
  861. v = input_handle_char (in, ascii_alpha_to_cntrl (tty_getch ()));
  862. quote = 0;
  863. return v;
  864. }
  865. /* Keys we want others to handle */
  866. if (parm == KEY_UP || parm == KEY_DOWN || parm == ESC_CHAR
  867. || parm == KEY_F (10) || parm == '\n')
  868. return MSG_NOT_HANDLED;
  869. /* When pasting multiline text, insert literal Enter */
  870. if ((parm & ~KEY_M_MASK) == '\n')
  871. {
  872. quote = 1;
  873. v = input_handle_char (in, '\n');
  874. quote = 0;
  875. return v;
  876. }
  877. return input_handle_char (in, parm);
  878. case MSG_ACTION:
  879. return input_execute_cmd (in, parm);
  880. case MSG_RESIZE:
  881. case MSG_FOCUS:
  882. case MSG_UNFOCUS:
  883. case MSG_DRAW:
  884. input_update (in, FALSE);
  885. return MSG_HANDLED;
  886. case MSG_CURSOR:
  887. widget_move (in, 0, str_term_width2 (in->buffer, in->point) - in->term_first_shown);
  888. return MSG_HANDLED;
  889. case MSG_DESTROY:
  890. /* unsubscribe from "history_load" event */
  891. mc_event_del (w->owner->event_group, MCEVENT_HISTORY_LOAD, input_load_history, w);
  892. /* unsubscribe from "history_save" event */
  893. mc_event_del (w->owner->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w);
  894. input_destroy (in);
  895. return MSG_HANDLED;
  896. default:
  897. return widget_default_callback (w, sender, msg, parm, data);
  898. }
  899. }
  900. /* --------------------------------------------------------------------------------------------- */
  901. /** Get default colors for WInput widget.
  902. * @return default colors
  903. */
  904. const int *
  905. input_get_default_colors (void)
  906. {
  907. static input_colors_t standart_colors;
  908. standart_colors[WINPUTC_MAIN] = INPUT_COLOR;
  909. standart_colors[WINPUTC_MARK] = INPUT_MARK_COLOR;
  910. standart_colors[WINPUTC_UNCHANGED] = INPUT_UNCHANGED_COLOR;
  911. standart_colors[WINPUTC_HISTORY] = INPUT_HISTORY_COLOR;
  912. return standart_colors;
  913. }
  914. /* --------------------------------------------------------------------------------------------- */
  915. cb_ret_t
  916. input_handle_char (WInput * in, int key)
  917. {
  918. cb_ret_t v;
  919. unsigned long command;
  920. if (quote != 0)
  921. {
  922. input_free_completions (in);
  923. v = insert_char (in, key);
  924. input_update (in, TRUE);
  925. quote = 0;
  926. return v;
  927. }
  928. command = keybind_lookup_keymap_command (input_map, key);
  929. if (command == CK_IgnoreKey)
  930. {
  931. if (key > 255)
  932. return MSG_NOT_HANDLED;
  933. if (in->first)
  934. port_region_marked_for_delete (in);
  935. input_free_completions (in);
  936. v = insert_char (in, key);
  937. }
  938. else
  939. {
  940. if (command != CK_Complete)
  941. input_free_completions (in);
  942. input_execute_cmd (in, command);
  943. v = MSG_HANDLED;
  944. if (in->first)
  945. input_update (in, TRUE); /* needed to clear in->first */
  946. }
  947. input_update (in, TRUE);
  948. return v;
  949. }
  950. /* --------------------------------------------------------------------------------------------- */
  951. /* This function is a test for a special input key used in complete.c */
  952. /* Returns 0 if it is not a special key, 1 if it is a non-complete key
  953. and 2 if it is a complete key */
  954. int
  955. input_key_is_in_map (WInput * in, int key)
  956. {
  957. unsigned long command;
  958. (void) in;
  959. command = keybind_lookup_keymap_command (input_map, key);
  960. if (command == CK_IgnoreKey)
  961. return 0;
  962. return (command == CK_Complete) ? 2 : 1;
  963. }
  964. /* --------------------------------------------------------------------------------------------- */
  965. void
  966. input_assign_text (WInput * in, const char *text)
  967. {
  968. Widget *w = WIDGET (in);
  969. size_t text_len, buffer_len;
  970. if (text == NULL)
  971. text = "";
  972. input_free_completions (in);
  973. in->mark = 0;
  974. in->need_push = TRUE;
  975. in->charpoint = 0;
  976. text_len = strlen (text);
  977. buffer_len = 1 + max ((size_t) w->cols, text_len);
  978. in->current_max_size = buffer_len;
  979. if (buffer_len > (size_t) w->cols)
  980. in->buffer = g_realloc (in->buffer, buffer_len);
  981. memmove (in->buffer, text, text_len + 1);
  982. in->point = str_length (in->buffer);
  983. input_update (in, TRUE);
  984. }
  985. /* --------------------------------------------------------------------------------------------- */
  986. /* Inserts text in input line */
  987. void
  988. input_insert (WInput * in, const char *text, gboolean insert_extra_space)
  989. {
  990. input_disable_update (in);
  991. while (*text != '\0')
  992. input_handle_char (in, (unsigned char) *text++); /* unsigned extension char->int */
  993. if (insert_extra_space)
  994. input_handle_char (in, ' ');
  995. input_enable_update (in);
  996. input_update (in, TRUE);
  997. }
  998. /* --------------------------------------------------------------------------------------------- */
  999. void
  1000. input_set_point (WInput * in, int pos)
  1001. {
  1002. int max_pos;
  1003. max_pos = str_length (in->buffer);
  1004. pos = min (pos, max_pos);
  1005. if (pos != in->point)
  1006. input_free_completions (in);
  1007. in->point = pos;
  1008. in->charpoint = 0;
  1009. input_update (in, TRUE);
  1010. }
  1011. /* --------------------------------------------------------------------------------------------- */
  1012. void
  1013. input_update (WInput * in, gboolean clear_first)
  1014. {
  1015. Widget *w = WIDGET (in);
  1016. int has_history = 0;
  1017. int i;
  1018. int buf_len;
  1019. const char *cp;
  1020. int pw;
  1021. if (in->disable_update != 0)
  1022. return;
  1023. /* don't draw widget not put into dialog */
  1024. if (w->owner == NULL || w->owner->state != DLG_ACTIVE)
  1025. return;
  1026. if (should_show_history_button (in))
  1027. has_history = HISTORY_BUTTON_WIDTH;
  1028. buf_len = str_length (in->buffer);
  1029. /* Adjust the mark */
  1030. in->mark = min (in->mark, buf_len);
  1031. pw = str_term_width2 (in->buffer, in->point);
  1032. /* Make the point visible */
  1033. if ((pw < in->term_first_shown) || (pw >= in->term_first_shown + w->cols - has_history))
  1034. {
  1035. in->term_first_shown = pw - (w->cols / 3);
  1036. if (in->term_first_shown < 0)
  1037. in->term_first_shown = 0;
  1038. }
  1039. if (has_history != 0)
  1040. draw_history_button (in);
  1041. if ((w->options & W_DISABLED) != 0)
  1042. tty_setcolor (DISABLED_COLOR);
  1043. else if (in->first)
  1044. tty_setcolor (in->color[WINPUTC_UNCHANGED]);
  1045. else
  1046. tty_setcolor (in->color[WINPUTC_MAIN]);
  1047. widget_move (in, 0, 0);
  1048. if (!in->is_password)
  1049. {
  1050. if (!in->highlight)
  1051. tty_print_string (str_term_substring (in->buffer, in->term_first_shown,
  1052. w->cols - has_history));
  1053. else
  1054. {
  1055. long m1, m2;
  1056. if (input_eval_marks (in, &m1, &m2))
  1057. {
  1058. tty_setcolor (in->color[WINPUTC_MAIN]);
  1059. cp = str_term_substring (in->buffer, in->term_first_shown, w->cols - has_history);
  1060. tty_print_string (cp);
  1061. tty_setcolor (in->color[WINPUTC_MARK]);
  1062. if (m1 < in->term_first_shown)
  1063. {
  1064. widget_move (in, 0, 0);
  1065. tty_print_string (str_term_substring
  1066. (in->buffer, in->term_first_shown,
  1067. m2 - in->term_first_shown));
  1068. }
  1069. else
  1070. {
  1071. int sel_width, buf_width;
  1072. widget_move (in, 0, m1 - in->term_first_shown);
  1073. buf_width = str_term_width2 (in->buffer, m1);
  1074. sel_width =
  1075. min (m2 - m1, (w->cols - has_history) - (buf_width - in->term_first_shown));
  1076. tty_print_string (str_term_substring (in->buffer, m1, sel_width));
  1077. }
  1078. }
  1079. }
  1080. }
  1081. else
  1082. {
  1083. cp = str_term_substring (in->buffer, in->term_first_shown, w->cols - has_history);
  1084. tty_setcolor (in->color[WINPUTC_MAIN]);
  1085. for (i = 0; i < w->cols - has_history; i++)
  1086. {
  1087. if (i < (buf_len - in->term_first_shown) && cp[0] != '\0')
  1088. tty_print_char ('*');
  1089. else
  1090. tty_print_char (' ');
  1091. if (cp[0] != '\0')
  1092. str_cnext_char (&cp);
  1093. }
  1094. }
  1095. if (clear_first)
  1096. in->first = FALSE;
  1097. }
  1098. /* --------------------------------------------------------------------------------------------- */
  1099. void
  1100. input_enable_update (WInput * in)
  1101. {
  1102. in->disable_update--;
  1103. input_update (in, FALSE);
  1104. }
  1105. /* --------------------------------------------------------------------------------------------- */
  1106. void
  1107. input_disable_update (WInput * in)
  1108. {
  1109. in->disable_update++;
  1110. }
  1111. /* --------------------------------------------------------------------------------------------- */
  1112. /**
  1113. * Cleans the input line and adds the current text to the history
  1114. *
  1115. * @param in the input line
  1116. */
  1117. void
  1118. input_clean (WInput * in)
  1119. {
  1120. push_history (in, in->buffer);
  1121. in->need_push = TRUE;
  1122. in->buffer[0] = '\0';
  1123. in->point = 0;
  1124. in->charpoint = 0;
  1125. in->mark = 0;
  1126. in->highlight = FALSE;
  1127. input_free_completions (in);
  1128. input_update (in, FALSE);
  1129. }
  1130. /* --------------------------------------------------------------------------------------------- */
  1131. void
  1132. input_free_completions (WInput * in)
  1133. {
  1134. g_strfreev (in->completions);
  1135. in->completions = NULL;
  1136. }
  1137. /* --------------------------------------------------------------------------------------------- */