diff --git a/rc/filetype/crystal.kak b/rc/filetype/crystal.kak index ae1ce819..6e76b2da 100644 --- a/rc/filetype/crystal.kak +++ b/rc/filetype/crystal.kak @@ -1,102 +1,118 @@ # Crystal # https://crystal-lang.org +# Detection +# ‾‾‾‾‾‾‾‾‾ + hook global BufCreate '.*\.cr' %{ - set-option buffer filetype crystal + set-option buffer filetype crystal } +# Initialization +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + hook global WinSetOption filetype=crystal %{ - require-module crystal - evaluate-commands set-option window static_words %opt{crystal_keywords} %opt{crystal_attributes} %opt{crystal_objects} - add-highlighter window/crystal ref crystal - hook -group crystal window InsertChar '\n' crystal-new-line-inserted - hook -always -once window WinSetOption filetype=.* %{ - remove-highlighter window/crystal - remove-hooks window 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' +provide-module crystal %§ - add-highlighter shared/crystal regions - add-highlighter shared/crystal/code default-region group +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' - # Comments - # https://crystal-lang.org/reference/syntax_and_semantics/comments.html - # Avoid string literals with interpolation - add-highlighter shared/crystal/comment region '#(?!\{)' '$' fill comment +# Highlighters +# ‾‾‾‾‾‾‾‾‾‾‾‾ - # 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 +# Comments +# https://crystal-lang.org/reference/syntax_and_semantics/comments.html +# Avoid string literals with interpolation +add-highlighter shared/crystal/comment region '#(?!\{)' '$' fill comment - # 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 +# 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 - # Regular expressions - # https://crystal-lang.org/reference/syntax_and_semantics/literals/regex.html - # https://crystal-lang.org/reference/syntax_and_semantics/literals/regex.html#modifiers - add-highlighter shared/crystal/regex region '/' '(?' fill string +add-highlighter shared/crystal/raw-pipe-string region '%[qwi]\|' '\|' fill string - # Percent regex literals - # https://crystal-lang.org/reference/syntax_and_semantics/literals/regex.html#percent-regex-literals - add-highlighter shared/crystal/parenthesis-regex region -recurse '\(' '%r?\(' '\)[imx]*' regions - add-highlighter shared/crystal/bracket-regex region -recurse '\[' '%r?\[' '\][imx]*' regions - add-highlighter shared/crystal/brace-regex region -recurse '\{' '%r?\{' '\}[imx]*' regions - add-highlighter shared/crystal/angle-regex region -recurse '<' '%r?<' '>[imx]*' regions - add-highlighter shared/crystal/pipe-regex region '%r?\|' '\|[imx]*' regions +# 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 - # 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 +# Regular expressions +# https://crystal-lang.org/reference/syntax_and_semantics/literals/regex.html +# https://crystal-lang.org/reference/syntax_and_semantics/literals/regex.html#modifiers +add-highlighter shared/crystal/regex 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" + regex="$regex|\\Q$keyword\\E" done regex="$regex)\\b" printf 'add-highlighter shared/crystal/code/keywords regex %s 0:keyword\n' "$regex" @@ -106,7 +122,7 @@ provide-module crystal %🐈 regex="\\b(?:\\Q$1\\E" shift for attribute do - regex="$regex|\\Q$attribute\\E" + regex="$regex|\\Q$attribute\\E" done regex="$regex)\\b" printf 'add-highlighter shared/crystal/code/attributes regex %s 0:attribute\n' "$regex" @@ -116,7 +132,7 @@ provide-module crystal %🐈 # Avoid to match modules regex="(?' - } - # Remove empty line indent - try %{ - execute-keys -draft 'ks^\h+$d' - } - } +# Commands +# ‾‾‾‾‾‾‾‾ - define-command -hidden crystal-fetch-keywords %{ +define-command -hidden crystal-trim-indent %{ + evaluate-commands -no-hooks -draft -itersel %{ + execute-keys + # 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 :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 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' + 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 %{ +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' + 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 %{ +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' + curl --location https://crystal-lang.org/api/ | + # Remove Top Level Namespace + kak -f '%1sdata-id="github.com/crystal-lang/crystal/(\w+)")y%aa' } - } -🐈 +} + +§