;;; syd-keybinds.el -*- lexical-binding: t; -*-
;;; Universal keybindings, not /too/ tied to any particular packages.

(require 'syd-general)

(defun syd-keybinds-initialise ()
  (syd-initialise-leader)

  (global-set-key [remap keyboard-quit] #'syd/escape)

  ;; Buffer
  (require 'syd-buffers)
  (general-def
    :prefix-map 'syd-leader-buffer-map
    "k" `("Kill buffer" . ,#'kill-current-buffer)
    "K" `("Kill all buffers" . ,#'syd/kill-all-buffers)
    "O" `("Kill other buffers" . ,#'syd/kill-other-buffers)
    "i" `("IBuffer" . ,#'ibuffer)
    "Z" `("Kill burried buffers" . ,#'syd/kill-burried-buffers)
    "C" `("Clone (indirect) buffer O/W" . ,#'clone-indirect-buffer-other-window)
    "c" `("Clone (indirect) buffer" . ,#'clone-indirect-buffer)
    "u" `("Save buffer as root" . ,#'syd/save-buffer-as-root)
    "r" `("Revert buffer" . ,#'revert-buffer))

  ;; Search
  (require 'syd-search)
  (general-def
    :prefix-map 'syd-leader-search-map
    "i" `("IMenu" . ,#'consult-imenu)
    "b" `("Search buffer" . ,#'syd-search-buffer)
    "d" `("Search directory" . ,#'syd-search-directory))

  ;; File
  (require 'syd-file)
  (general-def
    :prefix-map 'syd-leader-file-map
    "D" `("Delete file" . ,#'syd/delete-this-file)
    "R" `("Move file" . ,#'syd/move-this-file)
    "C" `("Copy file" . ,#'syd/copy-this-file)
    "F" `("Find file in" . ,#'syd-find-file-in)
    "P" `("Browse Emacs config" . ,#'syd-switch-to-emacs-user-directory)
    "u" `("Find file as root" . ,#'syd/find-file-as-root)
    "U" `("Open this file as root" . ,#'syd/open-this-file-as-root)
    "y" `("Yank buffer path" . ,#'syd/yank-buffer-path)
    "r" `("Browse recent file" . ,#'consult-recent-file))

  ;; Window
  (require 'syd-window)
  (general-def
    :prefix-map 'syd-leader-window-maximise-map
    "m" `("Maximise" . ,#'syd/window-maximise))
  (general-def
    :prefix-map 'syd-leader-window-map
    "h" `("Select window left" . ,#'evil-window-left)
    "j" `("Select window below" . ,#'evil-window-down)
    "k" `("Select window above" . ,#'evil-window-up)
    "l" `("Select window right" . ,#'evil-window-right)
    "H" `("Swap window left" . ,#'syd/window-swap-left)
    "J" `("Swap window below" . ,#'syd/window-swap-down)
    "K" `("Swap window above" . ,#'syd/window-swap-up)
    "L" `("Swap window right" . ,#'syd/window-swap-right)
    "T" `("Tear off window" . ,#'tear-off-window)
    "=" `("Balance windows" . ,#'balance-windows)
    "v" `("Vertical split" . ,#'evil-window-vsplit)
    "s" `("Horizontal split" . ,#'evil-window-split)
    "F" `("Fit window to contents" . ,#'fit-window-to-buffer)
    "r" `("Rotate window downwards" . ,#'evil-window-rotate-downwards)
    "R" `("Rotate window upwards" . ,#'evil-window-rotate-upwards)
    "u" `("Undo window change" . ,#'winner-undo)
    "C-r" `("Redo window change" . ,#'winner-redo)
    "m" `("Maximise" . ,syd-leader-window-maximise-map))

  ;; Open
  (require 'syd-handle-repl)
  (general-def
    :prefix-map 'syd-leader-open-map
    "r" `("Repl o/w" . ,#'+syd/open-repl-other-window))

  ;; Project
  (general-def
    :prefix-map 'syd-leader-project-map
    "C" `("Compile project" . ,#'project-compile)
    "&" `("Async cmd in project root" . ,#'project-async-shell-command)
    "p" `("Switch project" . ,#'project-switch-project)
    "." `("Browse project from root" . ,#'syd-project-root-find-file))

  (general-def
    :prefix-map 'syd-leader-help-package-map
    "u" `("Temporarily install package" . ,#'straight-use-package)
    "v" `("Browse package repo" . ,#'straight-visit-package))

  ;; Help
  (general-def
    :prefix-map 'help-map
    "F" #'describe-face
    "'" #'describe-char
    "T" #'consult-theme
    "p" `("Packages" . ,syd-leader-help-package-map))

  (general-def
    :prefix-map 'syd-leader-notes-map)

  (general-def
    :keymaps '(evil-ex-completion-map minibuffer-local-map minibuffer-mode-map
                                      read--expression-map)
    "C-k" #'previous-history-element
    "C-j" #'next-history-element)

  ;; Motion
  (general-def
    :states 'motion
    "[ b" #'previous-buffer
    "] b" #'next-buffer
    "] SPC" #'syd-insert-newline-below
    "[ SPC" #'syd-insert-newline-above)

  (general-def
    :keymaps 'global-map
    :states 'motion
    "M-:" #'eval-expression
    "M-x" #'execute-extended-command)

  (general-def
    :maps 'help-mode-map
    "<escape>" #'syd/escape)

  ;; Insert
  (general-def
    :prefix-map 'syd-leader-insert-map
    "u" #'insert-char)

  ;; Code
  (general-def
    :prefix-map 'syd-leader-code-map)

  ;; This is necessary to properly rebind `universal-argument'.
  ;; `universal-argument-more' is a command that provides additional prefixes
  ;; after the first.  Without it, the first 'C-u' will be interpreted as a
  ;; prefix argument for the second 'C-u'.
  (general-def
    :keymaps 'universal-argument-map
    "SPC u" #'universal-argument-more
    "u" #'universal-argument-more)

  ;; Leader
  (general-def
    :keymaps 'syd-leader-map
    "." #'find-file
    "SPC" `("Find file in project" . ,#'project-find-file)
    "x" `("Open scratch buffer" . ,#'scratch-buffer)
    "u" `("Universal argument" . ,#'universal-argument)
    "b" `("Buffer" . ,syd-leader-buffer-map)
    "o" `("Open" . ,syd-leader-open-map)
    "p" `("Project" . ,syd-leader-project-map)
    "w" `("Window" . ,syd-leader-window-map)
    "f" `("File" . ,syd-leader-file-map)
    "s" `("Search" . ,syd-leader-search-map)
    "h" `("Help" . ,help-map)
    "n" `("Notes" . ,syd-leader-notes-map)
    "i" `("Insert" . ,syd-leader-insert-map)
    "c" `("Code" . ,syd-leader-code-map)
    "," `("Switch buffer in project" . ,#'consult-project-buffer)
    "<" `("Switch buffer" . ,#'consult-buffer)
    "/" `("Search project" . ,#'syd-project-search)))

(syd-keybinds-initialise)

;; Show possible completions for a partially-entered key sequence.
(use-package which-key
  ;; BUG: (#4) If the first input is a prefix key, `which-key-mode' won't be
  ;; activated in time.
  :hook (on-first-input . which-key-mode)
  :custom ((which-key-allow-evil-operators t)
           (which-key-show-operator-state-maps t)))

(provide 'syd-keybinds)
