diff --git a/server/src/snippets.ts b/server/src/snippets.ts index 5ecb2e3c8..2730fc1f7 100644 --- a/server/src/snippets.ts +++ b/server/src/snippets.ts @@ -1,16 +1,14 @@ /** * Naming convention for `documentation`: * - for Bash operators it's ' operator' - * - for Bash parameter expansions it's ' expansion' * - for Bash documentation it's 'documentation definition' or '"" documentation definition' * - for Bash functions it's 'function definition' or '"" function definition' - * - for Bash builtins it's '"" invocation' * - for Bash character classes it's any string with optional mnemonics depicted via square brackets * - for shell shebang it's 'shebang' * - for anything else it's any string * * Naming convention for `label`: - * - for shell shebang it's 'shebang' + * - for shell shebang it's 'shebang' or 'shebang-with-arguments' * - for Bash operators it's '[]', where: * - is Bash operator * - is 'test' @@ -21,13 +19,8 @@ * used when expansion modifies variable or prints error to stderr * - is 'if-(set|unset)[-or-[not-]null]' * - term delimiter: dash, like 'set-if-unset-or-null' - * - for Bash brace expansion it's 'range' * - for Bash documentation it's one of 'documentation'/'' * - for Bash functions it's one of 'function'/'' - * - for Bash builtins it's '' - * - for Bash character classes it's '' - * - for Sed it's 'sed:' - * - for Awk it's 'awk:' * - for anything else it's any string */ import { CompletionItemKind, InsertTextFormat, MarkupKind } from 'vscode-languageserver' @@ -41,385 +34,627 @@ export const SNIPPETS: BashCompletionItem[] = [ insertText: '#!/usr/bin/env ${1|bash,sh|}', }, { - documentation: 'if operator', + documentation: 'shebang-with-arguments', + label: 'shebang-with-arguments', + insertText: '#!/usr/bin/env ${1|-S,--split-string|} ${2|bash,sh|} ${3|argument ...|}', + }, + { + label: 'and', + documentation: 'and operator', + insertText: '${1:first-expression} && ${2:second-expression}', + }, + { + label: 'or', + documentation: 'or operator', + insertText: '${1:first-expression} || ${2:second-expression}', + }, + { label: 'if', - insertText: ['if ${1:command}; then', '\t$0', 'fi'].join('\n'), + documentation: 'if operator', + insertText: ['if ${1:condition}; then', '\t${2:command ...}', 'fi'].join('\n'), }, { - documentation: 'if else operator', label: 'if-else', - insertText: ['if ${1:command}; then', '\t${2:echo}', 'else', '\t$0', 'fi'].join('\n'), + documentation: 'if-else operator', + insertText: [ + 'if ${1:condition}; then', + '\t${2:command ...}', + 'else', + '\t${3:command ...}', + 'fi', + ].join('\n'), }, { - documentation: 'if operator', - label: 'if-test', + label: 'if-less', + documentation: 'if with number comparison', insertText: [ - 'if [[ ${1:variable} ${2|-ef,-nt,-ot,==,=~,!=,<,>,-lt,-le,-gt,-ge|} ${3:variable} ]]; then', - '\t$0', + 'if (( "${1:first-expression}" < "${2:second-expression}" )); then', + '\t${3:command ...}', 'fi', ].join('\n'), }, { - documentation: 'if else operator', - label: 'if-else-test', + label: 'if-greater', + documentation: 'if with number comparison', insertText: [ - 'if [[ ${1:variable} ${2|-ef,-nt,-ot,==,=~,!=,<,>,-lt,-le,-gt,-ge|} ${3:variable} ]]; then', - 'else', - '\t$0', + 'if (( "${1:first-expression}" > "${2:second-expression}" )); then', + '\t${3:command ...}', 'fi', ].join('\n'), }, { - documentation: 'while operator', - label: 'while', - insertText: ['while ${1:command}; do', '\t$0', 'done'].join('\n'), + label: 'if-less-or-equal', + documentation: 'if with number comparison', + insertText: [ + 'if (( "${1:first-expression}" <= "${2:second-expression}" )); then', + '\t${3:command ...}', + 'fi', + ].join('\n'), + }, + { + label: 'if-greater-or-equal', + documentation: 'if with number comparison', + insertText: [ + 'if (( "${1:first-expression}" >= "${2:second-expression}" )); then', + '\t${3:command ...}', + 'fi', + ].join('\n'), + }, + { + label: 'if-equal', + documentation: 'if with number comparison', + insertText: [ + 'if (( "${1:first-expression}" == "${2:second-expression}" )); then', + '\t${3:command ...}', + 'fi', + ].join('\n'), }, { + label: 'if-not-equal', + documentation: 'if with number comparison', + insertText: [ + 'if (( "${1:first-expression}" != "${2:second-expression}" )); then', + '\t${3:command ...}', + 'fi', + ].join('\n'), + }, + { + label: 'if-string-equal', + documentation: 'if with string comparison', + insertText: [ + 'if [[ "${1:first-expression}" == "${2:second-expression}" ]]; then', + '\t${3:command ...}', + 'fi', + ].join('\n'), + }, + { + label: 'if-string-not-equal', + documentation: 'if with string comparison', + insertText: [ + 'if [[ "${1:first-expression}" != "${2:second-expression}" ]]; then', + '\t${3:command ...}', + 'fi', + ].join('\n'), + }, + { + label: 'if-string-empty', + documentation: 'if with string comparison (has [z]ero length)', + insertText: ['if [[ -z "${1:expression}" ]]; then', '\t${2:command ...}', 'fi'].join( + '\n', + ), + }, + { + label: 'if-string-not-empty', + documentation: 'if with string comparison ([n]ot empty)', + insertText: ['if [[ -n "${1:expression}" ]]; then', '\t${2:command ...}', 'fi'].join( + '\n', + ), + }, + { + label: 'if-defined', + documentation: 'if with variable existence check', + insertText: ['if [[ -n "${${1:variable}+x}" ]]', '\t${2:command ...}', 'fi'].join( + '\n', + ), + }, + { + label: 'if-not-defined', + documentation: 'if with variable existence check', + insertText: ['if [[ -z "${${1:variable}+x}" ]]', '\t${2:command ...}', 'fi'].join( + '\n', + ), + }, + { + label: 'while', documentation: 'while operator', - label: 'while-test', + insertText: ['while ${1:condition}; do', '\t${2:command ...}', 'done'].join('\n'), + }, + { + label: 'while-else', + documentation: 'while-else operator', insertText: [ - 'while [[ ${1:variable} ${2|-ef,-nt,-ot,==,=~,!=,<,>,-lt,-le,-gt,-ge|} ${3:variable} ]]; do', - '\t$0', + 'while ${1:condition}; do', + '\t${2:command ...}', + 'else', + '\t${3:command ...}', 'done', ].join('\n'), }, { - documentation: 'until operator', - label: 'until', - insertText: ['until ${1:command}; do', '\t$0', 'done'].join('\n'), + label: 'while-less', + documentation: 'while with number comparison', + insertText: [ + 'while (( "${1:first-expression}" < "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: 'until operator', - label: 'until-test', + label: 'while-greater', + documentation: 'while with number comparison', insertText: [ - 'until [[ ${1:variable} ${2|-ef,-nt,-ot,==,=~,!=,<,>,-lt,-le,-gt,-ge|} ${3:variable} ]]; do', - '\t$0', + 'while (( "${1:first-expression}" > "${2:second-expression}" )); do', + '\t${3:command ...}', 'done', ].join('\n'), }, { - documentation: 'for operator', - label: 'for', - insertText: ['for ${1:variable} in ${2:list}; do', '\t$0', 'done'].join('\n'), + label: 'while-less-or-equal', + documentation: 'while with number comparison', + insertText: [ + 'while (( "${1:first-expression}" <= "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: 'for operator', - label: 'for.range', - insertText: ['for ${1:variable} in $(seq ${2:to}); do', '\t$0', 'done'].join('\n'), + label: 'while-greater-or-equal', + documentation: 'while with number comparison', + insertText: [ + 'while (( "${1:first-expression}" >= "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: 'for operator', - label: 'for.file', - insertText: ['for ${1:variable} in *; do', '\t$0', 'done'].join('\n'), + label: 'while-equal', + documentation: 'while with number comparison', + insertText: [ + 'while (( "${1:first-expression}" == "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: 'for operator', - label: 'for.directory', - insertText: ['for ${1:variable} in */; do', '\t$0', 'done'].join('\n'), + label: 'while-not-equal', + documentation: 'while with number comparison', + insertText: [ + 'while (( "${1:first-expression}" != "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: 'function definition', - label: 'function', - insertText: ['${1:function_name}() {', '\t$0', '}'].join('\n'), + label: 'while-string-equal', + documentation: 'while with string comparison', + insertText: [ + 'while [[ "${1:first-expression}" == "${2:second-expression}" ]]; do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"main" function definition', - label: 'main', - insertText: ['main() {', '\t$0', '}'].join('\n'), + label: 'while-string-not-equal', + documentation: 'while with string comparison', + insertText: [ + 'while [[ "${1:first-expression}" != "${2:second-expression}" ]]; do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: 'documentation definition', - label: 'documentation', + label: 'while-string-empty', + documentation: 'while with string comparison (has [z]ero length)', insertText: [ - '# ${1:function_name} ${2:function_parameters}', - '# ${3:function_description}', - '#', - '# Output:', - '# ${4:function_output}', - '#', - '# Return:', - '# - ${5:0} when ${6:all parameters are correct}', - '# - ${7:1} ${8:otherwise}', + 'while [[ -z "${1:expression}" ]]; do', + '\t${2:command ...}', + 'done', ].join('\n'), }, { - documentation: ':- expansion', - label: 'if-unset-or-null', - insertText: '"\\${${1:variable}:-${2:default}}"', + label: 'while-string-not-empty', + documentation: 'while with string comparison ([n]ot empty)', + insertText: [ + 'while [[ -n "${1:expression}" ]]; do', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: '- expansion', - label: 'if-unset', - insertText: '"\\${${1:variable}-${2:default}}"', + label: 'while-defined', + documentation: 'while with variable existence check', + insertText: [ + 'while [[ -n "${${1:variable}+x}" ]]', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: ':= expansion', - label: 'set-if-unset-or-null', - insertText: '"\\${${1:variable}:=${2:default}}"', + label: 'while-not-defined', + documentation: 'while with variable existence check', + insertText: [ + 'while [[ -z "${${1:variable}+x}" ]]', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: '= expansion', - label: 'set-if-unset', - insertText: '"\\${${1:variable}=${2:default}}"', + label: 'until', + documentation: 'until operator', + insertText: ['until ${1:condition}; do', '\t${2:command ...}', 'done'].join('\n'), }, { - documentation: ':? expansion', - label: 'error-if-unset-or-null', - insertText: '"\\${${1:variable}:?${2:error_message}}"', + label: 'until-else', + documentation: 'until-else operator', + insertText: [ + 'until ${1:condition}; do', + '\t${2:command ...}', + 'else', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '? expansion', - label: 'error-if-unset', - insertText: '"\\${${1:variable}?${2:error_message}}"', + label: 'until-less', + documentation: 'until with number comparison', + insertText: [ + 'until (( "${1:first-expression}" < "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: ':+ expansion', - label: 'if-set-or-not-null', - insertText: '"\\${${1:variable}:+${2:alternative}}"', + label: 'until-greater', + documentation: 'until with number comparison', + insertText: [ + 'until (( "${1:first-expression}" > "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '+ expansion', - label: 'if-set', - insertText: '"\\${${1:variable}+${2:alternative}}"', + label: 'until-less-or-equal', + documentation: 'until with number comparison', + insertText: [ + 'until (( "${1:first-expression}" <= "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '# expansion', - label: 'without-shortest-leading-pattern', - insertText: '"\\${${1:variable}#${2:pattern}}"', + label: 'until-greater-or-equal', + documentation: 'until with number comparison', + insertText: [ + 'until (( "${1:first-expression}" >= "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '## expansion', - label: 'without-longest-leading-pattern', - insertText: '"\\${${1:variable}##${2:pattern}}"', + label: 'until-equal', + documentation: 'until with number comparison', + insertText: [ + 'until (( "${1:first-expression}" == "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '% expansion', - label: 'without-shortest-trailing-pattern', - insertText: '"\\${${1:variable}%${2:pattern}}"', + label: 'until-not-equal', + documentation: 'until with number comparison', + insertText: [ + 'until (( "${1:first-expression}" != "${2:second-expression}" )); do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '%% expansion', - label: 'without-longest-trailing-pattern', - insertText: '"\\${${1:variable}%%${2:pattern}}"', + label: 'until-string-equal', + documentation: 'until with string comparison', + insertText: [ + 'until [[ "${1:first-expression}" == "${2:second-expression}" ]]; do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '.. expansion', - label: 'range', - insertText: '{${1:from}..${2:to}}', + label: 'until-string-not-equal', + documentation: 'until with string comparison', + insertText: [ + 'until [[ "${1:first-expression}" != "${2:second-expression}" ]]; do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"echo" invocation', - label: 'echo', - insertText: 'echo "${1:message}"', + label: 'until-string-empty', + documentation: 'until with string comparison (has [z]ero length)', + insertText: [ + 'until [[ -z "${1:expression}" ]]; do', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"printf" invocation', - label: 'printf', - insertText: - 'printf \'${1|%c,%s,%d,%f,%15c,%15s,%15d,%15f,%.5s,%.5d,%.5f|}\' "${2:message}"', + label: 'until-string-not-empty', + documentation: 'until with string comparison ([n]ot empty)', + insertText: [ + 'until [[ -n "${1:expression}" ]]; do', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"source" invocation', - label: 'source', - insertText: '${1|source,.|} "${2:path/to/file}"', + label: 'until-defined', + documentation: 'until with variable existence check', + insertText: [ + 'until [[ -n "${${1:variable}+x}" ]]', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"alias" invocation', - label: 'alias', - insertText: 'alias ${1:name}=${2:value}', + label: 'until-not-defined', + documentation: 'until with variable existence check', + insertText: [ + 'until [[ -z "${${1:variable}+x}" ]]', + '\t${2:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"cd" invocation', - label: 'cd', - insertText: 'cd "${1:path/to/directory}"', + label: 'for', + documentation: 'for operator', + insertText: [ + 'for ${1:item} in ${2:expression}; do', + '\t${3:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"getopts" invocation', - label: 'getopts', - insertText: 'getopts ${1:optstring} ${2:name}', + label: 'for-range', + documentation: 'for with range', + insertText: [ + 'for ${1:item} in $(seq ${2:from} ${3:to}); do', + '\t${4:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"jobs" invocation', - label: 'jobs', - insertText: 'jobs -x ${1:command}', + label: 'for-stepped-range', + documentation: 'for with stepped range', + insertText: [ + 'for ${1:item} in $(seq ${2:from} ${3:step} ${4:to}); do', + '\t${5:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"kill" invocation', - label: 'kill', - insertText: 'kill ${1|-l,-L|}', + label: 'for-files', + documentation: 'for with files', + insertText: [ + 'for ${1:item} in *.${2:extension}; do', + '\t${4:command ...}', + 'done', + ].join('\n'), }, { - documentation: '"let" invocation', - label: 'let', - insertText: 'let ${1:argument}', + label: 'case', + documentation: 'case operator', + insertText: [ + 'case "${1:expression}" in', + '\t${2:pattern})', + '\t\t${3:command ...}', + '\t\t;;', + '\t*)', + '\t\t${4:command ...}', + '\t\t;;', + 'end', + ].join('\n'), }, { - documentation: '"test" invocation', - label: 'test', - insertText: - '[[ ${1:argument1} ${2|-ef,-nt,-ot,==,=,!=,=~,<,>,-eq,-ne,-lt,-le,-gt,-ge|} ${3:argument2} ]]', + label: 'function', + documentation: 'function definition', + insertText: ['${1:name}() {', '\t${2:command ...}', '}'].join('\n'), }, { - documentation: 'line print', - label: 'sed:print', - insertText: "sed '' ${1:path/to/file}", + documentation: 'documentation definition', + label: 'documentation', + insertText: [ + '# ${1:function_name} ${2:function_parameters}', + '# ${3:function_description}', + '#', + '# Output:', + '# ${4:function_output}', + '#', + '# Return:', + '# - ${5:0} when ${6:all parameters are correct}', + '# - ${7:1} ${8:otherwise}', + ].join('\n'), }, { - documentation: 'line pattern filter', - label: 'sed:filter-by-line-pattern', - insertText: - "sed ${1|--regexp-extended,-E|} ${2|--quiet,-n|} '/${3:pattern}/p' ${4:path/to/file}", + documentation: 'block', + label: 'block', + insertText: ['{', '\t${1:command ...}', '}'].join('\n'), }, { - documentation: 'line number filter', - label: 'sed:filter-by-line-number', - insertText: - "sed ${1|--regexp-extended,-E|} ${2|--quiet,-n|} '${3:number}p' ${4:path/to/file}", + documentation: 'block redirected', + label: 'block-redirected', + insertText: ['{', '\t${1:command ...}', '} > ${2:file}'].join('\n'), }, { - documentation: 'line number filter', - label: 'sed:filter-by-line-numbers', - insertText: - "sed ${1|--regexp-extended,-E|} ${2|--quiet,-n|} '${3:from},${4:to}p' ${5:path/to/file}", + documentation: 'block stderr redirected', + label: 'block-stderr-redirected', + insertText: ['{', '\t${1:command ...}', '} 2> ${2:file}'].join('\n'), }, { - documentation: 'single replacement', - label: 'sed:replace-first', - insertText: - "sed ${1|--regexp-extended,-E|} 's/${2:pattern}/${3:replacement}/' ${4:path/to/file}", + documentation: 'variable', + label: 'variable', + insertText: 'declare ${1:variable}=${2:value}', }, { - documentation: 'global replacement', - label: 'sed:replace-all', - insertText: - "sed ${1|--regexp-extended,-E|} 's/${2:pattern}/${3:replacement}/g' ${4:path/to/file}", + documentation: 'variable index', + label: 'variable-index', + insertText: '${1:variable}[${2:index}]=${3:value}', }, { - documentation: 'transliteration', - label: 'sed:transliterate', - insertText: - "sed ${1|--regexp-extended,-E|} 'y/${2:source-characters}/${3:replacement-characters}/g' ${4:path/to/file}", + documentation: 'variable append', + label: 'variable-append', + insertText: '${1:variable}+=${2:value}', }, { - documentation: 'whole file read', - label: 'sed:read-all', - insertText: - "sed ${1|--regexp-extended,-E|} ':${2:x} N $! b$2 ${3:command}' ${4:path/to/file}", + documentation: 'variable-prepend', + label: 'variable-prepend', + insertText: '${1:variable}=${2:value}\\$$1', }, { - documentation: 'line print', - label: 'awk:print', - insertText: "awk '/./' ${1:path/to/file}", + documentation: 'if unset or null', + label: 'if-unset-or-null', + insertText: '"\\${${1:variable}:-${2:default}}"', }, { - documentation: 'line pattern filter', - label: 'awk:filter-by-line-pattern', - insertText: "awk '/${1:pattern}/' ${2:path/to/file}", + documentation: 'if unset', + label: 'if-unset', + insertText: '"\\${${1:variable}-${2:default}}"', }, { - documentation: 'line number filter', - label: 'awk:filter-by-line-number', - insertText: "awk 'NR == ${1:number}' ${2:path/to/file}", + documentation: 'set if unset or null', + label: 'set-if-unset-or-null', + insertText: '"\\${${1:variable}:=${2:default}}"', }, { - documentation: 'line number filter', - label: 'awk:filter-by-line-numbers', - insertText: "awk 'NR >= ${1:from} && NR <= ${2:to}' ${3:path/to/file}", + documentation: 'set if unset', + label: 'set-if-unset', + insertText: '"\\${${1:variable}=${2:default}}"', }, { - documentation: 'single replacement', - label: 'awk:replace-first', - insertText: 'awk \'{ sub("${1:pattern}", "${2:replacement}") }\' ${3:path/to/file}', + documentation: 'error if unset or null', + label: 'error-if-unset-or-null', + insertText: '"\\${${1:variable}:?${2:error_message}}"', }, { - documentation: 'global replacement', - label: 'awk:replace-all', - insertText: 'awk \'{ gsub("${1:pattern}", "${2:replacement}") }\' ${3:path/to/file}', + documentation: 'error if unset', + label: 'error-if-unset', + insertText: '"\\${${1:variable}?${2:error_message}}"', }, { - documentation: 'whole file read', - label: 'awk:read-all', - insertText: "awk RS='^$' '{ ${1:command} }' ${2:path/to/file}", + documentation: 'if set or not null', + label: 'if-set-or-not-null', + insertText: '"\\${${1:variable}:+${2:alternative}}"', }, { - documentation: 'node print', - label: 'jq:print', - insertText: "jq '.${1:path/to/node}' ${2:path/to/file}", + documentation: 'if set', + label: 'if-set', + insertText: '"\\${${1:variable}+${2:alternative}}"', }, { - documentation: 'node print', - label: 'yq:print', - insertText: "yq '.${1:path/to/node}' ${2:path/to/file}", + documentation: 'string shortest leading replacement', + label: 'string-remove-leading', + insertText: '"\\${${1:variable}#${2:pattern}}"', }, { - documentation: 'home directory', - label: '~', - insertText: '$HOME', + documentation: 'string shortest trailing replacement', + label: 'string-remove-trailing', + insertText: '"\\${${1:variable}%${2:pattern}}"', }, { - documentation: '[dev]ice name', - label: 'dev', - insertText: '/dev/${1|null,stdin,stdout,stderr|}', + documentation: 'string filtering', + label: 'string-match', + insertText: "sed ${1|-E -n,--regexp-extended --quiet|} '/${2:pattern}/p'", + }, + { + documentation: 'string replacement', + label: 'string-replace', + insertText: "sed ${1|-E,--regexp-extended|} 's/${2:pattern}/${3:replacement}/'", + }, + { + documentation: 'string replacement', + label: 'string-replace-all', + insertText: "sed ${1|-E,--regexp-extended|} 's/${2:pattern}/${3:replacement}/g'", }, { - documentation: '[al]pha[num]eric characters', - label: 'alnum', - insertText: '[[:alnum:]]', + documentation: 'string transliterate', + label: 'string-transliterate', + insertText: + "sed ${1|-E,--regexp-extended|} 'y/${2:source-characters}/${3:replacement-characters}/g'", }, { - documentation: '[alpha]betic characters', - label: 'alpha', - insertText: '[[:alpha:]]', + documentation: 'file print', + label: 'file-print', + insertText: "sed '' ${1:file}", }, { - documentation: '[blank] characters', - label: 'blank', - insertText: '[[:blank:]]', + documentation: 'file read', + label: 'file-read', + insertText: + "sed ${1|-E,--regexp-extended|} ':${2:x} N $! b$2 ${3:command}' ${4:file}", }, { - documentation: '[c]o[nt]ro[l] characters', - label: 'cntrl', - insertText: '[[:cntrl:]]', + documentation: 'skip first', + label: 'skip-first', + insertText: 'tail ${1|-n,-c,--lines,--bytes|} +${2:count}', }, { - documentation: '[digit] characters', - label: 'digit', - insertText: '[[:digit:]]', + documentation: 'skip last', + label: 'skip-last', + insertText: 'head ${1|-n,-c,--lines,--bytes|} -${2:count}', }, { - documentation: '[graph]ical characters', - label: 'graph', - insertText: '[[:graph:]]', + documentation: 'take first', + label: 'take-first', + insertText: 'head ${1|-n,-c,--lines,--bytes|} ${2:count}', }, { - documentation: '[lower] characters', - label: 'lower', - insertText: '[[:lower:]]', + documentation: 'take last', + label: 'take-last', + insertText: 'tail ${1|-n,-c,--lines,--bytes|} ${2:count}', }, { - documentation: '[print]able characters', - label: 'print', - insertText: '[[:print:]]', + documentation: 'take range', + label: 'take-range', + insertText: "sed ${1|-n,--quiet|} '${2:from},${3:to}p'", }, { - documentation: '[punct]uation characters', - label: 'punct', - insertText: '[[:punct:]]', + documentation: 'take stepped range', + label: 'take-stepped-range', + insertText: "sed ${1|-n,--quiet|} '${2:from},${3:to}p' | sed $1 '1~${4:step}p'", }, { - documentation: '[space] characters', - label: 'space', - insertText: '[[:space:]]', + documentation: 'json print', + label: 'json-print', + insertText: "jq '.${1:node}' ${2:file}", }, { - documentation: '[upper] characters', - label: 'upper', - insertText: '[[:upper:]]', + documentation: 'device', + label: 'device', + insertText: '/dev/${1|null,stdin,stdout,stderr|}', + }, + { + documentation: 'completion', + label: 'completion definition', + insertText: [ + '_$1_completions()', + '{', + '\treadarray -t COMPREPLY < <(compgen -W "-h --help -v --version" "\\${COMP_WORDS[1]}")', + '}', + '', + 'complete -F _$1_completions ${1:command}', + ].join('\n'), }, { - documentation: 'hexadecimal characters', - label: 'xdigit', - insertText: '[[:xdigit:]]', + documentation: 'comment', + label: 'comment definition', + insertText: '# ${1:description}', }, ].map((item) => ({ ...item,