# Crystal # https://crystal-lang.org # Detection # ‾‾‾‾‾‾‾‾‾ hook global BufCreate '.*\.cr' %{ set-option buffer filetype crystal } # Initialization # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ hook global WinSetOption filetype=crystal %{ require-module crystal add-highlighter window/crystal ref crystal evaluate-commands set-option window static_words %opt{crystal_keywords} %opt{crystal_attributes} %opt{crystal_objects} hook window ModeChange pop:insert:.* -group crystal-trim-indent crystal-trim-indent hook window InsertChar .* -group crystal-indent crystal-indent-on-char hook window InsertChar '\n' -group crystal-indent crystal-indent-on-new-line hook window InsertChar '\n' -group crystal-insert crystal-insert-on-new-line hook -always -once window WinSetOption filetype=.* %{ remove-highlighter window/crystal remove-hooks window crystal-.+ } } provide-module crystal %§ declare-option -hidden str-list crystal_keywords 'abstract' 'alias' 'annotation' 'as' 'asm' 'begin' 'break' 'case' 'class' 'def' 'do' 'else' 'elsif' 'end' 'ensure' 'enum' 'extend' 'false' 'for' 'fun' 'if' 'include' 'instance_sizeof' 'is_a?' 'lib' 'macro' 'module' 'next' 'nil' 'nil?' 'of' 'offsetof' 'out' 'pointerof' 'private' 'protected' 'require' 'rescue' 'responds_to?' 'return' 'select' 'self' 'sizeof' 'struct' 'super' 'then' 'true' 'type' 'typeof' 'uninitialized' 'union' 'unless' 'until' 'verbatim' 'when' 'while' 'with' 'yield' # https://crystal-lang.org/reference/syntax_and_semantics/methods_and_instance_variables.html#getters-and-setters declare-option -hidden str-list crystal_attributes 'getter' 'setter' 'property' declare-option -hidden str-list crystal_operators '+' '-' '*' '/' '//' '%' '|' '&' '^' '~' '**' '<<' '<' '<=' '==' '!=' '=~' '!~' '>>' '>' '>=' '<=>' '===' '[]' '[]=' '[]?' '[' '&+' '&-' '&*' '&**' declare-option -hidden str-list crystal_objects 'Adler32' 'ArgumentError' 'Array' 'Atomic' 'Base64' 'Benchmark' 'BigDecimal' 'BigFloat' 'BigInt' 'BigRational' 'BitArray' 'Bool' 'Box' 'Bytes' 'Channel' 'Char' 'Class' 'Colorize' 'Comparable' 'Complex' 'Concurrent' 'ConcurrentExecutionException' 'CRC32' 'Crypto' 'Crystal' 'CSV' 'Debug' 'Deprecated' 'Deque' 'Digest' 'Dir' 'DivisionByZeroError' 'DL' 'ECR' 'Enum' 'Enumerable' 'ENV' 'Errno' 'Exception' 'Fiber' 'File' 'FileUtils' 'Flags' 'Flate' 'Float' 'Float32' 'Float64' 'GC' 'Gzip' 'Hash' 'HTML' 'HTTP' 'Indexable' 'IndexError' 'INI' 'Int' 'Int128' 'Int16' 'Int32' 'Int64' 'Int8' 'InvalidBigDecimalException' 'InvalidByteSequenceError' 'IO' 'IPSocket' 'Iterable' 'Iterator' 'JSON' 'KeyError' 'Levenshtein' 'Link' 'LLVM' 'Logger' 'Markdown' 'Math' 'MIME' 'Mutex' 'NamedTuple' 'Nil' 'NilAssertionError' 'NotImplementedError' 'Number' 'OAuth' 'OAuth2' 'Object' 'OpenSSL' 'OptionParser' 'OverflowError' 'PartialComparable' 'Path' 'Pointer' 'PrettyPrint' 'Proc' 'Process' 'Random' 'Range' 'Readline' 'Reference' 'Reflect' 'Regex' 'SemanticVersion' 'Set' 'Signal' 'Slice' 'Socket' 'Spec' 'StaticArray' 'String' 'StringPool' 'StringScanner' 'Struct' 'Symbol' 'System' 'TCPServer' 'TCPSocket' 'Termios' 'Time' 'Tuple' 'TypeCastError' 'UDPSocket' 'UInt128' 'UInt16' 'UInt32' 'UInt64' 'UInt8' 'Unicode' 'Union' 'UNIXServer' 'UNIXSocket' 'URI' 'UUID' 'VaList' 'Value' 'WeakRef' 'XML' 'YAML' 'Zip' 'Zlib' # Highlighters # ‾‾‾‾‾‾‾‾‾‾‾‾ add-highlighter shared/crystal regions add-highlighter shared/crystal/code default-region group # Comments # https://crystal-lang.org/reference/syntax_and_semantics/comments.html # Avoid string literals with interpolation add-highlighter shared/crystal/comment region '#(?!\{)' '$' fill comment # String # https://crystal-lang.org/reference/syntax_and_semantics/literals/string.html add-highlighter shared/crystal/string region '"' '(?' regions add-highlighter shared/crystal/pipe-string region '%Q?\|' '\|' regions # Raw # https://crystal-lang.org/reference/syntax_and_semantics/literals/string.html#percent-string-literals # https://crystal-lang.org/reference/syntax_and_semantics/literals/string.html#percent-string-array-literal # https://crystal-lang.org/reference/syntax_and_semantics/literals/symbol.html#percent-symbol-array-literal add-highlighter shared/crystal/raw-parenthesis-string region -recurse '\(' '%[qwi]\(' '\)' fill string add-highlighter shared/crystal/raw-bracket-string region -recurse '\[' '%[qwi]\[' '\]' fill string add-highlighter shared/crystal/raw-brace-string region -recurse '\{' '%[qwi]\{' '\}' fill string add-highlighter shared/crystal/raw-angle-string region -recurse '<' '%[qwi]<' '>' fill string add-highlighter shared/crystal/raw-pipe-string region '%[qwi]\|' '\|' fill string # Here document # https://crystal-lang.org/reference/syntax_and_semantics/literals/string.html#heredoc add-highlighter shared/crystal/heredoc region -match-capture '<<-(\w+)' '^\h*(\w+)$' regions # Raw add-highlighter shared/crystal/raw-heredoc region -match-capture "<<-'(\w+)'" '^\h*(\w+)$' regions add-highlighter shared/crystal/raw-heredoc/fill default-region fill string add-highlighter shared/crystal/raw-heredoc/interpolation region -recurse '\{' '#\{' '\}' fill meta # Symbol # https://crystal-lang.org/reference/syntax_and_semantics/literals/symbol.html add-highlighter shared/crystal/quoted-symbol region ':"' '(?[imx]*' regions add-highlighter shared/crystal/pipe-regex region '%r?\|' '\|[imx]*' regions # Command # https://crystal-lang.org/reference/syntax_and_semantics/literals/command.html add-highlighter shared/crystal/command region '`' '(?' regions add-highlighter shared/crystal/pipe-command region '%x?\|' '\|' regions evaluate-commands %sh[ # Keywords eval "set -- $kak_quoted_opt_crystal_keywords" regex="\\b(?:\\Q$1\\E" shift for keyword do regex="$regex|\\Q$keyword\\E" done regex="$regex)\\b" printf 'add-highlighter shared/crystal/code/keywords regex %s 0:keyword\n' "$regex" # Attributes eval "set -- $kak_quoted_opt_crystal_attributes" regex="\\b(?:\\Q$1\\E" shift for attribute do regex="$regex|\\Q$attribute\\E" done regex="$regex)\\b" printf 'add-highlighter shared/crystal/code/attributes regex %s 0:attribute\n' "$regex" # Symbols eval "set -- $kak_quoted_opt_crystal_operators" # Avoid to match modules regex="(? # remove trailing white spaces try %{ execute-keys -draft s \h+$ d } } } define-command -hidden crystal-indent-on-char %{ evaluate-commands -no-hooks -draft -itersel %{ # align 'else' to 'if/case' try %{ execute-keys -draft ^\h*else$ i ^\h*(?:if|case) 1 } # align 'elsif' to 'if' try %{ execute-keys -draft ^\h*elsif$ i ^\h*(?:if) 1 } # align 'when' to 'case' try %{ execute-keys -draft ^\h*when$ i ^\h*(?:case) 1 } # align 'rescue' to 'begin/def' try %{ execute-keys -draft ^\h*rescue$ i ^\h*(?:begin|def) 1 } # align 'end' to opening structure try %{ execute-keys -draft ^\h*end$ i ^\h*(?:begin|case|class|def|for|if|module|unless|until|while) 1 } } } define-command -hidden crystal-indent-on-new-line %{ evaluate-commands -no-hooks -draft -itersel %{ # Copy previous line indent try %{ execute-keys -draft K } # Remove previous line's trailing spaces try %{ execute-keys -draft k :crystal-trim-indent } # Indent after start structure/opening statement try %{ execute-keys -draft k ^\h*(?:begin|case|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while|.+\bdo$|.+\bdo\h\|.+(?=\|))[^0-9A-Za-z_!?] j } } } define-command -hidden crystal-insert-on-new-line %[ evaluate-commands -no-hooks -draft -itersel %[ # copy _#_ comment prefix and following white spaces try %{ execute-keys -draft k s '^\h*\K#\h*' y j P } # wisely add end structure evaluate-commands -save-regs x %[ try %{ execute-keys -draft k s ^ \h + \" x y } catch %{ reg x '' } try %[ evaluate-commands -draft %[ # Check if previous line opens a block execute-keys -draft k ^x(?:begin|case|class|def|for|if|module|unless|until|while|.+\bdo$|.+\bdo\h\|.+(?=\|))[^0-9A-Za-z_!?] # Check that we do not already have an end for this indent level which is first set via `crystal-indent-on-new-line` hook execute-keys -draft }i J ^x(?:end|else|elsif|rescue|when)[^0-9A-Za-z_!?] ] execute-keys -draft oxend # insert a new line with containing end ] ] ] ] define-command -hidden crystal-fetch-keywords %{ set-register dquote %sh{ curl --location https://github.com/crystal-lang/crystal/raw/master/src/compiler/crystal/syntax/lexer.cr | kak -f '%1scheck_ident_or_keyword\(:(\w+\??), \w+\)y%aa|sort' } } define-command -hidden crystal-fetch-operators %{ set-register dquote %sh{ curl --location https://github.com/crystal-lang/crystal/raw/master/src/compiler/crystal/syntax/parser.cr | kak -f '/AtomicWithMethodCheck =x1s:"([^"]+)"y%i''a''a' } } define-command -hidden crystal-fetch-objects %{ set-register dquote %sh{ curl --location https://crystal-lang.org/api/ | # Remove Top Level Namespace kak -f '%1sdata-id="github.com/crystal-lang/crystal/(\w+)")y%aa' } } §