Ticket #4114: persistent_subshell_command_buffer2.patch

File persistent_subshell_command_buffer2.patch, 24.1 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..eb794251f 100644
    a b  
    105105#include "lib/util.h" 
    106106#include "lib/widget.h" 
    107107 
     108#include "src/filemanager/layout.h"        /* setup_cmdline() */ 
     109#include "src/filemanager/command.h"        /* cmdline */ 
     110 
    108111#include "subshell.h" 
    109112#include "internal.h" 
    110113 
    GString *subshell_prompt = NULL; 
    123126/* We need to paint it after CONSOLE_RESTORE, see: load_prompt */ 
    124127gboolean update_subshell_prompt = FALSE; 
    125128 
     129/* If set, then a command has just finished executing, and we need */ 
     130/* to be on the lookout for a new prompt string from the subshell. */ 
     131gboolean should_read_new_subshell_prompt; 
     132 
    126133/*** file scope macro definitions ****************************************************************/ 
    127134 
    128135#ifndef WEXITSTATUS 
    enum 
    151158    WRITE = 1 
    152159}; 
    153160 
     161/* This is the keybinding that is sent to the shell, to make the shell send us the contents of 
     162 * the current command buffer. */ 
     163#define SHELL_BUFFER_KEYBINDING "[98~" 
     164 
     165/* This is the keybinding that is sent to the shell, to make the shell send us the location of 
     166 * the cursor. */ 
     167#define SHELL_CURSOR_KEYBINDING "[99~" 
     168 
    154169/*** file scope variables ************************************************************************/ 
    155170 
    156171/* tcsh closes all non-standard file descriptors, so we have to use a pipe */ 
    static char pty_buffer[PTY_BUFFER_SIZE] = "\0"; 
    169184/* To pass CWD info from the subshell to MC */ 
    170185static int subshell_pipe[2]; 
    171186 
     187/* To pass command buffer info from the subshell to MC */ 
     188static int command_buffer_pipe[2]; 
     189 
    172190/* The subshell's process ID */ 
    173191static pid_t subshell_pid = 1; 
    174192 
    static char subshell_cwd[MC_MAXPATHLEN + 1]; 
    178196/* Flag to indicate whether the subshell is ready for next command */ 
    179197static int subshell_ready; 
    180198 
     199/* Flag to indicate if the contents of the subshell command line need to be cleared before */ 
     200/* executing a command. This should only end up set to true if there is some sort of error.*/ 
     201/* This allows us to recover gracefully from an error.*/ 
     202static gboolean subshell_should_clear_command_line; 
     203 
     204/* This is the local variable where the subshell prompt is stored while we are working on it. */ 
     205static GString *subshell_prompt_temp_buffer = NULL; 
     206 
    181207/* The following two flags can be changed by the SIGCHLD handler. This is */ 
    182208/* OK, because the 'int' type is updated atomically on all known machines */ 
    183209static volatile int subshell_alive, subshell_stopped; 
    init_subshell_child (const char *pty_name) 
    362388    dup2 (subshell_pty_slave, STDERR_FILENO); 
    363389 
    364390    close (subshell_pipe[READ]); 
     391    if (mc_global.shell->type == SHELL_BASH 
     392        || mc_global.shell->type == SHELL_ZSH 
     393        || mc_global.shell->type == SHELL_FISH) 
     394        close (command_buffer_pipe[READ]); 
    365395    close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */ 
    366396    /* Close master side of pty.  This is important; apart from */ 
    367397    /* freeing up the descriptor for use in the subshell, it also       */ 
    synchronize (void) 
    469499} 
    470500 
    471501/* --------------------------------------------------------------------------------------------- */ 
     502/* Get the contents of the current subshell command line buffer, and */ 
     503/* transfer the contents to the panel command prompt. */ 
     504 
     505static gboolean 
     506read_command_line_buffer(void) 
     507{ 
     508    fd_set read_set; 
     509    int j; 
     510    int bytes; 
     511    char subshell_command_buffer[BUF_LARGE]; 
     512    struct timeval subshell_prompt_timer = { 0, 0 }; 
     513    int command_buffer_length; 
     514    int cursor_position; 
     515    int maxfdp; 
     516 
     517    if (mc_global.shell->type == SHELL_BASH 
     518        || mc_global.shell->type == SHELL_ZSH 
     519        || mc_global.shell->type == SHELL_FISH) 
     520    { 
     521        FD_ZERO (&read_set); 
     522        FD_SET (command_buffer_pipe[READ], &read_set); 
     523        maxfdp = command_buffer_pipe[READ]; 
     524        /* First, flush the command buffer pipe. This pipe shouldn't be written 
     525         * to under normal circumstances, but if it somehow does get written 
     526         * to, we need to make sure to discard whatever data is there before 
     527         * we try to use it. */ 
     528        while (select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer) != 0) 
     529        { 
     530            bytes = read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 
     531        } 
     532 
     533        subshell_prompt_timer.tv_sec = 1; 
     534        /* get contents of command line buffer */ 
     535        write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING, 
     536            sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 
     537        FD_ZERO (&read_set); 
     538        FD_SET (command_buffer_pipe[READ], &read_set); 
     539        maxfdp = command_buffer_pipe[READ]; 
     540        if (select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer) != 1) 
     541            return FALSE; 
     542        bytes = read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 
     543        if (bytes == sizeof(subshell_command_buffer)) 
     544            return FALSE; 
     545        subshell_command_buffer[bytes - 1] = 0; 
     546        /* Erase non-text characters in the command buffer, such as tab, or newline, as this 
     547         * could cause problems. */ 
     548        for(j = 0;j < bytes - 1;j++) 
     549        { 
     550            if ((unsigned char) subshell_command_buffer[j] < 32 
     551                || (unsigned char)subshell_command_buffer[j] == 127) 
     552                subshell_command_buffer[j] = ' '; 
     553        } 
     554        input_assign_text (cmdline, ""); 
     555        input_insert (cmdline, subshell_command_buffer, 0); 
     556        command_buffer_length = str_length(subshell_command_buffer); 
     557 
     558        /* get cursor position */ 
     559        write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING, 
     560            sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 
     561        FD_ZERO (&read_set); 
     562        FD_SET (command_buffer_pipe[READ], &read_set); 
     563        maxfdp = command_buffer_pipe[READ]; 
     564        if (select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer) != 1) 
     565            return FALSE; 
     566        bytes = read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 
     567        subshell_command_buffer[bytes - 1] = 0; 
     568        cursor_position = atoi(subshell_command_buffer); 
     569        if (mc_global.shell->type == SHELL_BASH) 
     570        { 
     571            for (j = 0;j < command_buffer_length;j++) 
     572                if (str_offset_to_pos(subshell_command_buffer, j) == cursor_position) 
     573                    break; 
     574            cursor_position = j; 
     575        } 
     576        if (cursor_position > command_buffer_length) 
     577            cursor_position = command_buffer_length; 
     578        cmdline->point = cursor_position; 
     579        /* We send any remaining data to STDOUT before we finish. */ 
     580        flush_subshell(0, VISIBLY); 
     581 
     582        /* Now we erase the current contents of the command line buffer */ 
     583        if (mc_global.shell->type != SHELL_ZSH) 
     584        /* In zsh, we can just press c-u to clear the line, without needing to go to the end of 
     585         * the line first first. In all other shells, we must go to the end of the line first. */ 
     586        { 
     587            /* If we are not at the end of the line, we go to the end. */ 
     588            if (cursor_position != command_buffer_length) 
     589            { 
     590                write_all (mc_global.tty.subshell_pty, "\005", 1); 
     591                if (flush_subshell(1, VISIBLY) != 1) 
     592                    return FALSE; 
     593            } 
     594        } 
     595        if (command_buffer_length > 0)    /* Now we clear the line. */ 
     596        { 
     597            write_all (mc_global.tty.subshell_pty, "\025", 1); 
     598            if (flush_subshell(1, VISIBLY) != 1) 
     599                return FALSE; 
     600        } 
     601    } 
     602    return TRUE; 
     603} 
     604 
     605/* --------------------------------------------------------------------------------------------- */ 
     606 
     607static void 
     608clear_subshell_prompt_string (void) 
     609{ 
     610    if(subshell_prompt_temp_buffer != NULL) 
     611        g_string_set_size (subshell_prompt_temp_buffer, 0); 
     612} 
     613 
     614/* --------------------------------------------------------------------------------------------- */ 
     615 
     616static gboolean 
     617parse_subshell_prompt_string (const char *buffer, int bytes) 
     618{ 
     619    int rc = 0; 
     620    int i; 
     621 
     622    /* First time through */ 
     623    if (subshell_prompt == NULL) 
     624    { 
     625        subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE); 
     626    } 
     627    if (subshell_prompt_temp_buffer == NULL) 
     628    { 
     629        subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE); 
     630    } 
     631 
     632    /* Extract the prompt from the shell output */ 
     633    for (i = 0; i < bytes; i++) 
     634        if (buffer[i] == '\n' || buffer[i] == '\r') 
     635        { 
     636            g_string_set_size (subshell_prompt_temp_buffer, 0); 
     637        } 
     638        else if (buffer[i] != '\0') 
     639            g_string_append_c (subshell_prompt_temp_buffer, buffer[i]); 
     640 
     641    return (rc != 0 || bytes != 0); 
     642} 
     643 
     644/* --------------------------------------------------------------------------------------------- */ 
     645 
     646static void 
     647set_prompt_string (void) 
     648{ 
     649    if (subshell_prompt_temp_buffer->len != 0) 
     650        g_string_assign (subshell_prompt, subshell_prompt_temp_buffer->str); 
     651 
     652    setup_cmdline(); 
     653} 
     654 
     655/* --------------------------------------------------------------------------------------------- */ 
    472656/** Feed the subshell our keyboard input until it says it's finished */ 
    473657 
    474658static gboolean 
    feed_subshell (int how, gboolean fail_on_error) 
    481665    struct timeval wtime;       /* Maximum time we wait for the subshell */ 
    482666    struct timeval *wptr; 
    483667 
     668    should_read_new_subshell_prompt = FALSE; 
     669    subshell_should_clear_command_line = FALSE; 
     670 
    484671    /* we wait up to 10 seconds if fail_on_error, forever otherwise */ 
    485672    wtime.tv_sec = 10; 
    486673    wtime.tv_usec = 0; 
    feed_subshell (int how, gboolean fail_on_error) 
    549736 
    550737            if (how == VISIBLY) 
    551738                write_all (STDOUT_FILENO, pty_buffer, bytes); 
     739            if (should_read_new_subshell_prompt) 
     740            { 
     741                parse_subshell_prompt_string(pty_buffer, bytes); 
     742            } 
     743 
    552744        } 
    553745 
    554746        else if (FD_ISSET (subshell_pipe[READ], &read_set)) 
    feed_subshell (int how, gboolean fail_on_error) 
    567759 
    568760            synchronize (); 
    569761 
     762            clear_subshell_prompt_string(); 
     763            should_read_new_subshell_prompt = TRUE; 
    570764            subshell_ready = TRUE; 
    571765            if (subshell_state == RUNNING_COMMAND) 
    572766            { 
    feed_subshell (int how, gboolean fail_on_error) 
    578772        else if (FD_ISSET (STDIN_FILENO, &read_set)) 
    579773            /* Read from stdin, write to the subshell */ 
    580774        { 
     775            should_read_new_subshell_prompt = FALSE; 
    581776            bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer)); 
    582777            if (bytes <= 0) 
    583778            { 
    feed_subshell (int how, gboolean fail_on_error) 
    592787                { 
    593788                    write_all (mc_global.tty.subshell_pty, pty_buffer, i); 
    594789                    if (subshell_ready) 
     790                    { 
    595791                        subshell_state = INACTIVE; 
     792                        set_prompt_string (); 
     793                        if (subshell_ready == TRUE) 
     794                        { 
     795                            if (!read_command_line_buffer()) 
     796                            { 
     797                                /* If we got here, some unforseen error must have occurred. */ 
     798                                flush_subshell(0, VISIBLY); 
     799                                input_assign_text (cmdline, ""); 
     800                                subshell_should_clear_command_line = TRUE; 
     801                                return TRUE; 
     802                            } 
     803                        } 
     804                    } 
    596805                    return TRUE; 
    597806                } 
    598807 
    599808            write_all (mc_global.tty.subshell_pty, pty_buffer, bytes); 
    600809 
    601810            if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r') 
     811            { 
     812                /* We should only clear the command line if we are using a shell that works 
     813                 * with persistent command buffer, otherwise we get awkward results. */ 
     814                if (mc_global.shell->type == SHELL_BASH 
     815                    || mc_global.shell->type == SHELL_ZSH 
     816                    || mc_global.shell->type == SHELL_FISH) 
     817                    input_assign_text (cmdline, ""); 
    602818                subshell_ready = FALSE; 
     819            } 
    603820        } 
    604821        else 
    605822            return FALSE; 
    init_subshell_precmd (char *precmd, size_t buff_size) 
    7841001    { 
    7851002    case SHELL_BASH: 
    7861003        g_snprintf (precmd, buff_size, 
     1004                    " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"echo $READLINE_LINE>&%d\"'\n" 
     1005                    " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING "\":\"echo $READLINE_POINT>&%d\"'\n" 
    7871006                    " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n" 
    788                     "PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]); 
     1007                    "PS1='\\u@\\h:\\w\\$ '\n", 
     1008                    command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 
    7891009        break; 
    7901010 
    7911011    case SHELL_ASH_BUSYBOX: 
    init_subshell_precmd (char *precmd, size_t buff_size) 
    8441064 
    8451065    case SHELL_ZSH: 
    8461066        g_snprintf (precmd, buff_size, 
     1067                    " mc_print_command_buffer () { echo $BUFFER >&%d}\n" 
     1068                    " zle -N mc_print_command_buffer\n" 
     1069                    " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n" 
     1070                    " mc_print_cursor_position () { echo $CURSOR >&%d}\n" 
     1071                    " zle -N mc_print_cursor_position\n" 
     1072                    " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n" 
    8471073                    " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n" 
    848                     "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]); 
     1074                    "PS1='%%n@%%m:%%~%%# '\n", 
     1075                    command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 
    8491076        break; 
    8501077 
    8511078    case SHELL_TCSH: 
    init_subshell_precmd (char *precmd, size_t buff_size) 
    8541081                    "set prompt='%%n@%%m:%%~%%# '; " 
    8551082                    "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo); 
    8561083        break; 
    857  
    8581084    case SHELL_FISH: 
    8591085        g_snprintf (precmd, buff_size, 
    8601086                    " if not functions -q fish_prompt_mc;" 
    8611087                    "functions -e fish_right_prompt;" 
    8621088                    "functions -c fish_prompt fish_prompt_mc; end;" 
    8631089                    "function fish_prompt;" 
     1090                    "bind \\e\\" SHELL_BUFFER_KEYBINDING " 'echo (commandline)>&%d'\n" 
     1091                    "bind \\e\\" SHELL_CURSOR_KEYBINDING " 'echo (commandline -C)>&%d'\n" 
    8641092                    "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n", 
    865                     subshell_pipe[WRITE]); 
     1093                    command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 
    8661094        break; 
    8671095 
    8681096    default: 
    init_subshell (void) 
    10401268            mc_global.tty.use_subshell = FALSE; 
    10411269            return; 
    10421270        } 
     1271        if (mc_global.shell->type == SHELL_BASH 
     1272            || mc_global.shell->type == SHELL_ZSH 
     1273            || mc_global.shell->type == SHELL_FISH) 
     1274        { 
     1275            if (pipe (command_buffer_pipe)) 
     1276            { 
     1277                perror (__FILE__ ": couldn't create pipe"); 
     1278                mc_global.tty.use_subshell = FALSE; 
     1279                return; 
     1280            } 
     1281        } 
    10431282    } 
    10441283 
    10451284    /* Fork the subshell */ 
    init_subshell (void) 
    10611300        /* We are in the child process */ 
    10621301        init_subshell_child (pty_name); 
    10631302    } 
    1064  
    10651303    init_subshell_precmd (precmd, BUF_MEDIUM); 
    10661304 
    10671305    write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd)); 
    init_subshell (void) 
    10841322int 
    10851323invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 
    10861324{ 
     1325    size_t i; 
    10871326    /* Make the MC terminal transparent */ 
    10881327    tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode); 
    10891328 
    invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 
    11001339            /* FIXME: possibly take out this hack; the user can re-play it by hitting C-hyphen a few times! */ 
    11011340            if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL) 
    11021341                write_all (mc_global.tty.subshell_pty, " \b", 2);       /* Hack to make prompt reappear */ 
     1342  
     1343            if (mc_global.shell->type == SHELL_BASH 
     1344                || mc_global.shell->type == SHELL_ZSH 
     1345                || mc_global.shell->type == SHELL_FISH) 
     1346            { 
     1347                /* Check to make sure there are no non text characters in the command buffer, 
     1348                 * such as tab, or newline, as this could cause problems. */ 
     1349                for(i = 0;i < strlen(cmdline->buffer);i++) 
     1350                { 
     1351                    if ((unsigned char) cmdline->buffer[i] < 32 
     1352                        || (unsigned char)cmdline->buffer[i] == 127) 
     1353                        cmdline->buffer[i] = ' '; 
     1354                } 
     1355 
     1356                /* Write the command buffer to the subshell. */ 
     1357                write_all (mc_global.tty.subshell_pty, cmdline->buffer, strlen (cmdline->buffer)); 
     1358 
     1359                /* Put the cursor in the correct place in the subshell. */ 
     1360                for (int j = 0;j < str_length (cmdline->buffer) - cmdline->point;j++) 
     1361                    write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3); 
     1362            } 
    11031363        } 
    11041364    } 
    11051365    else                        /* MC has passed us a user command */ 
    11061366    { 
     1367        /* Before we write to the command prompt, we need to clear whatever */ 
     1368        /* data is there, but only if we are using one of the shells that */ 
     1369        /* doesn't support keeping command buffer contents, OR if there was */ 
     1370        /* some sort of error. */ 
     1371        if (!(mc_global.shell->type == SHELL_BASH 
     1372            || mc_global.shell->type == SHELL_ZSH 
     1373            || mc_global.shell->type == SHELL_FISH) 
     1374            || subshell_should_clear_command_line) 
     1375        { 
     1376            write_all (mc_global.tty.subshell_pty, "\003", 1); 
     1377            subshell_state = RUNNING_COMMAND; 
     1378            if (mc_global.shell->type != SHELL_FISH) 
     1379                feed_subshell (QUIETLY, FALSE); 
     1380        } 
    11071381        if (how == QUIETLY) 
    11081382            write_all (mc_global.tty.subshell_pty, " ", 1); 
    11091383        /* FIXME: if command is long (>8KB ?) we go comma */ 
    invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 
    11311405    return subshell_get_mainloop_quit (); 
    11321406} 
    11331407 
    1134  
    11351408/* --------------------------------------------------------------------------------------------- */ 
    11361409 
    11371410gboolean 
    1138 read_subshell_prompt (void) 
     1411flush_subshell (int max_wait_length, int how) 
    11391412{ 
    11401413    int rc = 0; 
    11411414    ssize_t bytes = 0; 
    11421415    struct timeval timeleft = { 0, 0 }; 
    1143     GString *p; 
    1144     gboolean prompt_was_reset = FALSE; 
    1145  
     1416    int return_value = FALSE; 
    11461417    fd_set tmp; 
     1418 
     1419    timeleft.tv_sec = max_wait_length; 
    11471420    FD_ZERO (&tmp); 
    11481421    FD_SET (mc_global.tty.subshell_pty, &tmp); 
    11491422 
    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  
    11561423    while (subshell_alive 
    11571424           && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 
    11581425    { 
    1159         ssize_t i; 
    1160  
    11611426        /* Check for 'select' errors */ 
    11621427        if (rc == -1) 
    11631428        { 
    read_subshell_prompt (void) 
    11721437            fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 
    11731438            exit (EXIT_FAILURE); 
    11741439        } 
     1440        return_value = TRUE; 
     1441        timeleft.tv_sec = 0; 
     1442        timeleft.tv_usec = 0; 
    11751443 
    11761444        bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 
     1445        if (how == VISIBLY) 
     1446            write_all (STDOUT_FILENO, pty_buffer, bytes); 
     1447    } 
     1448    return return_value; 
     1449} 
     1450 
     1451/* --------------------------------------------------------------------------------------------- */ 
    11771452 
    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') 
     1453gboolean 
     1454read_subshell_prompt (void) 
     1455{ 
     1456    int rc = 0; 
     1457    ssize_t bytes = 0; 
     1458    struct timeval timeleft = { 0, 0 }; 
     1459    int should_reset_prompt = TRUE; 
     1460    int got_new_prompt = FALSE; 
     1461 
     1462    fd_set tmp; 
     1463    FD_ZERO (&tmp); 
     1464    FD_SET (mc_global.tty.subshell_pty, &tmp); 
     1465 
     1466    while (subshell_alive 
     1467           && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 
     1468    { 
     1469        /* Check for 'select' errors */ 
     1470        if (rc == -1) 
     1471        { 
     1472            if (errno == EINTR) 
    11811473            { 
    1182                 g_string_set_size (p, 0); 
    1183                 prompt_was_reset = TRUE; 
     1474                if (tty_got_winch ()) 
     1475                    tty_change_screen_size (); 
     1476 
     1477                continue; 
    11841478            } 
    1185             else if (pty_buffer[i] != '\0') 
    1186                 g_string_append_c (p, pty_buffer[i]); 
    1187     } 
    11881479 
    1189     if (p->len != 0 || prompt_was_reset) 
    1190         g_string_assign (subshell_prompt, p->str); 
     1480            fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 
     1481            exit (EXIT_FAILURE); 
     1482        } 
    11911483 
    1192     g_string_free (p, TRUE); 
     1484        bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 
     1485        if (should_reset_prompt) 
     1486        { 
     1487            should_reset_prompt = FALSE; 
     1488            clear_subshell_prompt_string(); 
     1489        } 
     1490        parse_subshell_prompt_string (pty_buffer, bytes); 
     1491        got_new_prompt = TRUE; 
     1492    } 
     1493    if (got_new_prompt == TRUE) 
     1494    { 
     1495        set_prompt_string (); 
     1496    } 
    11931497 
    11941498    return (rc != 0 || bytes != 0); 
    11951499} 
    exit_subshell (void) 
    12311535 
    12321536        g_string_free (subshell_prompt, TRUE); 
    12331537        subshell_prompt = NULL; 
     1538        g_string_free (subshell_prompt_temp_buffer, TRUE); 
     1539        subshell_prompt_temp_buffer = NULL; 
    12341540        pty_buffer[0] = '\0'; 
    12351541    } 
    12361542 
    do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt) 
    12591565        return; 
    12601566    } 
    12611567 
     1568    /* If we are using a shell that doesn't support persistent command buffer, we need to clear 
     1569     * the command prompt before we send the cd command. */ 
     1570    if (!(mc_global.shell->type == SHELL_BASH 
     1571        || mc_global.shell->type == SHELL_ZSH 
     1572        || mc_global.shell->type == SHELL_FISH) 
     1573        || subshell_should_clear_command_line) 
     1574    { 
     1575        write_all (mc_global.tty.subshell_pty, "\003", 1); 
     1576        subshell_state = RUNNING_COMMAND; 
     1577        if (mc_global.shell->type != SHELL_FISH) 
     1578            feed_subshell (QUIETLY, FALSE); 
     1579    } 
    12621580    /* The initial space keeps this out of the command history (in bash 
    12631581       because we set "HISTCONTROL=ignorespace") */ 
    12641582    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);