+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>
* doc/syntax/*.nanorc - Comment and punctuation tweaks.
* doc/syntax/sh.nanorc - Colour $VAR within a "" string
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
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)="
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
set_modified();
#ifndef NANO_TINY
}
+#endif
#endif
/* Update the screen. */
#ifdef DEBUG
dump_filestruct(openfile->current);
#endif
+ display_main_list();
}
/* Switch to the previous entry in the openfile filebuffer. */
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
{
/* 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);
#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)
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");
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
}
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,
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),
* 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);
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);
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);
#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);
}
+#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)
{
#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)
/* 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)
/* x position in the file we left off on */
struct poshiststruct *next;
} poshiststruct;
+
#endif /* NANO_TINY */
#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
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);
/* 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);
endsyntax->magics = NULL;
endsyntax->next = NULL;
endsyntax->nmultis = 0;
+ endsyntax->linter = NULL;
#ifdef DEBUG
fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
}
}
+
+
+/* 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)
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);
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. */
}
#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. */
* 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);
}