From 5575bfad2cd5d50078264de64afd993268dc2e9c Mon Sep 17 00:00:00 2001 From: Chris Allegretta Date: Mon, 24 Feb 2014 10:18:15 +0000 Subject: [PATCH] 2014-02-24 Chris Allegretta * 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 --- ChangeLog | 5 + doc/man/nanorc.5 | 5 + doc/syntax/nanorc.nanorc | 2 +- src/cut.c | 3 +- src/files.c | 9 +- src/global.c | 86 +++++++++-- src/nano.c | 5 +- src/nano.h | 22 ++- src/proto.h | 7 + src/rcfile.c | 29 ++++ src/search.c | 5 +- src/text.c | 300 +++++++++++++++++++++++++++++++++++++++ src/winio.c | 7 + 13 files changed, 463 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index aaf2f194..f8698f54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-02-24 Chris Allegretta + * 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 * doc/syntax/*.nanorc - Comment and punctuation tweaks. * doc/syntax/sh.nanorc - Colour $VAR within a "" string diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5 index b9c0a19b..8a68d209 100644 --- a/doc/man/nanorc.5 +++ b/doc/man/nanorc.5 @@ -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 match any other syntax's \fIfileregex\fP. .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" ... ] For the currently defined syntax, add one or more regexes which will be compared against the \fBmagic\fP database when attempting diff --git a/doc/syntax/nanorc.nanorc b/doc/syntax/nanorc.nanorc index 2c9f23a4..60ca9f09 100644 --- a/doc/syntax/nanorc.nanorc +++ b/doc/syntax/nanorc.nanorc @@ -5,7 +5,7 @@ syntax "nanorc" "\.?nanorc$" icolor brightwhite "^[[:space:]]*((un)?set|include|syntax|i?color).*$" ## 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 green "^[[:space:]]*(set|unset|include|syntax|header|magic)\>" +icolor green "^[[:space:]]*(set|unset|include|syntax|header|magic|linter)\>" ## 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 magenta "^[[:space:]]*i?color\>" "\<(start|end)=" diff --git a/src/cut.c b/src/cut.c index 552189b3..d4f29b37 100644 --- a/src/cut.c +++ b/src/cut.c @@ -206,7 +206,7 @@ void do_cut_text( UNSET(NO_NEWLINES); } else if (!undoing) update_undo(CUT); -#endif + /* Leave the text in the cutbuffer, and mark the file as * modified. */ #ifndef NANO_TINY @@ -215,6 +215,7 @@ void do_cut_text( set_modified(); #ifndef NANO_TINY } +#endif #endif /* Update the screen. */ diff --git a/src/files.c b/src/files.c index e4571869..3c18662d 100644 --- a/src/files.c +++ b/src/files.c @@ -457,6 +457,7 @@ void switch_to_prevnext_buffer(bool next_buf) #ifdef DEBUG dump_filestruct(openfile->current); #endif + display_main_list(); } /* Switch to the previous entry in the openfile filebuffer. */ @@ -1201,9 +1202,11 @@ void do_insertfile( ssize_t savedposline, savedposcol; display_buffer(); +#ifndef NANO_TINY if (!execute && ISSET(POS_HISTORY) && check_poshistory(answer, &savedposline, &savedposcol)) do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, FALSE); +#endif } else #endif { @@ -1485,11 +1488,11 @@ char *safe_tempfile(FILE **f) /* If $TMPDIR is unset, empty, or not a writable directory, and * full_tempdir is NULL, try P_tmpdir instead. */ - if (full_tempdir == NULL) + if (full_tempdir == NULL) full_tempdir = check_writable_directory(P_tmpdir); - /* if P_tmpdir is NULL, use /tmp. */ - if (full_tempdir == NULL) + /* if P_tmpdir is NULL, use /tmp. */ + if (full_tempdir == NULL) full_tempdir = mallocstrcpy(NULL, "/tmp/"); full_tempdir = charealloc(full_tempdir, strlen(full_tempdir) + 12); diff --git a/src/global.c b/src/global.c index 172ee50b..a8eeab8b 100644 --- a/src/global.c +++ b/src/global.c @@ -392,6 +392,22 @@ void add_to_sclist(int menu, const char *scstring, void (*func)(void), int toggl #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 (2nd arg). Assumes currmenu for the menu to check*/ 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"); #endif 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 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_gotodir_msg = N_("Go to directory"); #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 */ #ifndef DISABLE_HELP @@ -723,11 +751,11 @@ void shortcut_init(bool unjustify) } 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); 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); add_to_funcs(do_exit, MMAIN, @@ -774,6 +802,12 @@ void shortcut_init(bool unjustify) add_to_funcs(do_page_down, MMAIN|MHELP|MBROWSER, 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. */ add_to_funcs(do_cut_text_void, MMAIN, N_("Cut Text"), IFSCHELP(nano_cut_msg), @@ -800,10 +834,15 @@ void shortcut_init(bool unjustify) * on the command line. */ #ifndef DISABLE_SPELLER /* 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); +#endif + add_to_funcs(do_first_line, (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE), first_line_msg, IFSCHELP(nano_firstline_msg), FALSE, VIEW); @@ -1095,9 +1134,15 @@ void shortcut_init(bool unjustify) 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); - 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); add_to_sclist(MMAIN|MHELP|MBROWSER, "^X", 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|MBROWSER, "^W", 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, "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, "^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, "kpdown", do_page_down, 0, TRUE); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "^Y", 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|MLINTER, "kpup", do_page_up, 0, TRUE); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "^V", 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|MLINTER, "kpdown", do_page_down, 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, "^U", do_uncut_text, 0, TRUE); @@ -1254,7 +1299,7 @@ void shortcut_init(bool unjustify) #endif add_to_sclist(MGOTOLINE, "^T", gototext_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); add_to_sclist(MHELP, "^X", 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. */ void free_shortcutage(shortcut **shortcutage) { diff --git a/src/nano.c b/src/nano.c index 51545ebf..dfb62dcc 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2697,8 +2697,9 @@ int main(int argc, char **argv) #endif #ifdef ENABLE_COLOR - if (openfile->syntax && openfile->syntax->nmultis > 0) - precalc_multicolorinfo(); + if (openfile->syntax) + if (openfile->syntax->nmultis > 0) + precalc_multicolorinfo(); #endif if (startline > 1 || startcol > 1) diff --git a/src/nano.h b/src/nano.h index 4339f881..84fea3f2 100644 --- a/src/nano.h +++ b/src/nano.h @@ -238,12 +238,30 @@ typedef struct syntaxtype { /* Regexes to match libmagic results */ colortype *color; /* The colors used in this syntax. */ + char *linter; + /* Command to lint this type of file */ int nmultis; /* How many multi line strings this syntax has */ struct syntaxtype *next; /* Next syntax. */ } 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) /* Yay, regex doesn't apply to this line at all! */ #define CBEGINBEFORE (1<<2) @@ -333,6 +351,7 @@ typedef struct poshiststruct { /* x position in the file we left off on */ struct poshiststruct *next; } poshiststruct; + #endif /* NANO_TINY */ @@ -530,8 +549,9 @@ enum #define MWHEREISFILE (1<<11) #define MGOTODIR (1<<12) #define MYESNO (1<<13) +#define MLINTER (1<<14) /* 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. */ #define NANO_CONTROL_SPACE 0 diff --git a/src/proto.h b/src/proto.h index 3b002a4b..07c7ae64 100644 --- a/src/proto.h +++ b/src/proto.h @@ -333,6 +333,11 @@ void load_poshistory(void); void save_poshistory(void); int check_poshistory(const char *file, ssize_t *line, ssize_t *column); #endif +#ifdef ENABLE_COLOR +void do_linter(void); +void set_lint_shortcuts(void); +void set_spell_shortcuts(void); +#endif /* All functions in global.c. */ 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 */ void do_cancel(void); +void do_page_up(void); +void do_page_down(void); void case_sens_void(void); void regexp_void(void); void gototext_void(void); diff --git a/src/rcfile.c b/src/rcfile.c index e4b2d286..54213759 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -321,6 +321,7 @@ void parse_syntax(char *ptr) endsyntax->magics = NULL; endsyntax->next = NULL; endsyntax->nmultis = 0; + endsyntax->linter = NULL; #ifdef DEBUG 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 */ + + /* Check whether the user has unmapped every shortcut for a sequence we consider 'vital', like the exit function */ static void check_vitals_mapped(void) @@ -1050,6 +1076,9 @@ void parse_rcfile(FILE *rcstream parse_keybinding(ptr); else if (strcasecmp(keyword, "unbind") == 0) parse_unbinding(ptr); + else if (strcasecmp(keyword, "linter") == 0) { + parse_linter(ptr); + } #endif /* ENABLE_COLOR */ else rcfile_error(N_("Command \"%s\" not understood"), keyword); diff --git a/src/search.c b/src/search.c index 79984f2d..137df5e2 100644 --- a/src/search.c +++ b/src/search.c @@ -1083,10 +1083,11 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer, edit_update(save_pos ? NONE : CENTER); /* If allow_update is TRUE, update the screen. */ - if (allow_update) + if (allow_update) { edit_refresh(); - display_main_list(); + display_main_list(); + } } /* Go to the specified line and column, asking for them beforehand. */ diff --git a/src/text.c b/src/text.c index c0971b75..a15117f7 100644 --- a/src/text.c +++ b/src/text.c @@ -2976,6 +2976,306 @@ void do_spell(void) } #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 /* Our own version of "wc". Note that its character counts are in * multibyte characters instead of single-byte characters. */ diff --git a/src/winio.c b/src/winio.c index e2be997e..7b82dcae 100644 --- a/src/winio.c +++ b/src/winio.c @@ -3325,6 +3325,13 @@ void total_refresh(void) * portion of the window. */ void display_main_list(void) { +#ifdef ENABLE_COLOR + if (openfile->syntax && openfile->syntax->linter) + set_lint_shortcuts(); + else + set_spell_shortcuts(); +#endif + bottombars(MMAIN); } -- 2.39.5