;;; ~/.exwm -*-  mode: emacs-lisp; lexical-binding: t; -*-

(require 'exwm-systemtray)

;;; Functions

(defun exwm-spawn (command)
  (interactive (list (read-shell-command "$ ")))
  (start-process-shell-command command nil command))

(defun ^exwm-spawn (command)
  (lambda () (interactive) (exwm-spawn command)))

(defun exwm-autostart (command)
  (start-process-shell-command
   (format "<autostart> %s" command) " *autostart*" command))

(defun run-or-raise (command &optional buffer-name)
  "Raise BUFFER-NAME if it exists, else run COMMAND.
BUFFER-NAME defaults to the first word of COMMAND."
  (let ((buffer-name (or buffer-name (car (string-split command)))))
    (if (buffer-live-p (get-buffer buffer-name))
        (switch-to-buffer buffer-name)
      (exwm-spawn command))))

(defun ^run-or-raise (command)
  (lambda () (interactive) (run-or-raise command)))

;; Wifi info
(defun dBm->perc (dBm)
  (truncate (+ (- (/ (* dBm dBm) 105.0))
               (/ dBm 21.0)
               100)))

(defun %wifi-info ()
  (let (ssid dBm signal)
    (with-temp-buffer
      (call-process "iw" nil t nil "dev" "wlan0" "link")
      (goto-char (point-min))
      (setq ssid (progn (search-forward "SSID: " nil t)
                        (buffer-substring (point)
                                          (pos-eol))))
      (setq dBm (progn (search-forward "signal: " nil t)
                       (string-to-number
                        (buffer-substring (point)
                                          (progn (forward-word)
                                                 (point))))))
      (setq signal (dBm->perc dBm))
      (list ssid signal dBm))))

(defun wifi-info ()
  (interactive)
  (apply #'message "Connected to `%s' at %s%% (%s dBm)"
         (%wifi-info)))

(defvar display-wifi-info-timer nil)
(defvar display-wifi-info-string "")

(defun display-wifi-info-update ()
  (setq display-wifi-info-string
        (let ((info (%wifi-info)))
          (format " [🛜%s%%]" (cadr info))))
  (force-mode-line-update 'all))

(define-minor-mode display-wifi-info-mode
  "Toggle display of wifi connection status in mode line."
  :global t
  (cond
   (display-wifi-info-mode
    (or (memq 'display-wifi-info-string global-mode-string)
        (setq global-mode-string
              (append global-mode-string '(display-wifi-info-string))))
    (setq display-wifi-info-timer
          (run-with-timer 0 30 #'display-wifi-info-update)))
   (t (and (timerp display-wifi-info-timer)
           (cancel-timer display-wifi-info-timer))
      (setq display-wifi-info-timer nil)
      (setq display-wifi-info-string nil))))

;;; Options

(setopt exwm-workspace-number 4)

;; Tab bar
(tab-bar-mode)
(setopt tab-bar-show t)
(setopt tab-bar-format
        '(tab-bar-format-tabs
          tab-bar-format-align-right
          tab-bar-format-global))
(setopt tab-bar-close-button-show nil)

;; System information
(setopt display-time-default-load-average nil)
(setopt display-time-format "%e %a %R")
(setopt battery-mode-line-format "[🔋%b%p%]")

(display-wifi-info-mode)
(display-battery-mode)
(display-time-mode)

;; Must come after the above
(setopt global-mode-string
        '("" jabber-activity-mode-string
          display-wifi-info-string
          " " battery-mode-line-string
          " " (:propertize ("" display-time-string)
                           face tab-bar-tab)))

;;; Window management

(after exwm-mode-hook
  (setq-local mode-line-format nil))

(after exwm-update-class-hook
  (exwm-workspace-rename-buffer exwm-class-name))

;;; Keys

(setopt exwm-input-global-keys
        `(;; Command shortcuts
          ([?\s-p] . ,(^run-or-raise "keepassxc"))
          ([?\s-b] . ,(^run-or-raise browse-url-generic-program))
          ;; 's-r': Reset (to line-mode).
          ([?\s-r] . exwm-reset)
          ;; 's-w': Bury buffer (I honestly don't really use workspaces)
          ([?\s-w] . bury-buffer)
          ([?\s-o] . other-window-dwim)
          ;; 's-&': Launch application.
          ([?\s-&] . exwm-spawn)))

(setopt exwm-input-simulation-keys
        '(([?\C-b] . [left])
          ([?\C-f] . [right])
          ([?\C-p] . [up])
          ([?\C-n] . [down])
          ([?\C-a] . [home])
          ([?\C-e] . [end])
          ([?\M-v] . [prior])
          ([?\C-v] . [next])
          ([?\C-d] . [delete])
          ([?\C-k] . [S-end delete])
          ([?\M-w] . [?\C-c])
          ([?\C-w] . [?\C-x])
          ([?\C-y] . [?\C-v])
          ([?\C-s] . [?\C-f])))

;;; Startup

;; Start exwm
(exwm-enable)
(exwm-systemtray-enable)

;; Start other stuff
(after init
  (exwm-autostart "nextcloud")
  (exwm-autostart "dunst"))

;; Turn off debug mode
(setopt toggle-debug-on-error nil)