;; general-settings.el --- General settings  -*- lexical-binding: t -*-

;;; Commentary:

;; Requirements:

;;; Code:

;; Change "yes or no" to "y or n"
(fset 'yes-or-no-p 'y-or-n-p)

;; transparency
(defun transparency-p ()
  "Toggle transparency of the frame."
  (let ((alpha (frame-parameter nil 'alpha)))
    (if (eq
         (if (numberp alpha)
             alpha
           (cdr alpha)) ; may also be nil
         100)
        nil     ;; currently aplha 100
      t)))  ;; currently aplha active
(defun toggle-transparency ()
  "Toggle transparency of the frame."
  (interactive)
    (if (transparency-p)
        (set-frame-parameter nil 'alpha '(100 . 100))
      (set-frame-parameter nil 'alpha '(95 . 95))))

;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun my-rename-buffer-file (new-name)
  "Rename both current buffer and file it's visiting to NEW-NAME."
  (interactive "sNew name: ")
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not filename)
        (message "Buffer '%s' is not visiting a file!" name)
      (if (get-buffer new-name)
          (message "A buffer named '%s' already exists!" new-name)
        (progn
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          (set-buffer-modified-p nil))))))
(defun my-move-buffer-file (dir)
  "Move both current buffer and file it's visiting to DIR."
  (interactive "DNew directory: ")
  (let* ((name (buffer-name))
         (filename (buffer-file-name))
         (dir
          (if (string-match dir "\\(?:/\\|\\\\)$")
              (substring dir 0 -1) dir))
         (newname (concat dir "/" name)))
    (if (not filename)
        (message "Buffer '%s' is not visiting a file!" name)
      (progn
        (copy-file filename newname 1)
        (delete-file filename)
        (set-visited-file-name newname)
        (set-buffer-modified-p nil)
        t))))

;; recentf stuff
(use-package recentf
  :config
  (setq
   recentf-save-file (locate-user-emacs-file ".cache/recentf" "recentf")
   recentf-max-saved-items 1000
   recentf-max-menu-items 30
   recentf-auto-cleanup 'never   ;; disable before we start recentf! Set to never bc otherwise it tries to read also tramp (remote) files
   )
  (add-to-list 'recentf-exclude
               (recentf-expand-file-name user-cache-directory))
  ;;(global-set-key "\C-x\ \C-r" 'recentf-open-files)  ;; see completion-settings ivy counsel
  ;;(run-at-time nil (* 10 60) 'recentf-save-list)
  (run-with-idle-timer (* 10 60) t 'recentf-save-list)
  (recentf-mode)
  )

;; by default backup files are saved in the current directory, ending with ~
;; instead stashes them all in
(let ((backup-dir (concat user-cache-directory "backups"))
      (auto-saves-dir (concat user-cache-directory "auto-saves/")))
  (dolist (dir (list backup-dir auto-saves-dir))
    (when (not (file-directory-p dir))
      (make-directory dir t)))
  (setq backup-directory-alist `(("." . ,backup-dir)))
  (setq backup-by-copying t)
  (setq auto-save-file-name-transforms `((".*" ,auto-saves-dir t)))
  (setq auto-save-list-file-prefix (concat auto-saves-dir ".saves-"))
  (setq tramp-backup-directory-alist `((".*" . ,backup-dir)))
  (setq tramp-auto-save-directory auto-saves-dir))
(setq-default delete-by-moving-to-trash t)  ;; Delete files to trash

(use-package tramp
  :defer t
  :config
  ;; tramp-cache.el
  (setq tramp-persistency-file-name (concat user-cache-directory "tramp")))

(if (fboundp 'save-place-mode)
    (save-place-mode)
  (setq save-place t)
  )
;; Save point position between sessions
(setq save-place-file (concat user-cache-directory "places"))

;; minibuffer history, e.g. M-x with amex
(setq savehist-file (concat user-cache-directory "history"))
(savehist-mode)

(use-package x-win
  :defer t
  :config
  ;; overwrite
  (defun emacs-session-filename (session-id)
    "Construct a filename to save the session in based on SESSION-ID.
Return a filename in `user-emacs-directory', unless the session file
already exists in the home directory."
    (let ((basename (concat "session." session-id)))
      (concat user-cache-directory basename))))

;;; desktop
(require 'desktop)
;; save session
;;(desktop-save-mode 1)
(setq desktop-dirname user-cache-directory)
(setq history-length 500)  ;; Since all lists will be truncated when saved, it is important to have a high default history length
(add-to-list 'desktop-path user-cache-directory)
(defun desktop-settings-setup ()
  "Some settings setup for 'desktop-save-mode'."
  (interactive)
    
  ;; At this point the desktop.el hook in after-init-hook was
  ;; executed, so (desktop-read) is avoided.
  (when (not (eq (emacs-pid) (desktop-owner))) ; Check that emacs did not load a desktop yet
    ;; Here we activate the desktop mode
    (desktop-save-mode 1)

    ;; Since all lists will be truncated when saved, it is important to have a high default history length
    (setq history-length 250)

    ;; Set the location to save/load default desktop
    (setq desktop-dirname user-cache-directory)
    (add-to-list 'desktop-path user-cache-directory)

    ;; The default desktop is saved always
    (setq desktop-save t)

    ;; The default desktop is loaded anyway if it is locked
    (setq desktop-load-locked-desktop t)

    ;; Make sure that even if emacs or OS crashed, emacs
    ;; still have last opened files.
    (add-hook 'find-file-hook
     (lambda ()
       (run-with-timer 5 nil
          (lambda ()
            ;; Reset desktop modification time so the user is not bothered
            (setq desktop-file-modtime (nth 5 (file-attributes (desktop-full-file-name))))
            (desktop-save user-emacs-directory)))))

    ;; Read default desktop
    (if (file-exists-p (concat desktop-dirname desktop-base-file-name))
        (desktop-read desktop-dirname))

    ;; Add a hook when emacs is closed to we reset the desktop
    ;; modification time (in this way the user does not get a warning
    ;; message about desktop modifications)
    (add-hook 'kill-emacs-hook
              (lambda ()
                ;; Reset desktop modification time so the user is not bothered
                (setq desktop-file-modtime (nth 5 (file-attributes (desktop-full-file-name))))))
    )
  )
;; (add-hook 'after-init-hook
;;           'desktop-settings-setup
;;           (lambda ()
;;             ;; No splash screen
;;             (setq inhibit-startup-screen t)

;;             ;; If the *scratch* buffer is the current one, then create a new
;;             ;; empty untitled buffer to hide *scratch*
;;             (if (string= (buffer-name) "*scratch*")
;;                 (new-empty-buffer))
;;             )
;;           t) ;; append this hook to the tail


;; auto revert buffer
(when (fboundp 'global-auto-revert-mode)
  ;; All the "reverting buffer foo" messages are _really_ distracting.
  (setq auto-revert-verbose nil)
  (global-auto-revert-mode 1)
  ;; just as the docs warn, this can really make Emacs sluggish.
  (if running-on-windows
      (if (fboundp 'lwarn)
          (lwarn
           'global-auto-revert-mode
           :warning
           "`global-auto-revert-mode' is turned on.  It's nifty,
but it's REALLY SLOW when you have buffers that are visiting
remote files.  And despite its documentation, it does NOT ignore
those files, if you're using windows, and the file name begins
with a drive letter and a colon."))
    (setq global-auto-revert-non-file-buffers t)))
(setq revert-without-query '(".*"))

(use-package uniquify
  :defer t
  :config
  (setq uniquify-buffer-name-style 'forward))  ;; forward: bar/mumble/name insead of post-forward-angle-brackets: name<bar/mumble>

;; overwrite selected text
(delete-selection-mode t)

;; always use spaces, not tabs, when indenting
(setq-default indent-tabs-mode nil)
;; width for tabs
(setq-default tab-width 2)

;; ignore case when searching
(setq case-fold-search t)

;; require final newlines in files when they are saved
(setq require-final-newline t)

;; don't show the startup screen
(setq inhibit-startup-screen t)

;; each line of text gets one line on the screen (i.e., text will run
;; off the right instead of wrapping around onto a new line)
(setq-default truncate-lines t)
;; truncate lines even in partial-width windows
;;(setq truncate-partial-width-windows t)

(defun my-unfill-paragraph ()
  "Replace newline chars in current paragraph by single spaces.
This command does the inverse of `fill-paragraph'.

URL `http://ergoemacs.org/emacs/emacs_unfill-paragraph.html'
Version 2016-07-13"
  (interactive)
  (let ((fill-column most-positive-fixnum))
    (fill-paragraph)))

(defun my-unfill-region (start end)
  "Replace newline chars in region by single spaces.
This command does the inverse of `fill-region'.

URL `http://ergoemacs.org/emacs/emacs_unfill-paragraph.html'
Version 2016-07-13"
  (interactive "r")
  (let ((fill-column most-positive-fixnum))
    (fill-region start end)))

(use-package so-long
  :config
  ;;(add-to-list 'so-long-target-modes 'mhtml-mode t)
  (setq so-long-max-lines nil)  ;; by default only 5 non-blank lines are tested
  (setq so-long-threshold 500)
  (setq so-long-action 'so-long-minor-mode)  ;; so-long-mode
  (global-so-long-mode 1))

;; display line numbers to the right of the window
;; (global-linum-mode t)  ;; deactivated because the DocView showing pdf files becomes extremly slow when global-linum-mode is on.

;; show the current line and column numbers in the stats bar as well
(line-number-mode t)
(column-number-mode t)

;; highlight parentheses when the cursor is next to them
(use-package paren
  :defer 0.1
  :config
  (show-paren-mode t))

;; emacs warning:
;;   ad-handle-definition: `text-scale-increase' got redefined
;; these warnings are generated when functions are redefined with defadvice.
(setq ad-redefinition-action 'accept)

;; gravatars from magit use this to store their cache
(setq url-configuration-directory (concat user-cache-directory "url/"))

;; https://adam.kruszewski.name/2017/09/emacs-in-wsl-and-opening-links/
;; For WSL open links in Windows web browser of choice
(when running-on-windows-wsl
  (let ((cmd-exe "/mnt/c/Windows/System32/cmd.exe")
        (cmd-args '("/c" "start")))
    (when (file-exists-p cmd-exe)
      (setq browse-url-generic-program  cmd-exe
            browse-url-generic-args     cmd-args
            browse-url-browser-function 'browse-url-generic))))

(setq bookmark-default-file (concat user-cache-directory "bookmarks"))

(use-package transient
  :defer t
  :config
  (setq transient-levels-file (concat user-cache-directory "transient/levels.el"))
  (setq transient-values-file (concat user-cache-directory "transient/values.el"))
  (setq transient-history-file (concat user-cache-directory "transient/history.el")))

;; A better *Help* buffer
(use-package helpful
  :bind
  (;; Note that the built-in `describe-function' includes both functions
   ;; and macros. `helpful-function' is functions only, so we provide
   ;; `helpful-callable' as a drop-in replacement to include `helpful-macro'.
   ("C-h f" . describe-function)
   ;; ("C-h f" . helpful-callable)
   ("C-h v" . describe-variable)
   ;; ("C-h v" . helpful-variable)
   ("C-h k" . helpful-key)
   ;; Lookup the current symbol at point. C-c C-d is a common keybinding
   ;; for this in lisp modes.
   ("C-c C-d" . helpful-at-point)
   ;; Look up *F*unctions (excludes macros).
   ;; By default, C-h F is bound to `Info-goto-emacs-command-node'. Helpful
   ;; already links to the manual, if a function is referenced there.
   ("C-h F" . helpful-function)
   ;; Look up *C*ommands.
   ;; By default, C-h C is bound to describe `describe-coding-system'. I
   ;; don't find this very useful, but it's frequently useful to only
   ;; look at interactive functions.
   ("C-h C" . helpful-command))
  :config
  (with-eval-after-load 'ivy
    ;; Ivy users can use Helpful with counsel commands:
    (setq counsel-describe-function-function #'helpful-callable)
    (setq counsel-describe-variable-function #'helpful-variable)))

;;
;; keyboard
;;
;; https://github.com/syl20bnr/spacemacs/blob/c7a103a772d808101d7635ec10f292ab9202d9ee/layers/%2Bdistributions/spacemacs-base/keybindings.el
;; Make <escape> quit as much as possible
(define-key minibuffer-local-map (kbd "<escape>") 'keyboard-escape-quit)
(define-key minibuffer-local-ns-map (kbd "<escape>") 'keyboard-escape-quit)
(define-key minibuffer-local-completion-map (kbd "<escape>") 'keyboard-escape-quit)
(define-key minibuffer-local-must-match-map (kbd "<escape>") 'keyboard-escape-quit)
(define-key minibuffer-local-isearch-map (kbd "<escape>") 'keyboard-escape-quit)
;;
(define-key global-map "\M-Q" 'my-unfill-paragraph)
;;
(global-set-key (kbd "C-r") 'query-replace-regexp)  ;; isearch-backward
(global-set-key (kbd "C-x C-b") 'ibuffer)           ;; list-buffers
;; applications
(global-set-key (kbd "M-m !") 'shell-command)
(global-set-key (kbd "M-m a c") 'calc-dispatch)
(global-set-key (kbd "M-m a P") 'proced)
;; buffers
(global-set-key (kbd "M-m b d") 'kill-this-buffer)
(global-set-key (kbd "M-m b e") 'erase-buffer)
(global-set-key (kbd "M-m b C-d") 'kill-matching-buffers)
(global-set-key (kbd "M-m b n") 'next-buffer)
(global-set-key (kbd "M-m b p") 'previous-buffer)
(global-set-key (kbd "M-m b R") 'revert-buffer)
(global-set-key (kbd "M-m b w") 'read-only-mode)
;; compile/comments
(global-set-key (kbd "M-m c C") 'compile)
(global-set-key (kbd "M-m c k") 'kill-compilation)
(global-set-key (kbd "M-m c r") 'recompile)
;; (with-eval-after-load 'compile
;;   (define-key compilation-mode-map "r" 'recompile)
;;   (define-key compilation-mode-map "g" nil)
;;   )
;; errors
(global-set-key (kbd "M-m e n") 'next-error)
(global-set-key (kbd "M-m e p") 'previous-error)
;; files
(global-set-key (kbd "M-m f c") 'copy-file)
(global-set-key (kbd "M-m f D") 'delete-file)
(global-set-key (kbd "M-m f g") 'rgrep)
(global-set-key (kbd "M-m f l") 'find-file-literally)
(global-set-key (kbd "M-m f R") 'rename-file)
(global-set-key (kbd "M-m f s") 'save-buffer)
(global-set-key (kbd "M-m f v d") 'add-dir-local-variable)
(global-set-key (kbd "M-m f v f") 'add-file-local-variable)
(global-set-key (kbd "M-m f v p") 'add-file-local-variable-prop-line)
;; help
(global-set-key (kbd "M-m h d b") 'describe-bindings)
(global-set-key (kbd "M-m h d c") 'describe-char)
(global-set-key (kbd "M-m h d C") 'describe-coding-system)
(global-set-key (kbd "M-m h d C-c") 'describe-copying)
(global-set-key (kbd "M-m h d M-c") 'describe-categories)
(global-set-key (kbd "M-m h d f") 'describe-function)
(global-set-key (kbd "M-m h d F") 'describe-face)
(global-set-key (kbd "M-m h d C-f") 'describe-font)
(global-set-key (kbd "M-m h d M-f") 'describe-fontset)
(global-set-key (kbd "M-m h d k") 'describe-key)
(global-set-key (kbd "M-m h d K") 'describe-keymap)
(global-set-key (kbd "M-m h d m") 'describe-mode)
(global-set-key (kbd "M-m h d M") 'describe-minor-mode)
(global-set-key (kbd "M-m h d o") 'describe-symbol)
(global-set-key (kbd "M-m h d p") 'describe-package)
(global-set-key (kbd "M-m h d s") 'describe-syntax)
(global-set-key (kbd "M-m h d t") 'describe-theme)
(global-set-key (kbd "M-m h d v") 'describe-variable)
(global-set-key (kbd "M-m h n") 'view-emacs-news)
;; format
(global-set-key (kbd "M-m j o") 'open-line)
(global-set-key (kbd "M-m j =") 'indent-region)
(global-set-key (kbd "M-m j S") 'split-line)
;; navigation/jumping
(global-set-key (kbd "M-m j f") 'find-function)
(global-set-key (kbd "M-m j l") 'find-library)
(global-set-key (kbd "M-m j v") 'find-variable)
;; narrow & widen
(global-set-key (kbd "M-m n r") 'narrow-to-region)
(global-set-key (kbd "M-m n p") 'narrow-to-page)
(global-set-key (kbd "M-m n f") 'narrow-to-defun)
(global-set-key (kbd "M-m n w") 'widen)
;; quit
(global-set-key (kbd "M-m q s") 'save-buffers-kill-emacs)
(global-set-key (kbd "M-m q Q") 'kill-emacs)
;; toggles
(global-set-key (kbd "M-m t F") 'auto-fill-mode)
(global-set-key (kbd "M-m t h h") 'global-hl-line-mode)
(global-set-key (kbd "M-m t h s") 'font-lock-mode)
(global-set-key (kbd "M-m t l") 'toggle-truncate-lines)
(global-set-key (kbd "M-m t L") 'visual-line-mode)
(global-set-key (kbd "M-m t m t") 'display-time-mode)
(global-set-key (kbd "M-m t W") 'ace-window-display-mode)
(global-set-key (kbd "M-m T f") 'fringe-mode)
(global-set-key (kbd "M-m T F") 'toggle-frame-fullscreen)
(global-set-key (kbd "M-m T m") 'menu-bar-mode)
(global-set-key (kbd "M-m T M") 'toggle-frame-maximized)
(global-set-key (kbd "M-m T S") 'semantic-stickyfunc-mode)
(global-set-key (kbd "M-m T C-S") 'global-semantic-stickyfunc-mode)
(global-set-key (kbd "M-m T t") 'tool-bar-mode)
(global-set-key (kbd "M-m T p") 'toggle-transparency)
;; window
(global-set-key (kbd "M-m w d") 'delete-window)
(global-set-key (kbd "M-m w D") 'ace-delete-window)
(global-set-key (kbd "M-m w f") 'follow-mode)
(global-set-key (kbd "M-m w F") 'make-frame)
(global-set-key (kbd "M-m w h") 'windmove-left)
(global-set-key (kbd "M-m w j") 'windmove-down)
(global-set-key (kbd "M-m w k") 'windmove-up)
(global-set-key (kbd "M-m w l") 'windmove-right)
(global-set-key (kbd "M-m w m") 'maximize-window)
(global-set-key (kbd "M-m w M") 'ace-swap-window)
(global-set-key (kbd "M-m w n") 'next-window)
(global-set-key (kbd "M-m w o") 'other-frame)
(global-set-key (kbd "M-m w p") 'previous-window)
(global-set-key (kbd "M-m w s") 'split-window-below)
(with-eval-after-load 'winner-mode
  (global-set-key (kbd "M-m w u") 'winner-undo)
  (global-set-key (kbd "M-m w U") 'winner-redo))
(global-set-key (kbd "M-m w v") 'split-window-right)
(global-set-key (kbd "M-m w w") 'other-window)
(global-set-key (kbd "M-m w W") 'ace-window)  ;; same as ace-selct-window
(global-set-key (kbd "M-m w -") 'split-window-below)
(global-set-key (kbd "M-m w /") 'split-window-right)
(global-set-key (kbd "M-m w =") 'balance-windows)
(global-set-key (kbd "M-m w <left>") 'windmove-left)
(global-set-key (kbd "M-m w <down>") 'windmove-down)
(global-set-key (kbd "M-m w <up>") 'windmove-up)
(global-set-key (kbd "M-m w <right>") 'windmove-right)
(global-set-key (kbd "M-m w TAB") 'other-window)
;; text
(global-set-key (kbd "M-m x a a") 'align)
(global-set-key (kbd "M-m x a c") 'align-current)
(global-set-key (kbd "M-m x c") 'count-words-region)
(global-set-key (kbd "M-m x d w") 'delete-trailing-whitespace)
(global-set-key (kbd "M-m x j c") 'set-justification-center)
(global-set-key (kbd "M-m x j f") 'set-justification-full)
(global-set-key (kbd "M-m x j l") 'set-justification-left)
(global-set-key (kbd "M-m x j n") 'set-justification-none)
(global-set-key (kbd "M-m x j r") 'set-justification-right)
(global-set-key (kbd "M-m x l s") 'sort-lines)
(global-set-key (kbd "M-m x t c") 'transpose-chars)
(global-set-key (kbd "M-m x t l") 'transpose-lines)
(global-set-key (kbd "M-m x t w") 'transpose-words)
(global-set-key (kbd "M-m x u") 'downcase-region)
(global-set-key (kbd "M-m x U") 'upcase-region)
(global-set-key (kbd "M-m x TAB") 'indent-rigidly)
;; Bind commands to move around windows
(global-set-key [(C-M-left)] 'windmove-left)
(global-set-key [(C-M-right)] 'windmove-right)
(global-set-key [(C-M-up)] 'windmove-up)
(global-set-key [(C-M-down)] 'windmove-down)
(defun toggle-window-split ()
  "Toggle between horizontal and vertical split with two windows."
  (interactive)
  (if (> (length (window-list)) 2)
      (error "Can't toggle with more than 2 windows!")
    (let ((func (if (window-full-height-p)
                    #'split-window-vertically
                  #'split-window-horizontally)))
      (delete-other-windows)
      (funcall func)
      (save-selected-window
        (other-window 1)
        (switch-to-buffer (other-buffer))))))
(global-set-key (kbd "C-x |") 'toggle-window-split)
;; move current line up and down
(defun move-line-up()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (forward-line -2)
  (indent-according-to-mode))
(defun move-line-down()
  "Move down the current line."
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1)
  (indent-according-to-mode))
(global-set-key [(M-up)] 'move-line-up)
(global-set-key [(M-down)] 'move-line-down)

;;
;; mouse
;;
;; Enable mouse support, https://stackoverflow.com/questions/5710334/how-can-i-get-mouse-selection-to-work-in-emacs-and-iterm2-on-mac
(unless (display-graphic-p)
  (require 'mouse)
  (xterm-mouse-mode t)
  (global-set-key [mouse-4] (lambda () (interactive) (scroll-down 1)))
  (global-set-key [mouse-5] (lambda () (interactive) (scroll-up 1)))
  (defun track-mouse (e))
  (setq mouse-sel-mode t))
(global-set-key (kbd "<mouse-8>") (lambda () (interactive) (previous-buffer)))
(global-set-key (kbd "<mouse-9>") (lambda () (interactive) (next-buffer)))
;;; Scrolling
;;(setq mouse-wheel-scroll-amount '(1)) ; Distance in pixel-resolution to scroll each mouse wheel event.
(setq mouse-wheel-progressive-speed nil) ; Progressive speed is too fast for me.
(setq mouse-wheel-tilt-scroll t) ; Turn on horizontal scrolling with mouse wheel
(setq mouse-wheel-flip-direction t) ; Swap direction of `wheel-right' and `wheel-left'
;; for scroll-all-mode add mouse wheel support
;; https://www.emacswiki.org/emacs/ScrollAllMode
(defun my-mwheel-scroll-all-function (func &optional arg)
  (if (and scroll-all-mode arg)
      (save-selected-window
        (walk-windows
         (lambda (win)
           (select-window win)
           (condition-case nil
               (funcall func arg)
             (error nil)))))
    (funcall func arg)))
(defun my-mwheel-scroll-all-scroll-up (&optional arg)
  (my-mwheel-scroll-all-function 'scroll-up arg))
(defun my-mwheel-scroll-all-scroll-down (&optional arg)
  (my-mwheel-scroll-all-function 'scroll-down arg))
(setq mwheel-scroll-up-function 'my-mwheel-scroll-all-scroll-up)
(setq mwheel-scroll-down-function 'my-mwheel-scroll-all-scroll-down)

;; https://www.reddit.com/r/emacs/comments/8sw3r0/finally_scrolling_over_large_images_with_pixel/
;; Good speed and allow scrolling through large images (pixel-scroll).
;; Note: Scroll lags when point must be moved but increasing the number
;;       of lines that point moves in pixel-scroll.el ruins large image
;;       scrolling. So unfortunately I think we'll just have to live with
;;       this.
(use-package pixel-scroll
  :defer t
  :config
  (setq pixel-dead-time 0) ; Never go back to the old scrolling behaviour.
  (setq pixel-resolution-fine-flag t) ; Scroll by number of pixels instead of lines (t = frame-char-height pixels).
  ;;(pixel-scroll-mode)  ;; default off
  )

;;
;; Menu
;;
;; Creating a major menu pane in the menu bar in the “File” menu before the “Save” entry.
;; Easy-Menu
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Easy-Menu.html
;; https://stackoverflow.com/questions/26638015/elisp-easy-menu-positioning#29396939
;; add menus to the global menu bar: map nil
(use-package easymenu
  :after (org)  ;; org export async needs org loaded before
  :config
  (easy-menu-add-item nil '("File") ["Kill Emacs" kill-emacs  :help "Run function `kill-emacs'"] "Quit")
  
  (easy-menu-define my-menu nil "My Menu"
    '("My"))
  (easy-menu-define my-major-menu nil "My Major Menu"
    (list "Major Modes"
      ["Unknown"      (progn ()) :style radio :selected major-mode :active nil
       :label (concat "Current: " (prin1-to-string major-mode))]
      ["Deft"         (progn (deft)) :style radio :selected (eq major-mode 'deft-mode) :help "deft"]
      ["Eshell [🅢ｅ]" (progn (eshell-mode)) :style radio :selected (eq major-mode 'eshell-mode) :help "eshell-mode"]
      ["Magit"        (progn (magit)) :style radio :selected (eq major-mode 'magit-status-mode) :help "magit"]
      ["Notmuch [🅝]" (progn (notmuch)) :style radio :selected (eq major-mode 'notmuch-mode) :help "notmuch"]
      ["mu4e [Ⓜ]"    (progn (mu4e)) :style radio :selected (eq major-mode 'mu4e-mode) :help "mu4e"]
      ["Org Brain"    (progn (call-interactively 'org-brain-visualize)) :style radio :selected (eq major-mode 'org-brain-visualize-mode) :help "org-brain-visualize"]
      ["Org Drill"    (progn (org-drill)) :style radio :selected (eq major-mode 'org-drill-mode) :help "org-drill"]
      ["Powershell"   (progn (powershell)) :style radio :selected (eq major-mode 'powershell-mode) :help "powershell"]
      ["Shell"        (progn (shell)) :style radio :selected (eq major-mode 'shell-mode) :help "shell"]
      ["Treemacs"     (progn (treemacs)) :style radio :selected (eq major-mode 'treemacs-mode) :help "treemacs"]
      ))
  (easy-menu-define my-lang-menu nil "My Lang Menu"
    '("Language Modes"
      ["Unknown" (progn ())
       :style radio :selected major-mode :active nil
       :label (concat "Current: " (prin1-to-string major-mode))]
      ["Batch script" (progn (bat-mode))
       :style radio :selected (eq major-mode 'bat-mode) :help "bat-mode"]
      ["C" (progn (c-mode))
       :style radio :selected (eq major-mode 'c-mode) :help "c-mode"]
      ["C++" (progn (c++-mode))
       :style radio :selected (eq major-mode 'c++-mode) :help "c++-mode"]
      ["CSS [🅒SS]" (progn (css-mode))
       :style radio :selected (eq major-mode 'css-mode) :help "css-mode"]
      ["Emacs-Lisp [🅛ｅ]" (progn (emacs-lisp-mode))
       :style radio :selected (eq major-mode 'emacs-lisp-mode) :help "emacs-lisp-mode"]
      ["Gnuplot" (progn (gnuplot-mode))
       :style radio :selected (eq major-mode 'gnuplot-mode) :help "gnuplot-mode"]
      ["HTML" (progn (html-mode))
       :style radio :selected (eq major-mode 'html-mode) :help "html-mode"]
      ["Java" (progn (java-mode))
       :style radio :selected (eq major-mode 'java-mode) :help "java-mode"]
      ;; js2-mode better than js-mode
      ["Javascript" (progn (js2-mode))
       :style radio :selected (eq major-mode 'js2-mode) :help "js2-mode"]
      ["LaTeX [🅛ａ]" (progn (latex-mode))
       :style radio :selected (eq major-mode 'latex-mode) :help "latex-mode"]
      ["Ledger [🅛ｄ]" (progn (ledger-mode))
       :style radio :selected (eq major-mode 'ledger-mode) :help "ledger-mode"]
      ["Lisp Interaction [🅛ｉ]" (progn (lisp-interaction-mode))
       :style radio :selected (eq major-mode 'lisp-interaction-mode) :help "lisp-interaction-mode"]
      ["Markdown" (progn (markdown-mode))
       :style radio :selected (eq major-mode 'markdown-mode) :help "markdown-mode"]
      ["Octave" (progn (octave-mode))
       :style radio :selected (eq major-mode 'octave-mode) :help "octave-mode"]
      ["Org [🅞]" (progn (org-mode))
       :style radio :selected (eq major-mode 'org-mode) :help "org-mode"]
      ;; cperl-mode offers much more features than perl-mode.
      ["Perl" (progn (cperl-mode))
       :style radio :selected (eq major-mode 'cperl-mode) :help "cperl-mode"]
      ["PHP" (progn (php-mode))
       :style radio :selected (eq major-mode 'php-mode) :help "php-mode"]
      ["PlantUML" (progn (plantuml-mode))
       :style radio :selected (eq major-mode 'plantuml-mode) :help "plantuml-mode"]
      ["Powershell script" (progn (powershell-mode))
       :style radio :selected (eq major-mode 'powershell-mode) :help "powershell-mode"]
      ["Python [🅟]" (progn (python-mode))
       :style radio :selected (eq major-mode 'python-mode) :help "python-mode"]
      ["Python-Web (Poly)" (progn (poly-python-web-mode-map))
       :style radio :selected (eq major-mode 'poly-python-web-mode-map) :help "poly-python-web-mode-map"]
      ["R (ESS)" (progn (ess-r-mode))
       :style radio :selected (eq major-mode 'ess-r-mode) :help "ess-r-mode"]
      ["reStructuredText (ReST)" (progn (rst-mode))
       :style radio :selected (eq major-mode 'rst-mode) :help "rst-mode"]
      ["Ruby" (progn (ruby-mode))
       :style radio :selected (eq major-mode 'ruby-mode) :help "ruby-mode"]
      ;; shell-mode is to run shell inside Emacs, sh-mode for shell script editing, shell-script-mode is an alias for sh-mode.
      ["Shell script" (progn (sh-mode))
       :style radio :selected (eq major-mode 'sh-mode) :help "sh-mode"]
      ["SQL" (progn (sql-mode))
       :style radio :selected (eq major-mode 'sql-mode) :help "sql-mode"]
      ["Tcl" (progn (tcl-mode))
       :style radio :selected (eq major-mode 'tcl-mode) :help "tcl-mode"]
      ["XML (nxml-mode)" (progn (nxml-mode))
       :style radio :selected (eq major-mode 'nxml-mode) :help "nxml-mode"]
      ["XML (xml-mode)" (progn (xml-mode))
       :style radio :selected (eq major-mode 'xml-mode) :help "xml-mode"]
      ))
  (easy-menu-define my-minor-menu nil "My Minor Menu"
    '("Minor Modes"
      ["Ace Window Display" ace-window-display-mode
       :style toggle :selected ace-window-display-mode :help "ace-window-display-mode"]
      ["Company [Ⓒ]" company-mode
       :style toggle :selected company-mode :help "company-mode"]
      ["Compilation Shell [Ⓒｓ]" compilation-shell-minor-mode
       :style toggle :selected compilation-shell-minor-mode :help "compilation-shell-minor-mode"]
      ["Diff Highlighting" diff-hl-mode
       :style toggle :selected diff-hl-mode :help "diff-hl-mode"]
      ["Display Fill Column Indicator" display-fill-column-indicator-mode
       :style toggle :selected display-fill-column-indicator-mode :help "display-fill-column-indicator-mode"]
      ["Eldoc [Ⓔ]" eldoc-mode
       :style toggle :selected eldoc-mode :help "eldoc-mode"]
      ["Emojify" emojify-mode
       :style toggle :selected emojify-mode :help "emojify-mode"]
      ["Flycheck [𝓕]" flycheck-mode
       :style toggle :selected flycheck-mode :help "flycheck-mode"]  ;; flymake supports less languages
      ["Flyspell" flyspell-mode
       :style toggle :selected flyspell-mode :help "flyspell-mode"]  ;; uses ispell
      ["HideShow" hs-minor-mode
       :style toggle :selected hs-minor-mode :help "hs-minor-mode"]
      ["Horizontal Scroll Bar" horizontal-scroll-bar-mode
       :style toggle :selected horizontal-scroll-bar-mode :help "horizontal-scroll-bar-mode"]
  ;;    ["Ido" ido-mode
  ;;     :style toggle :selected ido-mode :help "ido-mode"]
      ["Ivy [Ⓘ]" ivy-mode
       :style toggle :selected ivy-mode :help "ivy-mode"]
      ["Line Numbers" linum-mode
       :style toggle :selected linum-mode :help "linum-mode"]
      ("Line Wrapping"
       ["Auto Fill Function [↵]" auto-fill-mode
        :style toggle :selected auto-fill-function :help "auto-fill-mode"]
       ["Truncate Long Lines" toggle-truncate-lines   ;; menu-bar--toggle-truncate-long-lines
        :style toggle :selected (or truncate-lines
                                    (truncated-partial-width-window-p))
        :help "toggle-truncate-lines"]
       ["Virtual Auto Fill [Ⓥｆ]" virtual-auto-fill-mode
        :style toggle :selected virtual-auto-fill-mode :help "virtual-auto-fill-mode"]
       ["Visual Line (Word Wrap) [↩]" visual-line-mode
        :style toggle :selected visual-line-mode :help "visual-line-mode"]
       )
      ["Pixel Scroll" pixel-scroll-mode
       :style toggle :selected pixel-scroll-mode :help "pixel-scroll-mode"]
      ["Rainbow" rainbow-mode
       :style toggle :selected rainbow-mode :help "rainbow-mode"]
      ["Scroll-All" scroll-all-mode
       :style toggle :selected scroll-all-mode :help "scroll-all-mode"]
      ["Semantic" semantic-mode
       :style toggle :selected semantic-mode :help "semantic-mode"]
      ["Sphinx Doc [Ⓢ]" sphinx-doc-mode
       :style toggle :selected sphinx-doc-mode :help "sphinx-doc-mode"]
      ["YASnippet [Ⓨ]" yas-minor-mode
       :style toggle :selected yas-minor-mode :help "yas-minor-mode"]
      ["Which Key [Ⓚ]" which-key-mode
       :style toggle :selected which-key-mode :help "which-key-mode"]
      ["Whitespace [␣]" whitespace-mode
       :style toggle :selected whitespace-mode :help "whitespace-mode"]
      ;; "--"  ;; separator
      ;; ["--" 'ignore :visible (featurep 'bookmark+-lit)]  ;; conditional separator
      ;; ["How Many..." how-many]
      ))
  
  (easy-menu-add-item nil () my-menu              ;; add empty my menu to menu-bar
                      ;; "Edit"                   ;; before Edit
                      )
  (easy-menu-add-item nil '("My") my-major-menu)  ;; add submenu to my menu
  (easy-menu-add-item nil '("My") my-lang-menu)
  (easy-menu-add-item nil '("My") my-minor-menu)
  
  (easy-menu-add-item nil '("My") '("--"))
  (easy-menu-define my-view-menu nil "My Views Menu"
    '("Views"
      ["ELisp"  my-view-elisp  :help "my-view-elisp"]
      ["Gnuplot" my-view-gnuplot :help "my-view-gnuplot"]
      ["Org PDF" my-view-org-pdf :help "my-view-org-pdf"]
      ["Python" my-view-python :help "my-view-python"]
      ["Shell" my-view-shell :help "my-view-shell"]
      ))
  (easy-menu-add-item nil '("My") my-view-menu)
  
  (easy-menu-add-item nil '("My") '["Transparency" toggle-transparency :style toggle :selected (transparency-p) :help "toggle-transparency"])

  (with-eval-after-load 'org            ;; org-mode, org-toggle-pretty-entities
    (easy-menu-define my-org-export-menu nil "My Org Export Menu"
      '("Org Export" :visible (eq major-mode 'org-mode)
        ["Article HTML"       my-org-article-html-export-to-html              :help "my-org-article-html-export-to-html"]
        ["Article HTML async" my-org-article-html-export-to-html-notify-async :help "my-org-article-html-export-to-html-notify-async"]
        ["Article PDF"        my-org-article-latex-export-to-pdf              :help "my-org-article-latex-export-to-pdf"]
        ["Article PDF async"  my-org-article-latex-export-to-pdf-notify-async :help "my-org-article-latex-export-to-pdf-notify-async"]
        ))
    (easy-menu-define my-org-minor-mode-menu nil "My Org Minor Mode Menu"
      '("Org Minor Mode / Toggles" :visible (eq major-mode 'org-mode)
        ["Org Fancy Priorities [Ⓟ]" org-fancy-priorities-mode
         :style toggle :selected org-fancy-priorities-mode :help "org-sticky-header-mode"]
        ["Org Latex Remove Logfiles" (setq org-latex-remove-logfiles (not org-latex-remove-logfiles))
         :style toggle :selected org-latex-remove-logfiles :help "org-latex-remove-logfiles"]
        ["Org Link Descriptive" org-toggle-link-display
         :style toggle :selected org-link-descriptive :help "org-toggle-link-display"]
        ["Org Num [＃]" org-num-mode
         :style toggle :selected org-num-mode :help "org-num-mode"]
        ["Org Pretty Entities \\xyz to UTF8 char" org-toggle-pretty-entities
         :style toggle :selected org-pretty-entities :help "org-toggle-pretty-entities"]
        ["Org Sticky Header" org-sticky-header-mode
         :style toggle :selected org-sticky-header-mode :help "org-sticky-header-mode"]
        ["Org Superstar" org-superstar-mode
         :style toggle :selected org-superstar-mode :help "org-superstar-mode"]
        ["Org Table Sticky Header [Ⓣ]" org-table-sticky-header-mode
         :style toggle :selected org-table-sticky-header-mode :help "org-table-sticky-header-mode"]
        ))
    (easy-menu-add-item nil '("My") ["---" 'ignore :visible (eq major-mode 'org-mode)])
    (easy-menu-add-item nil '("My") my-org-export-menu)
    (easy-menu-add-item nil '("My") my-org-minor-mode-menu)
    (easy-menu-add-item nil '("My") '["Org Link Description Update" my-org-link-description-update :visible (eq major-mode 'org-mode) :help "my-org-link-description-update"])
    (easy-menu-add-item nil '("My") '["Org Article Help" my-org-article-help :visible (eq major-mode 'org-mode) :help "my-org-article-help"])
    )

  (with-eval-after-load 'notmuch
    (easy-menu-add-item nil '("My") '["Notmuch Execute Offlineimap" my-mail-exec-offlineimap
                                      :visible (or (eq major-mode 'notmuch-hello-mode)
                                                   (eq major-mode 'notmuch-message-mode)
                                                   (eq major-mode 'notmuch-search-mode)
                                                   (eq major-mode 'notmuch-show-mode)
                                                   (eq major-mode 'notmuch-tree-mode))
                                      :help "my-mail-exec-offlineimap"])
    )
  )

(provide 'general-settings)
;;; general-settings.el ends here
