From 363281b347b9acfc8fbff3013102c243011a55e3 Mon Sep 17 00:00:00 2001 From: Alice M <40308596+alice-mm@users.noreply.github.com> Date: Mon, 10 Jun 2019 13:29:03 +0200 Subject: [PATCH] Bash improvements (#1443) A bunch for improvements for Bash. --- components/prism-bash.js | 169 +++++-- components/prism-bash.min.js | 2 +- .../bash/arithmetic_environment_feature.test | 2 +- tests/languages/bash/assign-left_feature.test | 23 + tests/languages/bash/builtin_feature.test | 95 ++++ .../bash/command_substitution_feature.test | 10 +- tests/languages/bash/comment_feature.test | 14 +- .../bash/entities_in_strings_feature.test | 28 ++ tests/languages/bash/environment_feature.test | 247 ++++++++++ .../languages/bash/for-or-select_feature.test | 25 + .../languages/bash/function-name_feature.test | 41 ++ tests/languages/bash/function_feature.test | 441 ++++++++++++++---- tests/languages/bash/keyword_feature.test | 43 +- tests/languages/bash/operator_feature.test | 68 +++ tests/languages/bash/shebang_feature.test | 8 +- tests/languages/bash/string_feature.test | 26 +- tests/languages/bash/variable_feature.test | 21 +- 17 files changed, 1095 insertions(+), 168 deletions(-) create mode 100644 tests/languages/bash/assign-left_feature.test create mode 100644 tests/languages/bash/builtin_feature.test create mode 100644 tests/languages/bash/entities_in_strings_feature.test create mode 100644 tests/languages/bash/environment_feature.test create mode 100644 tests/languages/bash/for-or-select_feature.test create mode 100644 tests/languages/bash/function-name_feature.test create mode 100644 tests/languages/bash/operator_feature.test diff --git a/components/prism-bash.js b/components/prism-bash.js index 534fbe6ac5..2fac80997c 100644 --- a/components/prism-bash.js +++ b/components/prism-bash.js @@ -1,84 +1,197 @@ (function(Prism) { + // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|' + // + LC_ALL, RANDOM, REPLY, SECONDS. + // + make sure PS1..4 are here as they are not always set, + // - some useless things. + var envVars = '\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b'; var insideString = { - variable: [ - // Arithmetic Environment + 'environment': { + pattern: RegExp("\\$" + envVars), + alias: 'constant' + }, + 'variable': [ + // [0]: Arithmetic Environment { pattern: /\$?\(\([\s\S]+?\)\)/, + greedy: true, inside: { // If there is a $ sign at the beginning highlight $(( and )) as variable - variable: [{ + 'variable': [ + { pattern: /(^\$\(\([\s\S]+)\)\)/, lookbehind: true }, /^\$\(\(/ ], - number: /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/, + 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/, // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic - operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/, + 'operator': /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/, // If there is no $ sign at the beginning highlight (( and )) as punctuation - punctuation: /\(\(?|\)\)?|,|;/ + 'punctuation': /\(\(?|\)\)?|,|;/ + } + }, + // [1]: Command Substitution + { + pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/, + greedy: true, + inside: { + 'variable': /^\$\(|^`|\)$|`$/ } }, - // Command Substitution + // [2]: Brace expansion { - pattern: /\$\([^)]+\)|`[^`]+`/, + pattern: /\$\{[^}]+\}/, greedy: true, inside: { - variable: /^\$\(|^`|\)$|`$/ + 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/, + 'punctuation': /[\[\]]/, + 'environment': { + pattern: RegExp("(\\{)" + envVars), + lookbehind: true, + alias: 'constant' + } } }, - /\$(?:[\w#?*!@]+|\{[^}]+\})/i - ] + /\$(?:\w+|[#?*!@$])/ + ], + // Escape sequences from echo and printf's manuals, and escaped quotes. + 'entity': /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/ }; Prism.languages.bash = { 'shebang': { - pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/, + pattern: /^#!\s*\/.*/, alias: 'important' }, 'comment': { - pattern: /(^|[^"{\\])#.*/, + pattern: /(^|[^"{\\$])#.*/, + lookbehind: true + }, + 'function-name': [ + // a) function foo { + // b) foo() { + // c) function foo() { + // but not “foo {” + { + // a) and c) + pattern: /(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/, + lookbehind: true, + alias: 'function' + }, + { + // b) + pattern: /\b\w+(?=\s*\(\s*\)\s*\{)/, + alias: 'function' + } + ], + // Highlight variable names as variables in for and select beginnings. + 'for-or-select': { + pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/, + alias: 'variable', + lookbehind: true + }, + // Highlight variable names as variables in the left-hand part + // of assignments (“=” and “+=”). + 'assign-left': { + pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/, + inside: { + 'environment': { + pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars), + lookbehind: true, + alias: 'constant' + } + }, + alias: 'variable', lookbehind: true }, 'string': [ - //Support for Here-Documents https://en.wikipedia.org/wiki/Here_document + // Support for Here-documents https://en.wikipedia.org/wiki/Here_document { - pattern: /((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/, + pattern: /((?:^|[^<])<<-?\s*)(\w+?)\s*(?:\r?\n|\r)(?:[\s\S])*?(?:\r?\n|\r)\2/, lookbehind: true, greedy: true, inside: insideString }, + // Here-document with quotes around the tag + // → No expansion (so no “inside”). + { + pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s*(?:\r?\n|\r)(?:[\s\S])*?(?:\r?\n|\r)\3/, + lookbehind: true, + greedy: true + }, + // “Normal” string { pattern: /(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/, greedy: true, inside: insideString } ], + 'environment': { + pattern: RegExp("\\$?" + envVars), + alias: 'constant' + }, 'variable': insideString.variable, - // Originally based on http://ss64.com/bash/ 'function': { - pattern: /(^|[\s;|&])(?:add|alias|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|hash|head|help|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logout|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tail|tar|tee|test|time|timeout|times|top|touch|tr|traceroute|trap|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zip|zypper)(?=$|[\s;|&])/, + pattern: /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/, lookbehind: true }, 'keyword': { - pattern: /(^|[\s;|&])(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|[\s;|&])/, + pattern: /(^|[\s;|&]|[<>]\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\s;|&])/, lookbehind: true }, + // https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html + 'builtin': { + pattern: /(^|[\s;|&]|[<>]\()(?:\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\s;|&])/, + lookbehind: true, + // Alias added to make those easier to distinguish from strings. + alias: 'class-name' + }, 'boolean': { - pattern: /(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/, + pattern: /(^|[\s;|&]|[<>]\()(?:true|false)(?=$|[)\s;|&])/, lookbehind: true }, - 'operator': /&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/, - 'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/ + 'file-descriptor': { + pattern: /\B&\d\b/, + alias: 'important' + }, + 'operator': { + // Lots of redirections here, but not just that. + pattern: /\d?<>|>\||\+=|==?|!=?|=~|<<[<-]?|[&\d]?>>|\d?[<>]&?|&[>&]?|\|[&|]?|<=?|>=?/, + inside: { + 'file-descriptor': { + pattern: /^\d/, + alias: 'important' + } + } + }, + 'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/, + 'number': { + pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/, + lookbehind: true + } }; + /* Patterns in command substitution. */ + var toBeCopied = [ + 'comment', + 'function-name', + 'for-or-select', + 'assign-left', + 'string', + 'environment', + 'function', + 'keyword', + 'builtin', + 'boolean', + 'file-descriptor', + 'operator', + 'punctuation', + 'number' + ]; var inside = insideString.variable[1].inside; - inside.string = Prism.languages.bash.string; - inside['function'] = Prism.languages.bash['function']; - inside.keyword = Prism.languages.bash.keyword; - inside['boolean'] = Prism.languages.bash['boolean']; - inside.operator = Prism.languages.bash.operator; - inside.punctuation = Prism.languages.bash.punctuation; - + for(var i = 0; i < toBeCopied.length; i++) { + inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]]; + } + Prism.languages.shell = Prism.languages.bash; })(Prism); diff --git a/components/prism-bash.min.js b/components/prism-bash.min.js index bb6819656b..5cde45fc37 100644 --- a/components/prism-bash.min.js +++ b/components/prism-bash.min.js @@ -1 +1 @@ -!function(e){var a={variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\([^)]+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},/\$(?:[\w#?*!@]+|\{[^}]+\})/i]};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/,lookbehind:!0,greedy:!0,inside:a},{pattern:/(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,greedy:!0,inside:a}],variable:a.variable,function:{pattern:/(^|[\s;|&])(?:add|alias|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|hash|head|help|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logout|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tail|tar|tee|test|time|timeout|times|top|touch|tr|traceroute|trap|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zip|zypper)(?=$|[\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&])(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|[\s;|&])/,lookbehind:!0},boolean:{pattern:/(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/,lookbehind:!0},operator:/&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/,punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];]/};var t=a.variable[1].inside;t.string=e.languages.bash.string,t.function=e.languages.bash.function,t.keyword=e.languages.bash.keyword,t.boolean=e.languages.bash.boolean,t.operator=e.languages.bash.operator,t.punctuation=e.languages.bash.punctuation,e.languages.shell=e.languages.bash}(Prism); \ No newline at end of file +!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b\w+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+?)\s*(?:\r?\n|\r)(?:[\s\S])*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s*(?:\r?\n|\r)(?:[\s\S])*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0},{pattern:/(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,greedy:!0,inside:n}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:true|false)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|==?|!=?|=~|<<[<-]?|[&\d]?>>|\d?[<>]&?|&[>&]?|\|[&|]?|<=?|>=?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}};for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],r=n.variable[1].inside,s=0;s c +a >&2 +a 2<& +a <> b +a &>> b +a && b || c + +<(yes) <(if true; then :; fi) <(echo) <(true) +<(for x in a b; do :; done) +<(select x in a b; do :; done) +>(yes) >(if true; then :; fi) >(echo) >(true) +>(for x in a b; do :; done) +>(select x in a b; do :; done) + +${x:1:2} ${x:-a} ${x:=a} ${x:?a} ${x:+a} +${!x} ${x/a/b} +${x#*a} ${x##*a} ${x%a*} ${x%%a*} +${x^a} ${x^^a} ${x,a} ${x,,a} + +---------------------------------------------------- + +[ + "a ", ["operator", ["|&"]], " b ", ["operator", ["&>"]], " c\r\na ", + ["operator", [">"]], ["file-descriptor", "&2"], "\r\na ", + ["operator", [ + ["file-descriptor", "2"], "<&" + ]], + "\r\na ", ["operator", ["<>"]], " b\r\na ", + ["operator", ["&>>"]], " b\r\na ", + ["operator", ["&&"]], " b ", ["operator", ["||"]], " c\r\n\r\n", + ["operator", ["<"]], ["punctuation", "("], ["function", "yes"], ["punctuation", ")"], + ["operator", ["<"]], ["punctuation", "("], ["keyword", "if"], ["boolean", "true"], ["punctuation", ";"], + ["keyword", "then"], ["builtin", ":"], ["punctuation", ";"], ["keyword", "fi"], ["punctuation", ")"], + ["operator", ["<"]], ["punctuation", "("], ["builtin", "echo"], ["punctuation", ")"], + ["operator", ["<"]], ["punctuation", "("], ["boolean", "true"], ["punctuation", ")"], + ["operator", ["<"]], ["punctuation", "("], ["keyword", "for"], ["for-or-select", "x"], ["keyword", "in"], " a b", ["punctuation", ";"], + ["keyword", "do"], ["builtin", ":"], ["punctuation", ";"], ["keyword", "done"], ["punctuation", ")"], + ["operator", ["<"]], ["punctuation", "("], ["keyword", "select"], ["for-or-select", "x"], ["keyword", "in"], " a b", ["punctuation", ";"], + ["keyword", "do"], ["builtin", ":"], ["punctuation", ";"], ["keyword", "done"], ["punctuation", ")"], + ["operator", [">"]], ["punctuation", "("], ["function", "yes"], ["punctuation", ")"], + ["operator", [">"]], ["punctuation", "("], ["keyword", "if"], ["boolean", "true"], ["punctuation", ";"], + ["keyword", "then"], ["builtin", ":"], ["punctuation", ";"], ["keyword", "fi"], ["punctuation", ")"], + ["operator", [">"]], ["punctuation", "("], ["builtin", "echo"], ["punctuation", ")"], + ["operator", [">"]], ["punctuation", "("], ["boolean", "true"], ["punctuation", ")"], + ["operator", [">"]], ["punctuation", "("], ["keyword", "for"], ["for-or-select", "x"], ["keyword", "in"], " a b", ["punctuation", ";"], + ["keyword", "do"], ["builtin", ":"], ["punctuation", ";"], ["keyword", "done"], ["punctuation", ")"], + ["operator", [">"]], ["punctuation", "("], ["keyword", "select"], ["for-or-select", "x"], ["keyword", "in"], " a b", ["punctuation", ";"], + ["keyword", "do"], ["builtin", ":"], ["punctuation", ";"], ["keyword", "done"], ["punctuation", ")"], + ["variable", ["${x", ["operator", ":"], "1", ["operator", ":"], "2}"]], + ["variable", ["${x", ["operator", ":-"], "a}"]], + ["variable", ["${x", ["operator", ":="], "a}"]], + ["variable", ["${x", ["operator", ":?"], "a}"]], + ["variable", ["${x", ["operator", ":+"], "a}"]], + ["variable", ["${", ["operator", "!"], "x}"]], + ["variable", ["${x", ["operator", "/"], "a", ["operator", "/"], "b}"]], + ["variable", ["${x", ["operator", "#"], "*a}"]], + ["variable", ["${x", ["operator", "##"], "*a}"]], + ["variable", ["${x", ["operator", "%"], "a*}"]], + ["variable", ["${x", ["operator", "%%"], "a*}"]], + ["variable", ["${x", ["operator", "^"], "a}"]], + ["variable", ["${x", ["operator", "^^"], "a}"]], + ["variable", ["${x", ["operator", ","], "a}"]], + ["variable", ["${x", ["operator", ",,"], "a}"]] +] + +---------------------------------------------------- + +Checks for operators. diff --git a/tests/languages/bash/shebang_feature.test b/tests/languages/bash/shebang_feature.test index c41860d026..f113bc0176 100644 --- a/tests/languages/bash/shebang_feature.test +++ b/tests/languages/bash/shebang_feature.test @@ -1,11 +1,13 @@ -#!/bin/bash +#! /usr/bin/env bash +#/bin/bash ---------------------------------------------------- [ - ["shebang", "#!/bin/bash"] + ["shebang", "#! /usr/bin/env bash"], + ["comment", "#/bin/bash"] ] ---------------------------------------------------- -Checks for shebang. \ No newline at end of file +Checks for shebang. diff --git a/tests/languages/bash/string_feature.test b/tests/languages/bash/string_feature.test index fd2a30317d..d43fdcc704 100644 --- a/tests/languages/bash/string_feature.test +++ b/tests/languages/bash/string_feature.test @@ -14,6 +14,10 @@ bar' foo bar STRING_END +<<- STRING_END +foo +bar +STRING_END << EOF foo $@ bar @@ -24,7 +28,7 @@ EOF EOF << "EOF" foo -bar +$bar EOF << STRING_END # comment @@ -46,17 +50,19 @@ STRING_END "\"", ["variable", "$@"], "\"" ]], ["string", [ - "\"", ["variable", "${foo}"], "\"" + "\"", ["variable", ["${foo}"]], "\"" ]], - ["operator", "<<"], + ["operator", ["<<"]], + ["string", ["STRING_END\r\nfoo\r\nbar\r\nSTRING_END"]], + ["operator", ["<<-"]], ["string", ["STRING_END\r\nfoo\r\nbar\r\nSTRING_END"]], - ["operator", "<<"], + ["operator", ["<<"]], ["string", ["EOF\r\nfoo ", ["variable", "$@"], "\r\nbar\r\nEOF"]], - ["operator", "<<"], - ["string", ["'EOF'\r\n'single quoted string'\r\n\"double quoted string\"\r\nEOF"]], - ["operator", "<<"], - ["string", ["\"EOF\"\r\nfoo\r\nbar\r\nEOF"]], - ["operator", "<<"], + ["operator", ["<<"]], + ["string", "'EOF'\r\n'single quoted string'\r\n\"double quoted string\"\r\nEOF"], + ["operator", ["<<"]], + ["string", "\"EOF\"\r\nfoo\r\n$bar\r\nEOF"], + ["operator", ["<<"]], ["string", ["STRING_END\r\n# comment\r\nSTRING_END"]], ["string", ["\" # comment \""]] ] @@ -64,4 +70,4 @@ STRING_END ---------------------------------------------------- Checks for single-quoted and double-quoted strings. -Also checks for variables in strings. \ No newline at end of file +Also checks for variables in strings. diff --git a/tests/languages/bash/variable_feature.test b/tests/languages/bash/variable_feature.test index 16b7448aa3..546631e156 100644 --- a/tests/languages/bash/variable_feature.test +++ b/tests/languages/bash/variable_feature.test @@ -1,15 +1,28 @@ $foo -$@ -${foo bar} +$* $@ $# $? $$ $! $0 +${foo} +$!!!! $???? ---------------------------------------------------- [ ["variable", "$foo"], + ["variable", "$*"], ["variable", "$@"], - ["variable", "${foo bar}"] + ["variable", "$#"], + ["variable", "$?"], + ["variable", "$$"], + ["variable", "$!"], + ["variable", "$0"], + ["variable", ["${foo}"]], + ["variable", "$!"], + ["operator", ["!"]], + ["operator", ["!"]], + ["operator", ["!"]], + ["variable", "$?"], + "???" ] ---------------------------------------------------- -Checks for variables. \ No newline at end of file +Checks for variables.