input.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366
  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/vfs/mc-vfs/vfs.h"
  35. #include "lib/fileloc.h"
  36. #include "lib/skin.h"
  37. #include "lib/strutil.h"
  38. #include "lib/util.h"
  39. #include "lib/keybind.h" /* global_keymap_t */
  40. #include "lib/widget.h"
  41. #include "src/main.h" /* home_dir */
  42. #include "src/filemanager/midnight.h" /* current_panel */
  43. #include "src/clipboard.h" /* copy_file_to_ext_clip, paste_to_file_from_ext_clip */
  44. #include "src/keybind-defaults.h" /* input_map */
  45. /*** global variables ****************************************************************************/
  46. int quote = 0;
  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. static gboolean
  64. save_text_to_clip_file (const char *text)
  65. {
  66. int file;
  67. char *fname = NULL;
  68. ssize_t ret;
  69. size_t str_len;
  70. fname = g_build_filename (home_dir, EDIT_CLIP_FILE, NULL);
  71. file = mc_open (fname, O_CREAT | O_WRONLY | O_TRUNC,
  72. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
  73. g_free (fname);
  74. if (file == -1)
  75. return FALSE;
  76. str_len = strlen (text);
  77. ret = mc_write (file, (char *) text, str_len);
  78. mc_close (file);
  79. return ret == (ssize_t) str_len;
  80. }
  81. /* --------------------------------------------------------------------------------------------- */
  82. static gboolean
  83. load_text_from_clip_file (char **text)
  84. {
  85. char buf[BUF_LARGE];
  86. FILE *f;
  87. char *fname = NULL;
  88. gboolean first = TRUE;
  89. fname = g_build_filename (home_dir, EDIT_CLIP_FILE, NULL);
  90. f = fopen (fname, "r");
  91. g_free (fname);
  92. if (f == NULL)
  93. return FALSE;
  94. *text = NULL;
  95. while (fgets (buf, sizeof (buf), f))
  96. {
  97. size_t len;
  98. len = strlen (buf);
  99. if (len > 0)
  100. {
  101. if (buf[len - 1] == '\n')
  102. buf[len - 1] = '\0';
  103. if (first)
  104. {
  105. first = FALSE;
  106. *text = g_strdup (buf);
  107. }
  108. else
  109. {
  110. /* remove \n on EOL */
  111. char *tmp;
  112. tmp = g_strconcat (*text, " ", buf, (char *) NULL);
  113. g_free (*text);
  114. *text = tmp;
  115. }
  116. }
  117. }
  118. fclose (f);
  119. return (*text != NULL);
  120. }
  121. /* --------------------------------------------------------------------------------------------- */
  122. static gboolean
  123. panel_save_curent_file_to_clip_file (void)
  124. {
  125. gboolean res = FALSE;
  126. if (current_panel->marked == 0)
  127. res = save_text_to_clip_file (selection (current_panel)->fname);
  128. else
  129. {
  130. int i;
  131. gboolean first = TRUE;
  132. char *flist = NULL;
  133. for (i = 0; i < current_panel->count; i++)
  134. if (current_panel->dir.list[i].f.marked != 0)
  135. { /* Skip the unmarked ones */
  136. if (first)
  137. {
  138. flist = g_strdup (current_panel->dir.list[i].fname);
  139. first = FALSE;
  140. }
  141. else
  142. {
  143. /* Add empty lines after the file */
  144. char *tmp;
  145. tmp =
  146. g_strconcat (flist, "\n", current_panel->dir.list[i].fname, (char *) NULL);
  147. g_free (flist);
  148. flist = tmp;
  149. }
  150. }
  151. if (flist != NULL)
  152. {
  153. res = save_text_to_clip_file (flist);
  154. g_free (flist);
  155. }
  156. }
  157. return res;
  158. }
  159. /* --------------------------------------------------------------------------------------------- */
  160. static void
  161. draw_history_button (WInput * in)
  162. {
  163. char c;
  164. gboolean disabled = (((Widget *) in)->options & W_DISABLED) != 0;
  165. c = in->history->next ? (in->history->prev ? '|' : 'v') : '^';
  166. widget_move (&in->widget, 0, in->field_width - HISTORY_BUTTON_WIDTH);
  167. tty_setcolor (disabled ? DISABLED_COLOR : in->color[WINPUTC_HISTORY]);
  168. #ifdef LARGE_HISTORY_BUTTON
  169. {
  170. Dlg_head *h;
  171. h = in->widget.owner;
  172. tty_print_string ("[ ]");
  173. widget_move (&in->widget, 0, in->field_width - HISTORY_BUTTON_WIDTH + 1);
  174. }
  175. #endif
  176. tty_print_char (c);
  177. }
  178. /* --------------------------------------------------------------------------------------------- */
  179. static void
  180. input_set_markers (WInput * in, long m1)
  181. {
  182. in->mark = m1;
  183. }
  184. /* --------------------------------------------------------------------------------------------- */
  185. static void
  186. input_mark_cmd (WInput * in, gboolean mark)
  187. {
  188. if (mark == 0)
  189. {
  190. in->highlight = FALSE;
  191. input_set_markers (in, 0);
  192. }
  193. else
  194. {
  195. in->highlight = TRUE;
  196. input_set_markers (in, in->point);
  197. }
  198. }
  199. /* --------------------------------------------------------------------------------------------- */
  200. static gboolean
  201. input_eval_marks (WInput * in, long *start_mark, long *end_mark)
  202. {
  203. if (in->highlight)
  204. {
  205. *start_mark = min (in->mark, in->point);
  206. *end_mark = max (in->mark, in->point);
  207. return TRUE;
  208. }
  209. else
  210. {
  211. *start_mark = *end_mark = 0;
  212. return FALSE;
  213. }
  214. }
  215. /* --------------------------------------------------------------------------------------------- */
  216. static void
  217. delete_region (WInput * in, int x_first, int x_last)
  218. {
  219. int first = min (x_first, x_last);
  220. int last = max (x_first, x_last);
  221. size_t len;
  222. input_mark_cmd (in, FALSE);
  223. in->point = first;
  224. last = str_offset_to_pos (in->buffer, last);
  225. first = str_offset_to_pos (in->buffer, first);
  226. len = strlen (&in->buffer[last]) + 1;
  227. memmove (&in->buffer[first], &in->buffer[last], len);
  228. in->charpoint = 0;
  229. in->need_push = TRUE;
  230. }
  231. /* --------------------------------------------------------------------------------------------- */
  232. static void
  233. do_show_hist (WInput * in)
  234. {
  235. char *r;
  236. r = history_show (&in->history, &in->widget);
  237. if (r != NULL)
  238. {
  239. input_assign_text (in, r);
  240. g_free (r);
  241. }
  242. }
  243. /* --------------------------------------------------------------------------------------------- */
  244. static void
  245. push_history (WInput * in, const char *text)
  246. {
  247. /* input widget where urls with passwords are entered without any
  248. vfs prefix */
  249. const char *password_input_fields[] = {
  250. " Link to a remote machine ",
  251. " FTP to machine ",
  252. " SMB link to machine "
  253. };
  254. const size_t ELEMENTS = (sizeof (password_input_fields) / sizeof (password_input_fields[0]));
  255. char *t;
  256. size_t i;
  257. gboolean empty;
  258. if (text == NULL)
  259. return;
  260. #ifdef ENABLE_NLS
  261. for (i = 0; i < ELEMENTS; i++)
  262. password_input_fields[i] = _(password_input_fields[i]);
  263. #endif
  264. t = g_strstrip (g_strdup (text));
  265. empty = *t == '\0';
  266. g_free (t);
  267. t = g_strdup (empty ? "" : text);
  268. if (in->history_name != NULL)
  269. {
  270. /* FIXME: It is the strange code. Rewrite is needed. */
  271. const char *p = in->history_name + 3;
  272. for (i = 0; i < ELEMENTS; i++)
  273. if (strcmp (p, password_input_fields[i]) == 0)
  274. break;
  275. strip_password (t, i >= ELEMENTS);
  276. }
  277. in->history = list_append_unique (in->history, t);
  278. in->need_push = FALSE;
  279. }
  280. /* --------------------------------------------------------------------------------------------- */
  281. static void
  282. move_buffer_backward (WInput * in, int start, int end)
  283. {
  284. int i, pos, len;
  285. int str_len;
  286. str_len = str_length (in->buffer);
  287. if (start >= str_len || end > str_len + 1)
  288. return;
  289. pos = str_offset_to_pos (in->buffer, start);
  290. len = str_offset_to_pos (in->buffer, end) - pos;
  291. for (i = pos; in->buffer[i + len - 1]; i++)
  292. in->buffer[i] = in->buffer[i + len];
  293. }
  294. /* --------------------------------------------------------------------------------------------- */
  295. static cb_ret_t
  296. insert_char (WInput * in, int c_code)
  297. {
  298. size_t i;
  299. int res;
  300. if (in->highlight)
  301. {
  302. long m1, m2;
  303. if (input_eval_marks (in, &m1, &m2))
  304. delete_region (in, m1, m2);
  305. }
  306. if (c_code == -1)
  307. return MSG_NOT_HANDLED;
  308. if (in->charpoint >= MB_LEN_MAX)
  309. return MSG_HANDLED;
  310. in->charbuf[in->charpoint] = c_code;
  311. in->charpoint++;
  312. res = str_is_valid_char (in->charbuf, in->charpoint);
  313. if (res < 0)
  314. {
  315. if (res != -2)
  316. in->charpoint = 0; /* broken multibyte char, skip */
  317. return MSG_HANDLED;
  318. }
  319. in->need_push = TRUE;
  320. if (strlen (in->buffer) + 1 + in->charpoint >= in->current_max_size)
  321. {
  322. /* Expand the buffer */
  323. size_t new_length = in->current_max_size + in->field_width + in->charpoint;
  324. char *narea = g_try_renew (char, in->buffer, new_length);
  325. if (narea)
  326. {
  327. in->buffer = narea;
  328. in->current_max_size = new_length;
  329. }
  330. }
  331. if (strlen (in->buffer) + in->charpoint < in->current_max_size)
  332. {
  333. /* bytes from begin */
  334. size_t ins_point = str_offset_to_pos (in->buffer, in->point);
  335. /* move chars */
  336. size_t rest_bytes = strlen (in->buffer + ins_point);
  337. for (i = rest_bytes + 1; i > 0; i--)
  338. in->buffer[ins_point + i + in->charpoint - 1] = in->buffer[ins_point + i - 1];
  339. memcpy (in->buffer + ins_point, in->charbuf, in->charpoint);
  340. in->point++;
  341. }
  342. in->charpoint = 0;
  343. return MSG_HANDLED;
  344. }
  345. /* --------------------------------------------------------------------------------------------- */
  346. static void
  347. beginning_of_line (WInput * in)
  348. {
  349. in->point = 0;
  350. in->charpoint = 0;
  351. }
  352. /* --------------------------------------------------------------------------------------------- */
  353. static void
  354. end_of_line (WInput * in)
  355. {
  356. in->point = str_length (in->buffer);
  357. in->charpoint = 0;
  358. }
  359. /* --------------------------------------------------------------------------------------------- */
  360. static void
  361. backward_char (WInput * in)
  362. {
  363. const char *act;
  364. act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  365. if (in->point > 0)
  366. in->point -= str_cprev_noncomb_char (&act, in->buffer);
  367. in->charpoint = 0;
  368. }
  369. /* --------------------------------------------------------------------------------------------- */
  370. static void
  371. forward_char (WInput * in)
  372. {
  373. const char *act;
  374. act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  375. if (act[0] != '\0')
  376. in->point += str_cnext_noncomb_char (&act);
  377. in->charpoint = 0;
  378. }
  379. /* --------------------------------------------------------------------------------------------- */
  380. static void
  381. forward_word (WInput * in)
  382. {
  383. const char *p;
  384. p = in->buffer + str_offset_to_pos (in->buffer, in->point);
  385. while (p[0] != '\0' && (str_isspace (p) || str_ispunct (p)))
  386. {
  387. str_cnext_char (&p);
  388. in->point++;
  389. }
  390. while (p[0] != '\0' && !str_isspace (p) && !str_ispunct (p))
  391. {
  392. str_cnext_char (&p);
  393. in->point++;
  394. }
  395. }
  396. /* --------------------------------------------------------------------------------------------- */
  397. static void
  398. backward_word (WInput * in)
  399. {
  400. const char *p, *p_tmp;
  401. for (p = in->buffer + str_offset_to_pos (in->buffer, in->point);
  402. (p != in->buffer) && (p[0] == '\0'); str_cprev_char (&p), in->point--);
  403. while (p != in->buffer)
  404. {
  405. p_tmp = p;
  406. str_cprev_char (&p);
  407. if (!str_isspace (p) && !str_ispunct (p))
  408. {
  409. p = p_tmp;
  410. break;
  411. }
  412. in->point--;
  413. }
  414. while (p != in->buffer)
  415. {
  416. str_cprev_char (&p);
  417. if (str_isspace (p) || str_ispunct (p))
  418. break;
  419. in->point--;
  420. }
  421. }
  422. /* --------------------------------------------------------------------------------------------- */
  423. static void
  424. backward_delete (WInput * in)
  425. {
  426. const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  427. int start;
  428. if (in->point == 0)
  429. return;
  430. start = in->point - str_cprev_noncomb_char (&act, in->buffer);
  431. move_buffer_backward (in, start, in->point);
  432. in->charpoint = 0;
  433. in->need_push = TRUE;
  434. in->point = start;
  435. }
  436. /* --------------------------------------------------------------------------------------------- */
  437. static void
  438. delete_char (WInput * in)
  439. {
  440. const char *act;
  441. int end = in->point;
  442. act = in->buffer + str_offset_to_pos (in->buffer, in->point);
  443. end += str_cnext_noncomb_char (&act);
  444. move_buffer_backward (in, in->point, end);
  445. in->charpoint = 0;
  446. in->need_push = TRUE;
  447. }
  448. /* --------------------------------------------------------------------------------------------- */
  449. static void
  450. copy_region (WInput * in, int x_first, int x_last)
  451. {
  452. int first = min (x_first, x_last);
  453. int last = max (x_first, x_last);
  454. if (last == first)
  455. {
  456. /* Copy selected files to clipboard */
  457. panel_save_curent_file_to_clip_file ();
  458. /* try use external clipboard utility */
  459. copy_file_to_ext_clip ();
  460. return;
  461. }
  462. g_free (kill_buffer);
  463. first = str_offset_to_pos (in->buffer, first);
  464. last = str_offset_to_pos (in->buffer, last);
  465. kill_buffer = g_strndup (in->buffer + first, last - first);
  466. save_text_to_clip_file (kill_buffer);
  467. /* try use external clipboard utility */
  468. copy_file_to_ext_clip ();
  469. }
  470. /* --------------------------------------------------------------------------------------------- */
  471. static void
  472. kill_word (WInput * in)
  473. {
  474. int old_point = in->point;
  475. int new_point;
  476. forward_word (in);
  477. new_point = in->point;
  478. in->point = old_point;
  479. delete_region (in, old_point, new_point);
  480. in->need_push = TRUE;
  481. in->charpoint = 0;
  482. }
  483. /* --------------------------------------------------------------------------------------------- */
  484. static void
  485. back_kill_word (WInput * in)
  486. {
  487. int old_point = in->point;
  488. int new_point;
  489. backward_word (in);
  490. new_point = in->point;
  491. in->point = old_point;
  492. delete_region (in, old_point, new_point);
  493. in->need_push = TRUE;
  494. }
  495. /* --------------------------------------------------------------------------------------------- */
  496. static void
  497. yank (WInput * in)
  498. {
  499. if (kill_buffer != NULL)
  500. {
  501. char *p;
  502. in->charpoint = 0;
  503. for (p = kill_buffer; *p != '\0'; p++)
  504. insert_char (in, *p);
  505. in->charpoint = 0;
  506. }
  507. }
  508. /* --------------------------------------------------------------------------------------------- */
  509. static void
  510. kill_line (WInput * in)
  511. {
  512. int chp;
  513. chp = str_offset_to_pos (in->buffer, in->point);
  514. g_free (kill_buffer);
  515. kill_buffer = g_strdup (&in->buffer[chp]);
  516. in->buffer[chp] = '\0';
  517. in->charpoint = 0;
  518. }
  519. /* --------------------------------------------------------------------------------------------- */
  520. static void
  521. clear_line (WInput * in)
  522. {
  523. in->need_push = 1;
  524. in->buffer[0] = '\0';
  525. in->point = 0;
  526. in->mark = 0;
  527. in->highlight = FALSE;
  528. in->charpoint = 0;
  529. }
  530. static void
  531. ins_from_clip (WInput * in)
  532. {
  533. char *p = NULL;
  534. /* try use external clipboard utility */
  535. paste_to_file_from_ext_clip ();
  536. if (load_text_from_clip_file (&p))
  537. {
  538. char *pp;
  539. for (pp = p; *pp != '\0'; pp++)
  540. insert_char (in, *pp);
  541. g_free (p);
  542. }
  543. }
  544. /* --------------------------------------------------------------------------------------------- */
  545. static void
  546. hist_prev (WInput * in)
  547. {
  548. GList *prev;
  549. if (in->history == NULL)
  550. return;
  551. if (in->need_push)
  552. push_history (in, in->buffer);
  553. prev = g_list_previous (in->history);
  554. if (prev != NULL)
  555. {
  556. in->history = prev;
  557. input_assign_text (in, (char *) prev->data);
  558. in->need_push = FALSE;
  559. }
  560. }
  561. /* --------------------------------------------------------------------------------------------- */
  562. static void
  563. hist_next (WInput * in)
  564. {
  565. if (in->need_push)
  566. {
  567. push_history (in, in->buffer);
  568. input_assign_text (in, "");
  569. return;
  570. }
  571. if (in->history == NULL)
  572. return;
  573. if (in->history->next == NULL)
  574. input_assign_text (in, "");
  575. else
  576. {
  577. in->history = g_list_next (in->history);
  578. input_assign_text (in, (char *) in->history->data);
  579. in->need_push = FALSE;
  580. }
  581. }
  582. /* --------------------------------------------------------------------------------------------- */
  583. static void
  584. port_region_marked_for_delete (WInput * in)
  585. {
  586. in->buffer[0] = '\0';
  587. in->point = 0;
  588. in->first = FALSE;
  589. in->charpoint = 0;
  590. }
  591. /* --------------------------------------------------------------------------------------------- */
  592. static cb_ret_t
  593. input_execute_cmd (WInput * in, unsigned long command)
  594. {
  595. cb_ret_t res = MSG_HANDLED;
  596. /* a highlight command like shift-arrow */
  597. if (command == CK_InputLeftHighlight ||
  598. command == CK_InputRightHighlight ||
  599. command == CK_InputWordLeftHighlight ||
  600. command == CK_InputWordRightHighlight ||
  601. command == CK_InputBolHighlight || command == CK_InputEolHighlight)
  602. {
  603. if (!in->highlight)
  604. {
  605. input_mark_cmd (in, FALSE); /* clear */
  606. input_mark_cmd (in, TRUE); /* marking on */
  607. }
  608. }
  609. switch (command)
  610. {
  611. case CK_InputForwardWord:
  612. case CK_InputBackwardWord:
  613. case CK_InputForwardChar:
  614. case CK_InputBackwardChar:
  615. if (in->highlight)
  616. input_mark_cmd (in, FALSE);
  617. }
  618. switch (command)
  619. {
  620. case CK_InputBol:
  621. case CK_InputBolHighlight:
  622. beginning_of_line (in);
  623. break;
  624. case CK_InputEol:
  625. case CK_InputEolHighlight:
  626. end_of_line (in);
  627. break;
  628. case CK_InputMoveLeft:
  629. case CK_InputLeftHighlight:
  630. backward_char (in);
  631. break;
  632. case CK_InputWordLeft:
  633. case CK_InputWordLeftHighlight:
  634. backward_word (in);
  635. break;
  636. case CK_InputMoveRight:
  637. case CK_InputRightHighlight:
  638. forward_char (in);
  639. break;
  640. case CK_InputWordRight:
  641. case CK_InputWordRightHighlight:
  642. forward_word (in);
  643. break;
  644. case CK_InputBackwardChar:
  645. backward_char (in);
  646. break;
  647. case CK_InputBackwardWord:
  648. backward_word (in);
  649. break;
  650. case CK_InputForwardChar:
  651. forward_char (in);
  652. break;
  653. case CK_InputForwardWord:
  654. forward_word (in);
  655. break;
  656. case CK_InputBackwardDelete:
  657. if (in->highlight)
  658. {
  659. long m1, m2;
  660. if (input_eval_marks (in, &m1, &m2))
  661. delete_region (in, m1, m2);
  662. }
  663. else
  664. backward_delete (in);
  665. break;
  666. case CK_InputDeleteChar:
  667. if (in->first)
  668. port_region_marked_for_delete (in);
  669. else if (in->highlight)
  670. {
  671. long m1, m2;
  672. if (input_eval_marks (in, &m1, &m2))
  673. delete_region (in, m1, m2);
  674. }
  675. else
  676. delete_char (in);
  677. break;
  678. case CK_InputKillWord:
  679. kill_word (in);
  680. break;
  681. case CK_InputBackwardKillWord:
  682. back_kill_word (in);
  683. break;
  684. case CK_InputSetMark:
  685. input_mark_cmd (in, TRUE);
  686. break;
  687. case CK_InputKillRegion:
  688. delete_region (in, in->point, in->mark);
  689. break;
  690. case CK_InputKillLine:
  691. /* clear command line from cursor to the EOL */
  692. kill_line (in);
  693. break;
  694. case CK_InputClearLine:
  695. /* clear command line */
  696. clear_line (in);
  697. break;
  698. case CK_InputCopyRegion:
  699. copy_region (in, in->mark, in->point);
  700. break;
  701. case CK_InputKillSave:
  702. copy_region (in, in->mark, in->point);
  703. delete_region (in, in->point, in->mark);
  704. break;
  705. case CK_InputYank:
  706. yank (in);
  707. break;
  708. case CK_InputPaste:
  709. ins_from_clip (in);
  710. break;
  711. case CK_InputHistoryPrev:
  712. hist_prev (in);
  713. break;
  714. case CK_InputHistoryNext:
  715. hist_next (in);
  716. break;
  717. case CK_InputHistoryShow:
  718. do_show_hist (in);
  719. break;
  720. case CK_InputComplete:
  721. complete (in);
  722. break;
  723. default:
  724. res = MSG_NOT_HANDLED;
  725. }
  726. if (command != CK_InputLeftHighlight &&
  727. command != CK_InputRightHighlight &&
  728. command != CK_InputWordLeftHighlight &&
  729. command != CK_InputWordRightHighlight &&
  730. command != CK_InputBolHighlight && command != CK_InputEolHighlight)
  731. in->highlight = FALSE;
  732. return res;
  733. }
  734. /* --------------------------------------------------------------------------------------------- */
  735. static void
  736. input_destroy (WInput * in)
  737. {
  738. if (in == NULL)
  739. {
  740. fprintf (stderr, "Internal error: null Input *\n");
  741. exit (EXIT_FAILURE);
  742. }
  743. input_clean (in);
  744. if (in->history != NULL)
  745. {
  746. if (!in->is_password && (((Widget *) in)->owner->ret_value != B_CANCEL))
  747. history_put (in->history_name, in->history);
  748. in->history = g_list_first (in->history);
  749. g_list_foreach (in->history, (GFunc) g_free, NULL);
  750. g_list_free (in->history);
  751. }
  752. g_free (in->buffer);
  753. input_free_completions (in);
  754. g_free (in->history_name);
  755. g_free (kill_buffer);
  756. kill_buffer = NULL;
  757. }
  758. /* --------------------------------------------------------------------------------------------- */
  759. static int
  760. input_event (Gpm_Event * event, void *data)
  761. {
  762. WInput *in = (WInput *) data;
  763. if ((event->type & GPM_DOWN) != 0)
  764. {
  765. in->first = FALSE;
  766. input_mark_cmd (in, FALSE);
  767. }
  768. if ((event->type & (GPM_DOWN | GPM_DRAG)) != 0)
  769. {
  770. dlg_select_widget (in);
  771. if (event->x >= in->field_width - HISTORY_BUTTON_WIDTH + 1
  772. && should_show_history_button (in))
  773. do_show_hist (in);
  774. else
  775. {
  776. in->point = str_length (in->buffer);
  777. if (event->x + in->term_first_shown - 1 < str_term_width1 (in->buffer))
  778. in->point = str_column_to_pos (in->buffer, event->x + in->term_first_shown - 1);
  779. }
  780. input_update (in, TRUE);
  781. }
  782. /* A lone up mustn't do anything */
  783. if (in->highlight && (event->type & (GPM_UP | GPM_DRAG)) != 0)
  784. return MOU_NORMAL;
  785. if ((event->type & GPM_DRAG) == 0)
  786. input_mark_cmd (in, TRUE);
  787. return MOU_NORMAL;
  788. }
  789. /* --------------------------------------------------------------------------------------------- */
  790. /*** public functions ****************************************************************************/
  791. /* --------------------------------------------------------------------------------------------- */
  792. /** Create new instance of WInput object.
  793. * @param y Y coordinate
  794. * @param x X coordinate
  795. * @param input_colors Array of used colors
  796. * @param width Widget width
  797. * @param def_text Default text filled in widget
  798. * @param histname Name of history
  799. * @param completion_flags Flags for specify type of completions
  800. * @returns WInput object
  801. */
  802. WInput *
  803. input_new (int y, int x, const int *input_colors, int width, const char *def_text,
  804. const char *histname, input_complete_t completion_flags)
  805. {
  806. WInput *in = g_new (WInput, 1);
  807. size_t initial_buffer_len;
  808. init_widget (&in->widget, y, x, 1, width, input_callback, input_event);
  809. /* history setup */
  810. in->history_name = NULL;
  811. in->history = NULL;
  812. if ((histname != NULL) && (*histname != '\0'))
  813. {
  814. in->history_name = g_strdup (histname);
  815. in->history = history_get (histname);
  816. }
  817. if (def_text == NULL)
  818. def_text = "";
  819. else if (def_text == INPUT_LAST_TEXT)
  820. {
  821. if ((in->history != NULL) && (in->history->data != NULL))
  822. def_text = (char *) in->history->data;
  823. else
  824. def_text = "";
  825. }
  826. initial_buffer_len = strlen (def_text);
  827. initial_buffer_len = 1 + max ((size_t) width, initial_buffer_len);
  828. in->widget.options |= W_IS_INPUT;
  829. in->completions = NULL;
  830. in->completion_flags = completion_flags;
  831. in->current_max_size = initial_buffer_len;
  832. in->buffer = g_new (char, initial_buffer_len);
  833. memmove (in->color, input_colors, sizeof (input_colors_t));
  834. in->field_width = width;
  835. in->first = TRUE;
  836. in->highlight = FALSE;
  837. in->term_first_shown = 0;
  838. in->disable_update = 0;
  839. in->mark = 0;
  840. in->need_push = TRUE;
  841. in->is_password = FALSE;
  842. strcpy (in->buffer, def_text);
  843. in->point = str_length (in->buffer);
  844. in->charpoint = 0;
  845. return in;
  846. }
  847. /* --------------------------------------------------------------------------------------------- */
  848. cb_ret_t
  849. input_callback (Widget * w, widget_msg_t msg, int parm)
  850. {
  851. WInput *in = (WInput *) w;
  852. cb_ret_t v;
  853. switch (msg)
  854. {
  855. case WIDGET_KEY:
  856. if (parm == XCTRL ('q'))
  857. {
  858. quote = 1;
  859. v = input_handle_char (in, ascii_alpha_to_cntrl (tty_getch ()));
  860. quote = 0;
  861. return v;
  862. }
  863. /* Keys we want others to handle */
  864. if (parm == KEY_UP || parm == KEY_DOWN || parm == ESC_CHAR
  865. || parm == KEY_F (10) || parm == '\n')
  866. return MSG_NOT_HANDLED;
  867. /* When pasting multiline text, insert literal Enter */
  868. if ((parm & ~KEY_M_MASK) == '\n')
  869. {
  870. quote = 1;
  871. v = input_handle_char (in, '\n');
  872. quote = 0;
  873. return v;
  874. }
  875. return input_handle_char (in, parm);
  876. case WIDGET_COMMAND:
  877. return input_execute_cmd (in, parm);
  878. case WIDGET_FOCUS:
  879. case WIDGET_UNFOCUS:
  880. case WIDGET_DRAW:
  881. input_update (in, FALSE);
  882. return MSG_HANDLED;
  883. case WIDGET_CURSOR:
  884. widget_move (&in->widget, 0, str_term_width2 (in->buffer, in->point)
  885. - in->term_first_shown);
  886. return MSG_HANDLED;
  887. case WIDGET_DESTROY:
  888. input_destroy (in);
  889. return MSG_HANDLED;
  890. default:
  891. return default_proc (msg, parm);
  892. }
  893. }
  894. /* --------------------------------------------------------------------------------------------- */
  895. /** Get default colors for WInput widget.
  896. * @returns default colors
  897. */
  898. const int *
  899. input_get_default_colors (void)
  900. {
  901. static input_colors_t standart_colors;
  902. standart_colors[WINPUTC_MAIN] = INPUT_COLOR;
  903. standart_colors[WINPUTC_MARK] = INPUT_MARK_COLOR;
  904. standart_colors[WINPUTC_UNCHANGED] = INPUT_UNCHANGED_COLOR;
  905. standart_colors[WINPUTC_HISTORY] = INPUT_HISTORY_COLOR;
  906. return standart_colors;
  907. }
  908. /* --------------------------------------------------------------------------------------------- */
  909. void
  910. input_set_origin (WInput * in, int x, int field_width)
  911. {
  912. in->widget.x = x;
  913. in->field_width = in->widget.cols = field_width;
  914. input_update (in, FALSE);
  915. }
  916. /* --------------------------------------------------------------------------------------------- */
  917. cb_ret_t
  918. input_handle_char (WInput * in, int key)
  919. {
  920. cb_ret_t v;
  921. unsigned long command;
  922. v = MSG_NOT_HANDLED;
  923. if (quote != 0)
  924. {
  925. input_free_completions (in);
  926. v = insert_char (in, key);
  927. input_update (in, TRUE);
  928. quote = 0;
  929. return v;
  930. }
  931. command = keybind_lookup_keymap_command (input_map, key);
  932. if (command == CK_Ignore_Key)
  933. {
  934. if (key > 255)
  935. return MSG_NOT_HANDLED;
  936. if (in->first)
  937. port_region_marked_for_delete (in);
  938. input_free_completions (in);
  939. v = insert_char (in, key);
  940. }
  941. else
  942. {
  943. if (command != CK_InputComplete)
  944. input_free_completions (in);
  945. input_execute_cmd (in, command);
  946. v = MSG_HANDLED;
  947. if (in->first)
  948. input_update (in, TRUE); /* needed to clear in->first */
  949. }
  950. input_update (in, TRUE);
  951. return v;
  952. }
  953. /* --------------------------------------------------------------------------------------------- */
  954. /* This function is a test for a special input key used in complete.c */
  955. /* Returns 0 if it is not a special key, 1 if it is a non-complete key
  956. and 2 if it is a complete key */
  957. int
  958. input_key_is_in_map (WInput * in, int key)
  959. {
  960. unsigned long command;
  961. (void) in;
  962. command = keybind_lookup_keymap_command (input_map, key);
  963. if (command == CK_Ignore_Key)
  964. return 0;
  965. return (command == CK_InputComplete) ? 2 : 1;
  966. }
  967. /* --------------------------------------------------------------------------------------------- */
  968. void
  969. input_assign_text (WInput * in, const char *text)
  970. {
  971. input_free_completions (in);
  972. g_free (in->buffer);
  973. in->buffer = g_strdup (text); /* was in->buffer->text */
  974. in->current_max_size = strlen (in->buffer) + 1;
  975. in->point = str_length (in->buffer);
  976. in->mark = 0;
  977. in->need_push = TRUE;
  978. in->charpoint = 0;
  979. }
  980. /* --------------------------------------------------------------------------------------------- */
  981. /* Inserts text in input line */
  982. void
  983. input_insert (WInput * in, const char *text, gboolean insert_extra_space)
  984. {
  985. input_disable_update (in);
  986. while (*text != '\0')
  987. input_handle_char (in, (unsigned char) *text++); /* unsigned extension char->int */
  988. if (insert_extra_space)
  989. input_handle_char (in, ' ');
  990. input_enable_update (in);
  991. input_update (in, TRUE);
  992. }
  993. /* --------------------------------------------------------------------------------------------- */
  994. void
  995. input_set_point (WInput * in, int pos)
  996. {
  997. int max_pos;
  998. max_pos = str_length (in->buffer);
  999. pos = min (pos, max_pos);
  1000. if (pos != in->point)
  1001. input_free_completions (in);
  1002. in->point = pos;
  1003. in->charpoint = 0;
  1004. input_update (in, TRUE);
  1005. }
  1006. /* --------------------------------------------------------------------------------------------- */
  1007. void
  1008. input_update (WInput * in, gboolean clear_first)
  1009. {
  1010. int has_history = 0;
  1011. int i;
  1012. int buf_len;
  1013. const char *cp;
  1014. int pw;
  1015. if (should_show_history_button (in))
  1016. has_history = HISTORY_BUTTON_WIDTH;
  1017. if (in->disable_update != 0)
  1018. return;
  1019. buf_len = str_length (in->buffer);
  1020. pw = str_term_width2 (in->buffer, in->point);
  1021. /* Make the point visible */
  1022. if ((pw < in->term_first_shown) || (pw >= in->term_first_shown + in->field_width - has_history))
  1023. {
  1024. in->term_first_shown = pw - (in->field_width / 3);
  1025. if (in->term_first_shown < 0)
  1026. in->term_first_shown = 0;
  1027. }
  1028. /* Adjust the mark */
  1029. in->mark = min (in->mark, buf_len);
  1030. if (has_history != 0)
  1031. draw_history_button (in);
  1032. if ((((Widget *) in)->options & W_DISABLED) != 0)
  1033. tty_setcolor (DISABLED_COLOR);
  1034. else if (in->first)
  1035. tty_setcolor (in->color[WINPUTC_UNCHANGED]);
  1036. else
  1037. tty_setcolor (in->color[WINPUTC_MAIN]);
  1038. widget_move (&in->widget, 0, 0);
  1039. if (!in->is_password)
  1040. {
  1041. if (!in->highlight)
  1042. tty_print_string (str_term_substring (in->buffer, in->term_first_shown,
  1043. in->field_width - has_history));
  1044. else
  1045. {
  1046. long m1, m2;
  1047. if (input_eval_marks (in, &m1, &m2))
  1048. {
  1049. tty_setcolor (in->color[WINPUTC_MAIN]);
  1050. cp = str_term_substring (in->buffer, in->term_first_shown,
  1051. in->field_width - has_history);
  1052. tty_print_string (cp);
  1053. tty_setcolor (in->color[WINPUTC_MARK]);
  1054. if (m1 < in->term_first_shown)
  1055. {
  1056. widget_move (&in->widget, 0, 0);
  1057. tty_print_string (str_term_substring
  1058. (in->buffer, in->term_first_shown,
  1059. m2 - in->term_first_shown));
  1060. }
  1061. else
  1062. {
  1063. int sel_width;
  1064. widget_move (&in->widget, 0, m1 - in->term_first_shown);
  1065. sel_width =
  1066. min (m2 - m1,
  1067. (in->field_width - has_history) - (str_term_width2 (in->buffer, m1) -
  1068. in->term_first_shown));
  1069. tty_print_string (str_term_substring (in->buffer, m1, sel_width));
  1070. }
  1071. }
  1072. }
  1073. }
  1074. else
  1075. {
  1076. cp = str_term_substring (in->buffer, in->term_first_shown, in->field_width - has_history);
  1077. for (i = 0; i < in->field_width - has_history; i++)
  1078. {
  1079. if (i >= 0)
  1080. {
  1081. tty_setcolor (in->color[WINPUTC_MAIN]);
  1082. tty_print_char ((cp[0] != '\0') ? '*' : ' ');
  1083. }
  1084. if (cp[0] != '\0')
  1085. str_cnext_char (&cp);
  1086. }
  1087. }
  1088. if (clear_first)
  1089. in->first = FALSE;
  1090. }
  1091. /* --------------------------------------------------------------------------------------------- */
  1092. void
  1093. input_enable_update (WInput * in)
  1094. {
  1095. in->disable_update--;
  1096. input_update (in, FALSE);
  1097. }
  1098. /* --------------------------------------------------------------------------------------------- */
  1099. void
  1100. input_disable_update (WInput * in)
  1101. {
  1102. in->disable_update++;
  1103. }
  1104. /* --------------------------------------------------------------------------------------------- */
  1105. /* Cleans the input line and adds the current text to the history */
  1106. void
  1107. input_clean (WInput * in)
  1108. {
  1109. push_history (in, in->buffer);
  1110. in->need_push = TRUE;
  1111. in->buffer[0] = '\0';
  1112. in->point = 0;
  1113. in->charpoint = 0;
  1114. in->mark = 0;
  1115. in->highlight = FALSE;
  1116. input_free_completions (in);
  1117. input_update (in, FALSE);
  1118. }
  1119. /* --------------------------------------------------------------------------------------------- */
  1120. void
  1121. input_free_completions (WInput * in)
  1122. {
  1123. g_strfreev (in->completions);
  1124. in->completions = NULL;
  1125. }
  1126. /* --------------------------------------------------------------------------------------------- */