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-d3aeb78583b8master
parent
1dd389e403
commit
5575bfad2c
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)="
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
86
src/global.c
86
src/global.c
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
22
src/nano.h
22
src/nano.h
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
29
src/rcfile.c
29
src/rcfile.c
|
@ -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);
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
300
src/text.c
300
src/text.c
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue