You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

579 lines
23 KiB

  1. --- a/lib/global.c
  2. +++ b/lib/global.c
  3. @@ -97,6 +97,7 @@ mc_global_t mc_global = {
  4. #endif /* !ENABLE_SUBSHELL */
  5. .shell = NULL,
  6. + .shell_realpath = NULL,
  7. .xterm_flag = FALSE,
  8. .disable_x11 = FALSE,
  9. --- a/lib/global.h
  10. +++ b/lib/global.h
  11. @@ -255,6 +255,7 @@ typedef struct
  12. /* The user's shell */
  13. char *shell;
  14. + char *shell_realpath;
  15. /* This flag is set by xterm detection routine in function main() */
  16. /* It is used by function view_other_cmd() */
  17. --- a/lib/mcconfig/paths.c
  18. +++ b/lib/mcconfig/paths.c
  19. @@ -84,6 +84,7 @@ static const struct
  20. /* data */
  21. { "skins", &mc_data_str, MC_SKINS_SUBDIR},
  22. { "fish", &mc_data_str, FISH_PREFIX},
  23. + { "ashrc", &mc_data_str, "ashrc"},
  24. { "bashrc", &mc_data_str, "bashrc"},
  25. { "inputrc", &mc_data_str, "inputrc"},
  26. { "extfs.d", &mc_data_str, MC_EXTFS_DIR},
  27. --- a/src/main.c
  28. +++ b/src/main.c
  29. @@ -87,6 +87,9 @@
  30. /*** file scope variables ************************************************************************/
  31. /*** file scope functions ************************************************************************/
  32. +
  33. +static char rp_shell[PATH_MAX];
  34. +
  35. /* --------------------------------------------------------------------------------------------- */
  36. static void
  37. @@ -118,6 +121,44 @@ check_codeset (void)
  38. }
  39. /* --------------------------------------------------------------------------------------------- */
  40. +/**
  41. + * Get a system shell.
  42. + *
  43. + * @return newly allocated string with shell name
  44. + */
  45. +
  46. +static char *
  47. +mc_get_system_shell (void)
  48. +{
  49. + char *sh_str;
  50. + /* 3rd choice: look for existing shells supported as MC subshells. */
  51. + if (access ("/bin/bash", X_OK) == 0)
  52. + sh_str = g_strdup ("/bin/bash");
  53. + else if (access ("/bin/ash", X_OK) == 0)
  54. + sh_str = g_strdup ("/bin/ash");
  55. + else if (access ("/bin/dash", X_OK) == 0)
  56. + sh_str = g_strdup ("/bin/dash");
  57. + else if (access ("/bin/busybox", X_OK) == 0)
  58. + sh_str = g_strdup ("/bin/busybox");
  59. + else if (access ("/bin/zsh", X_OK) == 0)
  60. + sh_str = g_strdup ("/bin/zsh");
  61. + else if (access ("/bin/tcsh", X_OK) == 0)
  62. + sh_str = g_strdup ("/bin/tcsh");
  63. + /* No fish as fallback because it is so much different from other shells and
  64. + * in a way exotic (even though user-friendly by name) that we should not
  65. + * present it as a subshell without the user's explicit intention. We rather
  66. + * will not use a subshell but just a command line.
  67. + * else if (access("/bin/fish", X_OK) == 0)
  68. + * mc_global.tty.shell = g_strdup ("/bin/fish");
  69. + */
  70. + else
  71. + /* Fallback and last resort: system default shell */
  72. + sh_str = g_strdup ("/bin/sh");
  73. +
  74. + return sh_str;
  75. +}
  76. +
  77. +/* --------------------------------------------------------------------------------------------- */
  78. /** POSIX version. The only version we support. */
  79. static void
  80. @@ -126,9 +167,11 @@ OS_Setup (void)
  81. const char *shell_env;
  82. const char *datadir_env;
  83. +
  84. shell_env = getenv ("SHELL");
  85. if ((shell_env == NULL) || (shell_env[0] == '\0'))
  86. {
  87. + /* 2nd choice: user login shell */
  88. struct passwd *pwd;
  89. pwd = getpwuid (geteuid ());
  90. @@ -136,13 +179,15 @@ OS_Setup (void)
  91. mc_global.tty.shell = g_strdup (pwd->pw_shell);
  92. }
  93. else
  94. + /* 1st choice: SHELL environment variable */
  95. mc_global.tty.shell = g_strdup (shell_env);
  96. if ((mc_global.tty.shell == NULL) || (mc_global.tty.shell[0] == '\0'))
  97. {
  98. g_free (mc_global.tty.shell);
  99. - mc_global.tty.shell = g_strdup ("/bin/sh");
  100. + mc_global.tty.shell = mc_get_system_shell ();
  101. }
  102. + mc_global.tty.shell_realpath = mc_realpath (mc_global.tty.shell, rp_shell);
  103. /* This is the directory, where MC was installed, on Unix this is DATADIR */
  104. /* and can be overriden by the MC_DATADIR environment variable */
  105. --- a/src/subshell.c
  106. +++ b/src/subshell.c
  107. @@ -114,6 +114,8 @@ enum
  108. static enum
  109. {
  110. BASH,
  111. + ASH_BUSYBOX, /* BusyBox default shell (ash) */
  112. + DASH, /* Debian variant of ash */
  113. TCSH,
  114. ZSH,
  115. FISH
  116. @@ -209,6 +211,7 @@ static void
  117. init_subshell_child (const char *pty_name)
  118. {
  119. char *init_file = NULL;
  120. + char *putenv_str = NULL;
  121. pid_t mc_sid;
  122. (void) pty_name;
  123. @@ -257,32 +260,53 @@ init_subshell_child (const char *pty_nam
  124. switch (subshell_type)
  125. {
  126. case BASH:
  127. + /* Do we have a custom init file ~/.local/share/mc/bashrc? */
  128. init_file = mc_config_get_full_path ("bashrc");
  129. + /* Otherwise use ~/.bashrc */
  130. if (access (init_file, R_OK) == -1)
  131. {
  132. g_free (init_file);
  133. init_file = g_strdup (".bashrc");
  134. }
  135. - /* Make MC's special commands not show up in bash's history */
  136. - putenv ((char *) "HISTCONTROL=ignorespace");
  137. + /* Make MC's special commands not show up in bash's history and also suppress
  138. + * consecutive identical commands*/
  139. + putenv ((char *) "HISTCONTROL=ignoreboth");
  140. /* Allow alternative readline settings for MC */
  141. {
  142. char *input_file = mc_config_get_full_path ("inputrc");
  143. if (access (input_file, R_OK) == 0)
  144. {
  145. - char *putenv_str = g_strconcat ("INPUTRC=", input_file, NULL);
  146. + putenv_str = g_strconcat ("INPUTRC=", input_file, NULL);
  147. putenv (putenv_str);
  148. - g_free (putenv_str);
  149. }
  150. g_free (input_file);
  151. }
  152. break;
  153. - /* TODO: Find a way to pass initfile to TCSH and ZSH */
  154. + case ASH_BUSYBOX:
  155. + case DASH:
  156. + /* Do we have a custom init file ~/.local/share/mc/ashrc? */
  157. + init_file = mc_config_get_full_path ("ashrc");
  158. +
  159. + /* Otherwise use ~/.profile */
  160. + if (access (init_file, R_OK) == -1)
  161. + {
  162. + g_free (init_file);
  163. + init_file = g_strdup (".profile");
  164. + }
  165. +
  166. + /* Put init file to ENV variable used by ash */
  167. + putenv_str = g_strconcat ("ENV=", init_file, NULL);
  168. + putenv (putenv_str);
  169. + /* Do not use "g_free (putenv_str)" here, otherwise ENV will be undefined! */
  170. +
  171. + break;
  172. +
  173. + /* TODO: Find a way to pass initfile to TCSH, ZSH and FISH */
  174. case TCSH:
  175. case ZSH:
  176. case FISH:
  177. @@ -320,10 +344,6 @@ init_subshell_child (const char *pty_nam
  178. execl (mc_global.tty.shell, "bash", "-rcfile", init_file, (char *) NULL);
  179. break;
  180. - case TCSH:
  181. - execl (mc_global.tty.shell, "tcsh", (char *) NULL);
  182. - break;
  183. -
  184. case ZSH:
  185. /* Use -g to exclude cmds beginning with space from history
  186. * and -Z to use the line editor on non-interactive term */
  187. @@ -331,8 +351,11 @@ init_subshell_child (const char *pty_nam
  188. break;
  189. + case ASH_BUSYBOX:
  190. + case DASH:
  191. + case TCSH:
  192. case FISH:
  193. - execl (mc_global.tty.shell, "fish", (char *) NULL);
  194. + execl (mc_global.tty.shell, mc_global.tty.shell, (char *) NULL);
  195. break;
  196. default:
  197. @@ -341,6 +364,7 @@ init_subshell_child (const char *pty_nam
  198. /* If we get this far, everything failed miserably */
  199. g_free (init_file);
  200. + g_free (putenv_str);
  201. my_exit (FORK_FAILURE);
  202. }
  203. @@ -742,6 +766,171 @@ pty_open_slave (const char *pty_name)
  204. }
  205. #endif /* !HAVE_GRANTPT */
  206. +
  207. +/* --------------------------------------------------------------------------------------------- */
  208. +/**
  209. + * Get a subshell type and store in subshell_type variable
  210. + *
  211. + * @return TRUE if subtype was gotten, FALSE otherwise
  212. + */
  213. +
  214. +static gboolean
  215. +init_subshell_type (void)
  216. +{
  217. + gboolean result = TRUE;
  218. +
  219. + /* Find out what type of shell we have. Also consider real paths (resolved symlinks)
  220. + * because e.g. csh might point to tcsh, ash to dash or busybox, sh to anything. */
  221. +
  222. + if (strstr (mc_global.tty.shell, "/zsh") || strstr (mc_global.tty.shell_realpath, "/zsh")
  223. + || getenv ("ZSH_VERSION"))
  224. + /* Also detects ksh symlinked to zsh */
  225. + subshell_type = ZSH;
  226. + else if (strstr (mc_global.tty.shell, "/tcsh")
  227. + || strstr (mc_global.tty.shell_realpath, "/tcsh"))
  228. + /* Also detects csh symlinked to tcsh */
  229. + subshell_type = TCSH;
  230. + else if (strstr (mc_global.tty.shell, "/fish")
  231. + || strstr (mc_global.tty.shell_realpath, "/fish"))
  232. + subshell_type = FISH;
  233. + else if (strstr (mc_global.tty.shell, "/dash")
  234. + || strstr (mc_global.tty.shell_realpath, "/dash"))
  235. + /* Debian ash (also found if symlinked to by ash/sh) */
  236. + subshell_type = DASH;
  237. + else if (strstr (mc_global.tty.shell_realpath, "/busybox"))
  238. + {
  239. + /* If shell is symlinked to busybox, assume it is an ash, even though theoretically
  240. + * it could also be a hush (a mini shell for non-MMU systems deactivated by default).
  241. + * For simplicity's sake we assume that busybox always contains an ash, not a hush.
  242. + * On embedded platforms or on server systems, /bin/sh often points to busybox.
  243. + * Sometimes even bash is symlinked to busybox (CONFIG_FEATURE_BASH_IS_ASH option),
  244. + * so we need to check busybox symlinks *before* checking for the name "bash"
  245. + * in order to avoid that case. */
  246. + subshell_type = ASH_BUSYBOX;
  247. + }
  248. + else if (strstr (mc_global.tty.shell, "/bash") || getenv ("BASH"))
  249. + /* If bash is not symlinked to busybox, it is safe to assume it is a real bash */
  250. + subshell_type = BASH;
  251. + else
  252. + {
  253. + mc_global.tty.use_subshell = FALSE;
  254. + result = FALSE;
  255. + }
  256. + return result;
  257. +}
  258. +
  259. +/* --------------------------------------------------------------------------------------------- */
  260. +/**
  261. + * Set up `precmd' or equivalent for reading the subshell's CWD.
  262. + *
  263. + * Attention! Never forget that these are *one-liners* even though the concatenated
  264. + * substrings contain line breaks and indentation for better understanding of the
  265. + * shell code. It is vital that each one-liner ends with a line feed character ("\n" ).
  266. + *
  267. + * @return initialized pre-command string
  268. + */
  269. +
  270. +static void
  271. +init_subshell_precmd (char *precmd, size_t buff_size)
  272. +{
  273. +
  274. + switch (subshell_type)
  275. + {
  276. + case BASH:
  277. + g_snprintf (precmd, buff_size,
  278. + " PROMPT_COMMAND='pwd>&%d; kill -STOP $$';\n", subshell_pipe[WRITE]);
  279. + break;
  280. +
  281. + case ASH_BUSYBOX:
  282. + /* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
  283. + * that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
  284. + *
  285. + * A: This leads to a stopped subshell (=frozen mc) if user calls "ash" command
  286. + * "PS1='$(pwd>&%d; kill -STOP $$)\\u@\\h:\\w\\$ '\n",
  287. + *
  288. + * B: This leads to "sh: precmd: not found" in sub-subshell if user calls "ash" command
  289. + * "precmd() { pwd>&%d; kill -STOP $$; }; "
  290. + * "PS1='$(precmd)\\u@\\h:\\w\\$ '\n",
  291. + *
  292. + * C: This works if user calls "ash" command because in sub-subshell
  293. + * PRECMD is unfedined, thus evaluated to empty string - no damage done.
  294. + * Attention: BusyBox must be built with FEATURE_EDITING_FANCY_PROMPT to
  295. + * permit \u, \w, \h, \$ escape sequences. Unfortunately this cannot be guaranteed,
  296. + * especially on embedded systems where people try to save space, so let's use
  297. + * the dash version below. It should work on virtually all systems.
  298. + * "precmd() { pwd>&%d; kill -STOP $$; }; "
  299. + * "PRECMD=precmd; "
  300. + * "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
  301. + */
  302. + case DASH:
  303. + /* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
  304. + * but does not support escape sequences for user, host and cwd in prompt.
  305. + * Attention! Make sure that the buffer for precmd is big enough.
  306. + *
  307. + * We want to have a fancy dynamic prompt with user@host:cwd just like in the BusyBox
  308. + * examples above, but because replacing the home directory part of the path by "~" is
  309. + * complicated, it bloats the precmd to a size > BUF_SMALL (128).
  310. + *
  311. + * The following example is a little less fancy (home directory not replaced)
  312. + * and shows the basic workings of our prompt for easier understanding:
  313. + *
  314. + * "precmd() { "
  315. + * "echo \"$USER@$(hostname -s):$PWD\"; "
  316. + * "pwd>&%d; "
  317. + * "kill -STOP $$; "
  318. + * "}; "
  319. + * "PRECMD=precmd; "
  320. + * "PS1='$($PRECMD)$ '\n",
  321. + */
  322. + g_snprintf (precmd, buff_size,
  323. + "precmd() { "
  324. + "if [ ! \"${PWD##$HOME}\" ]; then "
  325. + "MC_PWD=\"~\"; "
  326. + "else "
  327. + "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; "
  328. + "fi; "
  329. + "echo \"$USER@openwrt:$MC_PWD\"; "
  330. + "pwd>&%d; "
  331. + "kill -STOP $$; "
  332. + "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
  333. + break;
  334. +
  335. + case ZSH:
  336. + g_snprintf (precmd, buff_size,
  337. + " precmd() { pwd>&%d; kill -STOP $$; }; "
  338. + "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]);
  339. + break;
  340. +
  341. + case TCSH:
  342. + g_snprintf (precmd, buff_size,
  343. + "set echo_style=both; "
  344. + "set prompt='%%n@%%m:%%~%%# '; "
  345. + "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
  346. + break;
  347. +
  348. + case FISH:
  349. + /* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also
  350. + * use colours, which is what we will do. But first here is a simpler, uncoloured version:
  351. + * "function fish_prompt; "
  352. + * "echo (whoami)@(hostname -s):(pwd)\\$\\ ; "
  353. + * "echo \"$PWD\">&%d; "
  354. + * "kill -STOP %%self; "
  355. + * "end\n",
  356. + *
  357. + * TODO: fish prompt is shown when panel is hidden (Ctrl-O), but not when it is visible.
  358. + * Find out how to fix this.
  359. + */
  360. + g_snprintf (precmd, buff_size,
  361. + "function fish_prompt; "
  362. + "echo (whoami)@(hostname -s):(set_color $fish_color_cwd)(pwd)(set_color normal)\\$\\ ; "
  363. + "echo \"$PWD\">&%d; " "kill -STOP %%self; " "end\n", subshell_pipe[WRITE]);
  364. + break;
  365. +
  366. + default:
  367. + break;
  368. + }
  369. +}
  370. +
  371. /* --------------------------------------------------------------------------------------------- */
  372. /*** public functions ****************************************************************************/
  373. /* --------------------------------------------------------------------------------------------- */
  374. @@ -761,6 +950,7 @@ init_subshell (void)
  375. {
  376. /* This must be remembered across calls to init_subshell() */
  377. static char pty_name[BUF_SMALL];
  378. + /* Must be considerably longer than BUF_SMALL (128) to support fancy shell prompts */
  379. char precmd[BUF_MEDIUM];
  380. switch (check_sid ())
  381. @@ -782,23 +972,8 @@ init_subshell (void)
  382. if (mc_global.tty.subshell_pty == 0)
  383. { /* First time through */
  384. - /* Find out what type of shell we have */
  385. -
  386. - if (strstr (mc_global.tty.shell, "/zsh") || getenv ("ZSH_VERSION"))
  387. - subshell_type = ZSH;
  388. - else if (strstr (mc_global.tty.shell, "/tcsh"))
  389. - subshell_type = TCSH;
  390. - else if (strstr (mc_global.tty.shell, "/csh"))
  391. - subshell_type = TCSH;
  392. - else if (strstr (mc_global.tty.shell, "/bash") || getenv ("BASH"))
  393. - subshell_type = BASH;
  394. - else if (strstr (mc_global.tty.shell, "/fish"))
  395. - subshell_type = FISH;
  396. - else
  397. - {
  398. - mc_global.tty.use_subshell = FALSE;
  399. + if (!init_subshell_type ())
  400. return;
  401. - }
  402. /* Open a pty for talking to the subshell */
  403. @@ -844,7 +1019,7 @@ init_subshell (void)
  404. return;
  405. }
  406. }
  407. - else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe))
  408. + else if (pipe (subshell_pipe)) /* subshell_type is BASH, ASH_BUSYBOX, DASH or ZSH */
  409. {
  410. perror (__FILE__ ": couldn't create pipe");
  411. mc_global.tty.use_subshell = FALSE;
  412. @@ -872,39 +1047,116 @@ init_subshell (void)
  413. init_subshell_child (pty_name);
  414. }
  415. - /* Set up 'precmd' or equivalent for reading the subshell's CWD */
  416. + init_subshell_precmd (precmd, BUF_MEDIUM);
  417. +
  418. + /* Set up `precmd' or equivalent for reading the subshell's CWD
  419. + *
  420. + * Attention! Never forget that these are *one-liners* even though the concatenated
  421. + * substrings contain line breaks and indentation for better understanding of the
  422. + * shell code. It is vital that each one-liner ends with a line feed character ("\n" ).
  423. + */
  424. switch (subshell_type)
  425. {
  426. case BASH:
  427. g_snprintf (precmd, sizeof (precmd),
  428. - " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n",
  429. - subshell_pipe[WRITE]);
  430. + " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n"
  431. + "PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]);
  432. + break;
  433. +
  434. + case ASH_BUSYBOX:
  435. + /* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
  436. + * that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
  437. + *
  438. + * A: This leads to a stopped subshell (=frozen mc) if user calls "ash" command
  439. + * "PS1='$(pwd>&%d; kill -STOP $$)\\u@\\h:\\w\\$ '\n",
  440. + *
  441. + * B: This leads to "sh: precmd: not found" in sub-subshell if user calls "ash" command
  442. + * "precmd() { pwd>&%d; kill -STOP $$; }; "
  443. + * "PS1='$(precmd)\\u@\\h:\\w\\$ '\n",
  444. + *
  445. + * C: This works if user calls "ash" command because in sub-subshell
  446. + * PRECMD is unfedined, thus evaluated to empty string - no damage done.
  447. + * Attention: BusyBox must be built with FEATURE_EDITING_FANCY_PROMPT to
  448. + * permit \u, \w, \h, \$ escape sequences. Unfortunately this cannot be guaranteed,
  449. + * especially on embedded systems where people try to save space, so let's use
  450. + * the dash version below. It should work on virtually all systems.
  451. + * "precmd() { pwd>&%d; kill -STOP $$; }; "
  452. + * "PRECMD=precmd; "
  453. + * "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
  454. + */
  455. + case DASH:
  456. + /* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
  457. + * but does not support escape sequences for user, host and cwd in prompt.
  458. + * Attention! Make sure that the buffer for precmd is big enough.
  459. + *
  460. + * We want to have a fancy dynamic prompt with user@host:cwd just like in the BusyBox
  461. + * examples above, but because replacing the home directory part of the path by "~" is
  462. + * complicated, it bloats the precmd to a size > BUF_SMALL (128).
  463. + *
  464. + * The following example is a little less fancy (home directory not replaced)
  465. + * and shows the basic workings of our prompt for easier understanding:
  466. + *
  467. + * "precmd() { "
  468. + * "echo \"$USER@$(hostname -s):$PWD\"; "
  469. + * "pwd>&%d; "
  470. + * "kill -STOP $$; "
  471. + * "}; "
  472. + * "PRECMD=precmd; "
  473. + * "PS1='$($PRECMD)$ '\n",
  474. + */
  475. + g_snprintf (precmd, sizeof (precmd),
  476. + "precmd() { "
  477. + "if [ ! \"${PWD##$HOME}\" ]; then "
  478. + "MC_PWD=\"~\"; "
  479. + "else "
  480. + "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; "
  481. + "fi; "
  482. + "echo \"$USER@openwrt:$MC_PWD\"; "
  483. + "pwd>&%d; "
  484. + "kill -STOP $$; "
  485. + "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
  486. break;
  487. case ZSH:
  488. g_snprintf (precmd, sizeof (precmd),
  489. - " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n",
  490. - subshell_pipe[WRITE]);
  491. + " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n"
  492. + "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]);
  493. break;
  494. case TCSH:
  495. g_snprintf (precmd, sizeof (precmd),
  496. - "set echo_style=both;"
  497. - "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n", tcsh_fifo);
  498. + "set echo_style=both; "
  499. + "set prompt='%%n@%%m:%%~%%# '; "
  500. + "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
  501. break;
  502. +
  503. case FISH:
  504. /* Use fish_prompt_mc function for prompt, if not present then copy fish_prompt to it. */
  505. + /* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also
  506. + * use colours, which is what we will do. But first here is a simpler, uncoloured version:
  507. + * "function fish_prompt; "
  508. + * "echo (whoami)@(hostname -s):(pwd)\\$\\ ; "
  509. + * "echo \"$PWD\">&%d; "
  510. + * "kill -STOP %%self; "
  511. + * "end\n",
  512. + *
  513. + * TODO: fish prompt is shown when panel is hidden (Ctrl-O), but not when it is visible.
  514. + * Find out how to fix this.
  515. + */
  516. g_snprintf (precmd, sizeof (precmd),
  517. "if not functions -q fish_prompt_mc;"
  518. "functions -c fish_prompt fish_prompt_mc; end;"
  519. - "function fish_prompt; echo $PWD>&%d; fish_prompt_mc; kill -STOP %%self; end\n",
  520. + "function fish_prompt;"
  521. + "echo (whoami)@(hostname -s):(set_color $fish_color_cwd)(pwd)(set_color normal)\\$\\ ; "
  522. + "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n",
  523. subshell_pipe[WRITE]);
  524. break;
  525. default:
  526. break;
  527. }
  528. +
  529. write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd));
  530. /* Wait until the subshell has started up and processed the command */
  531. @@ -1108,6 +1360,13 @@ subshell_name_quote (const char *s)
  532. quote_cmd_start = "(printf \"%b\" '";
  533. quote_cmd_end = "')";
  534. }
  535. + /* TODO: When BusyBox printf is fixed, get rid of this "else if", see
  536. + http://lists.busybox.net/pipermail/busybox/2012-March/077460.html */
  537. + /* else if (subshell_type == ASH_BUSYBOX)
  538. + {
  539. + quote_cmd_start = "\"`echo -en '";
  540. + quote_cmd_end = "'`\"";
  541. + } */
  542. else
  543. {
  544. quote_cmd_start = "\"`printf \"%b\" '";