2014-02-24 Chris Allegretta <chrisa@asty.org>

* new linter functionality.  rcfile option "linter"
        * src/global.c (shortcut_init) - Actually free the sclist
          if it was allocated before.



git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4600 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
master
Chris Allegretta 2014-02-24 10:18:15 +00:00
parent 1dd389e403
commit 5575bfad2c
13 changed files with 463 additions and 22 deletions

View File

@ -1,3 +1,8 @@
2014-02-24 Chris Allegretta <chrisa@asty.org>
* new linter functionality. rcfile option "linter"
* src/global.c (shortcut_init) - Actually free the sclist
if it was allocated before.
2014-02-23 Benno Schulenberg <bensberg@justemail.net> 2014-02-23 Benno Schulenberg <bensberg@justemail.net>
* doc/syntax/*.nanorc - Comment and punctuation tweaks. * doc/syntax/*.nanorc - Comment and punctuation tweaks.
* doc/syntax/sh.nanorc - Colour $VAR within a "" string * doc/syntax/sh.nanorc - Colour $VAR within a "" string

View File

@ -245,6 +245,11 @@ the same as not having a syntax at all. The \fIdefault\fP syntax is
special: it takes no \fIfileregex\fP, and applies to files that don't special: it takes no \fIfileregex\fP, and applies to files that don't
match any other syntax's \fIfileregex\fP. match any other syntax's \fIfileregex\fP.
.TP .TP
.B linter \fIprogram\fP [\fIargs\fP ... ]
For the currently defined syntax, add the following command
to invoke the linter (overrides the speller function when
defined.
.TP
.B magic ["\fIregex\fP" ... ] .B magic ["\fIregex\fP" ... ]
For the currently defined syntax, add one or more regexes which For the currently defined syntax, add one or more regexes which
will be compared against the \fBmagic\fP database when attempting will be compared against the \fBmagic\fP database when attempting

View File

@ -5,7 +5,7 @@ syntax "nanorc" "\.?nanorc$"
icolor brightwhite "^[[:space:]]*((un)?set|include|syntax|i?color).*$" icolor brightwhite "^[[:space:]]*((un)?set|include|syntax|i?color).*$"
## Keywords ## Keywords
icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(allow_insecure_backup|autoindent|backup|backupdir|backwards|boldtext|brackets|casesensitive|const|cut|fill|historylog|matchbrackets|morespace|mouse|multibuffer|noconvert|nofollow|nohelp|nonewlines|nowrap|operatingdir|poslog|preserve|punct)\>" "^[[:space:]]*(set|unset)[[:space:]]+(quickblank|quotestr|rebinddelete|rebindkeypad|regexp|smarthome|smooth|softwrap|speller|suspend|suspendenable|tabsize|tabstospaces|tempfile|undo|view|whitespace|wordbounds|locking)\>" icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(allow_insecure_backup|autoindent|backup|backupdir|backwards|boldtext|brackets|casesensitive|const|cut|fill|historylog|matchbrackets|morespace|mouse|multibuffer|noconvert|nofollow|nohelp|nonewlines|nowrap|operatingdir|poslog|preserve|punct)\>" "^[[:space:]]*(set|unset)[[:space:]]+(quickblank|quotestr|rebinddelete|rebindkeypad|regexp|smarthome|smooth|softwrap|speller|suspend|suspendenable|tabsize|tabstospaces|tempfile|undo|view|whitespace|wordbounds|locking)\>"
icolor green "^[[:space:]]*(set|unset|include|syntax|header|magic)\>" icolor green "^[[:space:]]*(set|unset|include|syntax|header|magic|linter)\>"
## Colors ## Colors
icolor yellow "^[[:space:]]*i?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan)?(,(white|black|red|blue|green|yellow|magenta|cyan))?\>" icolor yellow "^[[:space:]]*i?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan)?(,(white|black|red|blue|green|yellow|magenta|cyan))?\>"
icolor magenta "^[[:space:]]*i?color\>" "\<(start|end)=" icolor magenta "^[[:space:]]*i?color\>" "\<(start|end)="

View File

@ -206,7 +206,7 @@ void do_cut_text(
UNSET(NO_NEWLINES); UNSET(NO_NEWLINES);
} else if (!undoing) } else if (!undoing)
update_undo(CUT); update_undo(CUT);
#endif
/* Leave the text in the cutbuffer, and mark the file as /* Leave the text in the cutbuffer, and mark the file as
* modified. */ * modified. */
#ifndef NANO_TINY #ifndef NANO_TINY
@ -215,6 +215,7 @@ void do_cut_text(
set_modified(); set_modified();
#ifndef NANO_TINY #ifndef NANO_TINY
} }
#endif
#endif #endif
/* Update the screen. */ /* Update the screen. */

View File

@ -457,6 +457,7 @@ void switch_to_prevnext_buffer(bool next_buf)
#ifdef DEBUG #ifdef DEBUG
dump_filestruct(openfile->current); dump_filestruct(openfile->current);
#endif #endif
display_main_list();
} }
/* Switch to the previous entry in the openfile filebuffer. */ /* Switch to the previous entry in the openfile filebuffer. */
@ -1201,9 +1202,11 @@ void do_insertfile(
ssize_t savedposline, savedposcol; ssize_t savedposline, savedposcol;
display_buffer(); display_buffer();
#ifndef NANO_TINY
if (!execute && ISSET(POS_HISTORY) if (!execute && ISSET(POS_HISTORY)
&& check_poshistory(answer, &savedposline, &savedposcol)) && check_poshistory(answer, &savedposline, &savedposcol))
do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, FALSE); do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, FALSE);
#endif
} else } else
#endif #endif
{ {

View File

@ -392,6 +392,22 @@ void add_to_sclist(int menu, const char *scstring, void (*func)(void), int toggl
#endif #endif
} }
/* Assign one menu's shortcuts to another function */
void replace_scs_for(void (*oldfunc)(void), void (*newfunc)(void))
{
sc *s;
if (sclist == NULL)
return;
for (s = sclist; s->next != NULL; s = s->next)
if (s->scfunc == oldfunc) {
s->scfunc = newfunc;
}
}
/* Return the given menu's first shortcut sequence, or the default value /* Return the given menu's first shortcut sequence, or the default value
(2nd arg). Assumes currmenu for the menu to check*/ (2nd arg). Assumes currmenu for the menu to check*/
int sc_seq_or (void (*func)(void), int defaultval) int sc_seq_or (void (*func)(void), int defaultval)
@ -561,6 +577,14 @@ void shortcut_init(bool unjustify)
const char *insert_file_msg = N_("Insert File"); const char *insert_file_msg = N_("Insert File");
#endif #endif
const char *go_to_line_msg = N_("Go To Line"); const char *go_to_line_msg = N_("Go To Line");
const char *spell_msg = N_("To Spell");
#ifdef ENABLE_COLOR
const char *lint_msg = N_("To Linter");
const char *nano_lint_msg =
N_("Invoke the linter, if available");
const char *prev_lint_msg = N_("Prev Lint Msg");
const char *next_lint_msg = N_("Next Lint Msg");
#endif
#ifndef DISABLE_JUSTIFY #ifndef DISABLE_JUSTIFY
const char *nano_justify_msg = N_("Justify the current paragraph"); const char *nano_justify_msg = N_("Justify the current paragraph");
@ -708,6 +732,10 @@ void shortcut_init(bool unjustify)
const char *nano_backfile_msg = N_("Go to the previous file in the list"); const char *nano_backfile_msg = N_("Go to the previous file in the list");
const char *nano_gotodir_msg = N_("Go to directory"); const char *nano_gotodir_msg = N_("Go to directory");
#endif #endif
#ifdef ENABLE_COLOR
const char *nano_prevlint_msg = N_("Go to previous linter msg");
const char *nano_nextlint_msg = N_("Go to next linter msg");
#endif
#endif /* !DISABLE_HELP */ #endif /* !DISABLE_HELP */
#ifndef DISABLE_HELP #ifndef DISABLE_HELP
@ -723,11 +751,11 @@ void shortcut_init(bool unjustify)
} }
add_to_funcs(do_help_void, add_to_funcs(do_help_void,
(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR), (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR|MLINTER),
get_help_msg, IFSCHELP(nano_help_msg), FALSE, VIEW); get_help_msg, IFSCHELP(nano_help_msg), FALSE, VIEW);
add_to_funcs( do_cancel, add_to_funcs( do_cancel,
(MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MWHEREISFILE|MGOTODIR|MYESNO), (MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MWHEREISFILE|MGOTODIR|MYESNO|MLINTER),
cancel_msg, IFSCHELP(nano_cancel_msg), FALSE, VIEW); cancel_msg, IFSCHELP(nano_cancel_msg), FALSE, VIEW);
add_to_funcs(do_exit, MMAIN, add_to_funcs(do_exit, MMAIN,
@ -774,6 +802,12 @@ void shortcut_init(bool unjustify)
add_to_funcs(do_page_down, MMAIN|MHELP|MBROWSER, add_to_funcs(do_page_down, MMAIN|MHELP|MBROWSER,
next_page_msg, IFSCHELP(nano_nextpage_msg), TRUE, VIEW); next_page_msg, IFSCHELP(nano_nextpage_msg), TRUE, VIEW);
#ifdef ENABLE_COLOR
add_to_funcs(do_page_up, MLINTER,
prev_lint_msg, IFSCHELP(nano_prevlint_msg), FALSE, VIEW);
add_to_funcs(do_page_down, MLINTER,
next_lint_msg, IFSCHELP(nano_nextlint_msg), FALSE, VIEW);
#endif
/* TRANSLATORS: Try to keep this at most 10 characters. */ /* TRANSLATORS: Try to keep this at most 10 characters. */
add_to_funcs(do_cut_text_void, MMAIN, N_("Cut Text"), IFSCHELP(nano_cut_msg), add_to_funcs(do_cut_text_void, MMAIN, N_("Cut Text"), IFSCHELP(nano_cut_msg),
@ -800,7 +834,12 @@ void shortcut_init(bool unjustify)
* on the command line. */ * on the command line. */
#ifndef DISABLE_SPELLER #ifndef DISABLE_SPELLER
/* TRANSLATORS: Try to keep this at most 10 characters. */ /* TRANSLATORS: Try to keep this at most 10 characters. */
add_to_funcs(do_spell, MMAIN, N_("To Spell"), IFSCHELP(nano_spell_msg), add_to_funcs(do_spell, MMAIN, spell_msg, IFSCHELP(nano_spell_msg),
TRUE, NOVIEW);
#endif
#ifdef ENABLE_COLOR
add_to_funcs(do_linter, MMAIN, lint_msg, IFSCHELP(nano_lint_msg),
TRUE, NOVIEW); TRUE, NOVIEW);
#endif #endif
@ -1095,9 +1134,15 @@ void shortcut_init(bool unjustify)
currmenu = MMAIN; currmenu = MMAIN;
add_to_sclist(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR, while (sclist != NULL) {
sc *s = sclist;
sclist = (s)->next;
free(s);
}
add_to_sclist(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR|MLINTER,
"^G", do_help_void, 0, TRUE); "^G", do_help_void, 0, TRUE);
add_to_sclist(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR, add_to_sclist(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR|MLINTER,
"F1", do_help_void, 0, TRUE); "F1", do_help_void, 0, TRUE);
add_to_sclist(MMAIN|MHELP|MBROWSER, "^X", do_exit, 0, TRUE); add_to_sclist(MMAIN|MHELP|MBROWSER, "^X", do_exit, 0, TRUE);
add_to_sclist(MMAIN|MHELP|MBROWSER, "F2", do_exit, 0, TRUE); add_to_sclist(MMAIN|MHELP|MBROWSER, "F2", do_exit, 0, TRUE);
@ -1115,12 +1160,12 @@ void shortcut_init(bool unjustify)
add_to_sclist(MMAIN, "kinsert", do_insertfile_void, 0, TRUE); add_to_sclist(MMAIN, "kinsert", do_insertfile_void, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER, "^W", do_search, 0, TRUE); add_to_sclist(MMAIN|MBROWSER, "^W", do_search, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER, "F6", do_search, 0, TRUE); add_to_sclist(MMAIN|MBROWSER, "F6", do_search, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "^Y", do_page_up, 0, TRUE); add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "^Y", do_page_up, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "F7", do_page_up, 0, TRUE); add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "F7", do_page_up, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "kpup", do_page_up, 0, TRUE); add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "kpup", do_page_up, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "^V", do_page_down, 0, TRUE); add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "^V", do_page_down, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "F8", do_page_down, 0, TRUE); add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "F8", do_page_down, 0, TRUE);
add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "kpdown", do_page_down, 0, TRUE); add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "kpdown", do_page_down, 0, TRUE);
add_to_sclist(MMAIN, "^K", do_cut_text_void, 0, TRUE); add_to_sclist(MMAIN, "^K", do_cut_text_void, 0, TRUE);
add_to_sclist(MMAIN, "F9", do_cut_text_void, 0, TRUE); add_to_sclist(MMAIN, "F9", do_cut_text_void, 0, TRUE);
add_to_sclist(MMAIN, "^U", do_uncut_text, 0, TRUE); add_to_sclist(MMAIN, "^U", do_uncut_text, 0, TRUE);
@ -1254,7 +1299,7 @@ void shortcut_init(bool unjustify)
#endif #endif
add_to_sclist(MGOTOLINE, "^T", gototext_void, 0, FALSE); add_to_sclist(MGOTOLINE, "^T", gototext_void, 0, FALSE);
add_to_sclist(MINSERTFILE|MEXTCMD, "M-F", new_buffer_void, 0, FALSE); add_to_sclist(MINSERTFILE|MEXTCMD, "M-F", new_buffer_void, 0, FALSE);
add_to_sclist((MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MWHEREISFILE|MGOTODIR|MYESNO), add_to_sclist((MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MWHEREISFILE|MGOTODIR|MYESNO|MLINTER),
"^C", do_cancel, 0, FALSE); "^C", do_cancel, 0, FALSE);
add_to_sclist(MHELP, "^X", do_exit, 0, TRUE); add_to_sclist(MHELP, "^X", do_exit, 0, TRUE);
add_to_sclist(MHELP, "F2", do_exit, 0, TRUE); add_to_sclist(MHELP, "F2", do_exit, 0, TRUE);
@ -1282,6 +1327,23 @@ void shortcut_init(bool unjustify)
} }
#ifdef ENABLE_COLOR
void set_lint_shortcuts(void)
{
#ifndef DISABLE_SPELLER
replace_scs_for(do_spell, do_linter);
#endif
}
void set_spell_shortcuts(void)
{
#ifndef DISABLE_SPELLER
replace_scs_for(do_linter, do_spell);
#endif
}
#endif
/* Free the given shortcut. */ /* Free the given shortcut. */
void free_shortcutage(shortcut **shortcutage) void free_shortcutage(shortcut **shortcutage)
{ {

View File

@ -2697,7 +2697,8 @@ int main(int argc, char **argv)
#endif #endif
#ifdef ENABLE_COLOR #ifdef ENABLE_COLOR
if (openfile->syntax && openfile->syntax->nmultis > 0) if (openfile->syntax)
if (openfile->syntax->nmultis > 0)
precalc_multicolorinfo(); precalc_multicolorinfo();
#endif #endif

View File

@ -238,12 +238,30 @@ typedef struct syntaxtype {
/* Regexes to match libmagic results */ /* Regexes to match libmagic results */
colortype *color; colortype *color;
/* The colors used in this syntax. */ /* The colors used in this syntax. */
char *linter;
/* Command to lint this type of file */
int nmultis; int nmultis;
/* How many multi line strings this syntax has */ /* How many multi line strings this syntax has */
struct syntaxtype *next; struct syntaxtype *next;
/* Next syntax. */ /* Next syntax. */
} syntaxtype; } syntaxtype;
typedef struct lintstruct {
ssize_t lineno;
/* Line number of the error. */
ssize_t colno;
/* Column # of the error. */
char *msg;
/* Error message text */
char *filename;
/* Filename */
struct lintstruct *next;
/* Next error. */
struct lintstruct *prev;
/* Previous error */
} lintstruct;
#define CNONE (1<<1) #define CNONE (1<<1)
/* Yay, regex doesn't apply to this line at all! */ /* Yay, regex doesn't apply to this line at all! */
#define CBEGINBEFORE (1<<2) #define CBEGINBEFORE (1<<2)
@ -333,6 +351,7 @@ typedef struct poshiststruct {
/* x position in the file we left off on */ /* x position in the file we left off on */
struct poshiststruct *next; struct poshiststruct *next;
} poshiststruct; } poshiststruct;
#endif /* NANO_TINY */ #endif /* NANO_TINY */
@ -530,8 +549,9 @@ enum
#define MWHEREISFILE (1<<11) #define MWHEREISFILE (1<<11)
#define MGOTODIR (1<<12) #define MGOTODIR (1<<12)
#define MYESNO (1<<13) #define MYESNO (1<<13)
#define MLINTER (1<<14)
/* This really isnt all but close enough */ /* This really isnt all but close enough */
#define MALL (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR|MHELP) #define MALL (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR|MHELP|MLINTER)
/* Control key sequences. Changing these would be very, very bad. */ /* Control key sequences. Changing these would be very, very bad. */
#define NANO_CONTROL_SPACE 0 #define NANO_CONTROL_SPACE 0

View File

@ -333,6 +333,11 @@ void load_poshistory(void);
void save_poshistory(void); void save_poshistory(void);
int check_poshistory(const char *file, ssize_t *line, ssize_t *column); int check_poshistory(const char *file, ssize_t *line, ssize_t *column);
#endif #endif
#ifdef ENABLE_COLOR
void do_linter(void);
void set_lint_shortcuts(void);
void set_spell_shortcuts(void);
#endif
/* All functions in global.c. */ /* All functions in global.c. */
size_t length_of_list(int menu); size_t length_of_list(int menu);
@ -849,6 +854,8 @@ void do_credits(void);
/* May as just throw these here since they are just placeholders */ /* May as just throw these here since they are just placeholders */
void do_cancel(void); void do_cancel(void);
void do_page_up(void);
void do_page_down(void);
void case_sens_void(void); void case_sens_void(void);
void regexp_void(void); void regexp_void(void);
void gototext_void(void); void gototext_void(void);

View File

@ -321,6 +321,7 @@ void parse_syntax(char *ptr)
endsyntax->magics = NULL; endsyntax->magics = NULL;
endsyntax->next = NULL; endsyntax->next = NULL;
endsyntax->nmultis = 0; endsyntax->nmultis = 0;
endsyntax->linter = NULL;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr); fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
@ -940,8 +941,33 @@ void parse_headers(char *ptr)
} }
} }
/* Parse the linter requested for this syntax. Simple? */
void parse_linter(char *ptr)
{
assert(ptr != NULL);
if (syntaxes == NULL) {
rcfile_error(
N_("Cannot add a linter without a syntax command"));
return;
}
if (*ptr == '\0') {
rcfile_error(N_("Missing linter command"));
return;
}
if (endsyntax->linter != NULL)
free(endsyntax->linter);
endsyntax->linter = mallocstrcpy(syntaxes->linter, ptr);
}
#endif /* ENABLE_COLOR */ #endif /* ENABLE_COLOR */
/* Check whether the user has unmapped every shortcut for a /* Check whether the user has unmapped every shortcut for a
sequence we consider 'vital', like the exit function */ sequence we consider 'vital', like the exit function */
static void check_vitals_mapped(void) static void check_vitals_mapped(void)
@ -1050,6 +1076,9 @@ void parse_rcfile(FILE *rcstream
parse_keybinding(ptr); parse_keybinding(ptr);
else if (strcasecmp(keyword, "unbind") == 0) else if (strcasecmp(keyword, "unbind") == 0)
parse_unbinding(ptr); parse_unbinding(ptr);
else if (strcasecmp(keyword, "linter") == 0) {
parse_linter(ptr);
}
#endif /* ENABLE_COLOR */ #endif /* ENABLE_COLOR */
else else
rcfile_error(N_("Command \"%s\" not understood"), keyword); rcfile_error(N_("Command \"%s\" not understood"), keyword);

View File

@ -1083,10 +1083,11 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
edit_update(save_pos ? NONE : CENTER); edit_update(save_pos ? NONE : CENTER);
/* If allow_update is TRUE, update the screen. */ /* If allow_update is TRUE, update the screen. */
if (allow_update) if (allow_update) {
edit_refresh(); edit_refresh();
display_main_list(); display_main_list();
}
} }
/* Go to the specified line and column, asking for them beforehand. */ /* Go to the specified line and column, asking for them beforehand. */

View File

@ -2976,6 +2976,306 @@ void do_spell(void)
} }
#endif /* !DISABLE_SPELLER */ #endif /* !DISABLE_SPELLER */
#ifdef ENABLE_COLOR
/* Run linter. Based on alt-speller code. Return NULL for normal
* termination, and the error string otherwise. */
void do_linter(void)
{
char *read_buff, *read_buff_ptr, *read_buff_word, *ptr;
size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
size_t parsesuccess = 0;
int lint_fd[2], tempfile_fd = -1;
pid_t pid_lint;
int lint_status;
static int arglen = 3;
static char **lintargs = NULL;
FILE *temp_file;
char *lintcopy;
char *convendptr = NULL;
const sc *s;
lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL;
if (!openfile->syntax || !openfile->syntax->linter) {
statusbar(_("No linter defined for this file!"));
return;
}
if (ISSET(RESTRICTED)) {
nano_disabled_msg();
return;
}
if (openfile->modified) {
int i = do_yesno_prompt(FALSE,
_("Save modified buffer before linting?"));
if (i == 1) {
if (do_writeout(FALSE) != TRUE) {
return;
}
}
}
lintcopy = mallocstrcpy(NULL, openfile->syntax->linter);
/* Create pipe up front. */
if (pipe(lint_fd) == -1) {
statusbar(_("Could not create pipe"));
return;
}
statusbar(_("Invoking linter, please wait"));
/* Set up an argument list to pass execvp(). */
if (lintargs == NULL) {
lintargs = (char **)nmalloc(arglen * sizeof(char *));
lintargs[0] = strtok(lintcopy, " ");
while ((ptr = strtok(NULL, " ")) != NULL) {
arglen++;
lintargs = (char **)nrealloc(lintargs, arglen *
sizeof(char *));
lintargs[arglen - 3] = ptr;
}
lintargs[arglen - 1] = NULL;
}
lintargs[arglen - 2] = openfile->filename;
/* A new process to run linter. */
if ((pid_lint = fork()) == 0) {
/* Child continues (i.e. future spell process). */
close(lint_fd[0]);
/* Send spell's standard output/err to the pipe. */
if (dup2(lint_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
exit(1);
if (dup2(lint_fd[1], STDERR_FILENO) != STDERR_FILENO)
exit(1);
close(lint_fd[1]);
/* Start the linter program; we are using $PATH. */
execvp(lintargs[0], lintargs);
/* This should not be reached if linter is found. */
exit(1);
}
/* Parent continues here. */
close(lint_fd[1]);
/* The child process was not forked successfully. */
if (pid_lint < 0) {
close(lint_fd[0]);
statusbar(_("Could not fork"));
return;
}
/* Get the system pipe buffer size. */
if ((pipe_buff_size = fpathconf(lint_fd[0], _PC_PIPE_BUF)) < 1) {
close(lint_fd[0]);
statusbar(_("Could not get size of pipe buffer"));
return;
}
/* Read in the returned spelling errors. */
read_buff_read = 0;
read_buff_size = pipe_buff_size + 1;
read_buff = read_buff_ptr = charalloc(read_buff_size);
while ((bytesread = read(lint_fd[0], read_buff_ptr,
pipe_buff_size)) > 0) {
#ifdef DEBUG
fprintf(stderr, "text.c:do_linter:%d bytes (%s)\n", bytesread, read_buff_ptr);
#endif
read_buff_read += bytesread;
read_buff_size += pipe_buff_size;
read_buff = read_buff_ptr = charealloc(read_buff,
read_buff_size);
read_buff_ptr += read_buff_read;
}
*read_buff_ptr = '\0';
close(lint_fd[0]);
#ifdef DEBUG
fprintf(stderr, "text.c:do_lint:Raw output: %s\n", read_buff);
#endif
/* Process output. */
read_buff_word = read_buff_ptr = read_buff;
while (*read_buff_ptr != '\0') {
if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
*read_buff_ptr = '\0';
if (read_buff_word != read_buff_ptr) {
char *filename = NULL, *linestr = NULL, *maybecol = NULL;
char *message = mallocstrcpy(NULL, read_buff_word);
/* At the moment we're assuming the following formats:
filenameorcategory:line:column:message (e.g. splint)
filenameorcategory:line:message (e.g. pyflakes)
filenameorcategory:line,col:message (e.g. pylint)
This could be turnes into some scanf() based parser but ugh.
*/
if ((filename = strtok(read_buff_word, ":")) != NULL) {
if ((linestr = strtok(NULL, ":")) != NULL) {
if ((maybecol = strtok(NULL, ":")) != NULL) {
ssize_t tmplineno = 0, tmpcolno = 0;
char *tmplinecol;
tmplineno = strtol(linestr, NULL, 10);
if (tmplineno <= 0) {
read_buff_ptr++;
free(message);
continue;
}
tmpcolno = strtol(maybecol, &convendptr, 10);
if (*convendptr != '\0') {
/* Prev field might still be line,col format */
strtok(linestr, ",");
if ((tmplinecol = strtok(NULL, ",")) != NULL)
tmpcolno = strtol(tmplinecol, NULL, 10);
}
#ifdef DEBUG
fprintf(stderr, "text.c:do_lint:Successful parse! %d:%d:%s\n", tmplineno, tmpcolno, message);
#endif
/* Nice we have a lint message we can use */
parsesuccess++;
tmplint = curlint;
curlint = nmalloc(sizeof(lintstruct));
curlint->next = NULL;
curlint->prev = tmplint;
if (curlint->prev != NULL)
curlint->prev->next = curlint;
curlint->msg = mallocstrcpy(NULL, message);
curlint->lineno = tmplineno;
curlint->colno = tmpcolno;
curlint->filename = mallocstrcpy(NULL, filename);
if (lints == NULL)
lints = curlint;
}
}
} else
free(message);
}
read_buff_word = read_buff_ptr + 1;
}
read_buff_ptr++;
}
/* Process the end of the lint process. */
waitpid(pid_lint, &lint_status, 0);
free(read_buff);
if (parsesuccess == 0) {
statusbar(_("Got 0 parsable lines from command: %s"), openfile->syntax->linter);
return;
}
currmenu = MLINTER;
bottombars(MLINTER);
tmplint = NULL;
curlint = lints;
while (1) {
ssize_t tmpcol = 1;
int kbinput;
bool meta_key, func_key;
struct stat lintfileinfo;
if (curlint->colno > 0)
tmpcol = curlint->colno;
if (tmplint != curlint) {
struct stat lintfileinfo;
#ifndef NANO_TINY
new_lint_loop:
if (stat(curlint->filename, &lintfileinfo) != -1) {
if (openfile->current_stat->st_ino != lintfileinfo.st_ino) {
openfilestruct *tmpof = openfile;
while (tmpof != openfile->next) {
if (tmpof->current_stat->st_ino == lintfileinfo.st_ino)
break;
tmpof = tmpof->next;
}
if (tmpof->current_stat->st_ino != lintfileinfo.st_ino) {
char *msg = charalloc(1024 + strlen(curlint->filename));
int i;
sprintf(msg, _("This message is for unopened file %s, open it in a new buffer?"),
curlint->filename);
i = do_yesno_prompt(FALSE, msg);
free(msg);
if (i == 1) {
SET(MULTIBUFFER);
open_buffer(curlint->filename, FALSE);
} else {
char *dontwantfile = curlint->filename;
while (curlint != NULL && !strcmp(curlint->filename, dontwantfile))
curlint = curlint->next;
if (curlint == NULL) {
statusbar("No more errors in un-opened filed, cancelling");
break;
} else
goto new_lint_loop;
}
} else
openfile = tmpof;
}
}
#endif /* NANO_TINY */
do_gotolinecolumn(curlint->lineno, tmpcol, FALSE, FALSE, FALSE, FALSE);
titlebar(NULL);
edit_refresh();
statusbar(curlint->msg);
bottombars(MLINTER);
}
kbinput = get_kbinput(bottomwin, &meta_key, &func_key);
s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key);
tmplint = curlint;
if (!s)
continue;
else if (s->scfunc == do_cancel)
break;
else if (s->scfunc == do_help_void) {
tmplint = NULL;
do_help_void();
} else if (s->scfunc == do_page_down) {
if (curlint->next != NULL)
curlint = curlint->next;
else {
statusbar(_("At last message"));
continue;
}
} else if (s->scfunc == do_page_up) {
if (curlint->prev != NULL)
curlint = curlint->prev;
else {
statusbar(_("At first message"));
continue;
}
}
}
for (tmplint = lints; tmplint != NULL; tmplint = tmplint->next) {
free(tmplint->msg);
free(tmplint->filename);
free(tmplint);
}
blank_statusbar();
currmenu = MMAIN;
display_main_list();
}
#endif /* ENABLE_COLOR */
#ifndef NANO_TINY #ifndef NANO_TINY
/* Our own version of "wc". Note that its character counts are in /* Our own version of "wc". Note that its character counts are in
* multibyte characters instead of single-byte characters. */ * multibyte characters instead of single-byte characters. */

View File

@ -3325,6 +3325,13 @@ void total_refresh(void)
* portion of the window. */ * portion of the window. */
void display_main_list(void) void display_main_list(void)
{ {
#ifdef ENABLE_COLOR
if (openfile->syntax && openfile->syntax->linter)
set_lint_shortcuts();
else
set_spell_shortcuts();
#endif
bottombars(MMAIN); bottombars(MMAIN);
} }