input.c 32 KB

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