;;; vterm-input-buffer.el --- Compose input for vterm buffers -*- lexical-binding: t; -*-

(defvar-local circ/vterm-input-buffer--target nil
  "The vterm buffer to send input to.")

(defvar circ/vterm-input-buffer-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-c C-c") #'circ/vterm-input-buffer-send-and-delete)
    (define-key map (kbd "C-c C-s") #'circ/vterm-input-buffer-send)
    (define-key map (kbd "C-c C-k") #'circ/vterm-input-buffer-cancel)
    map)
  "Keymap for `circ/vterm-input-buffer-mode'.")

(define-derived-mode circ/vterm-input-buffer-mode text-mode "VTerm Input"
  "Major mode for composing input to send to a vterm buffer.")

(defun circ/vterm-input-buffer ()
  "Open a vterm input buffer associated with the current vterm buffer."
  (interactive)
  (unless (derived-mode-p 'vterm-mode)
    (user-error "Not in a vterm buffer"))
  (let ((target (current-buffer))
        (buf (generate-new-buffer "*vterm-input*")))
    (pop-to-buffer buf)
    (circ/vterm-input-buffer-mode)
    (setq circ/vterm-input-buffer--target target)
    (setq header-line-format
          "C-c C-c: send & delete  |  C-c C-s: send  |  C-c C-k: cancel")))

(defun circ/vterm-input-buffer-cancel ()
  "Kill the vterm input buffer without sending anything."
  (interactive)
  (quit-window t))

(defun circ/vterm-input-buffer--get-text-and-region ()
  "Return (TEXT BEG END) for the active region, or the entire buffer."
  (if (use-region-p)
      (list (buffer-substring-no-properties (region-beginning) (region-end))
            (region-beginning) (region-end))
    (list (buffer-substring-no-properties (point-min) (point-max))
          (point-min) (point-max))))

(defun circ/vterm-input-buffer--send-text (text)
  "Send TEXT to the associated vterm buffer and select its window."
  (unless (buffer-live-p circ/vterm-input-buffer--target)
    (user-error "Target vterm buffer no longer exists"))
  (let ((target circ/vterm-input-buffer--target))
    (select-window (get-buffer-window target))
    (vterm-insert text)))

(defun circ/vterm-input-buffer-send ()
  "Send text to vterm. With region, send region. Otherwise send entire buffer."
  (interactive)
  (let ((text (car (circ/vterm-input-buffer--get-text-and-region))))
    (when (use-region-p)
      (deactivate-mark))
    (arf-nav-state)
    (circ/vterm-input-buffer--send-text text)))

(defun circ/vterm-input-buffer-send-and-delete ()
  "Send text to vterm and delete it. With region, delete region. Otherwise clear buffer."
  (interactive)
  (pcase-let ((`(,text ,beg ,end) (circ/vterm-input-buffer--get-text-and-region)))
    (delete-region beg end)
    (arf-nav-state)
    (circ/vterm-input-buffer--send-text text)))

(provide 'vterm-input-buffer)
;;; vterm-input-buffer.el ends here
