diff --git a/configure.ac b/configure.ac index 0c42e1e..a06b3fc 100644 --- a/configure.ac +++ b/configure.ac @@ -108,6 +108,28 @@ if test "x$enable_justify" = xno; then AC_DEFINE(DISABLE_JUSTIFY, 1, [Define this to disable the justify routines.]) fi +AC_ARG_ENABLE(comment, +AS_HELP_STRING([--disable-comment], [Disable comment/uncomment functions])) +if test "x$enable_color" = xno; then + if test "x$enable_comment" = xyes; then + AC_MSG_ERROR([--enable-comment cannot work with --disable-color, --disable-nanorc or --enable-tiny]) + else + # Disabling nanorc silently disables comment support. + enable_comment=no + fi +fi +if test "x$enable_tiny" = xyes; then + if test "x$enable_comment" = xyes; then + AC_MSG_ERROR([--enable-comment cannot work with --disable-color, --disable-nanorc or --enable-tiny]) + else + # Disabling nanorc silently disables comment support. + enable_comment=no + fi +fi +if test "x$enable_comment" = xno; then + AC_DEFINE(DISABLE_COMMENT, 1, [Define this to disable the comment/uncomment functionality.]) +fi + AC_ARG_ENABLE(libmagic, AS_HELP_STRING([--disable-libmagic], [Disable detection of file types via libmagic])) @@ -184,6 +206,9 @@ if test "x$enable_tiny" = xyes; then AC_MSG_ERROR([--enable-color with --enable-tiny cannot work without --enable-nanorc]) fi fi + if test "x$enable_comment" != xyes; then + AC_DEFINE(DISABLE_COMMENT, 1, [Define this to disable the comment/uncomment functionality.]) + fi if test "x$enable_extra" != xyes; then AC_DEFINE(DISABLE_EXTRA, 1, [Define this to disable extra stuff.]) fi diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5 index 6d61619..dbc4b60 100644 --- a/doc/man/nanorc.5 +++ b/doc/man/nanorc.5 @@ -302,6 +302,16 @@ syntax should be used for that file. This functionality only works when \fBlibmagic\fP is installed on the system and will be silently ignored otherwise. .TP +.BI comment " string" +Use the given string for commenting and uncommenting lines. A vertical bar or +pipe character (|) designates bracket style comments; for example, "/*|*/" for +CSS files. The characters before the pipe are prepended to the line and the +characters after the pipe are appended at the end of the line. If no pipe +character is present, the entire string is prepended; for example, "# " for +Python files. If empty double quotes are specified, the comment/uncomment +functions are disabled; for example, "" for JSON. Double quotes or backslashes +may be escaped with a backslash; for example, ".\\"" for man page source. +.TP .B color \fIfgcolor\fR,\fIbgcolor\fR """\fIregex\fR""" ... Display all pieces of text that match the extended regular expression \fIregex\fP with foreground color @@ -336,7 +346,7 @@ to \fBicolor\fP. .BI extendsyntax " str directive " \fR[ "arg " \fR...] Extend the syntax previously defined as \fIstr\fP to include new information. This allows you to add a new \fBcolor\fP, \fBicolor\fP, -\fBheader\fP, \fBmagic\fP, \fBlinter\fP, or \fBformatter\fP directive +\fBheader\fP, \fBmagic\fP, \fBcomment\fP, \fBlinter\fP, or \fBformatter\fP directive to an already defined syntax -- useful when you want to slightly improve a syntax defined in one of the system-installed files (which are normally not writable) @@ -455,6 +465,14 @@ Indents (shifts to the right) the currently marked text. .B unindent Unindents (shifts to the left) the currently marked text. .TP +.B comment +Comments the current line or marked lines, using the comment style specified +in the active syntax. +.TP +.B uncomment +Uncomments the current line or marked lines. Only whole lines which are +commented by the active comment style will be uncommented. +.TP .B left Goes left one position (in the editor or browser). .TP diff --git a/doc/syntax/asm.nanorc b/doc/syntax/asm.nanorc index f1719a4..228a185 100644 --- a/doc/syntax/asm.nanorc +++ b/doc/syntax/asm.nanorc @@ -2,6 +2,7 @@ syntax "asm" "\.(S|s|asm)$" magic "[Aa]ssembl(y|er)" +comment "//" color red "\<[A-Z_]{2,}\>" color brightgreen "\.(data|subsection|text)" diff --git a/doc/syntax/autoconf.nanorc b/doc/syntax/autoconf.nanorc index 58a9b07..b578abe 100644 --- a/doc/syntax/autoconf.nanorc +++ b/doc/syntax/autoconf.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Autoconf. syntax "autoconf" "\.(ac|m4)$" +comment "#" # Keywords: color yellow "\<(if|test|then|elif|else|fi|for|in|do|done)\>" diff --git a/doc/syntax/awk.nanorc b/doc/syntax/awk.nanorc index bfc6387..34e7176 100644 --- a/doc/syntax/awk.nanorc +++ b/doc/syntax/awk.nanorc @@ -2,6 +2,7 @@ syntax "awk" "\.awk$" magic "awk.*script text" +comment "#" # Records. icolor brightred "address@hidden" diff --git a/doc/syntax/c.nanorc b/doc/syntax/c.nanorc index ef156ab..0553b6b 100644 --- a/doc/syntax/c.nanorc +++ b/doc/syntax/c.nanorc @@ -2,6 +2,7 @@ syntax "c" "\.(c(c|pp|xx|\+\+)?|C)$" "\.(h(h|pp|xx)?|H)$" "\.ii?$" magic "(ASCII|UTF-8 Unicode) C(\+\+)? program text" +comment "//" color brightred "\<[A-Z_][0-9A-Z_]+\>" color green "\<(float|double|bool|char|int|short|long|sizeof|enum|void|auto|static|const|struct|union|typedef|extern|(un)?signed|inline)\>" diff --git a/doc/syntax/cmake.nanorc b/doc/syntax/cmake.nanorc index dc43702..524c842 100644 --- a/doc/syntax/cmake.nanorc +++ b/doc/syntax/cmake.nanorc @@ -1,6 +1,7 @@ ## Syntax highlighting for CMake files. syntax "cmake" "(CMakeLists\.txt|\.cmake)$" +comment "#" icolor green "^[[:space:]]*[A-Z0-9_]+" icolor brightyellow "^[[:space:]]*(include|include_directories|include_external_msproject)\>" diff --git a/doc/syntax/css.nanorc b/doc/syntax/css.nanorc index a806d7c..a0531cd 100644 --- a/doc/syntax/css.nanorc +++ b/doc/syntax/css.nanorc @@ -1,6 +1,7 @@ ## Here is an example for CSS files. syntax "css" "\.css$" +comment "/*|*/" color brightred "." color brightyellow start="\{" end="\}" diff --git a/doc/syntax/debian.nanorc b/doc/syntax/debian.nanorc index 7d0a637..10e8a32 100644 --- a/doc/syntax/debian.nanorc +++ b/doc/syntax/debian.nanorc @@ -1,6 +1,7 @@ ## Here is an example for apt's sources.list. syntax "sources.list" "sources\.list(~|\.old|\.save)?$" "sources\.list\.d/.*\.list(~|\.old|\.save)?$" +comment "#" # Coloring the deb lines, working from tail to head. First the # components -- well, everything, and thus also the components. diff --git a/doc/syntax/default.nanorc b/doc/syntax/default.nanorc index 34ff29b..61d5152 100644 --- a/doc/syntax/default.nanorc +++ b/doc/syntax/default.nanorc @@ -2,6 +2,7 @@ ## for files that do not match any other syntax. syntax "default" +comment "#" # Spaces in front of tabs. color ,red " + +" diff --git a/doc/syntax/elisp.nanorc b/doc/syntax/elisp.nanorc index 2a2bd2e..785827e 100644 --- a/doc/syntax/elisp.nanorc +++ b/doc/syntax/elisp.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Emacs Lisp. syntax "elisp" "\.el$" +comment ";" # Basic functions/macros color brightcyan "\<(if|when|unless|cond|and|or|lambda|let|progn|while|dolist|dotimes)\>" diff --git a/doc/syntax/fortran.nanorc b/doc/syntax/fortran.nanorc index 45873ac..2a56bc7 100644 --- a/doc/syntax/fortran.nanorc +++ b/doc/syntax/fortran.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Fortran 90/95. syntax "fortran" "\.(f|f90|f95)$" +comment "!" color red "\<[0-9]+\>" diff --git a/doc/syntax/gentoo.nanorc b/doc/syntax/gentoo.nanorc index 249e224..7de1cba 100644 --- a/doc/syntax/gentoo.nanorc +++ b/doc/syntax/gentoo.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Gentoo ebuilds/eclasses. syntax "ebuild" "\.e(build|class)$" +comment "#" ## All the standard portage functions color brightgreen "(^|\" diff --git a/doc/syntax/go.nanorc b/doc/syntax/go.nanorc index e52d188..308e976 100644 --- a/doc/syntax/go.nanorc +++ b/doc/syntax/go.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Go. syntax "go" "\.go$" +comment "//" # Set up a formatter since spelling is probably useless... formatter gofmt -w diff --git a/doc/syntax/groff.nanorc b/doc/syntax/groff.nanorc index 5f57f8e..109f9cd 100644 --- a/doc/syntax/groff.nanorc +++ b/doc/syntax/groff.nanorc @@ -1,6 +1,7 @@ ## Here is an example for groff. syntax "groff" "\.m[ems]$" "\.rof" "\.tmac$" "^tmac." +comment ".\"" # The argument of .ds or .nr color cyan "^\.(ds|nr) [^[:space:]]*" diff --git a/doc/syntax/guile.nanorc b/doc/syntax/guile.nanorc index 1feb09b..1f93a7c 100644 --- a/doc/syntax/guile.nanorc +++ b/doc/syntax/guile.nanorc @@ -3,6 +3,7 @@ syntax "guile" "\.scm$" header "^#!.*guile" magic "guile" +comment ";" # Basic scheme functions color green "\<(do|if|lambda|let(rec)?|map|unless|when)\>" diff --git a/doc/syntax/html.nanorc b/doc/syntax/html.nanorc index 8782dc3..8cadb27 100644 --- a/doc/syntax/html.nanorc +++ b/doc/syntax/html.nanorc @@ -2,7 +2,10 @@ syntax "html" "\.html?$" magic "HTML document text" +comment "" color cyan start="<" end=">" color red "&[^;[:space:]]*;" color green ""(\\.|[^"])*"" + +color yellow start="" diff --git a/doc/syntax/java.nanorc b/doc/syntax/java.nanorc index 829c8af..f0bd01d 100644 --- a/doc/syntax/java.nanorc +++ b/doc/syntax/java.nanorc @@ -2,6 +2,7 @@ syntax "java" "\.java$" magic "Java " +comment "//" color green "\<(boolean|byte|char|double|float|int|long|new|short|this|transient|void)\>" color red "\<(break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\>" diff --git a/doc/syntax/javascript.nanorc b/doc/syntax/javascript.nanorc index 991f54b..f6a5415 100644 --- a/doc/syntax/javascript.nanorc +++ b/doc/syntax/javascript.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Javascript. syntax "javascript" "\.js$" +comment "//" color brightred "\<[A-Z_][0-9A-Z_]+\>" color green "\<(const|function|let|this|typeof|var|void)\>" diff --git a/doc/syntax/json.nanorc b/doc/syntax/json.nanorc index 0f799f1..20d50c1 100644 --- a/doc/syntax/json.nanorc +++ b/doc/syntax/json.nanorc @@ -5,6 +5,8 @@ # License: GPLv3 or newer syntax "json" "\.json$" +# No comments are permitted in JSON. +comment "" # Numbers (used as value). color green ":[[:space:]]*\-?(0|[1-9][0-9]*)(\.[0-9]+)?([Ee]?[-+]?[0-9]+)?" diff --git a/doc/syntax/lua.nanorc b/doc/syntax/lua.nanorc index 3dbbea8..70f69d4 100644 --- a/doc/syntax/lua.nanorc +++ b/doc/syntax/lua.nanorc @@ -5,6 +5,7 @@ ## Version: 2011-05-05 syntax "lua" "\.lua$" +comment "--" color brightwhite "\[\[.*\]\]" diff --git a/doc/syntax/makefile.nanorc b/doc/syntax/makefile.nanorc index e376445..188f004 100644 --- a/doc/syntax/makefile.nanorc +++ b/doc/syntax/makefile.nanorc @@ -1,6 +1,7 @@ ## Here is an example for Makefiles. syntax "makefile" "Makefile[^/]*$" "\.(make|mk)$" +comment "#" color red "[:=]" color magenta "\<(if|ifeq|else|endif)\>" diff --git a/doc/syntax/man.nanorc b/doc/syntax/man.nanorc index 6c296bb..dd7d23e 100644 --- a/doc/syntax/man.nanorc +++ b/doc/syntax/man.nanorc @@ -2,6 +2,7 @@ syntax "man" "\.[1-9]x?$" magic "troff or preprocessor input text" +comment ".\"" color green "\.(SH|SS|TH) .*$" color brightgreen "\.(SH|SS|TH) " "\.([HIT]P)" diff --git a/doc/syntax/mgp.nanorc b/doc/syntax/mgp.nanorc index c0a5d20..1e9d718 100644 --- a/doc/syntax/mgp.nanorc +++ b/doc/syntax/mgp.nanorc @@ -2,6 +2,7 @@ syntax "mgp" "\.mgp$" header "^%include.*" +comment "#" icolor green "^%[a-z].*$" color cyan "(^|[[:space:]])#.*$" diff --git a/doc/syntax/nanorc.nanorc b/doc/syntax/nanorc.nanorc index e730708..3d2e353 100644 --- a/doc/syntax/nanorc.nanorc +++ b/doc/syntax/nanorc.nanorc @@ -1,9 +1,10 @@ ## Here is an example for nanorc files. syntax "nanorc" "\.?nanorc$" +comment "#" # Possible errors and parameters -icolor brightred "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|linter|i?color|extendsyntax).*$" +icolor brightred "^[[:space:]]*((un)?(bind|set)|include|syntax|header|comment|magic|linter|i?color|extendsyntax).*$" # Keywords icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(allow_insecure_backup|autoindent|backup|backwards|boldtext|casesensitive|const(antshow)?|cut|fill|historylog|justifytrim|locking|morespace|mouse|multibuffer|noconvert|nohelp|nonewlines|nowrap|pos(ition)?log|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|smarthome|smooth|softwrap|suspend|tabsize|tabstospaces|tempfile|unix|view|wordbounds)\>" @@ -11,8 +12,8 @@ icolor yellow "^[[:space:]]*set[[:space:]]+(functioncolor|keycolor|statuscolor|t icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|functioncolor|keycolor|matchbrackets|operatingdir|punct|quotestr|speller|statuscolor|titlecolor|whitespace)[[:space:]]+" icolor brightgreen "^[[:space:]]*bind[[:space:]]+((\^|M-)([[:alpha:]]|space|[]]|[0-9^_=+{}|;:'\",./<>\?-])|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+[[:alpha:]]+[[:space:]]+(all|main|search|replace(2|with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)" icolor brightgreen "^[[:space:]]*unbind[[:space:]]+((\^|M-)([[:alpha:]]|space|[]]|[0-9^_=+{}|;:'\",./<>\?-])|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+(all|main|search|replace(2|with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)" -icolor brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|linter|formatter)[[:space:]]+.*$" -icolor green "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|linter|formatter|extendsyntax)\>" +icolor brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|comment|linter|formatter)[[:space:]]+.*$" +icolor green "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comment|linter|formatter|extendsyntax)\>" # Colors icolor yellow "^[[:space:]]*i?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan)?(,(white|black|red|blue|green|yellow|magenta|cyan))?\>" diff --git a/doc/syntax/nftables.nanorc b/doc/syntax/nftables.nanorc index 9c24677..5bec940 100644 --- a/doc/syntax/nftables.nanorc +++ b/doc/syntax/nftables.nanorc @@ -2,6 +2,7 @@ syntax "nftables" "\.(nft|nftables)$" header "^#!.*(nft|nftables)" +comment "#" # Objects and operations color green "\<(chain|hook|policy|priority|ruleset|set|table|type|v?map)\>" diff --git a/doc/syntax/objc.nanorc b/doc/syntax/objc.nanorc index a2a11d6..5a14ada 100644 --- a/doc/syntax/objc.nanorc +++ b/doc/syntax/objc.nanorc @@ -1,6 +1,7 @@ ## Here is an example for C/C++/Obj-C. syntax "m" "\.m$" +comment "//" # Stuffs, color brightwhite "\<[A-Z_][0-9A-Z_]+\>" diff --git a/doc/syntax/ocaml.nanorc b/doc/syntax/ocaml.nanorc index 5806c67..b2b3aa0 100644 --- a/doc/syntax/ocaml.nanorc +++ b/doc/syntax/ocaml.nanorc @@ -1,6 +1,7 @@ ## Syntax highlighting for OCaml. syntax "ocaml" "\.mli?$" +comment "(*|*)" # Uid: color red "\<[A-Z][0-9a-z_]{2,}\>" diff --git a/doc/syntax/patch.nanorc b/doc/syntax/patch.nanorc index 744408c..b3660bf 100644 --- a/doc/syntax/patch.nanorc +++ b/doc/syntax/patch.nanorc @@ -2,6 +2,8 @@ syntax "patch" "\.(patch|diff|debdiff)$" magic "diff output text" +# There is no official support for comments in patch files. +comment "" # Added lines. color brightgreen "^\+.*" diff --git a/doc/syntax/perl.nanorc b/doc/syntax/perl.nanorc index 6a70d3d..97ab68a 100644 --- a/doc/syntax/perl.nanorc +++ b/doc/syntax/perl.nanorc @@ -3,6 +3,7 @@ syntax "perl" "\.p[lm]$" header "^#!.*perl[-0-9._]*" magic "Perl script text" +comment "#" color red "\<(accept|alarm|atan2|bin(d|mode)|c(aller|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork))\>" "\<(get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join)\>" "\<(keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek(dir)?)\>" "\<(se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr(y)?|truncate|umask)\>" "\<(un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\>" color magenta "\<(continue|else|elsif|do|for|foreach|if|unless|until|while|eq|ne|lt|gt|le|ge|cmp|x|my|sub|use|package|can|isa)\>" diff --git a/doc/syntax/php.nanorc b/doc/syntax/php.nanorc index ea9acee..0b803c9 100644 --- a/doc/syntax/php.nanorc +++ b/doc/syntax/php.nanorc @@ -2,6 +2,7 @@ syntax "php" "\.php[2345s~]?$" magic "PHP script text" +comment "//" # PHP markings. color brightgreen "(<\?(php)?|\?>)" diff --git a/doc/syntax/po.nanorc b/doc/syntax/po.nanorc index c4e11eb..ac8d63c 100644 --- a/doc/syntax/po.nanorc +++ b/doc/syntax/po.nanorc @@ -1,6 +1,7 @@ ## Colouring for PO files. syntax "po" "\.pot?$" +comment "#" # Comments. color green "^#.*$" diff --git a/doc/syntax/postgresql.nanorc b/doc/syntax/postgresql.nanorc index cf389c4..6dd471d 100644 --- a/doc/syntax/postgresql.nanorc +++ b/doc/syntax/postgresql.nanorc @@ -2,6 +2,7 @@ syntax "sql" "\.sql[2345s~]?$" magic "PostgreSQL script text" +comment "-- " # Functions. color white "\<[a-z_]*\(" diff --git a/doc/syntax/pov.nanorc b/doc/syntax/pov.nanorc index b7033b1..7c5d764 100644 --- a/doc/syntax/pov.nanorc +++ b/doc/syntax/pov.nanorc @@ -1,6 +1,7 @@ ## Here is an example for POV-Ray. syntax "pov" "\.(pov|POV|povray|POVRAY)$" +comment "//" color brightcyan "^[[:space:]]*#[[:space:]]*(declare)" color brightyellow "\<(sphere|cylinder|translate|matrix|rotate|scale)\>" diff --git a/doc/syntax/python.nanorc b/doc/syntax/python.nanorc index 5c35f3b..7d4c40b 100644 --- a/doc/syntax/python.nanorc +++ b/doc/syntax/python.nanorc @@ -3,6 +3,7 @@ syntax "python" "\.py$" header "^#!.*python[-0-9._]*" linter pyflakes +comment "#" # Function definitions. icolor brightblue "def [0-9A-Z_]+" diff --git a/doc/syntax/ruby.nanorc b/doc/syntax/ruby.nanorc index a707221..0c5abce 100644 --- a/doc/syntax/ruby.nanorc +++ b/doc/syntax/ruby.nanorc @@ -3,6 +3,7 @@ syntax "ruby" "\.rb$" header "^#!.*ruby[-0-9._]*" linter ruby -w -c +comment "#" # Reserved words. color yellow "\<(BEGIN|END|alias|and|begin|break|case|class|def|defined\?|do|else|elsif|end|ensure|false|for|if|in|module)\>" diff --git a/doc/syntax/sh.nanorc b/doc/syntax/sh.nanorc index 11eb9a4..17e6dd9 100644 --- a/doc/syntax/sh.nanorc +++ b/doc/syntax/sh.nanorc @@ -4,6 +4,7 @@ syntax "sh" "\.sh$" header "^#!.*((ba|da|k|pdk)?sh[-0-9_]*|openrc-run|runscript)" magic "(POSIX|Bourne.*) shell script text" linter dash -n +comment "#" icolor brightgreen "^[0-9A-Z_]+\(\)" color green "\<(break|case|continue|do|done|elif|else|esac|exit|fi|for|function|if|in|read|return|select|shift|then|time|until|while)\>" diff --git a/doc/syntax/spec.nanorc b/doc/syntax/spec.nanorc index 47de211..407cab1 100644 --- a/doc/syntax/spec.nanorc +++ b/doc/syntax/spec.nanorc @@ -1,6 +1,7 @@ ## Syntax highlighting for RPM spec files. syntax "spec" "\.(spec$|spec\.*)" +comment "#" # Main tags. color brightblue "((Icon|ExclusiveOs|ExcludeOs)[[:space:]]*:)" diff --git a/doc/syntax/tcl.nanorc b/doc/syntax/tcl.nanorc index 8bcec24..adbb605 100644 --- a/doc/syntax/tcl.nanorc +++ b/doc/syntax/tcl.nanorc @@ -1,6 +1,7 @@ ## Syntax highlighting for Tcl files. syntax "tcl" "\.tcl$" +comment "#" # Standard Tcl [info commands]: color green "\<(after|append|array|auto_execok|auto_import|auto_load|auto_load_index|auto_qualify|binary|break|case|catch|cd|clock|close|concat|continue|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|file|fileevent|flush|for|foreach|format|gets|glob|global|history|if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort|namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return|scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace|unknown|unset|update|uplevel|upvar|variable|vwait|while)\>" diff --git a/doc/syntax/tex.nanorc b/doc/syntax/tex.nanorc index a89cff9..6f2d7ab 100644 --- a/doc/syntax/tex.nanorc +++ b/doc/syntax/tex.nanorc @@ -2,6 +2,7 @@ syntax "tex" "\.tex$" linter chktex -v0 -q -I +comment "%" icolor green "\\.|\\[A-Z]*" color magenta "[{}]" diff --git a/doc/syntax/texinfo.nanorc b/doc/syntax/texinfo.nanorc index 63354ba..2ec2306 100644 --- a/doc/syntax/texinfo.nanorc +++ b/doc/syntax/texinfo.nanorc @@ -3,6 +3,7 @@ syntax "texinfo" "\.texi$" header "^\\input texinfo" magic "Texinfo source text" +comment "#" # Command arguments, trailing and enclosed. color cyan "address@hidden:space:]]+.*$" diff --git a/doc/syntax/xml.nanorc b/doc/syntax/xml.nanorc index 10e6867..914cdf9 100644 --- a/doc/syntax/xml.nanorc +++ b/doc/syntax/xml.nanorc @@ -2,6 +2,7 @@ syntax "xml" "\.([jrsx]html?|jnlp|mml|pom|rng|sgml?|svg|w[as]dl|wsdd|xjb|xml|xs(d|lt?)|xul)$" magic "(XML|SGML) (sub)?document text" +comment "" # The entire content of the tag: color green start="<" end=">" diff --git a/doc/texinfo/nano.texi b/doc/texinfo/nano.texi index 3589f21..8547e3b 100644 --- a/doc/texinfo/nano.texi +++ b/doc/texinfo/nano.texi @@ -886,6 +886,16 @@ to be edited, to determine whether this syntax should be used for that file. This functionality only works when libmagic is installed on the system and will be silently ignored otherwise. address@hidden comment "string" +Use the given string for commenting and uncommenting lines. A vertical bar or +pipe character (|) designates bracket style comments; for example, "/*|*/" for +CSS files. The characters before the pipe are prepended to the line and the +characters after the pipe are appended at the end of the line. If no pipe +character is present, the entire string is prepended; for example, "# " for +Python files. If empty double quotes are specified, the comment/uncomment +functions are disabled; for example, "" for JSON. Double quotes or backslashes +may be escaped with a backslash; for example, ".\\"" for man page source. + @item color fgcolor,bgcolor "regex" @dots{} Display all pieces of text that match the extended regular expression "regex" with foreground color "fgcolor" and @@ -918,7 +928,7 @@ to @code{icolor}. @item extendsyntax str directive [arg @dots{}] Extend the syntax previously defined as str to include new information. This allows you to add a new @code{color}, @code{icolor}, @code{header}, address@hidden, @code{linter}, or @code{formatter} directive to an already address@hidden, @code{comment}, @code{linter}, or @code{formatter} directive to an already defined syntax --- useful when you want to slightly improve a syntax defined in one of the system-installed files (which are normally not writable). @@ -1043,6 +1053,14 @@ Indents (shifts to the right) the currently marked text. @item unindent Unindents (shifts to the left) the currently marked text. address@hidden comment +Comments the current line or marked lines, using the comment style specified +in the active syntax. + address@hidden uncomment +Uncomments the current line or marked lines. Only whole lines which are +commented by the active comment style will be uncommented. + @item left Goes left one position (in the editor or browser). diff --git a/src/global.c b/src/global.c index 1a3b2ff..0c083d4 100644 --- a/src/global.c +++ b/src/global.c @@ -549,6 +549,10 @@ void shortcut_init(void) N_("Copy the current line and store it in the cutbuffer"); const char *nano_indent_msg = N_("Indent the current line"); const char *nano_unindent_msg = N_("Unindent the current line"); +#ifndef DISABLE_COMMENT + const char *nano_comment_msg = N_("Comment the current line or marked lines"); + const char *nano_uncomment_msg = N_("Uncomment the current line or marked lines"); +#endif const char *nano_undo_msg = N_("Undo the last operation"); const char *nano_redo_msg = N_("Redo the last undone operation"); #endif @@ -826,6 +830,13 @@ void shortcut_init(void) add_to_funcs(do_unindent, MMAIN, N_("Unindent Text"), IFSCHELP(nano_unindent_msg), BLANKAFTER, NOVIEW); +#ifndef DISABLE_COMMENT + add_to_funcs(do_comment_void, MMAIN, + N_("Comment Lines"), IFSCHELP(nano_comment_msg), TOGETHER, NOVIEW); + add_to_funcs(do_uncomment, MMAIN, + N_("Uncomment"), IFSCHELP(nano_uncomment_msg), BLANKAFTER, NOVIEW); +#endif + add_to_funcs(do_undo, MMAIN, N_("Undo"), IFSCHELP(nano_undo_msg), TOGETHER, NOVIEW); add_to_funcs(do_redo, MMAIN, @@ -1088,6 +1099,10 @@ void shortcut_init(void) add_to_sclist(MMAIN, "M-U", do_undo, 0); add_to_sclist(MMAIN, "M-E", do_redo, 0); #endif +#ifndef DISABLE_COMMENT + add_to_sclist(MMAIN, "M-3", do_comment_void, 0); + add_to_sclist(MMAIN, "M-4", do_uncomment, 0); +#endif add_to_sclist(MMOST, "^B", do_left, 0); add_to_sclist(MMOST, "Left", do_left, 0); add_to_sclist(MMOST, "^F", do_right, 0); diff --git a/src/nano.c b/src/nano.c index 152f809..896a7ef 100644 --- a/src/nano.c +++ b/src/nano.c @@ -996,6 +996,9 @@ void version(void) #ifdef DISABLE_COLOR printf(" --disable-color"); #endif +#ifdef DISABLE_COMMENT + printf(" --disable-comment"); +#endif #ifdef DISABLE_EXTRA printf(" --disable-extra"); #endif diff --git a/src/nano.h b/src/nano.h index 7a9e008..c2b957f 100644 --- a/src/nano.h +++ b/src/nano.h @@ -188,6 +188,9 @@ typedef enum { #ifndef DISABLE_WRAPPING SPLIT_BEGIN, SPLIT_END, #endif +#ifndef DISABLE_COMMENT + COMMENT, UNCOMMENT, +#endif JOIN, PASTE, INSERT, ENTER, OTHER } undo_type; @@ -247,6 +250,8 @@ typedef struct syntaxtype { /* The command with which to lint this type of file. */ char *formatter; /* The formatting command (for programming languages mainly). */ + char *comment; + /* The line comment prefix (and postfix) for this type of file. */ colortype *color; /* The colors and their regexes used in this syntax. */ int nmultis; @@ -318,6 +323,14 @@ typedef struct partition { } partition; #ifndef NANO_TINY +typedef struct undo_group { + ssize_t top_line; + /* First line of group. */ + ssize_t bottom_line; + /* Last line of group. */ + struct undo_group *next; +} undo_group; + typedef struct undo { ssize_t lineno; undo_type type; @@ -332,6 +345,8 @@ typedef struct undo { /* The file size after the action. */ int xflags; /* Some flag data we need. */ + undo_group *grouping; + /* Undo info specific to groups of lines. */ /* Cut-specific stuff we need. */ filestruct *cutbuffer; diff --git a/src/proto.h b/src/proto.h index 0712942..b2b5662 100644 --- a/src/proto.h +++ b/src/proto.h @@ -652,6 +652,11 @@ void do_unindent(void); void do_undo(void); void do_redo(void); #endif +#ifndef DISABLE_COMMENT +void do_comment(undo_type add_comment); +void do_comment_void(void); +void do_uncomment(void); +#endif void do_enter(void); #ifndef NANO_TINY RETSIGTYPE cancel_command(int signal); @@ -744,6 +749,11 @@ void mark_order(const filestruct **top, size_t *top_x, const filestruct void discard_until(const undo *thisitem, openfilestruct *thefile); void add_undo(undo_type action); void update_undo(undo_type action); +#ifndef DISABLE_COMMENT +void add_comment_undo(undo_type action, const char *comment_seq); +void update_comment_undo(ssize_t lineno); +bool comment_line(bool add_comment, filestruct *f, const char *comment_seq); +#endif #endif size_t get_totsize(const filestruct *begin, const filestruct *end); filestruct *fsfromline(ssize_t lineno); diff --git a/src/rcfile.c b/src/rcfile.c index d18ab44..a7c4190 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -306,6 +306,7 @@ void parse_syntax(char *ptr) live_syntax->magics = NULL; live_syntax->linter = NULL; live_syntax->formatter = NULL; + live_syntax->comment = NULL; live_syntax->color = NULL; lastcolor = NULL; live_syntax->nmultis = 0; @@ -868,6 +869,24 @@ void pick_up_name(const char *kind, char *ptr, char **storage) /* Allow unsetting the command by using an empty string. */ if (!strcmp(ptr, "\"\"")) *storage = NULL; + else if (*ptr == '"') { + *storage = mallocstrcpy(NULL, ++ptr); + char* q = *storage; + char* p = *storage; + /* Snip out the backslashes of escaped characters. */ + while (*p != '"') { + if (*p == '\0') { + rcfile_error(N_("Argument of '%s' lacks closing \""), kind); + free(*storage); + *storage = NULL; + return; + } else if (*p == '\\' && *(p + 1) != '\0') { + p++; + } + *q++ = *p++; + } + *q = '\0'; + } else *storage = mallocstrcpy(NULL, ptr); } @@ -1006,6 +1025,12 @@ void parse_rcfile(FILE *rcstream set = 1; else if (strcasecmp(keyword, "unset") == 0) set = -1; + else if (strcasecmp(keyword, "comment") == 0) +#ifndef DISABLE_COMMENT + pick_up_name("comment", ptr, &live_syntax->comment); +#else + ; +#endif else if (strcasecmp(keyword, "bind") == 0) parse_binding(ptr, TRUE); else if (strcasecmp(keyword, "unbind") == 0) diff --git a/src/text.c b/src/text.c index f5d134f..05a66cb 100644 --- a/src/text.c +++ b/src/text.c @@ -425,7 +425,162 @@ void do_unindent(void) { do_indent(-tabsize); } +#endif /* !NANO_TINY */ + +#ifndef DISABLE_COMMENT +/* Comment or uncomment the current line or marked lines. */ +void do_comment(undo_type action) { + + const char *comment_seq = "#"; + + filestruct *top, *bot, *f; + size_t top_x, bot_x; + + bool file_changed = FALSE; + /* Whether any comment has been added or deleted. */ + + assert(openfile->current != NULL && openfile->current->data != NULL); + + if (openfile->syntax && openfile->syntax->comment) + comment_seq = openfile->syntax->comment; + + /* Does the syntax not allow comments? */ + if (strlen(comment_seq) == 0) { + statusbar(_("Commenting is not supported for this file type")); + return; + } + + /* Determine which lines to work on. */ + if (openfile->mark_set) + mark_order((const filestruct **) &top, &top_x, + (const filestruct **) &bot, &bot_x, NULL); + else { + top = openfile->current; + bot = top; + } + + /* Process the selected line or lines. */ + for (f = top; f != bot->next; f = f->next) { + if (comment_line(action == COMMENT, f, comment_seq)) { + if (!file_changed) { + /* Start building undo data on the first modified line. */ + add_comment_undo(action, comment_seq); + file_changed = TRUE; + } + /* Add undo data for each modified line. */ + update_comment_undo(f->lineno); + } + } + + if (file_changed) { + set_modified(); + refresh_needed = TRUE; + } else { + /* Let the user know nothing was changed. */ + if (top == bot) + statusbar(action == COMMENT ? _("The line is not commentable") : + _("The line is not uncommentable")); + else + statusbar(_("None of the marked lines are uncommentable")); + } +} + +/* Comment the current line, or all lines covered by the mark. */ +void do_comment_void(void) +{ + do_comment(COMMENT); +} + +/* Uncomment the current line, or all lines covered by the mark. */ +void do_uncomment(void) +{ + do_comment(UNCOMMENT); +} + +/* Add or remove a comment from the specified line. Return TRUE if anything + * was added or removed, and FALSE otherwise. */ +bool comment_line(bool add_comment, filestruct *f, const char *comment_seq) { + size_t comment_seq_len = strlen(comment_seq); + const char *post_seq = strchr(comment_seq, '|'); + /* The postfix, if this is a bracketing type comment sequence. */ + size_t pre_len = post_seq ? post_seq++ - comment_seq : comment_seq_len; + /* Length of prefix. */ + size_t post_len = post_seq ? comment_seq_len - pre_len - 1 : 0; + /* Length of postfix. */ + size_t line_len = strlen(f->data); + + if (!ISSET(NO_NEWLINES) && f == openfile->filebot) + return FALSE; + + if (add_comment) { + /* Make room for the comment sequence(s), move the text right and + * copy them in. */ + f->data = charealloc(f->data, line_len + pre_len + post_len + 1); + charmove(&f->data[pre_len], f->data, line_len); + charmove(f->data, comment_seq, pre_len); + if (post_len) + charmove(&f->data[pre_len + line_len], post_seq, post_len); + f->data[pre_len + line_len + post_len] = '\0'; + + openfile->totsize += pre_len + post_len; + + /* If needed, adjust the position of the mark and the cursor. */ + if (openfile->mark_set && f == openfile->mark_begin) + openfile->mark_begin_x += pre_len; + if (f == openfile->current) + openfile->current_x += pre_len; + + return TRUE; + } + + /* In order to uncomment, see if this line is commented. */ + if (strncmp(f->data, comment_seq, pre_len) == 0 && (post_len == 0 || + strcmp(&f->data[line_len-post_len], post_seq) == 0)) { + /* Erase the comment prefix by moving the non-comment part. */ + charmove(f->data, &f->data[pre_len], line_len - pre_len); + /* Truncate the postfix if there was one. */ + f->data[line_len - pre_len - post_len] = '\0'; + + openfile->totsize -= pre_len + post_len; + + /* If needed, adjust the position of the mark and then the cursor. */ + if (openfile->mark_set && f == openfile->mark_begin) { + if (openfile->mark_begin_x < comment_seq_len) + openfile->mark_begin_x = 0; + else + openfile->mark_begin_x -= pre_len; + } + if (f == openfile->current) { + if (openfile->current_x < pre_len) + openfile->current_x = 0; + else + openfile->current_x -= pre_len; + } + + return TRUE; + } + + return FALSE; +} + +/* Perform an undo or redo for a comment or uncomment action. */ +void handle_comment_action(undo *u, bool undoing, bool add_comment) { + filestruct *f; + undo_group *group = u->grouping; + + while (group) { + for (f = fsfromline(group->top_line); f->lineno <= group->bottom_line; + f = f->next) { + comment_line(undoing ^ add_comment, f, u->strdata); + } + group = group->next; + } + goto_line_posx(u->lineno, u->begin); + refresh_needed = TRUE; +} +#endif /* !DISABLE_COMMENT */ +#ifndef NANO_TINY #define redo_paste undo_cut #define undo_paste redo_cut @@ -575,6 +730,16 @@ void do_undo(void) unlink_node(f->next); goto_line_posx(u->lineno, u->begin); break; +#ifndef DISABLE_COMMENT + case COMMENT: + handle_comment_action(u, TRUE, TRUE); + undidmsg = _("comment"); + break; + case UNCOMMENT: + handle_comment_action(u, TRUE, FALSE); + undidmsg = _("uncomment"); + break; +#endif case INSERT: undidmsg = _("text insert"); filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom; @@ -737,6 +902,16 @@ void do_redo(void) free_filestruct(u->cutbuffer); u->cutbuffer = NULL; break; +#ifndef DISABLE_COMMENT + case COMMENT: + handle_comment_action(u, FALSE, TRUE); + redidmsg = _("comment"); + break; + case UNCOMMENT: + handle_comment_action(u, FALSE, FALSE); + redidmsg = _("uncomment"); + break; +#endif default: statusbar(_("Internal error: unknown type. Please save your work.")); break; @@ -907,11 +1082,18 @@ bool execute_command(const char *command) void discard_until(const undo *thisitem, openfilestruct *thefile) { undo *dropit = thefile->undotop; + undo_group *group; while (dropit != NULL && dropit != thisitem) { thefile->undotop = dropit->next; free(dropit->strdata); free_filestruct(dropit->cutbuffer); + group = dropit->grouping; + while (group != NULL) { + undo_group *next = group->next; + free(group); + group = next; + } free(dropit); dropit = thefile->undotop; } @@ -967,6 +1149,7 @@ void add_undo(undo_type action) u->mark_set = FALSE; u->wassize = openfile->totsize; u->xflags = 0; + u->grouping = NULL; switch (u->type) { /* We need to start copying data into the undo buffer @@ -1034,6 +1217,11 @@ void add_undo(undo_type action) break; case ENTER: break; +#ifndef DISABLE_COMMENT + case COMMENT: + case UNCOMMENT: + break; +#endif default: statusbar(_("Internal error: unknown type. Please save your work.")); break; @@ -1046,6 +1234,36 @@ void add_undo(undo_type action) openfile->last_action = action; } +#ifndef DISABLE_COMMENT +/* Add a comment undo action. This should be called once for each use + * of the comment or uncomment feature that modifies the document. */ +void add_comment_undo(undo_type action, const char *comment_seq) { + add_undo(action); + + /* Store the comment sequence used for the operation, because it could + * change when the file name changes; need to know what it was. */ + openfile->current_undo->strdata = + mallocstrcpy(openfile->current_undo->strdata, comment_seq); +} + +/* Update a comment undo action This should be called once for each line + * affected by a use of the comment or uncomment feature. */ +void update_comment_undo(ssize_t lineno) +{ + undo *u = openfile->current_undo; + + if (u->grouping && u->grouping->bottom_line+1 == lineno) + u->grouping->bottom_line++; + else { + undo_group *born = (undo_group *)nmalloc(sizeof(undo_group)); + born->next = u->grouping; + u->grouping = born; + born->top_line = lineno; + born->bottom_line = lineno; + } +} +#endif + /* Update an undo item, or determine whether a new one is really needed * and bounce the data to add_undo instead. The latter functionality * just feels gimmicky and may just be more hassle than it's worth,