mirror of
git://git.sv.gnu.org/nano.git
synced 2024-11-22 04:41:21 +03:00
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:
parent
a44def03a0
commit
4b3f2771b5
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
20
src/global.c
20
src/global.c
@ -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"))
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
28
src/rcfile.c
28
src/rcfile.c
@ -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);
|
||||
|
154
src/text.c
154
src/text.c
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user