# 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 %{(?|<|%)=? 0:operator add-highlighter shared/rust/code/operators_as regex \bas\b 0:operator add-highlighter shared/rust/code/ref_ref regex (&\h+[&~@*])[^)=\s\t\r\n] 1:type add-highlighter shared/rust/code/ref regex ([&~@*])[^)=\s\t\r\n] 1:type add-highlighter shared/rust/code/operators_logic regex &&|\|\| 0:operator add-highlighter shared/rust/code/lifetime_or_loop_label regex ('([a-zA-Z]\w+|_\w+))\b 1:meta add-highlighter shared/rust/code/namespace regex \b[a-zA-Z](\w+)?(\h+)?(?=::) 0:module add-highlighter shared/rust/code/mod_path_sep regex :: 0:meta add-highlighter shared/rust/code/question_mark regex \? 0:meta # 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/function_call regex _?[a-zA-Z]\w*\s*(?=\() 0:function add-highlighter shared/rust/code/generic_function_call regex _?[a-zA-Z]\w*\s*(?=::<) 0:function add-highlighter shared/rust/code/function_declaration regex (?:fn\h+)(_?\w+)(?:<[^>]+?>)?\( 1:function add-highlighter shared/rust/code/keywords regex \b(?:as|break|continue|crate|else|enum|extern|false|fn|for|if|impl|in|let|loop|match|mod|pub|return|self|Self|struct|super|trait|true|type|unsafe|use|where|while|async|await|dyn|abstract|become|box|do|try)\b 0:keyword add-highlighter shared/rust/code/storage regex \b(move|mut|ref|static|const)\b 0:type add-highlighter shared/rust/code/pub_with_scope regex \b(pub)\h*(\()\h*(crate|super|self|in\h+[\w:]+)\h*(\)) 1:keyword 2:meta 4:meta # after let can be an arbitrary pattern match add-highlighter shared/rust/code/macro regex \b\w+! 0:meta # the number literals syntax is defined here: # https://doc.rust-lang.org/reference/tokens.html#numb ers 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/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 by te 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 add-highlighter shared/rust/code/enum regex \b(Option|Result)\b 0:type add-highlighter shared/rust/code/enum_variant regex \b(Some|None|Ok|Err)\b 0:value add-highlighter shared/rust/code/std_traits regex \b(Copy|Send|Sized|Sync|Drop|Fn|FnMut|FnOnce|Box|ToOwned|Clone|PartialEq|PartialOrd|Eq|Ord|AsRef|AsMut|Into|From|Default|Iterator|Extend|IntoIterator|DoubleEndedIterator|ExactSizeIterator|SliceConcatExt|String|ToString|Vec)\b 0:type # 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 # string literal parsing within extern does not handle escape try %% execute-keys -draft k ^\h*where\b hh ^\h*\b(impl|((|pub\ |pub\((crate|self|super|in\ (::)?([a-zA-Z][a-zA-Z0-9_]*|_[a-zA-Z0-9_]+)(::[a-zA-Z][a-zA-Z0-9_]*|_[a-zA-Z0-9_]+)*)\)\ )((async\ |const\ )?(unsafe\ )?(extern\ ("[^"]*"\ )?)?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 (} or ) or .await maybe with ?) try %_ execute-keys -draft k ^\h*\. ([,]|(([})]|\.await)\?*))\h*$ j _ # dedent after lines ending with " => {}" - part of empty match try %# execute-keys -draft k \ =>\ \{\}\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|((|pub\ |pub\((crate|self|super|in\ (::)?([a-zA-Z][a-zA-Z0-9_]*|_[a-zA-Z0-9_]+)(::[a-zA-Z][a-zA-Z0-9_]*|_[a-zA-Z0-9_]+)*)\)\ )((async\ |const\ )?(unsafe\ )?(extern\ ("[^"]*"\ )?)?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 > _ ~ §