# http://rust-lang.org # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Detection # ‾‾‾‾‾‾‾‾‾ hook global BufCreate .*[.](rust|rs) %{ set-option buffer filetype rust } # Initialization # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ hook global WinSetOption filetype=rust %< require-module rust hook window ModeChange pop:insert:.* -group rust-trim-indent rust-trim-indent hook window InsertChar \n -group rust-indent rust-indent-on-new-line hook window InsertChar \{ -group rust-indent rust-indent-on-opening-curly-brace hook window InsertChar [)}\]] -group rust-indent rust-indent-on-closing hook -once -always window WinSetOption filetype=.* %{ remove-hooks window rust-.+ } > hook -group rust-highlight global WinSetOption filetype=rust %{ add-highlighter window/rust ref rust hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/rust } } provide-module rust %§ # Highlighters # ‾‾‾‾‾‾‾‾‾‾‾‾ add-highlighter shared/rust regions add-highlighter shared/rust/code default-region group add-highlighter shared/rust/string region %{(?]+?>)?\( 1:function add-highlighter shared/rust/code/variable_declaration regex (?:let\h+(?:mut\h+)?)(_?\w+) 1:variable add-highlighter shared/rust/code/macro regex \b[A-z0-9_]+! 0:meta # the number literals syntax is defined here: # https://doc.rust-lang.org/reference/tokens.html#numbers add-highlighter shared/rust/code/values regex \b(?:self|true|false|[0-9][_0-9]*(?:\.[0-9][_0-9]*|(?:\.[0-9][_0-9]*)?E[\+\-][_0-9]+)(?:f(?:32|64))?|(?:0x[_0-9a-fA-F]+|0o[_0-7]+|0b[_01]+|[0-9][_0-9]*)(?:(?:i|u|f)(?:8|16|32|64|128|size))?)\b 0:value add-highlighter shared/rust/code/attributes regex \b(?:trait|struct|enum|union|type|mut|ref|static|const|default)\b 0:attribute # the language keywords are defined here, but many of them are reserved and unused yet: # https://doc.rust-lang.org/reference/keywords.html add-highlighter shared/rust/code/keywords regex \b(?:let|as|fn|return|match|if|else|loop|for|in|while|break|continue|move|box|where|impl|dyn|pub|unsafe|async|await|mod|crate|use|extern)\b 0:keyword add-highlighter shared/rust/code/char_character regex "'([^\\]|\\(.|x[0-9a-fA-F]{2}|u\{[0-9a-fA-F]{1,6}\}))'" 0:green # TODO highlight error for unicode or single escape byte character add-highlighter shared/rust/code/byte_character regex b'([\x00-\x5B\x5D-\x7F]|\\(.|x[0-9a-fA-F]{2}))' 0:yellow add-highlighter shared/rust/code/builtin_types regex \b(?:u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize|f32|f64|bool|char|str|Self)\b 0:type add-highlighter shared/rust/code/return regex \breturn\b 0:meta # Commands # ‾‾‾‾‾‾‾‾ define-command -hidden rust-trim-indent %{ # remove trailing white spaces try %{ execute-keys -draft -itersel s \h+$ d } } define-command -hidden rust-indent-on-new-line %~ evaluate-commands -draft -itersel %< try %{ try %[ # line comment evaluate-commands -draft -save-regs '/"' %[ # copy the commenting prefix execute-keys -save-regs '' k s ^\h*//[!/]{0,2}\h* y try %[ # if the previous comment isn't empty, create a new one execute-keys ^\h*//[!/]{0,2}$ js^\h*P ] catch %[ # TODO figure out a way to not delete empty comment in current line # if there is no space and text in the previous comment, remove it completely execute-keys s //.* d ] ] ] catch %[ # block comment # if the previous line isn't within a comment scope, break execute-keys -draft k ^(\h*/\*|\h+\*(?!/)) # find comment opening, validate it was not closed, and check its using star prefixes execute-keys -draft /\* \*/ \A\h*/\*([^\n]*\n\h*\*)*[^\n]*\n\h*.\z try %[ # if the previous line is opening the comment, insert star preceeded by space execute-keys -draft k^\h*/\* execute-keys -draft i* ] catch %[ try %[ # if the next line is a comment line insert a star execute-keys -draft j^\h+\* execute-keys -draft i* ] catch %[ try %[ # if the previous line is an empty comment line, close the comment scope execute-keys -draft k^\h+\*\h+$ 1s\*(\h*)c/ ] catch %[ # if the previous line is a non-empty comment line, add a star execute-keys -draft i* ] ] ] # trim trailing whitespace on the previous line try %[ execute-keys -draft s\h+$ d ] # align the new star with the previous one execute-keys K1s^[^*]*(\*)& ] } catch %` # re-indent previous line if it starts with where to match previous block try %+ execute-keys -draft k ^\h*where\b hh ^\h*\b(impl|fn|struct|enum|union)\b 1 + # preserve previous line indent try %{ execute-keys -draft K } # indent after lines ending with [{([].+ and move first parameter to own line try %< execute-keys -draft [c[({[],[)}\]] \A[({[][^\n]+\n[^\n]*\n?\z L i > # indent after non-empty lines not starting with operator and not ending with , or ; or { # XXX simplify this into a single without s try %< execute-keys -draft k s [^\h].+ \A[-+*/&|^})#] [,{](\h*/[/*].*|)$ j > # indent after lines ending with { try %< execute-keys -draft k \{$ j > # dedent after lines starting with . and ending with } or ) or , or ; or .await try %_ execute-keys -draft k ^\h*\. ([}),]|\.await)\h*$ j _ # align to opening curly brace or paren when newline is inserted before a single closing try %< execute-keys -draft ^\h*[)}] h m 1 > # todo dedent additional unmatched parenthesis # try %& execute-keys -draft k s \((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\) l Gl s\) %sh{ # count previous selections length # printf "j $(echo $kak_selections_length | wc -w) " # } & ` # filter previous line try %{ execute-keys -draft k : rust-trim-indent } > ~ define-command -hidden rust-indent-on-opening-curly-brace %[ evaluate-commands -draft -itersel %_ # align indent with opening paren when { is entered on a new line after the closing paren try %[ execute-keys -draft h ) M \A\(.*\)\h*\n\h*\{\z s \A|.\z 1 ] # dedent standalone { after impl and related block without any { in between try %< execute-keys -draft hh ^\h*\b(impl|fn|struct|enum|union|if|for)\b \{ ll ^\h*\{$ > _ ] define-command -hidden rust-indent-on-closing %~ evaluate-commands -draft -itersel %_ # align to opening curly brace or paren when alone on a line try %< execute-keys -draft ^\h*[)}\]]$ h m 1 > _ ~ §