diff --git a/ChangeLog b/ChangeLog
index aaf2f19424cd6d08f4b05ecdf4efc7e96755172f..f8698f54998dd1d8935aa8c980dc040f40786093 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 	* 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 b9c0a19bae42c38b004ab043335a1f7e45fe97d2..8a68d20926ad3afbadac8486b5ab3c0d659059be 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 2c9f23a426b7d7717e80a0c7660a479ad6657c5f..60ca9f09a5a16dcb3f5cf9d24570802449e6cdee 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 552189b3447073da04adfdcdab70a4cb8340d262..d4f29b37c2c45e9676f6081d4afbf7084743bcd3 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 e45718690035c4775583e6377fade18879b2c34a..3c18662db8be82054a3f78d76d88c4d24f43911b 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 172ee50b7c56959d1c9021da0c3b56c59023ab86..a8eeab8bdda689b999884de98d6728ff6fab98fc 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 51545ebf7e4c8e795ee438c178e8b3762a79c801..dfb62dccbe51b66bd9a7df09f2b2c2e5553444a1 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 4339f8815fa82504209c69b7781555e96e27801f..84fea3f247dbc9cc175f0c569034bc8a65cae919 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 3b002a4b8d3bd633979f61dba16c0ad27861320b..07c7ae6459fff7523ec60bfa1cd534a2bd7d13ca 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 e4b2d286428a7c12340e82fe46b59808d3a075f9..54213759aa93101993ecb7b9f3e783a1ca13d996 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 79984f2dead1100bc7821fc1f824422983a8cbcd..137df5e2d1a92a1642aeae16b2599fd93f94d3dd 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 c0971b7522b98077ffe1b00ba581cf968250997f..a15117f72b977331425a1d830956debd65fc9e00 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 e2be997e98a96114b335128496adc7c64ee4f803..7b82dcae9b3e14c1554bdac2a8a3f2609a42162c 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);
 }