diff --git a/configure.ac b/configure.ac index 0c42e1e2..c47885ba 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,22 @@ else fi fi +AC_ARG_ENABLE(comment, +AS_HELP_STRING([--disable-comment], [Disable comment/uncomment functions])) +if test "x$enable_tiny" = xyes; then + if test "x$enable_comment" = xyes; then + AC_MSG_ERROR([--enable-comment cannot work with --enable-tiny]) + else + # Disabling nanorc silently disables comment support. + enable_comment=no + fi +fi +if test "x$disable_comment" != xyes; then + if test "x$enable_comment" != xno; then + AC_DEFINE(ENABLE_COMMENT, 1, [Define this to disable the comment/uncomment functionality.]) + fi +fi + AC_ARG_ENABLE(extra, AS_HELP_STRING([--disable-extra], [Disable extra features, currently only easter eggs])) if test "x$enable_extra" = xno; then diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5 index 6d616198..d94c7ed8 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 +function is 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,10 @@ Indents (shifts to the right) the currently marked text. .B unindent Unindents (shifts to the left) the currently marked text. .TP +.B comment +Comments or uncomments the current line or marked lines, using the comment +style specified in the active syntax. +.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 f1719a4a..228a185f 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 58a9b072..b578abef 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 bfc6387c..34e7176f 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 "\$[0-9A-Z_!@#$*?-]+" diff --git a/doc/syntax/c.nanorc b/doc/syntax/c.nanorc index ef156ab4..0553b6b5 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 dc437024..524c842d 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 a806d7c5..a0531cdc 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 7d0a6375..10e8a321 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 34ff29b0..61d51524 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 2a2bd2eb..785827ee 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 45873ac7..2a56bc78 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 249e224d..7de1cba9 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 e52d188b..308e976d 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 5f57f8e6..109f9cd6 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 1feb09b2..1f93a7c0 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 8782dc36..8cadb276 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 829c8afa..f0bd01dd 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 991f54bf..f6a54152 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 0f799f16..20d50c1d 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 3dbbea8d..70f69d47 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 e3764450..188f004a 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 6c296bb6..dd7d23ea 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 c0a5d203..1e9d718f 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 e7307081..3d2e353c 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 9c246773..5bec940d 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 a2a11d63..5a14ada3 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 5806c67c..b2b3aa0f 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 744408cd..b3660bf9 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 6a70d3d1..97ab68ac 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 ea9aceed..0b803c9b 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 c4e11ebd..ac8d63c6 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 cf389c4c..6dd471d1 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 b7033b10..7c5d764b 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 5c35f3b6..7d4c40bf 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 a7072216..0c5abce9 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 11eb9a45..17e6dd9d 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 47de211a..407cab17 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 8bcec246..adbb6059 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 a89cff90..6f2d7ab5 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 63354bae..9d10ecad 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 "@c " # Command arguments, trailing and enclosed. color cyan "^@[a-z]+[[:space:]]+.*$" diff --git a/doc/syntax/xml.nanorc b/doc/syntax/xml.nanorc index 10e6867b..914cdf96 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 3589f210..2b3564fe 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. +@item 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}, -@code{magic}, @code{linter}, or @code{formatter} directive to an already +@code{magic}, @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,10 @@ Indents (shifts to the right) the currently marked text. @item unindent Unindents (shifts to the left) the currently marked text. +@item comment +Comments or uncomments the current line or marked lines, using the comment +style specified in the active syntax. + @item left Goes left one position (in the editor or browser). diff --git a/src/global.c b/src/global.c index 5805c187..1e15b177 100644 --- a/src/global.c +++ b/src/global.c @@ -554,6 +554,9 @@ 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"); +#ifdef ENABLE_COMMENT + const char *nano_comment_msg = N_("Comment/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 @@ -937,6 +940,10 @@ void shortcut_init(void) add_to_funcs(do_suspend_void, MMAIN, N_("Suspend"), IFSCHELP(nano_suspend_msg), BLANKAFTER, VIEW); +#ifdef ENABLE_COMMENT + add_to_funcs(do_comment, MMAIN, + N_("Comment Lines"), IFSCHELP(nano_comment_msg), BLANKAFTER, NOVIEW); +#endif #ifndef NANO_TINY add_to_funcs(do_savefile, MMAIN, N_("Save"), IFSCHELP(nano_savefile_msg), BLANKAFTER, NOVIEW); @@ -1103,6 +1110,9 @@ void shortcut_init(void) add_to_sclist(MMAIN, "M-{", do_unindent, 0); add_to_sclist(MMAIN, "M-U", do_undo, 0); add_to_sclist(MMAIN, "M-E", do_redo, 0); +#endif +#ifdef ENABLE_COMMENT + add_to_sclist(MMAIN, "M-3", do_comment, 0); #endif add_to_sclist(MMOST, "^B", do_left, 0); add_to_sclist(MMOST, "Left", do_left, 0); @@ -1419,6 +1429,10 @@ sc *strtosc(const char *input) else if (!strcasecmp(input, "endpara")) s->scfunc = do_para_end_void; #endif +#ifdef ENABLE_COMMENT + else if (!strcasecmp(input, "comment")) + s->scfunc = do_comment; +#endif #ifndef NANO_TINY else if (!strcasecmp(input, "indent")) s->scfunc = do_indent_void; diff --git a/src/nano.c b/src/nano.c index 68a13568..e4afe8b4 100644 --- a/src/nano.c +++ b/src/nano.c @@ -996,6 +996,9 @@ void version(void) #ifdef DISABLE_COLOR printf(" --disable-color"); #endif +#ifndef ENABLE_COMMENT + printf(" --disable-comment"); +#endif #ifdef DISABLE_EXTRA printf(" --disable-extra"); #endif diff --git a/src/nano.h b/src/nano.h index 9ffbbc16..829799d2 100644 --- a/src/nano.h +++ b/src/nano.h @@ -191,6 +191,9 @@ typedef enum { ADD, DEL, BACK, CUT, CUT_EOF, REPLACE, #ifndef DISABLE_WRAPPING SPLIT_BEGIN, SPLIT_END, +#endif +#ifndef DISABLE_COMMENT + COMMENT, UNCOMMENT, PREFLIGHT, #endif JOIN, PASTE, INSERT, ENTER, OTHER } undo_type; @@ -251,6 +254,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; @@ -322,6 +327,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; @@ -336,6 +349,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 1f5e1620..16a2a907 100644 --- a/src/proto.h +++ b/src/proto.h @@ -653,6 +653,9 @@ void do_unindent(void); void do_undo(void); void do_redo(void); #endif +#ifndef DISABLE_COMMENT +void do_comment(void); +#endif void do_enter(void); #ifndef NANO_TINY RETSIGTYPE cancel_command(int signal); @@ -745,6 +748,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, size_t undo_x); +void update_comment_undo(ssize_t lineno); +bool comment_line(undo_type action, 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 c760c3ff..8face04c 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); } @@ -982,6 +1001,12 @@ void parse_rcfile(FILE *rcstream grab_and_store("magic", ptr, &live_syntax->magics); #else ; +#endif + else if (strcasecmp(keyword, "comment") == 0) +#ifdef ENABLE_COMMENT + pick_up_name("comment", ptr, &live_syntax->comment); +#else + ; #endif else if (strcasecmp(keyword, "color") == 0) parse_colors(ptr, NANO_REG_EXTENDED); diff --git a/src/text.c b/src/text.c index 3f2bd4c9..9132cfb3 100644 --- a/src/text.c +++ b/src/text.c @@ -425,7 +425,194 @@ void do_unindent(void) { do_indent(-tabsize); } +#endif /* !NANO_TINY */ +#ifdef ENABLE_COMMENT +/* Test whether the string is empty or consists of only blanks. */ +bool white_string(const char *s) +{ + while (*s != '\0' && (is_blank_mbchar(s) || *s == '\r')) + s += move_mbright(s, 0); + + return !*s; +} + +/* Comment or uncomment the current line or the marked lines. */ +void do_comment() +{ + const char *comment_seq = "#"; + undo_type action = UNCOMMENT; + filestruct *top, *bot, *f; + size_t top_x, bot_x, was_x; + bool empty, all_empty = TRUE; + + bool file_changed = FALSE; + /* Whether any comment has been added or deleted. */ + + assert(openfile->current != NULL && openfile->current->data != NULL); + +#ifndef DISABLE_COLOR + 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; + } +#endif + + /* 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; + } + + /* Remember the cursor x position to be restored when undoing. */ + was_x = openfile->current_x; + + /* Figure out whether to comment or uncomment the selected line or lines. */ + for (f = top; f != bot->next; f = f->next) { + empty = white_string(f->data); + + /* If this line is not blank and not commented, we comment all. */ + if (!empty && !comment_line(PREFLIGHT, f, comment_seq)) { + action = COMMENT; + break; + } + all_empty = all_empty && empty; + } + + /* If all selected lines are blank, we comment them. */ + action = all_empty ? COMMENT : action; + + /* Process the selected line or lines. */ + for (f = top; f != bot->next; f = f->next) { + if (comment_line(action, f, comment_seq)) { + if (!file_changed) { + /* Start building undo data on the first modified line. */ + add_comment_undo(action, comment_seq, was_x); + file_changed = TRUE; + } + /* Add undo data for each modified line. */ + update_comment_undo(f->lineno); + } + } + + if (file_changed) { + set_modified(); + refresh_needed = TRUE; + } else + statusbar(_("Cannot comment past end of file")); +} + +/* Test whether the given line can be uncommented, or add or remove a comment, + * depending on action. Return TRUE if the line is uncommentable, or when + * anything was added or removed; FALSE otherwise. */ +bool comment_line(undo_type action, 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 (action == 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 of 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; + openfile->placewewant = xplustabs(); + } + + return TRUE; + } + + /* If the line is commented, report it as uncommentable, or uncomment it. */ + if (strncmp(f->data, comment_seq, pre_len) == 0 && (post_len == 0 || + strcmp(&f->data[line_len - post_len], post_seq) == 0)) { + + if (action == PREFLIGHT) + return TRUE; + + /* 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 < pre_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; + openfile->placewewant = xplustabs(); + } + + 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) +{ + undo_group *group = u->grouping; + + /* When redoing, reposition the cursor and let the commenter adjust it. */ + if (!undoing) + goto_line_posx(u->lineno, u->begin); + + while (group) { + filestruct *f = fsfromline(group->top_line); + + while (f && f->lineno <= group->bottom_line) { + comment_line(undoing ^ add_comment ? + COMMENT : UNCOMMENT, f, u->strdata); + f = f->next; + } + group = group->next; + } + + /* When undoing, reposition the cursor to the recorded location. */ + if (undoing) + goto_line_posx(u->lineno, u->begin); + + refresh_needed = TRUE; +} +#endif /* ENABLE_COMMENT */ + +#ifndef NANO_TINY #define redo_paste undo_cut #define undo_paste redo_cut @@ -574,6 +761,16 @@ void do_undo(void) unlink_node(f->next); goto_line_posx(u->lineno, u->begin); break; +#ifdef ENABLE_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; @@ -738,6 +935,16 @@ void do_redo(void) free_filestruct(u->cutbuffer); u->cutbuffer = NULL; break; +#ifdef ENABLE_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: statusline(ALERT, _("Internal error: unknown type. " "Please save your work.")); @@ -909,11 +1116,20 @@ 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); +#ifdef ENABLE_COMMENT + group = dropit->grouping; + while (group != NULL) { + undo_group *next = group->next; + free(group); + group = next; + } +#endif free(dropit); dropit = thefile->undotop; } @@ -969,6 +1185,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 @@ -1036,6 +1253,11 @@ void add_undo(undo_type action) break; case ENTER: break; +#ifdef ENABLE_COMMENT + case COMMENT: + case UNCOMMENT: + break; +#endif default: statusline(ALERT, _("Internal error: unknown type. " "Please save your work.")); @@ -1049,6 +1271,42 @@ void add_undo(undo_type action) openfile->last_action = action; } +#ifdef ENABLE_COMMENT +/* Add a comment undo item. This should be called once for each use + * of the comment/uncomment feature that modifies the document. */ +void add_comment_undo(undo_type action, const char *comment_seq, size_t was_x) +{ + add_undo(action); + + /* Store the comment sequence used for the operation, because it could + * change when the file name changes; we need to know what it was. */ + openfile->current_undo->strdata = mallocstrcpy(NULL, comment_seq); + + /* Remember the position of the cursor before the change was made. */ + openfile->current_undo->begin = was_x; +} + +/* Update a comment undo item. This should be called once for each line + * affected by the comment/uncomment feature. */ +void update_comment_undo(ssize_t lineno) +{ + undo *u = openfile->current_undo; + + /* If there already is a group and the current line is contiguous with it, + * extend the group; otherwise, create a new group. */ + 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 /* ENABLE_COMMENT */ + /* 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,