(local M {})

(fn make-uniq [str]
  (.. "<plug>(" str ")"))

(fn map [mode lhs rhs remap]
  (vim.keymap.set mode lhs rhs { :expr (vim.is_callable rhs) :remap remap }))

;;;@class Autos
;;;@field entering (fun(): string?|string)?
;;;@field repeating (fun(): string?|string)?
;;;@field leaving (fun(): string?|string)? (reserved)

;;;@class Follower
;;;@field key string
;;;@field run-when Autos?

;;;@param mode string|string[]
;;;@param leader string
;;;@param followers Follower[]
(fn M.set-submode-keymap [mode leader followers]
  (let [uniqid (make-uniq leader)
        uniqpre (.. uniqid leader)]
    (each [_ {: key : run-when} (ipairs followers)]
      (let [k (.. leader key)
            get-rhs (lambda [any]
                      (case (type any)
                        :nil :nil
                        :string (.. any uniqpre)
                        :function (.. (or (any) "") uniqpre)
                        _ (.. k uniqpre)))]
        (map mode k (get-rhs run-when.entering) true)
        (map mode (.. uniqpre key) (get-rhs run-when.repeating) true)))
    (map mode uniqpre "" true)))

;;;@class AccOpts
;;;@field base number?
;;;@field thre number?

;;;@param mode string|string[]
;;;@param key string
;;;@param callback (fun(): string?)?
;;;@param opts AccOpts?
(fn M.acceleration-key [mode key callback opts]
  (let [uniqid (make-uniq key)
        base (if opts opts.base 2)
        thre (if opts opts.thre 3)]
    (var count 0)
    (vim.keymap.set mode key
      #(if (> vim.v.count 0)
           key
           (do
             (set count 1)
             (if callback
                 (.. (or (callback) "") uniqid)
                 (.. key uniqid)))))

    (vim.keymap.set mode (.. uniqid key)
      #(let [spped (math.pow base (math.floor (/ count thre)))]
         (set count (+ count 1))
         (if callback
             (.. speed (or (callback) key) uniqid)
             (.. speed key uniqid)))
      { :expr true })

    (vim.keymap.set mode uniqid "")))

M