nano-devel
[Top][All Lists]
Advanced

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

[Nano-devel] [PATCH] restored feature: a per-syntax 'fixer' command that


From: Benno Schulenberg
Subject: [Nano-devel] [PATCH] restored feature: a per-syntax 'fixer' command that processes the buffer
Date: Thu, 10 Oct 2019 19:17:38 +0200

The command can be used to run some kind of formatter or corrector or
arranging tool on the buffer.  By default the command is bound to M-F.
The formatter/corrector/arranging program must be non-interactive.

This addresses https://savannah.gnu.org/bugs/?55365,
and addresses https://savannah.gnu.org/bugs/?54651.
---
 src/files.c  |  7 ++---
 src/global.c | 12 +++++++--
 src/nano.h   |  2 ++
 src/proto.h  |  4 ++-
 src/rcfile.c |  6 ++++-
 src/text.c   | 76 +++++++++++++++++++++++++++++++++++++++++++---------
 6 files changed, 88 insertions(+), 19 deletions(-)

diff --git a/src/files.c b/src/files.c
index 5f687645..ebf361f6 100644
--- a/src/files.c
+++ b/src/files.c
@@ -513,7 +513,8 @@ bool open_buffer(const char *filename, bool new_buffer)
 #ifdef ENABLE_SPELLER
 /* Open the specified file, and if that succeeds, remove the text of the marked
  * region or of the entire buffer and read the file contents into its place. */
-bool replace_buffer(const char *filename, undo_type action, bool marked)
+bool replace_buffer(const char *filename, undo_type action, bool marked,
+               const char *operation)
 {
        linestruct *was_cutbuffer = cutbuffer;
        int descriptor;
@@ -525,7 +526,7 @@ bool replace_buffer(const char *filename, undo_type action, 
bool marked)
                return FALSE;
 
 #ifndef NANO_TINY
-       add_undo(COUPLE_BEGIN, "spelling correction");
+       add_undo(COUPLE_BEGIN, operation);
 #endif
 
        /* When nothing is marked, start at the top of the buffer. */
@@ -550,7 +551,7 @@ bool replace_buffer(const char *filename, undo_type action, 
bool marked)
        read_file(f, descriptor, filename, TRUE);
 
 #ifndef NANO_TINY
-       add_undo(COUPLE_END, "spelling correction");
+       add_undo(COUPLE_END, operation);
 #endif
        return TRUE;
 }
diff --git a/src/global.c b/src/global.c
index c8b01c7e..b3a3c40e 100644
--- a/src/global.c
+++ b/src/global.c
@@ -693,6 +693,8 @@ void shortcut_init(void)
        const char *lint_gist = N_("Invoke the linter, if available");
        const char *prevlint_gist = N_("Go to previous linter msg");
        const char *nextlint_gist = N_("Go to next linter msg");
+       const char *fixer_gist =
+               N_("Invoke a program to manipulate the buffer, if available");
 #endif
 #endif /* ENABLE_HELP */
 
@@ -1001,9 +1003,12 @@ void shortcut_init(void)
                N_("Zap Text"), WITHORSANS(zap_gist), BLANKAFTER, NOVIEW);
 
 #ifdef ENABLE_COLOR
-       if (!ISSET(RESTRICTED))
+       if (!ISSET(RESTRICTED)) {
                add_to_funcs(do_linter, MMAIN,
-                               N_("To Linter"), WITHORSANS(lint_gist), 
BLANKAFTER, NOVIEW);
+                               N_("To Linter"), WITHORSANS(lint_gist), 
TOGETHER, NOVIEW);
+               add_to_funcs(do_fixer, MMAIN,
+                               N_("Manipulate"), WITHORSANS(fixer_gist), 
BLANKAFTER, NOVIEW);
+       }
 #endif
 #endif
        add_to_funcs(do_savefile, MMAIN,
@@ -1124,6 +1129,7 @@ void shortcut_init(void)
 #endif
 #ifdef ENABLE_COLOR
        add_to_sclist(MMAIN, "M-B", 0, do_linter, 0);
+       add_to_sclist(MMAIN, "M-F", 0, do_fixer, 0);
 #endif
        add_to_sclist(MMAIN, "^C", 0, do_cursorpos_void, 0);
        add_to_sclist(MMAIN, "^_", 0, do_gotolinecolumn_void, 0);
@@ -1502,6 +1508,8 @@ keystruct *strtosc(const char *input)
 #ifdef ENABLE_COLOR
        else if (!strcasecmp(input, "linter"))
                s->func = do_linter;
+       else if (!strcasecmp(input, "fixer"))
+               s->func = do_fixer;
 #endif
        else if (!strcasecmp(input, "curpos"))
                s->func = do_cursorpos_void;
diff --git a/src/nano.h b/src/nano.h
index 373ce5c2..f25e5382 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -234,6 +234,8 @@ typedef struct syntaxtype {
                /* The list of libmagic results that this syntax applies to. */
        char *linter;
                /* The command with which to lint this type of file. */
+       char *fixer;
+               /* The command with which to "fix"/format/modify this type of 
file. */
        char *tab;
                /* What the Tab key should produce; NULL for default behavior. 
*/
 #ifdef ENABLE_COMMENT
diff --git a/src/proto.h b/src/proto.h
index 14e4d139..c97cd863 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -276,7 +276,8 @@ void make_new_buffer(void);
 void set_modified(void);
 bool open_buffer(const char *filename, bool new_buffer);
 #ifdef ENABLE_SPELLER
-bool replace_buffer(const char *filename, undo_type action, bool marked);
+bool replace_buffer(const char *filename, undo_type action, bool marked,
+               const char *operation);
 #endif
 void prepare_for_display(void);
 #ifdef ENABLE_MULTIBUFFER
@@ -551,6 +552,7 @@ void do_spell(void);
 #endif
 #ifdef ENABLE_COLOR
 void do_linter(void);
+void do_fixer(void);
 #endif
 #ifndef NANO_TINY
 void do_wordlinechar_count(void);
diff --git a/src/rcfile.c b/src/rcfile.c
index eb8e842d..4a5d294e 100644
--- a/src/rcfile.c
+++ b/src/rcfile.c
@@ -333,6 +333,7 @@ void begin_new_syntax(char *ptr)
        live_syntax->headers = NULL;
        live_syntax->magics = NULL;
        live_syntax->linter = NULL;
+       live_syntax->fixer = NULL;
        live_syntax->tab = NULL;
 #ifdef ENABLE_COMMENT
        live_syntax->comment = mallocstrcpy(NULL, GENERAL_COMMENT_CHARACTER);
@@ -955,6 +956,8 @@ bool parse_syntax_commands(char *keyword, char *ptr)
 #endif
        } else if (strcasecmp(keyword, "linter") == 0)
                pick_up_name("linter", ptr, &live_syntax->linter);
+       else if (strcasecmp(keyword, "fixer") == 0)
+               pick_up_name("fixer", ptr, &live_syntax->fixer);
        else
                return FALSE;
 
@@ -1110,7 +1113,8 @@ void parse_rcfile(FILE *rcstream, bool just_syntax, bool 
intros_only)
                                                                
strcasecmp(keyword, "icolor") == 0 ||
                                                                
strcasecmp(keyword, "comment") == 0 ||
                                                                
strcasecmp(keyword, "tabgives") == 0 ||
-                                                               
strcasecmp(keyword, "linter") == 0)) {
+                                                               
strcasecmp(keyword, "linter") == 0 ||
+                                                               
strcasecmp(keyword, "fixer") == 0)) {
                        if (!opensyntax)
                                jot_error(N_("A '%s' command requires a 
preceding "
                                                                        
"'syntax' command"), keyword);
diff --git a/src/text.c b/src/text.c
index 7921eac7..295a6095 100644
--- a/src/text.c
+++ b/src/text.c
@@ -2534,28 +2534,31 @@ const char *do_int_speller(const char *tempfile_name)
 }
 
 /* Execute the given program, with the given temp file as last argument. */
-const char *treat(char *tempfile_name, char *theprogram)
+const char *treat(char *tempfile_name, char *theprogram, bool spelling)
 {
        ssize_t lineno_save = openfile->current->lineno;
        size_t current_x_save = openfile->current_x;
        size_t pww_save = openfile->placewewant;
        bool was_at_eol = (openfile->current->data[openfile->current_x] == 
'\0');
+       const char *msg = (spelling ? N_("spelling correction") : 
N_("manipulation"));
        struct stat fileinfo;
-       time_t timestamp;
+       long timestamp_sec, timestamp_nsec;
        static char **arguments = NULL;
        pid_t thepid;
        int program_status;
 
        /* Get the timestamp and the size of the temporary file. */
        stat(tempfile_name, &fileinfo);
-       timestamp = fileinfo.st_mtime;
+       timestamp_sec = (long)fileinfo.st_mtim.tv_sec;
+       timestamp_nsec = (long)fileinfo.st_mtim.tv_nsec;
 
        /* If the number of bytes to check is zero, get out. */
        if (fileinfo.st_size == 0)
                return NULL;
 
-       /* Exit from curses mode. */
-       endwin();
+       /* The spell checker needs the screen, so exit from curses mode. */
+       if (spelling)
+               endwin();
 
        construct_argument_list(&arguments, theprogram, tempfile_name);
 
@@ -2574,9 +2577,11 @@ const char *treat(char *tempfile_name, char *theprogram)
        wait(&program_status);
        block_sigwinch(FALSE);
 
-       /* Set the desired terminal state again, and reenter curses mode. */
-       terminal_init();
-       doupdate();
+       /* When needed, restore the terminal state and reenter curses mode. */
+       if (spelling) {
+               terminal_init();
+               doupdate();
+       }
 
        if (!WIFEXITED(program_status) || WEXITSTATUS(program_status) != 0)
                return invocation_error(theprogram);
@@ -2585,7 +2590,8 @@ const char *treat(char *tempfile_name, char *theprogram)
        stat(tempfile_name, &fileinfo);
 
        /* Read in the temporary file only when it changed. */
-       if (fileinfo.st_mtime != timestamp) {
+       if ((long)fileinfo.st_mtim.tv_sec != timestamp_sec ||
+                               (long)fileinfo.st_mtim.tv_nsec != 
timestamp_nsec) {
                bool replaced = FALSE;
 #ifndef NANO_TINY
                /* Replace the marked text (or entire text) with the corrected 
text. */
@@ -2595,7 +2601,7 @@ const char *treat(char *tempfile_name, char *theprogram)
                                                                        
openfile->mark_x < openfile->current_x));
                        ssize_t was_mark_lineno = openfile->mark->lineno;
 
-                       replaced = replace_buffer(tempfile_name, CUT, TRUE);
+                       replaced = replace_buffer(tempfile_name, CUT, TRUE, 
msg);
 
                        /* Adjust the end point of the marked region for any 
change in
                         * length of the region's last line. */
@@ -2608,7 +2614,7 @@ const char *treat(char *tempfile_name, char *theprogram)
                        openfile->mark = line_from_number(was_mark_lineno);
                } else
 #endif
-                       replaced = replace_buffer(tempfile_name, CUT_TO_EOF, 
FALSE);
+                       replaced = replace_buffer(tempfile_name, CUT_TO_EOF, 
FALSE, msg);
 
                /* Go back to the old position. */
                goto_line_posx(lineno_save, current_x_save);
@@ -2667,7 +2673,10 @@ void do_spell(void)
 
        blank_bottombars();
 
-       result_msg = (alt_speller ? treat(temp, alt_speller) : 
do_int_speller(temp));
+       if (alt_speller)
+               result_msg = treat(temp, alt_speller, TRUE);
+       else
+               result_msg = do_int_speller(temp);
 
        unlink(temp);
        free(temp);
@@ -3031,6 +3040,49 @@ void do_linter(void)
        currmenu = MMOST;
        titlebar(NULL);
 }
+
+#ifdef ENABLE_SPELLER
+/* Run a manipulation program on the contents of the buffer. */
+void do_fixer(void)
+{
+       FILE *stream;
+       char *temp_name;
+       bool okay = FALSE;
+       const char *result_msg;
+
+       if (in_restricted_mode())
+               return;
+
+       if (!openfile->syntax || !openfile->syntax->fixer) {
+               statusbar(_("No fixer is defined for this type of file"));
+               return;
+       }
+
+       temp_name = safe_tempfile(&stream);
+
+       if (temp_name != NULL)
+               okay = write_file(temp_name, stream, TRUE, OVERWRITE, TRUE);
+
+       if (!okay) {
+               statusline(ALERT, _("Error writing temp file: %s"), 
strerror(errno));
+               free(temp_name);
+               return;
+       }
+
+       /* Manipulation always happens on the whole buffer. */
+       openfile->mark = NULL;
+
+       result_msg = treat(temp_name, openfile->syntax->fixer, FALSE);
+
+       if (result_msg != NULL)
+               statusline(ALERT, result_msg);
+       else
+               statusbar(_("Buffer has been processed"));
+
+       unlink(temp_name);
+       free(temp_name);
+}
+#endif /* ENABLE_SPELLER */
 #endif /* ENABLE_COLOR */
 
 #ifndef NANO_TINY
-- 
2.23.0




reply via email to

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