]> git.wh0rd.org Git - nano.git/commitdiff
2015-01-03 Chris Allegretta <chrisa@asty.org>
authorChris Allegretta <chrisa@asty.org>
Sat, 3 Jan 2015 07:24:17 +0000 (07:24 +0000)
committerChris Allegretta <chrisa@asty.org>
Sat, 3 Jan 2015 07:24:17 +0000 (07:24 +0000)
        * New formatter code to support syntaxes like
        go which have tools to automatically lint and reformat the text for
        you (gofmt), which is lovely.  rcfile option formatter, function
        text.c:do_formatter() and some other calls.

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@5100 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
doc/man/nanorc.5
doc/syntax/go.nanorc
doc/syntax/nanorc.nanorc
src/global.c
src/nano.h
src/proto.h
src/rcfile.c
src/text.c
src/winio.c

index 75bdfe8a3fbbb2edab3c24f266ade5700215c921..bef2d03df474fba0de84016f3101b20d3d962005 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-01-03  Chris Allegretta <chrisa@asty.org>
+       * New formatter code to support syntaxes like
+       go which have tools to automatically lint and reformat the text for
+       you (gofmt), which is lovely.  rcfile option formatter, function
+       text.c:do_formatter() and some other calls.
+
 2014-12-28  Benno Schulenberg  <bensberg@justemail.net>
        * src/files.c (do_lockfile): Gettextize the "File being edited"
        prompt, and improve its wording.
index 7002368c161541fcd1ecad56e384815361fa0225..98efe6ef316fe1039f3cd8bb0df300a6d6bc114b 100644 (file)
@@ -270,6 +270,11 @@ For the currently defined syntax, use the given \fIprogram\fR
 to invoke the linter (this overrides the speller function when
 defined).
 .TP
+.BI formatter " program " \fR[ "arg " \fR...]
+For the currently defined syntax, use the given \fIprogram\fR
+to automatically re-format text, useful in certain programming
+languages (e.g. go)
+.TP
 .BR header " [""\fIregex\fR"" ...]
 For the currently defined syntax, add one or more regexes which will
 be compared against the very first line of the file to be edited,
index 58ef1812cb401b0f5a363c54f1940373cb535a46..0b6233475e35ecf544888d715e4c3fac7fd7d1eb 100644 (file)
@@ -40,3 +40,6 @@ color brightblue start="/\*" end="\*/"
 
 # Trailing whitespace.
 color ,green "[[:space:]]+$"
+
+# Set up the formatter since spelling is probably useless...
+formatter gofmt -w
index c71e49201a37578b93248012d6078c96baaedfa2..1858f2b054c6496652474d2246df8a5c3d8ed24f 100644 (file)
@@ -11,7 +11,7 @@ icolor yellow "^[[:space:]]*set[[:space:]]+(functioncolor|keycolor|statuscolor|t
 icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|functioncolor|keycolor|matchbrackets|operatingdir|punct|quotestr|speller|statuscolor|titlecolor|whitespace)[[:space:]]+"
 icolor brightgreen "^[[:space:]]*bind[[:space:]]+((\^|M-)([[:alpha:]]|space|[]]|[0-9_=+{}|;:'\",./<>\?-])|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+[[:alpha:]]+[[:space:]]+[[:alpha:]]+[[:space:]]*$"
 icolor brightgreen "^[[:space:]]*unbind[[:space:]]+((\^|M-)([[:alpha:]]|space|[]]|[0-9_=+{}|;:'\",./<>\?-])|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+[[:alpha:]]+[[:space:]]*$"
-icolor brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|linter)[[:space:]]+.*$"
+icolor brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|linter|formatter)[[:space:]]+.*$"
 icolor green "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|linter|extendsyntax)\>"
 
 # Colors
index 45d3e019b9af0d0ff399eb6046036fc1457fc096..6f7fbb38c8f7748ae7d9cead54c46e09c0551e5d 100644 (file)
@@ -639,6 +639,7 @@ void shortcut_init(void)
     const char *nano_lint_msg = N_("Invoke the linter, if available");
     const char *nano_prevlint_msg = N_("Go to previous linter msg");
     const char *nano_nextlint_msg = N_("Go to next linter msg");
+    const char *nano_formatter_msg = N_("Invoke formatter, if available");
 #endif
 #endif /* !DISABLE_HELP */
 
@@ -735,6 +736,8 @@ void shortcut_init(void)
 #ifndef DISABLE_COLOR
     add_to_funcs(do_linter, MMAIN,
        N_("To Linter"), IFSCHELP(nano_lint_msg), BLANKAFTER, NOVIEW);
+    add_to_funcs(do_formatter, MMAIN,
+       N_("Formatter"), IFSCHELP(nano_formatter_msg), TOGETHER, NOVIEW);
 #endif
 
 #ifndef NANO_TINY
@@ -1007,6 +1010,8 @@ void shortcut_init(void)
 #ifndef DISABLE_COLOR
     add_to_sclist(MMAIN, "^T", do_linter, 0);
     add_to_sclist(MMAIN, "F12", do_linter, 0);
+    add_to_sclist(MMAIN, "^T", do_formatter, 0);
+    add_to_sclist(MMAIN, "F12", do_formatter, 0);
 #endif
 #endif
     add_to_sclist(MMAIN, "^C", do_cursorpos_void, 0);
@@ -1178,17 +1183,24 @@ void shortcut_init(void)
 }
 
 #ifndef DISABLE_COLOR
-void set_lint_shortcuts(void)
+void set_lint_or_format_shortcuts(void)
 {
 #ifndef DISABLE_SPELLER
-    replace_scs_for(do_spell, do_linter);
+    if (openfile->syntax->formatter) {
+       replace_scs_for(do_spell, do_formatter);
+       replace_scs_for(do_linter, do_formatter);
+    } else {
+       replace_scs_for(do_spell, do_linter);
+       replace_scs_for(do_formatter, do_linter);
+    }
 #endif
 }
 
 void set_spell_shortcuts(void)
 {
 #ifndef DISABLE_SPELLER
-    replace_scs_for(do_linter, do_spell);
+       replace_scs_for(do_formatter, do_spell);
+       replace_scs_for(do_linter, do_spell);
 #endif
 }
 #endif
@@ -1516,7 +1528,7 @@ int strtomenu(char *input)
        return MHELP;
 #endif
 #ifndef DISABLE_SPELLER
-    else if (!strcasecmp(input, "spell"))
+    else if (!strcasecmp(input, "spell") || !strcasecmp(input, "formatter"))
        return MSPELL;
 #endif
     else if (!strcasecmp(input, "linter"))
index f4f43f3babbf0c4435e2d2158dad4bfaf12b0a19..ffd7d22d2b7630c92b9a449be330584e6d2b8043 100644 (file)
@@ -251,6 +251,8 @@ typedef struct syntaxtype {
        /* The colors used in this syntax. */
     char *linter;
        /* The command to lint this type of file. */
+    char *formatter;
+        /* Use this formatter command (for programming lang mainly) */
     int nmultis;
        /* How many multi-line strings this syntax has. */
     struct syntaxtype *next;
index 5cb280ff183cbd183a9180f94e9fc328e983c59b..2d5a803e1ccf31a8ef2d0e4fb064b4d07cf9fecd 100644 (file)
@@ -359,7 +359,7 @@ void assign_keyinfo(sc *s);
 void print_sclist(void);
 void shortcut_init(void);
 #ifndef DISABLE_COLOR
-void set_lint_shortcuts(void);
+void set_lint_or_format_shortcuts(void);
 void set_spell_shortcuts(void);
 #endif
 const subnfunc *sctofunc(sc *s);
@@ -688,6 +688,7 @@ void do_spell(void);
 #endif
 #ifndef DISABLE_COLOR
 void do_linter(void);
+void do_formatter(void);
 #endif
 #ifndef NANO_TINY
 void do_wordlinechar_count(void);
@@ -780,7 +781,7 @@ void check_statusblank(void);
 char *display_string(const char *buf, size_t start_col, size_t len, bool
        dollars);
 void titlebar(const char *path);
-void set_modified(void);
+extern void set_modified(void);
 void statusbar(const char *msg, ...);
 void bottombars(int menu);
 void onekey(const char *keystroke, const char *desc, size_t len);
index fe67530fbd8f8a3144c78c01bc47d77774029992..f7c897d6123405758a4e3bbe8065ed0461660ac6 100644 (file)
@@ -328,6 +328,7 @@ void parse_syntax(char *ptr)
     endsyntax->next = NULL;
     endsyntax->nmultis = 0;
     endsyntax->linter = NULL;
+    endsyntax->formatter = NULL;
 
 #ifdef DEBUG
     fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
@@ -995,6 +996,31 @@ void parse_linter(char *ptr)
     else
        endsyntax->linter = mallocstrcpy(syntaxes->linter, ptr);
 }
+
+void parse_formatter(char *ptr)
+{
+    assert(ptr != NULL);
+
+    if (syntaxes == NULL) {
+       rcfile_error(
+               N_("Cannot add formatter without a syntax command"));
+       return;
+    }
+
+    if (*ptr == '\0') {
+       rcfile_error(N_("Missing formatter command"));
+       return;
+    }
+
+    if (endsyntax->formatter != NULL)
+       free(endsyntax->formatter);
+
+    /* Let them unset the formatter by using "". */
+    if (!strcmp(ptr, "\"\""))
+       endsyntax->formatter = NULL;
+    else
+       endsyntax->formatter = mallocstrcpy(syntaxes->formatter, ptr);
+}
 #endif /* !DISABLE_COLOR */
 
 /* Check whether the user has unmapped every shortcut for a
@@ -1130,6 +1156,8 @@ void parse_rcfile(FILE *rcstream
            parse_colors(ptr, TRUE);
        else if (strcasecmp(keyword, "linter") == 0)
            parse_linter(ptr);
+       else if (strcasecmp(keyword, "formatter") == 0)
+           parse_formatter(ptr);
 #endif /* !DISABLE_COLOR */
        else if (strcasecmp(keyword, "bind") == 0)
            parse_binding(ptr, TRUE);
index 527ed3541dd529571371f1f56b181043b58ca41f..79a6892e47c4b702612340c32cf666df2a70be96 100644 (file)
@@ -3225,6 +3225,160 @@ free_lints_and_return:
     }
     lint_cleanup();
 }
+
+/* Run a formatter for the given syntax.
+ * Expects the formatter to be non-interactive and
+ * operate on a file in-place, which we'll pass it
+ * on the command line.  Another mashuhp of the speller
+ * and alt_speller routines.
+ */
+void do_formatter(void)
+{
+    bool status;
+    FILE *temp_file;
+    char *temp = safe_tempfile(&temp_file);
+    int format_status;
+    size_t current_x_save = openfile->current_x;
+    size_t pww_save = openfile->placewewant;
+    ssize_t current_y_save = openfile->current_y;
+    ssize_t lineno_save = openfile->current->lineno;
+    pid_t pid_format;
+    char *ptr;
+    static int arglen = 3;
+    static char **formatargs = NULL;
+    char *finalstatus = NULL;
+
+   /* Check whether we're using syntax highlighting
+    * and formatter option it set
+    */
+    if (openfile->syntax == NULL || openfile->syntax->formatter == NULL) {
+       statusbar(_("Error: no linter defined"));
+       return;
+    }
+
+    if (ISSET(RESTRICTED)) {
+       nano_disabled_msg();
+       return;
+    }
+
+    if (temp == NULL) {
+       statusbar(_("Error writing temp file: %s"), strerror(errno));
+       return;
+    }
+
+    /* we're not supporting partial formatting, oi vey */
+    openfile->mark_set = FALSE;
+    status = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
+
+    if (!status) {
+       statusbar(_("Error writing temp file: %s"), strerror(errno));
+       free(temp);
+       return;
+    }
+
+    if (openfile->totsize == 0) {
+       statusbar(_("Finished"));
+       return;
+    }
+
+    blank_bottombars();
+    statusbar(_("Invoking formatter, please wait"));
+    doupdate();
+
+    endwin();
+
+    /* Set up an argument list to pass execvp(). */
+    if (formatargs == NULL) {
+       formatargs = (char **)nmalloc(arglen * sizeof(char *));
+
+       formatargs[0] = strtok(openfile->syntax->formatter, " ");
+       while ((ptr = strtok(NULL, " ")) != NULL) {
+           arglen++;
+           formatargs = (char **)nrealloc(formatargs, arglen *
+               sizeof(char *));
+           formatargs[arglen - 3] = ptr;
+       }
+       formatargs[arglen - 1] = NULL;
+    }
+    formatargs[arglen - 2] = temp;
+
+    /* Start a new process for the formatter. */
+    if ((pid_format = fork()) == 0) {
+       /* Start alternate format program; we are using $PATH. */
+       execvp(formatargs[0], formatargs);
+
+       /* Should not be reached, if alternate formatter is found!!! */
+       exit(1);
+    }
+
+    /* If we couldn't fork, get out. */
+    if (pid_format < 0) {
+       statusbar(_("Could not fork"));
+       return;
+    }
+
+#ifndef NANO_TINY
+    /* Don't handle a pending SIGWINCH until the alternate format checker
+     * is finished and we've loaded the format-checked file back in. */
+    allow_pending_sigwinch(FALSE);
+#endif
+
+    /* Wait for the formatter to finish. */
+    wait(&format_status);
+
+    /* Reenter curses mode. */
+    doupdate();
+
+    /* Restore the terminal to its previous state. */
+    terminal_init();
+
+    /* Turn the cursor back on for sure. */
+    curs_set(1);
+
+    /* The screen might have been resized.  If it has, reinitialize all
+     * the windows based on the new screen dimensions. */
+    window_init();
+
+    if (!WIFEXITED(format_status) ||
+               WEXITSTATUS(format_status) != 0) {
+       char *format_error;
+       char *invoke_error = _("Error invoking \"%s\"");
+
+       format_error =
+               charalloc(strlen(invoke_error) +
+               strlen(openfile->syntax->formatter) + 1);
+       sprintf(format_error, invoke_error, openfile->syntax->formatter);
+       finalstatus = format_error;
+    } else {
+
+       /* Replace the text of the current buffer with the format-checked
+        * text. */
+       replace_buffer(temp);
+
+       /* Go back to the old position, and mark the file as modified. */
+       do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
+       set_modified();
+
+#ifndef NANO_TINY
+       /* Handle a pending SIGWINCH again. */
+       allow_pending_sigwinch(TRUE);
+#endif
+
+       finalstatus = _("Finished formatting");
+    }
+
+    unlink(temp);
+    free(temp);
+
+    currmenu = MMAIN;
+
+    /* If the spell-checker printed any error messages onscreen, make
+     * sure that they're cleared off. */
+    total_refresh();
+
+    statusbar(finalstatus);
+}
+
 #endif /* !DISABLE_COLOR */
 
 #ifndef NANO_TINY
index 8baff66b2abbfd5f223324e0dc021a64fd7722c8..8f5204abe50509ddb8c0a6b84d4c53545885734d 100644 (file)
@@ -3323,8 +3323,9 @@ void total_refresh(void)
 void display_main_list(void)
 {
 #ifndef DISABLE_COLOR
-    if (openfile->syntax && openfile->syntax->linter)
-       set_lint_shortcuts();
+    if (openfile->syntax
+         && (openfile->syntax->formatter || openfile->syntax->linter))
+       set_lint_or_format_shortcuts();
     else
        set_spell_shortcuts();
 #endif