Ticket #4114: persistent_subshell_command_buffer4.patch

File persistent_subshell_command_buffer4.patch, 26.2 KB (added by congest, 4 years ago)
  • src/execute.c

    diff --git a/src/execute.c b/src/execute.c
    index d9b306e67..f35c53d94 100644
    a b toggle_subshell (void) 
    551551    { 
    552552        if (mc_global.mc_run_mode == MC_RUN_FULL) 
    553553        { 
    554             do_load_prompt (); 
    555554            if (new_dir_vpath != NULL) 
    556555                do_possible_cd (new_dir_vpath); 
    557556        } 
  • src/filemanager/layout.c

    diff --git a/src/filemanager/layout.c b/src/filemanager/layout.c
    index dfffa96f5..56318d99d 100644
    a b load_prompt (int fd, void *unused) 
    14971497{ 
    14981498    (void) fd; 
    14991499    (void) unused; 
    1500  
    1501     do_load_prompt (); 
     1500    if (should_read_new_subshell_prompt) 
     1501        do_load_prompt (); 
     1502    else 
     1503        flush_subshell(0, QUIETLY); 
    15021504    return 0; 
    15031505} 
    15041506#endif /* ENABLE_SUBSHELL */ 
  • src/subshell/common.c

    diff --git a/src/subshell/common.c b/src/subshell/common.c
    index 06699233c..256c3df85 100644
    a b  
    1515   Claes Nästén <me@pekdon.net> 
    1616   Egmont Koblinger <egmont@gmail.com> 
    1717   Enrico Weigelt, metux IT service <weigelt@metux.de> 
     18   Eric Roberts <ericmrobertsdeveloper@gmail.com> 
    1819   Igor Urazov <z0rc3r@gmail.com> 
    1920   Ilia Maslakov <il.smind@gmail.com> 
    2021   Leonard den Ottolander <leonard@den.ottolander.nl> 
     
    105106#include "lib/util.h" 
    106107#include "lib/widget.h" 
    107108 
     109#include "src/filemanager/layout.h"        /* setup_cmdline() */ 
     110#include "src/filemanager/command.h"        /* cmdline */ 
     111 
    108112#include "subshell.h" 
    109113#include "internal.h" 
    110114 
    GString *subshell_prompt = NULL; 
    123127/* We need to paint it after CONSOLE_RESTORE, see: load_prompt */ 
    124128gboolean update_subshell_prompt = FALSE; 
    125129 
     130/* If set, then a command has just finished executing, and we need */ 
     131/* to be on the lookout for a new prompt string from the subshell. */ 
     132gboolean should_read_new_subshell_prompt; 
     133 
    126134/*** file scope macro definitions ****************************************************************/ 
    127135 
    128136#ifndef WEXITSTATUS 
    enum 
    151159    WRITE = 1 
    152160}; 
    153161 
     162/* This is the keybinding that is sent to the shell, to make the shell send us the contents of 
     163 * the current command buffer. */ 
     164#define SHELL_BUFFER_KEYBINDING "_" 
     165 
     166/* This is the keybinding that is sent to the shell, to make the shell send us the location of 
     167 * the cursor. */ 
     168#define SHELL_CURSOR_KEYBINDING "+" 
     169 
    154170/*** file scope variables ************************************************************************/ 
    155171 
    156172/* tcsh closes all non-standard file descriptors, so we have to use a pipe */ 
    static char pty_buffer[PTY_BUFFER_SIZE] = "\0"; 
    169185/* To pass CWD info from the subshell to MC */ 
    170186static int subshell_pipe[2]; 
    171187 
     188/* To pass command buffer info from the subshell to MC */ 
     189static int command_buffer_pipe[2]; 
     190 
    172191/* The subshell's process ID */ 
    173192static pid_t subshell_pid = 1; 
    174193 
    static char subshell_cwd[MC_MAXPATHLEN + 1]; 
    178197/* Flag to indicate whether the subshell is ready for next command */ 
    179198static int subshell_ready; 
    180199 
     200/* Flag to indicate if the subshell supports the persistent buffer feature. */ 
     201static gboolean use_persistent_buffer = FALSE; 
     202 
     203/* Flag to indicate if the contents of the subshell command line need to be cleared before */ 
     204/* executing a command. This should only end up set to true if there is some sort of error.*/ 
     205/* This allows us to recover gracefully from an error.*/ 
     206static gboolean subshell_should_clear_command_line = FALSE; 
     207 
     208/* This is the local variable where the subshell prompt is stored while we are working on it. */ 
     209static GString *subshell_prompt_temp_buffer = NULL; 
     210 
    181211/* The following two flags can be changed by the SIGCHLD handler. This is */ 
    182212/* OK, because the 'int' type is updated atomically on all known machines */ 
    183213static volatile int subshell_alive, subshell_stopped; 
    init_subshell_child (const char *pty_name) 
    362392    dup2 (subshell_pty_slave, STDERR_FILENO); 
    363393 
    364394    close (subshell_pipe[READ]); 
     395    if (use_persistent_buffer == TRUE) 
     396        close (command_buffer_pipe[READ]); 
    365397    close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */ 
    366398    /* Close master side of pty.  This is important; apart from */ 
    367399    /* freeing up the descriptor for use in the subshell, it also       */ 
    synchronize (void) 
    469501} 
    470502 
    471503/* --------------------------------------------------------------------------------------------- */ 
     504/* Get the contents of the current subshell command line buffer, and */ 
     505/* transfer the contents to the panel command prompt. */ 
     506 
     507static gboolean 
     508read_command_line_buffer(gboolean test_mode) 
     509{ 
     510    fd_set read_set; 
     511    int i; 
     512    ssize_t bytes; 
     513    char subshell_command_buffer[BUF_LARGE]; 
     514    char subshell_cursor_buffer[BUF_SMALL]; 
     515    struct timeval subshell_prompt_timer = { 0, 0 }; 
     516    int command_buffer_length; 
     517    int command_buffer_char_length; 
     518    int cursor_position; 
     519    int maxfdp; 
     520    int rc; 
     521    char *end; 
     522 
     523    if (use_persistent_buffer == TRUE) 
     524    { 
     525        FD_ZERO (&read_set); 
     526        FD_SET (command_buffer_pipe[READ], &read_set); 
     527        maxfdp = command_buffer_pipe[READ]; 
     528        /* First, flush the command buffer pipe. This pipe shouldn't be written 
     529         * to under normal circumstances, but if it somehow does get written 
     530         * to, we need to make sure to discard whatever data is there before 
     531         * we try to use it. */ 
     532        while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0) 
     533        { 
     534            if (rc == -1) 
     535            { 
     536                if (errno == EINTR) 
     537                    continue; 
     538                else 
     539                    return FALSE; 
     540            } 
     541            else if (rc == 1) 
     542                read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 
     543        } 
     544        /* get contents of command line buffer */ 
     545        write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING, 
     546            sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 
     547        subshell_prompt_timer.tv_sec = 1; 
     548        FD_ZERO (&read_set); 
     549        FD_SET (command_buffer_pipe[READ], &read_set); 
     550        while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1) 
     551        { 
     552            if (rc == -1) 
     553            { 
     554                if (errno == EINTR) 
     555                    continue; 
     556                else 
     557                    return FALSE; 
     558            } 
     559            else if (rc == 0) 
     560                return FALSE; 
     561        } 
     562 
     563        bytes = read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 
     564        if (bytes == sizeof(subshell_command_buffer)) 
     565            return FALSE; 
     566        if (bytes == 0) 
     567            return FALSE; 
     568        subshell_command_buffer[bytes - 1] = 0; 
     569        command_buffer_char_length = bytes - 1; 
     570        command_buffer_length = str_length(subshell_command_buffer); 
     571 
     572        /* get cursor position */ 
     573        write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING, 
     574            sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 
     575        subshell_prompt_timer.tv_sec = 1; 
     576        subshell_prompt_timer.tv_usec = 0; 
     577        FD_ZERO (&read_set); 
     578        FD_SET (command_buffer_pipe[READ], &read_set); 
     579        while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1) 
     580        { 
     581            if (rc == -1) 
     582            { 
     583                if (errno == EINTR) 
     584                    continue; 
     585                else 
     586                    return FALSE; 
     587            } 
     588            else if (rc == 0) 
     589                return FALSE; 
     590        } 
     591        bytes = read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof(subshell_cursor_buffer)); 
     592        if (bytes == 0) 
     593            return FALSE; 
     594        subshell_cursor_buffer[bytes - 1] = 0; 
     595        cursor_position = strtol(subshell_cursor_buffer, &end, 10); 
     596        if (end == subshell_cursor_buffer) 
     597            return FALSE; 
     598 
     599        if (test_mode == TRUE) 
     600            return TRUE; 
     601        /* Erase non-text characters in the command buffer, such as tab, or newline, as this 
     602         * could cause problems. */ 
     603        for(i = 0;i < command_buffer_char_length;i++) 
     604        { 
     605            if ((unsigned char) subshell_command_buffer[i] < 32 
     606                || (unsigned char)subshell_command_buffer[i] == 127) 
     607                subshell_command_buffer[i] = ' '; 
     608        } 
     609        input_assign_text (cmdline, ""); 
     610        input_insert (cmdline, subshell_command_buffer, 0); 
     611 
     612        if (mc_global.shell->type == SHELL_BASH) 
     613        { 
     614            /* We need to do this because bash gives the cursor position in a utf-8 string based 
     615             * on the location in bytes, not in unicode characters. */ 
     616            for (i = 0;i < command_buffer_length;i++) 
     617                if (str_offset_to_pos(subshell_command_buffer, i) == cursor_position) 
     618                    break; 
     619            cursor_position = i; 
     620        } 
     621        if (cursor_position > command_buffer_length) 
     622            cursor_position = command_buffer_length; 
     623        cmdline->point = cursor_position; 
     624        /* We send any remaining data to STDOUT before we finish. */ 
     625        flush_subshell(0, VISIBLY); 
     626 
     627        /* Now we erase the current contents of the command line buffer */ 
     628        if (mc_global.shell->type != SHELL_ZSH) 
     629        /* In zsh, we can just press c-u to clear the line, without needing to go to the end of 
     630         * the line first first. In all other shells, we must go to the end of the line first. */ 
     631        { 
     632            /* If we are not at the end of the line, we go to the end. */ 
     633            if (cursor_position != command_buffer_length) 
     634            { 
     635                write_all (mc_global.tty.subshell_pty, "\005", 1); 
     636                if (flush_subshell(1, VISIBLY) != 1) 
     637                    return FALSE; 
     638            } 
     639        } 
     640        if (command_buffer_length > 0)    /* Now we clear the line. */ 
     641        { 
     642            write_all (mc_global.tty.subshell_pty, "\025", 1); 
     643            if (flush_subshell(1, VISIBLY) != 1) 
     644                return FALSE; 
     645        } 
     646    } 
     647    return TRUE; 
     648} 
     649 
     650/* --------------------------------------------------------------------------------------------- */ 
     651 
     652static void 
     653clear_subshell_prompt_string (void) 
     654{ 
     655    if(subshell_prompt_temp_buffer != NULL) 
     656        g_string_set_size (subshell_prompt_temp_buffer, 0); 
     657} 
     658 
     659/* --------------------------------------------------------------------------------------------- */ 
     660 
     661static void 
     662parse_subshell_prompt_string (const char *buffer, int bytes) 
     663{ 
     664    int i; 
     665 
     666    /* First time through */ 
     667    if (subshell_prompt == NULL) 
     668    { 
     669        subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE); 
     670    } 
     671    if (subshell_prompt_temp_buffer == NULL) 
     672    { 
     673        subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE); 
     674    } 
     675 
     676    /* Extract the prompt from the shell output */ 
     677    for (i = 0; i < bytes; i++) 
     678        if (buffer[i] == '\n' || buffer[i] == '\r') 
     679        { 
     680            g_string_set_size (subshell_prompt_temp_buffer, 0); 
     681        } 
     682        else if (buffer[i] != '\0') 
     683            g_string_append_c (subshell_prompt_temp_buffer, buffer[i]); 
     684} 
     685 
     686/* --------------------------------------------------------------------------------------------- */ 
     687 
     688static void 
     689set_prompt_string (void) 
     690{ 
     691    if (subshell_prompt_temp_buffer->len != 0) 
     692        g_string_assign (subshell_prompt, subshell_prompt_temp_buffer->str); 
     693 
     694    setup_cmdline(); 
     695} 
     696 
     697/* --------------------------------------------------------------------------------------------- */ 
    472698/** Feed the subshell our keyboard input until it says it's finished */ 
    473699 
    474700static gboolean 
    feed_subshell (int how, gboolean fail_on_error) 
    481707    struct timeval wtime;       /* Maximum time we wait for the subshell */ 
    482708    struct timeval *wptr; 
    483709 
     710    should_read_new_subshell_prompt = FALSE; 
     711    subshell_should_clear_command_line = FALSE; 
     712 
    484713    /* we wait up to 10 seconds if fail_on_error, forever otherwise */ 
    485714    wtime.tv_sec = 10; 
    486715    wtime.tv_usec = 0; 
    feed_subshell (int how, gboolean fail_on_error) 
    549778 
    550779            if (how == VISIBLY) 
    551780                write_all (STDOUT_FILENO, pty_buffer, bytes); 
     781            if (should_read_new_subshell_prompt == TRUE) 
     782            { 
     783                parse_subshell_prompt_string(pty_buffer, bytes); 
     784            } 
     785 
    552786        } 
    553787 
    554788        else if (FD_ISSET (subshell_pipe[READ], &read_set)) 
    feed_subshell (int how, gboolean fail_on_error) 
    567801 
    568802            synchronize (); 
    569803 
     804            clear_subshell_prompt_string(); 
     805            should_read_new_subshell_prompt = TRUE; 
    570806            subshell_ready = TRUE; 
    571807            if (subshell_state == RUNNING_COMMAND) 
    572808            { 
    feed_subshell (int how, gboolean fail_on_error) 
    578814        else if (FD_ISSET (STDIN_FILENO, &read_set)) 
    579815            /* Read from stdin, write to the subshell */ 
    580816        { 
     817            should_read_new_subshell_prompt = FALSE; 
    581818            bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer)); 
    582819            if (bytes <= 0) 
    583820            { 
    feed_subshell (int how, gboolean fail_on_error) 
    592829                { 
    593830                    write_all (mc_global.tty.subshell_pty, pty_buffer, i); 
    594831                    if (subshell_ready) 
     832                    { 
    595833                        subshell_state = INACTIVE; 
     834                        set_prompt_string (); 
     835                        if (subshell_ready == TRUE) 
     836                        { 
     837                            if (!read_command_line_buffer(FALSE)) 
     838                            { 
     839                                /* If we got here, some unforseen error must have occurred. */ 
     840                                flush_subshell(0, VISIBLY); 
     841                                input_assign_text (cmdline, ""); 
     842                                subshell_should_clear_command_line = TRUE; 
     843                                return TRUE; 
     844                            } 
     845                        } 
     846                    } 
    596847                    return TRUE; 
    597848                } 
    598849 
    599850            write_all (mc_global.tty.subshell_pty, pty_buffer, bytes); 
    600851 
    601852            if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r') 
     853            { 
     854                /* We should only clear the command line if we are using a shell that works 
     855                 * with persistent command buffer, otherwise we get awkward results. */ 
     856                if (use_persistent_buffer == TRUE) 
     857                    input_assign_text (cmdline, ""); 
    602858                subshell_ready = FALSE; 
     859            } 
    603860        } 
    604861        else 
    605862            return FALSE; 
    init_subshell_precmd (char *precmd, size_t buff_size) 
    7841041    { 
    7851042    case SHELL_BASH: 
    7861043        g_snprintf (precmd, buff_size, 
     1044                    " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"echo $READLINE_LINE>&%d\"'\n" 
     1045                    " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING "\":\"echo $READLINE_POINT>&%d\"'\n" 
    7871046                    " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n" 
    788                     "PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]); 
     1047                    "PS1='\\u@\\h:\\w\\$ '\n", 
     1048                    command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 
    7891049        break; 
    7901050 
    7911051    case SHELL_ASH_BUSYBOX: 
    init_subshell_precmd (char *precmd, size_t buff_size) 
    8441104 
    8451105    case SHELL_ZSH: 
    8461106        g_snprintf (precmd, buff_size, 
     1107                    " mc_print_command_buffer () { echo $BUFFER >&%d}\n" 
     1108                    " zle -N mc_print_command_buffer\n" 
     1109                    " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n" 
     1110                    " mc_print_cursor_position () { echo $CURSOR >&%d}\n" 
     1111                    " zle -N mc_print_cursor_position\n" 
     1112                    " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n" 
    8471113                    " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n" 
    848                     "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]); 
     1114                    "PS1='%%n@%%m:%%~%%# '\n", 
     1115                    command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 
    8491116        break; 
    8501117 
    8511118    case SHELL_TCSH: 
    init_subshell_precmd (char *precmd, size_t buff_size) 
    8541121                    "set prompt='%%n@%%m:%%~%%# '; " 
    8551122                    "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo); 
    8561123        break; 
    857  
    8581124    case SHELL_FISH: 
    8591125        g_snprintf (precmd, buff_size, 
    8601126                    " if not functions -q fish_prompt_mc;" 
    8611127                    "functions -e fish_right_prompt;" 
    8621128                    "functions -c fish_prompt fish_prompt_mc; end;" 
    8631129                    "function fish_prompt;" 
     1130                    "bind \\e\\" SHELL_BUFFER_KEYBINDING " 'echo (commandline)>&%d'\n" 
     1131                    "bind \\e\\" SHELL_CURSOR_KEYBINDING " 'echo (commandline -C)>&%d'\n" 
    8641132                    "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n", 
    865                     subshell_pipe[WRITE]); 
     1133                    command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 
    8661134        break; 
    8671135 
    8681136    default: 
    init_subshell (void) 
    10401308            mc_global.tty.use_subshell = FALSE; 
    10411309            return; 
    10421310        } 
     1311        if (mc_global.shell->type == SHELL_BASH 
     1312            || mc_global.shell->type == SHELL_ZSH 
     1313            || mc_global.shell->type == SHELL_FISH) 
     1314            use_persistent_buffer = TRUE; 
     1315        if (use_persistent_buffer == TRUE) 
     1316        { 
     1317            if (pipe (command_buffer_pipe)) 
     1318            { 
     1319                perror (__FILE__ ": couldn't create pipe"); 
     1320                mc_global.tty.use_subshell = FALSE; 
     1321                return; 
     1322            } 
     1323        } 
    10431324    } 
    10441325 
    10451326    /* Fork the subshell */ 
    init_subshell (void) 
    10611342        /* We are in the child process */ 
    10621343        init_subshell_child (pty_name); 
    10631344    } 
    1064  
    10651345    init_subshell_precmd (precmd, BUF_MEDIUM); 
    10661346 
    10671347    write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd)); 
    init_subshell (void) 
    10771357    tty_disable_interrupt_key (); 
    10781358    if (!subshell_alive) 
    10791359        mc_global.tty.use_subshell = FALSE;     /* Subshell died instantly, so don't use it */ 
     1360 
     1361    /* Try out the persistent command buffer feature. If it doesn't work the first time, we 
     1362     * assume there must be something wrong with the shell, and we turn persistent buffer off 
     1363     * for good. This will save the user the trouble of having to wait for the persistent 
     1364     * buffer function to time out every time they try to close the subshell. */ 
     1365    if (use_persistent_buffer == TRUE) 
     1366    { 
     1367        if (read_command_line_buffer(TRUE) == FALSE) 
     1368            use_persistent_buffer = FALSE; 
     1369    } 
    10801370} 
    10811371 
    10821372/* --------------------------------------------------------------------------------------------- */ 
    init_subshell (void) 
    10841374int 
    10851375invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 
    10861376{ 
     1377    size_t i; 
    10871378    /* Make the MC terminal transparent */ 
    10881379    tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode); 
    10891380 
    invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 
    11001391            /* FIXME: possibly take out this hack; the user can re-play it by hitting C-hyphen a few times! */ 
    11011392            if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL) 
    11021393                write_all (mc_global.tty.subshell_pty, " \b", 2);       /* Hack to make prompt reappear */ 
     1394  
     1395            if (use_persistent_buffer == TRUE) 
     1396            { 
     1397                /* Check to make sure there are no non text characters in the command buffer, 
     1398                 * such as tab, or newline, as this could cause problems. */ 
     1399                for(i = 0;i < strlen(cmdline->buffer);i++) 
     1400                { 
     1401                    if ((unsigned char) cmdline->buffer[i] < 32 
     1402                        || (unsigned char)cmdline->buffer[i] == 127) 
     1403                        cmdline->buffer[i] = ' '; 
     1404                } 
     1405 
     1406                /* Write the command buffer to the subshell. */ 
     1407                write_all (mc_global.tty.subshell_pty, cmdline->buffer, strlen (cmdline->buffer)); 
     1408 
     1409                /* Put the cursor in the correct place in the subshell. */ 
     1410                for (int j = 0;j < str_length (cmdline->buffer) - cmdline->point;j++) 
     1411                    write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3); 
     1412            } 
    11031413        } 
    11041414    } 
    11051415    else                        /* MC has passed us a user command */ 
    11061416    { 
     1417        /* Before we write to the command prompt, we need to clear whatever */ 
     1418        /* data is there, but only if we are using one of the shells that */ 
     1419        /* doesn't support keeping command buffer contents, OR if there was */ 
     1420        /* some sort of error. */ 
     1421        if (use_persistent_buffer == FALSE || subshell_should_clear_command_line == TRUE) 
     1422        { 
     1423            write_all (mc_global.tty.subshell_pty, "\003", 1); 
     1424            subshell_state = RUNNING_COMMAND; 
     1425            /* We need to call feed_subshell here if we are using fish, because of a quirk 
     1426             * in the behavioral of that particular shell. */ 
     1427            if (mc_global.shell->type != SHELL_FISH) 
     1428                feed_subshell (QUIETLY, FALSE); 
     1429        } 
    11071430        if (how == QUIETLY) 
    11081431            write_all (mc_global.tty.subshell_pty, " ", 1); 
    11091432        /* FIXME: if command is long (>8KB ?) we go comma */ 
    invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 
    11311454    return subshell_get_mainloop_quit (); 
    11321455} 
    11331456 
    1134  
    11351457/* --------------------------------------------------------------------------------------------- */ 
    11361458 
    11371459gboolean 
    1138 read_subshell_prompt (void) 
     1460flush_subshell (int max_wait_length, int how) 
    11391461{ 
    11401462    int rc = 0; 
    11411463    ssize_t bytes = 0; 
    11421464    struct timeval timeleft = { 0, 0 }; 
    1143     GString *p; 
    1144     gboolean prompt_was_reset = FALSE; 
    1145  
     1465    int return_value = FALSE; 
    11461466    fd_set tmp; 
     1467 
     1468    timeleft.tv_sec = max_wait_length; 
    11471469    FD_ZERO (&tmp); 
    11481470    FD_SET (mc_global.tty.subshell_pty, &tmp); 
    11491471 
    1150     /* First time through */ 
    1151     if (subshell_prompt == NULL) 
    1152         subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE); 
    1153  
    1154     p = g_string_sized_new (INITIAL_PROMPT_SIZE); 
    1155  
    11561472    while (subshell_alive 
    11571473           && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 
    11581474    { 
    1159         ssize_t i; 
    1160  
    11611475        /* Check for 'select' errors */ 
    11621476        if (rc == -1) 
    11631477        { 
    read_subshell_prompt (void) 
    11721486            fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 
    11731487            exit (EXIT_FAILURE); 
    11741488        } 
     1489        return_value = TRUE; 
     1490        timeleft.tv_sec = 0; 
     1491        timeleft.tv_usec = 0; 
    11751492 
    11761493        bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 
     1494        if (how == VISIBLY) 
     1495            write_all (STDOUT_FILENO, pty_buffer, bytes); 
     1496    } 
     1497    return return_value; 
     1498} 
     1499 
     1500/* --------------------------------------------------------------------------------------------- */ 
     1501 
     1502gboolean 
     1503read_subshell_prompt (void) 
     1504{ 
     1505    int rc = 0; 
     1506    ssize_t bytes = 0; 
     1507    struct timeval timeleft = { 0, 0 }; 
     1508    int should_reset_prompt = TRUE; 
     1509    int got_new_prompt = FALSE; 
     1510 
     1511    fd_set tmp; 
     1512    FD_ZERO (&tmp); 
     1513    FD_SET (mc_global.tty.subshell_pty, &tmp); 
    11771514 
    1178         /* Extract the prompt from the shell output */ 
    1179         for (i = 0; i < bytes; i++) 
    1180             if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') 
     1515    while (subshell_alive 
     1516           && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 
     1517    { 
     1518        /* Check for 'select' errors */ 
     1519        if (rc == -1) 
     1520        { 
     1521            if (errno == EINTR) 
    11811522            { 
    1182                 g_string_set_size (p, 0); 
    1183                 prompt_was_reset = TRUE; 
     1523                if (tty_got_winch ()) 
     1524                    tty_change_screen_size (); 
     1525 
     1526                continue; 
    11841527            } 
    1185             else if (pty_buffer[i] != '\0') 
    1186                 g_string_append_c (p, pty_buffer[i]); 
    1187     } 
    11881528 
    1189     if (p->len != 0 || prompt_was_reset) 
    1190         g_string_assign (subshell_prompt, p->str); 
     1529            fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 
     1530            exit (EXIT_FAILURE); 
     1531        } 
    11911532 
    1192     g_string_free (p, TRUE); 
     1533        bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 
     1534        if (should_reset_prompt) 
     1535        { 
     1536            should_reset_prompt = FALSE; 
     1537            clear_subshell_prompt_string(); 
     1538        } 
     1539        parse_subshell_prompt_string (pty_buffer, bytes); 
     1540        got_new_prompt = TRUE; 
     1541    } 
     1542    if (got_new_prompt == TRUE) 
     1543    { 
     1544        set_prompt_string (); 
     1545    } 
    11931546 
    11941547    return (rc != 0 || bytes != 0); 
    11951548} 
    exit_subshell (void) 
    12311584 
    12321585        g_string_free (subshell_prompt, TRUE); 
    12331586        subshell_prompt = NULL; 
     1587        g_string_free (subshell_prompt_temp_buffer, TRUE); 
     1588        subshell_prompt_temp_buffer = NULL; 
    12341589        pty_buffer[0] = '\0'; 
    12351590    } 
    12361591 
    do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt) 
    12591614        return; 
    12601615    } 
    12611616 
     1617    /* If we are using a shell that doesn't support persistent command buffer, we need to clear 
     1618     * the command prompt before we send the cd command. */ 
     1619    if (use_persistent_buffer == FALSE || subshell_should_clear_command_line == TRUE) 
     1620    { 
     1621        write_all (mc_global.tty.subshell_pty, "\003", 1); 
     1622        subshell_state = RUNNING_COMMAND; 
     1623        if (mc_global.shell->type != SHELL_FISH) 
     1624            feed_subshell (QUIETLY, FALSE); 
     1625    } 
    12621626    /* The initial space keeps this out of the command history (in bash 
    12631627       because we set "HISTCONTROL=ignorespace") */ 
    12641628    write_all (mc_global.tty.subshell_pty, " cd ", 4); 
  • src/subshell/subshell.h

    diff --git a/src/subshell/subshell.h b/src/subshell/subshell.h
    index e0fdfb13e..bde19c469 100644
    a b extern GString *subshell_prompt; 
    3636 
    3737extern gboolean update_subshell_prompt; 
    3838 
     39extern gboolean should_read_new_subshell_prompt; 
     40 
    3941/*** declarations of public functions ************************************************************/ 
    4042 
    4143void init_subshell (void); 
    4244int invoke_subshell (const char *command, int how, vfs_path_t ** new_dir); 
     45gboolean flush_subshell (int max_wait_length, int how); 
    4346gboolean read_subshell_prompt (void); 
    4447void do_update_prompt (void); 
    4548gboolean exit_subshell (void);