mirror of
git://git.sv.gnu.org/nano.git
synced 2024-12-28 13:19:48 +03:00
new feature: allow piping (selected) text to an external command
When executing a command, it is now possible to pipe the entire buffer (or the marked region, if anything is marked) to the external command. The output from the command replaces the buffer (or the marked region), or goes to a new buffer. This fulfills https://savannah.gnu.org/bugs/?28993, and fulfills https://savannah.gnu.org/bugs/?53041. Signed-off-by: Marco Diego Aurélio Mesquita <marcodiegomesquita@gmail.com> Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
This commit is contained in:
parent
299e710845
commit
f304b9aee1
17
src/files.c
17
src/files.c
@ -1110,6 +1110,23 @@ void do_insertfile(void)
|
||||
i = 0;
|
||||
}
|
||||
#endif
|
||||
if (func == flip_pipe) {
|
||||
/* Remove or add the pipe character at the answer's head. */
|
||||
if (answer[0] == '|') {
|
||||
charmove(answer, answer + 1, strlen(answer) + 1);
|
||||
if (statusbar_x > 0)
|
||||
statusbar_x--;
|
||||
} else {
|
||||
answer = charealloc(answer, strlen(answer) + 2);
|
||||
charmove(answer + 1, answer, strlen(answer) + 1);
|
||||
answer[0] = '|';
|
||||
statusbar_x++;
|
||||
}
|
||||
|
||||
given = mallocstrcpy(given, answer);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we don't have a file yet, go back to the prompt. */
|
||||
if (i != 0 && (!ISSET(MULTIBUFFER) || i != -2))
|
||||
continue;
|
||||
|
14
src/global.c
14
src/global.c
@ -152,6 +152,8 @@ char *word_chars = NULL;
|
||||
|
||||
char *answer = NULL;
|
||||
/* The answer string used by the statusbar prompt. */
|
||||
size_t statusbar_x = HIGHEST_POSITIVE;
|
||||
/* The cursor position in answer. */
|
||||
|
||||
ssize_t tabsize = -1;
|
||||
/* The width of a tab in spaces. The default is set in main(). */
|
||||
@ -311,6 +313,9 @@ void backup_file_void(void)
|
||||
void flip_execute(void)
|
||||
{
|
||||
}
|
||||
void flip_pipe(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
void flip_newbuffer(void)
|
||||
@ -524,6 +529,8 @@ void shortcut_init(void)
|
||||
N_("Write the current buffer (or the marked region) to disk");
|
||||
const char *readfile_gist =
|
||||
N_("Insert another file into current buffer (or into new buffer)");
|
||||
const char *pipe_gist =
|
||||
N_("Pipe the current buffer (or marked region) to the command");
|
||||
const char *whereis_gist =
|
||||
N_("Search forward for a string or a regular expression");
|
||||
const char *wherewas_gist =
|
||||
@ -1034,6 +1041,9 @@ void shortcut_init(void)
|
||||
add_to_funcs(flip_newbuffer, MINSERTFILE|MEXTCMD,
|
||||
N_("New Buffer"), WITHORSANS(newbuffer_gist), TOGETHER, NOVIEW);
|
||||
#endif
|
||||
if (!ISSET(RESTRICTED))
|
||||
add_to_funcs(flip_pipe, MEXTCMD,
|
||||
N_("Pipe Text"), WITHORSANS(pipe_gist), TOGETHER, NOVIEW);
|
||||
|
||||
#ifdef ENABLE_BROWSER
|
||||
/* The file browser is only available when not in restricted mode. */
|
||||
@ -1329,8 +1339,10 @@ void shortcut_init(void)
|
||||
#endif
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
/* Only when not in restricted mode, allow multiple buffers. */
|
||||
if (!ISSET(RESTRICTED))
|
||||
if (!ISSET(RESTRICTED)) {
|
||||
add_to_sclist(MINSERTFILE|MEXTCMD, "M-F", 0, flip_newbuffer, 0);
|
||||
add_to_sclist(MEXTCMD, "M-\\", 0, flip_pipe, 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_BROWSER
|
||||
/* Only when not in restricted mode, allow entering the file browser. */
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
static char *prompt = NULL;
|
||||
/* The prompt string used for statusbar questions. */
|
||||
static size_t statusbar_x = HIGHEST_POSITIVE;
|
||||
/* The cursor position in answer. */
|
||||
|
||||
#ifdef ENABLE_MOUSE
|
||||
/* Handle a mouse click on the statusbar prompt or the shortcut list. */
|
||||
|
@ -124,6 +124,7 @@ extern char *quoteerr;
|
||||
extern char *word_chars;
|
||||
|
||||
extern char *answer;
|
||||
extern size_t statusbar_x;
|
||||
|
||||
extern ssize_t tabsize;
|
||||
|
||||
@ -709,6 +710,7 @@ void append_void(void);
|
||||
void prepend_void(void);
|
||||
void backup_file_void(void);
|
||||
void flip_execute(void);
|
||||
void flip_pipe(void);
|
||||
#endif
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
void flip_newbuffer(void);
|
||||
|
71
src/text.c
71
src/text.c
@ -1079,10 +1079,30 @@ RETSIGTYPE cancel_command(int signal)
|
||||
nperror("kill");
|
||||
}
|
||||
|
||||
/* Send the text that starts at the given line to file descriptor fd. */
|
||||
void send_data(const filestruct *line, int fd)
|
||||
{
|
||||
FILE *tube = fdopen(fd, "w");
|
||||
|
||||
if (tube == NULL)
|
||||
return;
|
||||
|
||||
/* Send each line, except a final empty line. */
|
||||
while (line != NULL && (line->next != NULL || line->data[0] != '\0')) {
|
||||
fprintf(tube, "%s%s", line->data, line->next == NULL ? "" : "\n");
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
fclose(tube);
|
||||
}
|
||||
|
||||
/* Execute command in a shell. Return TRUE on success. */
|
||||
bool execute_command(const char *command)
|
||||
{
|
||||
int fd[2];
|
||||
int fd[2], to_fd[2];
|
||||
/* The pipes through which text will written and read. */
|
||||
const bool has_selection = ISSET(MULTIBUFFER) ? openfile->prev->mark : openfile->mark;
|
||||
const bool should_pipe = (command[0] == '|');
|
||||
FILE *stream;
|
||||
const char *shellenv;
|
||||
struct sigaction oldaction, newaction;
|
||||
@ -1090,8 +1110,9 @@ bool execute_command(const char *command)
|
||||
bool setup_failed = FALSE;
|
||||
/* Whether setting up the temporary SIGINT handler failed. */
|
||||
|
||||
/* Create a pipe to read the command's output from. */
|
||||
if (pipe(fd) == -1) {
|
||||
/* Create a pipe to read the command's output from, and, if needed,
|
||||
* a pipe to feed the command's input through. */
|
||||
if (pipe(fd) == -1 || (should_pipe && pipe(to_fd) == -1)) {
|
||||
statusbar(_("Could not create pipe"));
|
||||
return FALSE;
|
||||
}
|
||||
@ -1110,8 +1131,15 @@ bool execute_command(const char *command)
|
||||
dup2(fd[1], fileno(stdout));
|
||||
dup2(fd[1], fileno(stderr));
|
||||
|
||||
/* If the parent sends text, connect the read end of the
|
||||
* feeding pipe to the child's input stream. */
|
||||
if (should_pipe) {
|
||||
dup2(to_fd[0], fileno(stdin));
|
||||
close(to_fd[1]);
|
||||
}
|
||||
|
||||
/* Run the given command inside the preferred shell. */
|
||||
execl(shellenv, tail(shellenv), "-c", command, NULL);
|
||||
execl(shellenv, tail(shellenv), "-c", should_pipe ? &command[1] : command, NULL);
|
||||
|
||||
/* If the exec call returns, there was an error. */
|
||||
exit(1);
|
||||
@ -1126,6 +1154,41 @@ bool execute_command(const char *command)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* If the command starts with "|", pipe buffer or region to the command. */
|
||||
if (should_pipe) {
|
||||
filestruct *was_cutbuffer = cutbuffer;
|
||||
cutbuffer = NULL;
|
||||
|
||||
if (ISSET(MULTIBUFFER))
|
||||
switch_to_prev_buffer();
|
||||
|
||||
if (has_selection || !ISSET(MULTIBUFFER)) {
|
||||
if (!has_selection) {
|
||||
openfile->current = openfile->fileage;
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
add_undo(CUT);
|
||||
do_cut_text(ISSET(MULTIBUFFER), !has_selection);
|
||||
update_undo(CUT);
|
||||
}
|
||||
|
||||
if (fork() == 0) {
|
||||
close(to_fd[0]);
|
||||
send_data(cutbuffer != NULL ? cutbuffer : openfile->fileage, to_fd[1]);
|
||||
close(to_fd[1]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
close(to_fd[0]);
|
||||
close(to_fd[1]);
|
||||
|
||||
if (ISSET(MULTIBUFFER))
|
||||
switch_to_next_buffer();
|
||||
|
||||
free_filestruct(cutbuffer);
|
||||
cutbuffer = was_cutbuffer;
|
||||
}
|
||||
|
||||
/* Re-enable interpretation of the special control keys so that we get
|
||||
* SIGINT when Ctrl-C is pressed. */
|
||||
enable_signals();
|
||||
|
Loading…
Reference in New Issue
Block a user