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.



git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@5100 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
This commit is contained in:
Chris Allegretta 2015-01-03 07:24:17 +00:00
parent a44def03a0
commit 4b3f2771b5
10 changed files with 221 additions and 9 deletions

View File

@ -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.

View 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,

View 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

View 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

View 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"))

View 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;

View 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);

View 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);

View 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

View 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