# http://hjson.github.io
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾

# Detection
# ‾‾‾‾‾‾‾‾‾

hook global BufCreate .*[.](hjson) %{
    set-option buffer filetype hjson
}

# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾

hook global WinSetOption filetype=hjson %{
    require-module hjson

    hook window ModeChange pop:insert:.* -group hjson-trim-indent hjson-trim-indent
    hook window InsertChar .* -group hjson-indent hjson-indent-on-char
    hook window InsertChar \n -group hjson-indent hjson-indent-on-new-line

    hook -once -always window WinSetOption filetype=.* %{ remove-hooks window hjson-.+ }
}

hook -group hjson-highlight global WinSetOption filetype=hjson %{
    add-highlighter window/hjson ref hjson
    hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/hjson }
}


provide-module hjson %(

# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾

add-highlighter shared/hjson regions
add-highlighter shared/hjson/code default-region group
add-highlighter shared/hjson/string region '"' (?<!\\)(\\\\)*" fill string
add-highlighter shared/hjson/string2 region "'" (?<!\\)(\\\\)*' fill string
add-highlighter shared/hjson/triple_string region -match-capture ("""|''') (?<!\\)(?:\\\\)*("""|''') fill string
add-highlighter shared/hjson/comment1 region '#' '$' fill comment
add-highlighter shared/hjson/comment2 region '//' '$' fill comment
add-highlighter shared/hjson/multiline_comment region /\* \*/ fill comment

# The below isn't perfect, as it doesn't work if multiple member-value pairs are defined on the same line,
# and it mistakenly highlights comments at the end of a quoteless string,
# but eh - it's good enough for the vast majority of real-world cases,
# and it's annoying to make this work right with Kakoune highlighters alone.
add-highlighter shared/hjson/code/ regex ^(\s*[^,:\[\]\{\}\s]+):\s+([^\{\}\[\]:,][^\r\n]*)? 1:variable 2:string

add-highlighter shared/hjson/code/ regex \b(true|false|null|\d+(?:\.\d+)?(?:[eE][+-]?\d*)?)\b 0:value

# Commands
# ‾‾‾‾‾‾‾‾

define-command -hidden hjson-trim-indent %{
    # remove trailing white spaces
    try %{ execute-keys -draft -itersel x s \h+$ <ret> d }
}

define-command -hidden hjson-indent-on-char %<
    evaluate-commands -draft -itersel %<
        # align closer token to its opener when alone on a line
        try %< execute-keys -draft <a-h> <a-k> ^\h+[\]}]$ <ret> m <a-S> 1<a-&> >
    >
>

define-command -hidden hjson-indent-on-new-line %{ 
    evaluate-commands -itersel -draft %{
        execute-keys <semicolon>
        try %{
            evaluate-commands -draft -save-regs '/"' %{
                # Ensure previous line is a comment
                # This only supports "#" comments (because hjson supporting # and // comments was a mistake)
                execute-keys -draft kxs^\h*#+\h*<ret>

                # now handle the coment continuation logic
                try %{
                    # try and match a regular block comment, copying the prefix
                    execute-keys -draft -save-regs '' k x 1s^(\h*#+\h*)\S.*$ <ret> y
                    execute-keys -draft P
                } catch %{
                    try %{
                        # try and match a regular block comment followed by a single
                        # empty comment line
                        execute-keys -draft -save-regs '' kKx 1s^(\h*#+\h*)\S+\n\h*#+\h*$ <ret> y
                        execute-keys -draft P
                    } catch %{
                        try %{
                            # try and match a pair of empty comment lines, and delete
                            # them if we match
                            execute-keys -draft kKx <a-k> ^\h*#+\h*\n\h*#+\h*$ <ret> <a-d>
                        } catch %{
                            # finally, we need a special case for a new line inserted
                            # into a file that consists of a single empty comment - in
                            # that case we can't expect to copy the trailing whitespace,
                            # so we add our own
                            execute-keys -draft -save-regs '' k x1s^(\h*#+)\h*$<ret> y
                            execute-keys -draft P
                            execute-keys -draft i<space>
                        }
                    }
                }
            }

            # trim trailing whitespace on the previous line
            try %{ execute-keys -draft k x s\h+$<ret> d }
        }
    }
}

)

