Ticket #213: mc_poc.diff

File mc_poc.diff, 8.3 KB (added by midenok, 15 years ago)

Busy shell and stacked prompt glitches fix (proof of concept)

  • src/command.c

    diff --git a/src/command.c b/src/command.c
    index e608bf0..81cbc5c 100644
    a b enter (WInput *cmdline) 
    229229#ifdef HAVE_SUBSHELL_SUPPORT 
    230230        /* Check this early before we clean command line 
    231231         * (will be checked again by shell_execute) */ 
    232         if (use_subshell && subshell_state != INACTIVE) { 
     232        if (use_subshell && subshell_state != INACTIVE 
     233            && subshell_state != ACTIVE2) { 
    233234            message (1, MSG_ERROR, 
    234235                     _(" The shell is already running a command ")); 
    235236            return MSG_NOT_HANDLED; 
  • src/execute.c

    diff --git a/src/execute.c b/src/execute.c
    index eb31cac..07e5f34 100644
    a b do_execute (const char *shell, const char *command, int flags) 
    131131                 && !console_flag)) && !quit 
    132132#ifdef HAVE_SUBSHELL_SUPPORT 
    133133            && subshell_state != RUNNING_COMMAND 
     134            && subshell_state != RUNNING_COMMAND2   
    134135#endif                          /* HAVE_SUBSHELL_SUPPORT */ 
    135136            ) { 
    136137            printf (_("Press any key to continue...")); 
    shell_execute (const char *command, int flags) 
    186187 
    187188#ifdef HAVE_SUBSHELL_SUPPORT 
    188189    if (use_subshell) 
    189         if (subshell_state == INACTIVE) 
     190        if (subshell_state == INACTIVE || subshell_state == ACTIVE2) 
    190191            do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL); 
    191192        else 
    192193            message (1, MSG_ERROR, 
  • src/main.c

    diff --git a/src/main.c b/src/main.c
    index db26945..9f68881 100644
    a b void 
    436436do_update_prompt (void) 
    437437{ 
    438438    if (update_prompt) { 
    439         printf ("%s", subshell_prompt); 
     439        /* FIXME: quick hack to eliminate 'stacked prompts bug'. 
     440        Actually should be done with ncurses. */ 
     441        printf ("\033[1K\033[1G%s", subshell_prompt); 
    440442        fflush (stdout); 
    441443        update_prompt = 0; 
    442444    } 
  • src/subshell.c

    diff --git a/src/subshell.c b/src/subshell.c
    index 8d98da5..e84527e 100644
    a b enum {READ=0, WRITE=1}; 
    123123static char *pty_buffer;        /* For reading/writing on the subshell's pty */ 
    124124static int pty_buffer_size;     /* The buffer grows as needed */ 
    125125static int subshell_pipe[2];    /* To pass CWD info from the subshell to MC */ 
     126static int subshell_pipe2[2];   /* To indicate subshell command run */ 
    126127static pid_t subshell_pid = 1;  /* The subshell's process ID */ 
    127128static char subshell_cwd[MC_MAXPATHLEN+1];  /* One extra char for final '\n' */ 
    128129 
    129130/* Subshell type (gleaned from the SHELL environment variable, if available) */ 
    130 static enum {BASH, TCSH, ZSH} subshell_type; 
     131enum subshell_type_enum subshell_type; 
    131132 
    132133/* Flag to indicate whether the subshell is ready for next command */ 
    133134static int subshell_ready; 
    init_subshell_child (const char *pty_name) 
    282283 
    283284    switch (subshell_type) { 
    284285    case BASH: 
     286        close (subshell_pipe[READ]); 
    285287        execl (shell, "bash", "-rcfile", init_file, (char *) NULL); 
    286288        break; 
    287289 
    init_subshell (void) 
    439441                use_subshell = FALSE; 
    440442                return; 
    441443            } 
    442         } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe)) { 
    443             perror (__FILE__": couldn't create pipe"); 
    444             use_subshell = FALSE; 
    445             return; 
    446         } 
     444        } else /* subshell_type is BASH or ZSH */ { 
     445            if (pipe (subshell_pipe) || pipe (subshell_pipe2)) { 
     446                perror (__FILE__": couldn't create pipe"); 
     447                use_subshell = FALSE; 
     448                return; 
     449            } 
     450        } 
    447451    } 
    448452 
    449453    /* Fork the subshell */ 
    init_subshell (void) 
    469473    switch (subshell_type) { 
    470474    case BASH: 
    471475        g_snprintf (precmd, sizeof (precmd), 
    472                     " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n", 
    473                     subshell_pipe[WRITE]); 
     476                    " PROMPT_COMMAND='pwd>&%d;kill -STOP $$';" 
     477                    "trap '[ \"$BASH_COMMAND\" != \"kill -STOP \\$\\$\" ] && echo $BASH_COMMAND>&%d' DEBUG\n", 
     478                    subshell_pipe[WRITE], 
     479                    subshell_pipe2[WRITE]); 
    474480        break; 
    475481 
    476482    case ZSH: 
    int invoke_subshell (const char *command, int how, char **new_dir) 
    548554    } 
    549555    else  /* MC has passed us a user command */ 
    550556    { 
     557        if (subshell_state == ACTIVE2) { 
     558            /* Send Ctrl-C if something was typed on subshell prompt */ 
     559            subshell_state = RUNNING_COMMAND; 
     560            write_all (subshell_pty, "\x3", 1); 
     561            feed_subshell (how, FALSE); 
     562        } 
     563 
    551564        if (how == QUIETLY) 
    552565            write_all (subshell_pty, " ", 1); 
    553566        /* FIXME: if command is long (>8KB ?) we go comma */ 
    554567        write_all (subshell_pty, command, strlen (command)); 
    555568        write_all (subshell_pty, "\n", 1); 
    556         subshell_state = RUNNING_COMMAND; 
    557         subshell_ready = FALSE; 
     569        subshell_state = RUNNING_COMMAND; 
     570        subshell_ready = FALSE; 
    558571    } 
    559572 
    560573    feed_subshell (how, FALSE); 
    subshell_name_quote (const char *s) 
    743756void 
    744757do_subshell_chdir (const char *directory, int do_update, int reset_prompt) 
    745758{ 
    746     if (! 
     759    if (subshell_state == ACTIVE2) { 
     760        /* Send Ctrl-C if something was typed on subshell prompt */ 
     761        subshell_state = RUNNING_COMMAND; 
     762        write_all (subshell_pty, "\x3", 1); 
     763        /* FIXME: command prompt with old typed characters should be visible */ 
     764        feed_subshell (VISIBLY, FALSE); 
     765    } else if (! 
    747766        (subshell_state == INACTIVE 
    748767         && strcmp (subshell_cwd, current_panel->cwd))) { 
    749768        /* We have to repaint the subshell prompt if we read it from 
    do_subshell_chdir (const char *directory, int do_update, int reset_prompt) 
    803822    } 
    804823 
    805824    if (reset_prompt) 
    806         prompt_pos = 0; 
     825        prompt_pos = 0; 
    807826    update_prompt = FALSE; 
    808827    /* Make sure that MC never stores the CWD in a silly format */ 
    809828    /* like /usr////lib/../bin, or the strcmp() above will fail */ 
    feed_subshell (int how, int fail_on_error) 
    902921        FD_ZERO (&read_set); 
    903922        FD_SET (subshell_pty, &read_set); 
    904923        FD_SET (subshell_pipe[READ], &read_set); 
    905         maxfdp = max (subshell_pty, subshell_pipe[READ]); 
     924        FD_SET (subshell_pipe2[READ], &read_set); 
     925        maxfdp = max(max (subshell_pty, subshell_pipe[READ]), subshell_pipe2[READ]); 
    906926        if (how == VISIBLY) { 
    907927            FD_SET (STDIN_FILENO, &read_set); 
    908928            maxfdp = max (maxfdp, STDIN_FILENO); 
    feed_subshell (int how, int fail_on_error) 
    918938                     unix_error_string (errno)); 
    919939            exit (1); 
    920940        } 
    921  
    922         if (FD_ISSET (subshell_pty, &read_set)) 
     941         
     942        if (subshell_type == BASH 
     943            && FD_ISSET (subshell_pipe2[READ], &read_set)) { 
     944            char buf[255]; 
     945            int s = read (subshell_pipe2[READ], buf, 255); 
     946            if (0 >= s) { 
     947                tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode); 
     948                fprintf (stderr, 
     949                         "read (subshell_pipe2[READ], buf...): %s\r\n", 
     950                         unix_error_string (errno)); 
     951                exit (1); 
     952            } 
     953            if (subshell_state == ACTIVE) { 
     954                subshell_state = RUNNING_COMMAND2; 
     955                subshell_ready = FALSE; 
     956            } 
     957        } 
     958 
     959        else if (FD_ISSET (subshell_pty, &read_set)) 
    923960            /* Read from the subshell, write to stdout */ 
    924961 
    925962            /* This loop improves performance by reducing context switches 
    feed_subshell (int how, int fail_on_error) 
    9651002            subshell_ready = TRUE; 
    9661003            if (subshell_state == RUNNING_COMMAND) { 
    9671004                subshell_state = INACTIVE; 
    968                 return 1; 
     1005                return TRUE; 
    9691006            } 
     1007            if (subshell_state == RUNNING_COMMAND2 || 
     1008                subshell_state == ACTIVE2) 
     1009            { 
     1010                subshell_state = INACTIVE; 
     1011            } 
    9701012        } 
    9711013 
    9721014        else if (FD_ISSET (STDIN_FILENO, &read_set)) 
    feed_subshell (int how, int fail_on_error) 
    9901032                } 
    9911033 
    9921034            write_all (subshell_pty, pty_buffer, bytes); 
    993             subshell_ready = FALSE; 
     1035            subshell_ready = FALSE; 
     1036            if (subshell_type == BASH) 
     1037                subshell_state = ACTIVE2; 
    9941038        } else { 
    9951039            return FALSE; 
    9961040        } 
  • src/subshell.h

    diff --git a/src/subshell.h b/src/subshell.h
    index 072871d..9c874e2 100644
    a b extern int use_subshell; 
    1414extern int subshell_pty; 
    1515 
    1616/* State of the subshell; see subshell.c for an explanation */ 
    17 enum subshell_state_enum {INACTIVE, ACTIVE, RUNNING_COMMAND}; 
     17enum subshell_state_enum {INACTIVE, ACTIVE, RUNNING_COMMAND, ACTIVE2, RUNNING_COMMAND2}; 
    1818extern enum subshell_state_enum subshell_state; 
    1919 
     20enum subshell_type_enum {BASH, TCSH, ZSH}; 
     21extern enum subshell_type_enum subshell_type; 
     22 
    2023/* Holds the latest prompt captured from the subshell */ 
    2124extern char *subshell_prompt; 
    2225