diff options
author | thing1 <thing1@seacrossedlovers.xyz> | 2025-01-28 09:14:32 +0000 |
---|---|---|
committer | thing1 <thing1@seacrossedlovers.xyz> | 2025-01-28 09:14:32 +0000 |
commit | 904cec3c4a329cf89fc3219d359239910d61f3f6 (patch) | |
tree | 8d113899921dfbaca0e77c49ab5fc827362d1091 /autoload/filetype/ocaml.kak |
Diffstat (limited to 'autoload/filetype/ocaml.kak')
-rw-r--r-- | autoload/filetype/ocaml.kak | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/autoload/filetype/ocaml.kak b/autoload/filetype/ocaml.kak new file mode 100644 index 0000000..06a1bf5 --- /dev/null +++ b/autoload/filetype/ocaml.kak @@ -0,0 +1,130 @@ +# http://ocaml.org +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +# Detection +# ‾‾‾‾‾‾‾‾‾ + +hook global BufCreate .*\.(ml|mli|mll|mly)$ %{ + set-option buffer filetype ocaml +} + +# Initialization +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +hook global WinSetOption filetype=ocaml %{ + require-module ocaml + set-option window static_words %opt{ocaml_static_words} + hook window InsertChar -group ocaml-insert '\*' ocaml-insert-closing-comment-bracket + hook window InsertChar \n -group ocaml-insert ocaml-insert-on-new-line + hook window ModeChange pop:insert:.* -group ocaml-trim-indent ocaml-trim-indent +} + +hook -group ocaml-highlight global WinSetOption filetype=ocaml %{ + add-highlighter window/ocaml ref ocaml + alias window alt ocaml-alternative-file + hook -once -always window WinSetOption filetype=.* %{ + unalias window alt ocaml-alternative-file + remove-highlighter window/ocaml + } +} + +provide-module ocaml %{ + +# Highlighters +# ‾‾‾‾‾‾‾‾‾‾‾‾ + +add-highlighter shared/ocaml regions +add-highlighter shared/ocaml/code default-region group +add-highlighter shared/ocaml/string region (?<!['\\])" (?<!\\)(\\\\)*" fill string +add-highlighter shared/ocaml/quotedstring region -match-capture %"\{(\w*)\|" %"\|(\w*)\}" fill string +add-highlighter shared/ocaml/comment region -recurse \Q(* \Q(* \Q*) fill comment + +add-highlighter shared/ocaml/code/char regex %{\B'([^'\\]|(\\[\\"'nrtb])|(\\\d{3})|(\\x[a-fA-F0-9]{2})|(\\o[0-7]{3}))'\B} 0:value + +# integer literals +add-highlighter shared/ocaml/code/ regex \b[0-9][0-9_]*([lLn]?)\b 0:value +add-highlighter shared/ocaml/code/ regex \b0[xX][A-Fa-f0-9][A-Fa-f0-9_]*([lLn]?)\b 0:value +add-highlighter shared/ocaml/code/ regex \b0[oO][0-7][0-7_]*([lLn]?)\b 0:value +add-highlighter shared/ocaml/code/ regex \b0[bB][01][01_]*([lLn]?)\b 0:value +# float literals +add-highlighter shared/ocaml/code/ regex \b[0-9][0-9_]*(\.[0-9_]*)?([eE][+-]?[0-9][0-9_]*)? 0:value +add-highlighter shared/ocaml/code/ regex \b0[xX][A-Fa-f0-9][A-Fa-f0-9]*(\.[a-fA-F0-9_]*)?([pP][+-]?[0-9][0-9_]*)? 0:value +# constructors. must be put before any module name highlighter, as a fallback for capitalized identifiers +add-highlighter shared/ocaml/code/ regex \b[A-Z][a-zA-Z0-9_]*\b 0:value +# the module name in a module path, e.g. 'M' in 'M.x' +add-highlighter shared/ocaml/code/ regex (\b[A-Z][a-zA-Z0-9_]*[\h\n]*)(?=\.) 0:module +# (simple) module declarations +add-highlighter shared/ocaml/code/ regex (?<=module)([\h\n]+[A-Z][a-zA-Z0-9_]*) 0:module +# (simple) signature declarations. 'type' is also highlighted, due to the lack of quantifiers in lookarounds. +# Hence we must put keyword highlighters after this to recover proper highlight for 'type' +add-highlighter shared/ocaml/code/ regex (?<=module)([\h\n]+type[\h\n]+[A-Z][a-zA-Z0-9_]*) 0:module +# (simple) open statements +add-highlighter shared/ocaml/code/ regex (?<=open)([\h\n]+[A-Z][a-zA-Z0-9_]*) 0:module +# operators +add-highlighter shared/ocaml/code/ regex [@!$%%^&*\-+=|<>/?]+ 0:operator + + +# Macro +# ‾‾‾‾‾ + +evaluate-commands %sh{ + keywords="and|as|asr|assert|begin|class|constraint|do|done|downto|else|end|exception|external|false" + keywords="${keywords}|for|fun|function|functor|if|in|include|inherit|initializer|land|lazy|let|lor" + keywords="${keywords}|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|object|of|open|or" + keywords="${keywords}|private|rec|sig|struct|then|to|true|try|type|val|virtual|when|while|with" + + printf %s\\n "declare-option str-list ocaml_static_words ${keywords}" | tr '|' ' ' + +# must be put at last, since we have highlighted some keywords ('type' in 'module type') to other things + printf %s " + add-highlighter shared/ocaml/code/ regex \b(${keywords})\b 0:keyword + " +} + +# Conveniences +# ‾‾‾‾‾‾‾‾‾‾‾‾ + +# C has header and source files and you need to often switch between them. +# Similarly OCaml has .ml (implementation) and .mli (interface files) and +# one often needs to switch between them. +# +# This command provides a simple functionality that allows you to accomplish this. +define-command ocaml-alternative-file -docstring 'Switch between .ml and .mli file or vice versa' %{ + evaluate-commands %sh{ + if [ "${kak_buffile##*.}" = 'ml' ]; then + printf "edit -- '%s'" "$(printf %s "${kak_buffile}i" | sed "s/'/''/g")" + elif [ "${kak_buffile##*.}" = 'mli' ]; then + printf "edit -- '%s'" "$(printf %s "${kak_buffile%i}" | sed "s/'/''/g")" + fi + } +} + +} + +# Remove trailing whitespaces +define-command -hidden ocaml-trim-indent %{ + evaluate-commands -no-hooks -draft -itersel %{ + try %{ execute-keys -draft x s \h+$ <ret> d } + } +} + +# Preserve indentation when creating new line +define-command -hidden ocaml-insert-on-new-line %{ + evaluate-commands -draft -itersel %{ + # copy white spaces at the beginnig of the previous line + try %{ execute-keys -draft k x s ^\h+ <ret> y jgh P x s \h+$ <a-d> } + # increase indentation if the previous line ended with either '=' sign or do keyword + try %{ execute-keys -draft k x s (=|\bdo)$ <ret> j <a-gt> } + } +} + +# The OCaml comment is `(* Some comment *)`. Like the C-family this can be a multiline comment. +# +# Recognize when the user is trying to commence a comment when they type `(*` and +# then automatically insert `*)` on behalf of the user. A small convenience. +define-command -hidden ocaml-insert-closing-comment-bracket %{ + try %{ + execute-keys -draft 'HH<a-k>\(\*<ret>' + execute-keys ' *)<left><left><left>' + } +} |