nano-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Nano-devel] [PATCH 1/3 V9] new feature: allow piping (selected) text to


From: Benno Schulenberg
Subject: [Nano-devel] [PATCH 1/3 V9] new feature: allow piping (selected) text to an external command
Date: Tue, 22 May 2018 11:37:25 +0200

From: Marco Diego Aurélio Mesquita <address@hidden>

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 <address@hidden>
Signed-off-by: Benno Schulenberg <address@hidden>
---
 src/files.c  | 17 +++++++++++++
 src/global.c | 14 ++++++++++-
 src/prompt.c |  2 --
 src/proto.h  |  2 ++
 src/text.c   | 71 +++++++++++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 99 insertions(+), 7 deletions(-)

diff --git a/src/files.c b/src/files.c
index c32fce1b..c4d1f764 100644
--- a/src/files.c
+++ b/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;
diff --git a/src/global.c b/src/global.c
index f5e6c0e7..4befbc4b 100644
--- a/src/global.c
+++ b/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. */
diff --git a/src/prompt.c b/src/prompt.c
index 47d3131b..07130568 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -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. */
diff --git a/src/proto.h b/src/proto.h
index 8cc8d14f..1100a91a 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -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);
diff --git a/src/text.c b/src/text.c
index 80fd7aad..86857446 100644
--- a/src/text.c
+++ b/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();
-- 
2.17.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]