Ticket #4114: persistent_subshell_command_buffer3.patch
File persistent_subshell_command_buffer3.patch, 26.3 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) 551 551 { 552 552 if (mc_global.mc_run_mode == MC_RUN_FULL) 553 553 { 554 do_load_prompt ();555 554 if (new_dir_vpath != NULL) 556 555 do_possible_cd (new_dir_vpath); 557 556 } -
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) 1497 1497 { 1498 1498 (void) fd; 1499 1499 (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); 1502 1504 return 0; 1503 1505 } 1504 1506 #endif /* ENABLE_SUBSHELL */ -
src/subshell/common.c
diff --git a/src/subshell/common.c b/src/subshell/common.c index 06699233c..9b7e5284d 100644
a b 15 15 Claes Nästén <me@pekdon.net> 16 16 Egmont Koblinger <egmont@gmail.com> 17 17 Enrico Weigelt, metux IT service <weigelt@metux.de> 18 Eric Roberts <ericmrobertsdeveloper@gmail.com> 18 19 Igor Urazov <z0rc3r@gmail.com> 19 20 Ilia Maslakov <il.smind@gmail.com> 20 21 Leonard den Ottolander <leonard@den.ottolander.nl> … … 105 106 #include "lib/util.h" 106 107 #include "lib/widget.h" 107 108 109 #include "src/filemanager/layout.h" /* setup_cmdline() */ 110 #include "src/filemanager/command.h" /* cmdline */ 111 108 112 #include "subshell.h" 109 113 #include "internal.h" 110 114 … … GString *subshell_prompt = NULL; 123 127 /* We need to paint it after CONSOLE_RESTORE, see: load_prompt */ 124 128 gboolean update_subshell_prompt = FALSE; 125 129 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. */ 132 gboolean should_read_new_subshell_prompt; 133 126 134 /*** file scope macro definitions ****************************************************************/ 127 135 128 136 #ifndef WEXITSTATUS … … enum 151 159 WRITE = 1 152 160 }; 153 161 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 154 170 /*** file scope variables ************************************************************************/ 155 171 156 172 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */ … … static char pty_buffer[PTY_BUFFER_SIZE] = "\0"; 169 185 /* To pass CWD info from the subshell to MC */ 170 186 static int subshell_pipe[2]; 171 187 188 /* To pass command buffer info from the subshell to MC */ 189 static int command_buffer_pipe[2]; 190 172 191 /* The subshell's process ID */ 173 192 static pid_t subshell_pid = 1; 174 193 … … static char subshell_cwd[MC_MAXPATHLEN + 1]; 178 197 /* Flag to indicate whether the subshell is ready for next command */ 179 198 static int subshell_ready; 180 199 200 /* Flag to indicate if the subshell supports the persistent buffer feature. */ 201 static 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.*/ 206 static 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. */ 209 static GString *subshell_prompt_temp_buffer = NULL; 210 181 211 /* The following two flags can be changed by the SIGCHLD handler. This is */ 182 212 /* OK, because the 'int' type is updated atomically on all known machines */ 183 213 static volatile int subshell_alive, subshell_stopped; … … init_subshell_child (const char *pty_name) 362 392 dup2 (subshell_pty_slave, STDERR_FILENO); 363 393 364 394 close (subshell_pipe[READ]); 395 if (use_persistent_buffer == TRUE) 396 close (command_buffer_pipe[READ]); 365 397 close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */ 366 398 /* Close master side of pty. This is important; apart from */ 367 399 /* freeing up the descriptor for use in the subshell, it also */ … … synchronize (void) 469 501 } 470 502 471 503 /* --------------------------------------------------------------------------------------------- */ 504 /* Get the contents of the current subshell command line buffer, and */ 505 /* transfer the contents to the panel command prompt. */ 506 507 static gboolean 508 read_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)) != 1) 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 else if (rc == 0) 544 break; 545 } 546 /* get contents of command line buffer */ 547 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING, 548 sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 549 subshell_prompt_timer.tv_sec = 1; 550 FD_ZERO (&read_set); 551 FD_SET (command_buffer_pipe[READ], &read_set); 552 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1) 553 { 554 if (rc == -1) 555 { 556 if (errno == EINTR) 557 continue; 558 else 559 return FALSE; 560 } 561 else if (rc == 0) 562 return FALSE; 563 } 564 565 bytes = read (command_buffer_pipe[READ], subshell_command_buffer, sizeof(subshell_command_buffer)); 566 if (bytes == sizeof(subshell_command_buffer)) 567 return FALSE; 568 if (bytes == 0) 569 return FALSE; 570 subshell_command_buffer[bytes - 1] = 0; 571 command_buffer_char_length = bytes - 1; 572 command_buffer_length = str_length(subshell_command_buffer); 573 574 /* get cursor position */ 575 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING, 576 sizeof(ESC_STR SHELL_CURSOR_KEYBINDING) - 1); 577 subshell_prompt_timer.tv_sec = 1; 578 subshell_prompt_timer.tv_usec = 0; 579 FD_ZERO (&read_set); 580 FD_SET (command_buffer_pipe[READ], &read_set); 581 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1) 582 { 583 if (rc == -1) 584 { 585 if (errno == EINTR) 586 continue; 587 else 588 return FALSE; 589 } 590 else if (rc == 0) 591 return FALSE; 592 } 593 bytes = read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof(subshell_cursor_buffer)); 594 if (bytes == 0) 595 return FALSE; 596 subshell_cursor_buffer[bytes - 1] = 0; 597 cursor_position = strtol(subshell_cursor_buffer, &end, 10); 598 if (end == subshell_cursor_buffer) 599 return FALSE; 600 601 if (test_mode == TRUE) 602 return TRUE; 603 /* Erase non-text characters in the command buffer, such as tab, or newline, as this 604 * could cause problems. */ 605 for(i = 0;i < command_buffer_char_length;i++) 606 { 607 if ((unsigned char) subshell_command_buffer[i] < 32 608 || (unsigned char)subshell_command_buffer[i] == 127) 609 subshell_command_buffer[i] = ' '; 610 } 611 input_assign_text (cmdline, ""); 612 input_insert (cmdline, subshell_command_buffer, 0); 613 614 if (mc_global.shell->type == SHELL_BASH) 615 { 616 /* We need to do this because bash gives the cursor position in a utf-8 string based 617 * on the location in bytes, not in unicode characters. */ 618 for (i = 0;i < command_buffer_length;i++) 619 if (str_offset_to_pos(subshell_command_buffer, i) == cursor_position) 620 break; 621 cursor_position = i; 622 } 623 if (cursor_position > command_buffer_length) 624 cursor_position = command_buffer_length; 625 cmdline->point = cursor_position; 626 /* We send any remaining data to STDOUT before we finish. */ 627 flush_subshell(0, VISIBLY); 628 629 /* Now we erase the current contents of the command line buffer */ 630 if (mc_global.shell->type != SHELL_ZSH) 631 /* In zsh, we can just press c-u to clear the line, without needing to go to the end of 632 * the line first first. In all other shells, we must go to the end of the line first. */ 633 { 634 /* If we are not at the end of the line, we go to the end. */ 635 if (cursor_position != command_buffer_length) 636 { 637 write_all (mc_global.tty.subshell_pty, "\005", 1); 638 if (flush_subshell(1, VISIBLY) != 1) 639 return FALSE; 640 } 641 } 642 if (command_buffer_length > 0) /* Now we clear the line. */ 643 { 644 write_all (mc_global.tty.subshell_pty, "\025", 1); 645 if (flush_subshell(1, VISIBLY) != 1) 646 return FALSE; 647 } 648 } 649 return TRUE; 650 } 651 652 /* --------------------------------------------------------------------------------------------- */ 653 654 static void 655 clear_subshell_prompt_string (void) 656 { 657 if(subshell_prompt_temp_buffer != NULL) 658 g_string_set_size (subshell_prompt_temp_buffer, 0); 659 } 660 661 /* --------------------------------------------------------------------------------------------- */ 662 663 static void 664 parse_subshell_prompt_string (const char *buffer, int bytes) 665 { 666 int i; 667 668 /* First time through */ 669 if (subshell_prompt == NULL) 670 { 671 subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE); 672 } 673 if (subshell_prompt_temp_buffer == NULL) 674 { 675 subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE); 676 } 677 678 /* Extract the prompt from the shell output */ 679 for (i = 0; i < bytes; i++) 680 if (buffer[i] == '\n' || buffer[i] == '\r') 681 { 682 g_string_set_size (subshell_prompt_temp_buffer, 0); 683 } 684 else if (buffer[i] != '\0') 685 g_string_append_c (subshell_prompt_temp_buffer, buffer[i]); 686 } 687 688 /* --------------------------------------------------------------------------------------------- */ 689 690 static void 691 set_prompt_string (void) 692 { 693 if (subshell_prompt_temp_buffer->len != 0) 694 g_string_assign (subshell_prompt, subshell_prompt_temp_buffer->str); 695 696 setup_cmdline(); 697 } 698 699 /* --------------------------------------------------------------------------------------------- */ 472 700 /** Feed the subshell our keyboard input until it says it's finished */ 473 701 474 702 static gboolean … … feed_subshell (int how, gboolean fail_on_error) 481 709 struct timeval wtime; /* Maximum time we wait for the subshell */ 482 710 struct timeval *wptr; 483 711 712 should_read_new_subshell_prompt = FALSE; 713 subshell_should_clear_command_line = FALSE; 714 484 715 /* we wait up to 10 seconds if fail_on_error, forever otherwise */ 485 716 wtime.tv_sec = 10; 486 717 wtime.tv_usec = 0; … … feed_subshell (int how, gboolean fail_on_error) 549 780 550 781 if (how == VISIBLY) 551 782 write_all (STDOUT_FILENO, pty_buffer, bytes); 783 if (should_read_new_subshell_prompt == TRUE) 784 { 785 parse_subshell_prompt_string(pty_buffer, bytes); 786 } 787 552 788 } 553 789 554 790 else if (FD_ISSET (subshell_pipe[READ], &read_set)) … … feed_subshell (int how, gboolean fail_on_error) 567 803 568 804 synchronize (); 569 805 806 clear_subshell_prompt_string(); 807 should_read_new_subshell_prompt = TRUE; 570 808 subshell_ready = TRUE; 571 809 if (subshell_state == RUNNING_COMMAND) 572 810 { … … feed_subshell (int how, gboolean fail_on_error) 578 816 else if (FD_ISSET (STDIN_FILENO, &read_set)) 579 817 /* Read from stdin, write to the subshell */ 580 818 { 819 should_read_new_subshell_prompt = FALSE; 581 820 bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer)); 582 821 if (bytes <= 0) 583 822 { … … feed_subshell (int how, gboolean fail_on_error) 592 831 { 593 832 write_all (mc_global.tty.subshell_pty, pty_buffer, i); 594 833 if (subshell_ready) 834 { 595 835 subshell_state = INACTIVE; 836 set_prompt_string (); 837 if (subshell_ready == TRUE) 838 { 839 if (!read_command_line_buffer(FALSE)) 840 { 841 /* If we got here, some unforseen error must have occurred. */ 842 flush_subshell(0, VISIBLY); 843 input_assign_text (cmdline, ""); 844 subshell_should_clear_command_line = TRUE; 845 return TRUE; 846 } 847 } 848 } 596 849 return TRUE; 597 850 } 598 851 599 852 write_all (mc_global.tty.subshell_pty, pty_buffer, bytes); 600 853 601 854 if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r') 855 { 856 /* We should only clear the command line if we are using a shell that works 857 * with persistent command buffer, otherwise we get awkward results. */ 858 if (use_persistent_buffer == TRUE) 859 input_assign_text (cmdline, ""); 602 860 subshell_ready = FALSE; 861 } 603 862 } 604 863 else 605 864 return FALSE; … … init_subshell_precmd (char *precmd, size_t buff_size) 784 1043 { 785 1044 case SHELL_BASH: 786 1045 g_snprintf (precmd, buff_size, 1046 " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"echo $READLINE_LINE>&%d\"'\n" 1047 " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING "\":\"echo $READLINE_POINT>&%d\"'\n" 787 1048 " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n" 788 "PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]); 1049 "PS1='\\u@\\h:\\w\\$ '\n", 1050 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 789 1051 break; 790 1052 791 1053 case SHELL_ASH_BUSYBOX: … … init_subshell_precmd (char *precmd, size_t buff_size) 844 1106 845 1107 case SHELL_ZSH: 846 1108 g_snprintf (precmd, buff_size, 1109 " mc_print_command_buffer () { echo $BUFFER >&%d}\n" 1110 " zle -N mc_print_command_buffer\n" 1111 " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n" 1112 " mc_print_cursor_position () { echo $CURSOR >&%d}\n" 1113 " zle -N mc_print_cursor_position\n" 1114 " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n" 847 1115 " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n" 848 "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]); 1116 "PS1='%%n@%%m:%%~%%# '\n", 1117 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 849 1118 break; 850 1119 851 1120 case SHELL_TCSH: … … init_subshell_precmd (char *precmd, size_t buff_size) 854 1123 "set prompt='%%n@%%m:%%~%%# '; " 855 1124 "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo); 856 1125 break; 857 858 1126 case SHELL_FISH: 859 1127 g_snprintf (precmd, buff_size, 860 1128 " if not functions -q fish_prompt_mc;" 861 1129 "functions -e fish_right_prompt;" 862 1130 "functions -c fish_prompt fish_prompt_mc; end;" 863 1131 "function fish_prompt;" 1132 "bind \\e\\" SHELL_BUFFER_KEYBINDING " 'echo (commandline)>&%d'\n" 1133 "bind \\e\\" SHELL_CURSOR_KEYBINDING " 'echo (commandline -C)>&%d'\n" 864 1134 "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n", 865 subshell_pipe[WRITE]);1135 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]); 866 1136 break; 867 1137 868 1138 default: … … init_subshell (void) 1040 1310 mc_global.tty.use_subshell = FALSE; 1041 1311 return; 1042 1312 } 1313 if (mc_global.shell->type == SHELL_BASH 1314 || mc_global.shell->type == SHELL_ZSH 1315 || mc_global.shell->type == SHELL_FISH) 1316 use_persistent_buffer = TRUE; 1317 if (use_persistent_buffer == TRUE) 1318 { 1319 if (pipe (command_buffer_pipe)) 1320 { 1321 perror (__FILE__ ": couldn't create pipe"); 1322 mc_global.tty.use_subshell = FALSE; 1323 return; 1324 } 1325 } 1043 1326 } 1044 1327 1045 1328 /* Fork the subshell */ … … init_subshell (void) 1061 1344 /* We are in the child process */ 1062 1345 init_subshell_child (pty_name); 1063 1346 } 1064 1065 1347 init_subshell_precmd (precmd, BUF_MEDIUM); 1066 1348 1067 1349 write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd)); … … init_subshell (void) 1077 1359 tty_disable_interrupt_key (); 1078 1360 if (!subshell_alive) 1079 1361 mc_global.tty.use_subshell = FALSE; /* Subshell died instantly, so don't use it */ 1362 1363 /* Try out the persistent command buffer feature. If it doesn't work the first time, we 1364 * assume there must be something wrong with the shell, and we turn persistent buffer off 1365 * for good. This will save the user the trouble of having to wait for the persistent 1366 * buffer function to time out every time they try to close the subshell. */ 1367 if (use_persistent_buffer == TRUE) 1368 { 1369 if (read_command_line_buffer(TRUE) == FALSE) 1370 use_persistent_buffer = FALSE; 1371 } 1080 1372 } 1081 1373 1082 1374 /* --------------------------------------------------------------------------------------------- */ … … init_subshell (void) 1084 1376 int 1085 1377 invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 1086 1378 { 1379 size_t i; 1087 1380 /* Make the MC terminal transparent */ 1088 1381 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode); 1089 1382 … … invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 1100 1393 /* FIXME: possibly take out this hack; the user can re-play it by hitting C-hyphen a few times! */ 1101 1394 if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL) 1102 1395 write_all (mc_global.tty.subshell_pty, " \b", 2); /* Hack to make prompt reappear */ 1396 1397 if (use_persistent_buffer == TRUE) 1398 { 1399 /* Check to make sure there are no non text characters in the command buffer, 1400 * such as tab, or newline, as this could cause problems. */ 1401 for(i = 0;i < strlen(cmdline->buffer);i++) 1402 { 1403 if ((unsigned char) cmdline->buffer[i] < 32 1404 || (unsigned char)cmdline->buffer[i] == 127) 1405 cmdline->buffer[i] = ' '; 1406 } 1407 1408 /* Write the command buffer to the subshell. */ 1409 write_all (mc_global.tty.subshell_pty, cmdline->buffer, strlen (cmdline->buffer)); 1410 1411 /* Put the cursor in the correct place in the subshell. */ 1412 for (int j = 0;j < str_length (cmdline->buffer) - cmdline->point;j++) 1413 write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3); 1414 } 1103 1415 } 1104 1416 } 1105 1417 else /* MC has passed us a user command */ 1106 1418 { 1419 /* Before we write to the command prompt, we need to clear whatever */ 1420 /* data is there, but only if we are using one of the shells that */ 1421 /* doesn't support keeping command buffer contents, OR if there was */ 1422 /* some sort of error. */ 1423 if (use_persistent_buffer == FALSE || subshell_should_clear_command_line == TRUE) 1424 { 1425 write_all (mc_global.tty.subshell_pty, "\003", 1); 1426 subshell_state = RUNNING_COMMAND; 1427 /* We need to call feed_subshell here if we are using fish, because of a quirk 1428 * in the behavioral of that particular shell. */ 1429 if (mc_global.shell->type != SHELL_FISH) 1430 feed_subshell (QUIETLY, FALSE); 1431 } 1107 1432 if (how == QUIETLY) 1108 1433 write_all (mc_global.tty.subshell_pty, " ", 1); 1109 1434 /* FIXME: if command is long (>8KB ?) we go comma */ … … invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath) 1131 1456 return subshell_get_mainloop_quit (); 1132 1457 } 1133 1458 1134 1135 1459 /* --------------------------------------------------------------------------------------------- */ 1136 1460 1137 1461 gboolean 1138 read_subshell_prompt (void)1462 flush_subshell (int max_wait_length, int how) 1139 1463 { 1140 1464 int rc = 0; 1141 1465 ssize_t bytes = 0; 1142 1466 struct timeval timeleft = { 0, 0 }; 1143 GString *p; 1144 gboolean prompt_was_reset = FALSE; 1145 1467 int return_value = FALSE; 1146 1468 fd_set tmp; 1469 1470 timeleft.tv_sec = max_wait_length; 1147 1471 FD_ZERO (&tmp); 1148 1472 FD_SET (mc_global.tty.subshell_pty, &tmp); 1149 1473 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 1156 1474 while (subshell_alive 1157 1475 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 1158 1476 { 1159 ssize_t i;1160 1161 1477 /* Check for 'select' errors */ 1162 1478 if (rc == -1) 1163 1479 { … … read_subshell_prompt (void) 1172 1488 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 1173 1489 exit (EXIT_FAILURE); 1174 1490 } 1491 return_value = TRUE; 1492 timeleft.tv_sec = 0; 1493 timeleft.tv_usec = 0; 1175 1494 1176 1495 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 1496 if (how == VISIBLY) 1497 write_all (STDOUT_FILENO, pty_buffer, bytes); 1498 } 1499 return return_value; 1500 } 1501 1502 /* --------------------------------------------------------------------------------------------- */ 1503 1504 gboolean 1505 read_subshell_prompt (void) 1506 { 1507 int rc = 0; 1508 ssize_t bytes = 0; 1509 struct timeval timeleft = { 0, 0 }; 1510 int should_reset_prompt = TRUE; 1511 int got_new_prompt = FALSE; 1512 1513 fd_set tmp; 1514 FD_ZERO (&tmp); 1515 FD_SET (mc_global.tty.subshell_pty, &tmp); 1177 1516 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') 1517 while (subshell_alive 1518 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0) 1519 { 1520 /* Check for 'select' errors */ 1521 if (rc == -1) 1522 { 1523 if (errno == EINTR) 1181 1524 { 1182 g_string_set_size (p, 0); 1183 prompt_was_reset = TRUE; 1525 if (tty_got_winch ()) 1526 tty_change_screen_size (); 1527 1528 continue; 1184 1529 } 1185 else if (pty_buffer[i] != '\0')1186 g_string_append_c (p, pty_buffer[i]);1187 }1188 1530 1189 if (p->len != 0 || prompt_was_reset) 1190 g_string_assign (subshell_prompt, p->str); 1531 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno)); 1532 exit (EXIT_FAILURE); 1533 } 1191 1534 1192 g_string_free (p, TRUE); 1535 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer)); 1536 if (should_reset_prompt) 1537 { 1538 should_reset_prompt = FALSE; 1539 clear_subshell_prompt_string(); 1540 } 1541 parse_subshell_prompt_string (pty_buffer, bytes); 1542 got_new_prompt = TRUE; 1543 } 1544 if (got_new_prompt == TRUE) 1545 { 1546 set_prompt_string (); 1547 } 1193 1548 1194 1549 return (rc != 0 || bytes != 0); 1195 1550 } … … exit_subshell (void) 1231 1586 1232 1587 g_string_free (subshell_prompt, TRUE); 1233 1588 subshell_prompt = NULL; 1589 g_string_free (subshell_prompt_temp_buffer, TRUE); 1590 subshell_prompt_temp_buffer = NULL; 1234 1591 pty_buffer[0] = '\0'; 1235 1592 } 1236 1593 … … do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt) 1259 1616 return; 1260 1617 } 1261 1618 1619 /* If we are using a shell that doesn't support persistent command buffer, we need to clear 1620 * the command prompt before we send the cd command. */ 1621 if (use_persistent_buffer == FALSE || subshell_should_clear_command_line == TRUE) 1622 { 1623 write_all (mc_global.tty.subshell_pty, "\003", 1); 1624 subshell_state = RUNNING_COMMAND; 1625 if (mc_global.shell->type != SHELL_FISH) 1626 feed_subshell (QUIETLY, FALSE); 1627 } 1262 1628 /* The initial space keeps this out of the command history (in bash 1263 1629 because we set "HISTCONTROL=ignorespace") */ 1264 1630 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; 36 36 37 37 extern gboolean update_subshell_prompt; 38 38 39 extern gboolean should_read_new_subshell_prompt; 40 39 41 /*** declarations of public functions ************************************************************/ 40 42 41 43 void init_subshell (void); 42 44 int invoke_subshell (const char *command, int how, vfs_path_t ** new_dir); 45 gboolean flush_subshell (int max_wait_length, int how); 43 46 gboolean read_subshell_prompt (void); 44 47 void do_update_prompt (void); 45 48 gboolean exit_subshell (void);