# 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 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/elsif' to 'if' try %{ execute-keys -draft ^\h*(?:else|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 previos line's trailing spaces try %{ execute-keys -draft k :ruby-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 whitespaces try %{ execute-keys -draft k s '^\h*\K#\h*' y j gl p } # Add `end` token if needs be # The 'x' register is to save the leading whitespaces of the opening token evaluate-commands -save-regs x %[ # Save the leading whitespaces in register 'x' try %{ execute-keys -draft k s ^\h* \" x y } try %[ evaluate-commands -draft %[ # Make sure previous line opens a block execute-keys -draft k ^x(?:begin|case|class|def|for|if|module|unless|until|while|.+\bdo\h\|.+(?=\|))[^0-9A-Za-z_!?] # Make sure `end` doesn't already exist on indent level execute-keys -draft }i J ^x(?:end|else|elsif|rescue|when)[^0-9A-Za-z_!?] ] # Insert new line with end prepended by contents of register 'x' execute-keys -draft o x 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' } } §