.emacs-my
author Oleksandr Gavenko <gavenkoa@gmail.com>
Fri, 29 Jan 2021 20:41:47 +0200
changeset 1708 e6320b167b77
parent 1707 84c30e639991
child 1709 5946ac9f14c7
permissions -rw-r--r--
It is more informative to get help on symbol type than just type.

;; -*- mode: emacs-lisp; coding: utf-8; fill-column: 78 -*-
;;
;; Written by Oleksandr Gavenko <gavenkoa@gmail.com>, 2008-2015.
;;
;; This file formed from parts and ideas from many sites/docs and
;; placed in public domain.
;;
;; Config file for GNU Emacs.
;;
;; For load order see README.

(require 'cl-lib)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "silent runing")

(setq inhibit-splash-screen t)
(setq inhibit-startup-message t)
(setq inhibit-startup-buffer-menu t)

(setq initial-scratch-message nil)
(setq initial-major-mode (quote fundamental-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "backuping")

;; Keep it above modes saving state into files or you'll see files like ".recentf~" in "~/.emacs.d".
(setq
 make-backup-files t
 ;; In other case (by renaming) you loose original file creation date.
 backup-by-copying t
 backup-directory-alist '(("." . "~/.emacs.d/.backup")) ; don't litter my fs tree
 delete-old-versions t                         ; delete excess backup versions silently
 kept-old-versions 1                           ; store first original version
 kept-new-versions 3                           ; store last 3 version
 version-control t)                            ; use versioned backups

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "lockfile")

;; (info "(elisp) File Locks")

;; Disable stupid file locking. It breaks editing WSL files from Cygwin Emacs.
;; https://emacs.stackexchange.com/questions/61962/what-is-interlocking-about
;; https://cygwin.com/pipermail/cygwin/2020-November/246887.html
(setq create-lockfiles nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "auto save")

;; Disable auto saving, files "#name#" might trigger false rebuild if there is
;; some file watcher. Also those files looks like garbage in other tools/IDE.
(setq auto-save-default nil)
;; If nil autosave to a different file than the original.
(setq auto-save-visited-file-name nil)
(setq auto-save-interval 300)
;; Note: if you kill unsaved file auto save file not deleted.
(setq delete-auto-save-files t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "helper buffers")

(define-key global-map "\C-v" nil)
(define-key global-map "\C-vt" (lambda nil (interactive) (switch-to-buffer "*scratch*")))

(defvar my-work-file (expand-file-name "~/work.txt"))
(setq initial-buffer-choice my-work-file)
(define-key global-map "\C-vw" (lambda nil (interactive) (find-file my-work-file)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "save-place")

;; `save-place-file' in ".emacs".
(save-place-mode 1) ; since v25.1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "recentf")

(eval-and-compile
  (require 'recentf))

;; (recentf-load-list)
(setq recentf-save-file (concat user-emacs-directory ".recentf"))

;; Prevent TRAMP to login on remote host when loading. Its take time and ask passwords!
(setq recentf-keep '(file-remote-p file-readable-p))
(setq recentf-exclude                   ; Use ``M-x recentf-cleanup`` to update recentf-list.
      '("/devel/[^/]*-\\(orig\\|tmp\\|xxx\\)"
        "/devel/my-\\(merge\\|pull\\)/"
        "/.cache/"
        "\\.png\\'"))

(setq recentf-max-saved-items 10000)
(setq recentf-max-menu-items 40)
(setq recentf-show-file-shortcuts-flag nil)

;; Need to be defined before loading "recentf" because default value is
;; "mode", meaning cleanup when turning the mode on.
(setq recentf-auto-cleanup 600)
;; Disable population of `file-name-history', it causes calls to
;;   abbreviate-file-name => file-name-case-insensitive-p => tramp-autoload-file-name-handler
;; taking 41% of startup time.
;; `ido-switch-buffer' doesn't depends on `file-name-history', nothing to lose.
(setq recentf-initialize-file-name-history nil)

(recentf-mode 1)

(global-set-key (kbd "\e\eq") 'recentf-open-files)
(global-set-key [?\s-q] 'recentf-open-files)

;; (setq recentf-menu-filter 'recentf-arrange-by-dir) ; Too slow with dir widgets.
;; Don't sort ``recentf-list`` so ``recentf-open-files`` show files in historical order!
(setq recentf-menu-filter nil)

(defun my-recentf-clean-project (dir)
  "Remove from recentf all files that belong to DIR directory."
  (interactive (list (read-directory-name "Exclude all paths")))
  (let ( recentf-exclude )
    (setq recentf-exclude (list (concat "^" (regexp-quote (expand-file-name dir)))))
    (recentf-cleanup) ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "revert buffer, auto-revert")

(cl-eval-when (compile) (require 'autorevert))

(global-set-key [f5]    'revert-buffer)
(setq revert-without-query '(".*"))
(setq auto-revert-interval 2)

;; (setq global-auto-revert-mode 1)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "debugging")

;; Shut off message buffer by setting nil.
(setq message-log-max 512)

;; Prevent Emacs from loading 'default.el', which loaded after '.emacs'.
;; Also '-q' prevent loading your init file.
(setq inhibit-default-init nil)         ; t/nil

(defun my-debug (mode)
  "With prefix enable enter to debuger and show backtrace when
problems occur, with double prefix enable debugging on event and
signal, else disable breaking to debugger."
  (interactive "P")
  (let ( (lvl1 (not (not mode))) (lvl2 (equal mode '(16))) )
    (setq debug-on-error lvl1)
    ;; Get trace when press C-g.
    (setq debug-on-quit lvl1)
    (setq debug-on-event lvl2)
    (setq debug-on-signal lvl2)
    (cond
     (lvl2 (message "Debugging on quit/event/signal..."))
     (lvl1 (message "Debugging on quit..."))
     (t (message "Debugging disabled...")))))

(defun my-eval-buffer ()
  "Evaluate entire buffer with re-assigning values to `defvar' / `defcustom'.
Useful during package development."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (eval-defun nil)
      (end-of-defun))))

(defun my-load-library (library)
  "Evaluate entire library with re-assigning values to `defvar' / `defcustom'.
Useful during package development."
  (interactive
   (list (completing-read "Load library: "
                          (apply-partially 'locate-file-completion-table
                                           load-path
                                           '("" ".el")))))
  (with-temp-buffer
    (insert-file-contents (locate-file library load-path '("" ".el")))
    (my-eval-buffer)))

(my-debug nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "user info")

(cl-eval-when (compile) (require 'info))

;; Set in ~/.emacs.d/.emacs-auth:
;; (setq user-full-name "Oleksandr Gavenko")
;; (setq user-mail-address "gavenkoa@gmail.com")
;; (setq user-nick "gavenkoa")
;; (setq user-home-page "http://gavenkoa.users.sf.net")
;; (setq user-home-page "http://defun.work/")

(defvar user-nick (user-login-name)
  "My nick name.")
;; auto-insert and copyright package use this to insert copyright owner. Gnus
;; uses this for Organization header.
(setenv "ORGANIZATION"
        (concat
         user-full-name
         " <" user-mail-address  ">"
         (when (boundp 'user-home-page) (concat ", " user-home-page))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "autoload")

;; Ensure the help doesn't trigger autoloading.
(setq help-enable-autoload nil)
(setq help-enable-completion-autoload nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "my defun, defmacro, defvar")

(defmacro my-filter (pred list)
  "Construct list with elements from LIST which satisfy PRED."
  (let ( (r (make-symbol "r_")) )
    `(let ( (,r (list nil)) )
       (mapc (lambda (item)
               (when (,pred item)
                 (nconc ,r (cons item nil))))
             ,list)
       (cdr ,r))))

(defun my-fold (f x list)
  "Recursively applies (F i j) to LIST starting with X.
For example, (fold F X '(1 2 3)) computes (F (F (F X 1) 2) 3)."
  (let ((li list) (x2 x))
    (while li
      (setq x2 (funcall f x2 (pop li)))
      )
    x2
    ) )

(defun my-assoc-push (key value alist)
  "Add association if `key' is not in `alist' and replace all
accociation with single, if there is `key'."
  (when (not (symbolp alist)) (error "alist is not a symbol."))
  (set alist
       (cons (cons key value)
             (cl-remove key (symbol-value alist) :key #'car :test #'equal))))

(unless (fboundp 'ignore-errors)
  (defmacro ignore-errors (&rest body)
    "Execute BODY; if an error occurs, return nil.
Otherwise, return result of last form in BODY."
    (declare (debug t) (indent 0))
    `(condition-case nil (progn ,@body) (error nil)))
  )

(defun my-lookup-key (key)
  "Search for KEY in all known keymaps."
  (let (result)
    (mapatoms (lambda (ob) (when (and (boundp ob)
                                 (keymapp (symbol-value ob))
                                 (functionp (lookup-key (symbol-value ob) key)))
                        (push ob result)))
              obarray)
    (remove-if-not 'identity result) ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "lisp, elisp")

(cl-eval-when (compile) (require 'chistory))

(setq list-command-history-max 256)

(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)

(defun my-emacs-lisp-mode-hook ()
  (setq tab-width 8))
(add-hook 'emacs-lisp-mode-hook 'my-emacs-lisp-mode-hook)

(defun my-elisp-find-tag ()
  (interactive)
  (require 'etags)
  (ring-insert find-tag-marker-ring (point-marker))
  (unless (find-variable-at-point)
    (find-function-at-point)
    ))
;; Goto elisp definition.
(define-key emacs-lisp-mode-map (kbd "M-.") 'my-elisp-find-tag)

(if (not (fboundp 'global-prettify-symbols-mode))
    ;; http://www.emacswiki.org/emacs/PrettyLambda
    (font-lock-add-keywords
     'emacs-lisp-mode
     `(("(\\<\\(lambda\\)\\>"
        (1 (progn (compose-region (match-beginning 1) (match-end 1) ,(make-char 'greek-iso8859-7 107)) font-lock-keyword-face)) )))
  (global-prettify-symbols-mode 1))

(defun my-dump-funcs ()
  "Dump all function calls in current buffer. Useful to explore
elisp API from somebody else files."
  (interactive)
  (let* ( (cur-buffer (current-buffer)) (new-buffer (get-buffer-create (concat (buffer-name cur-buffer) "-funcs.el"))) symb )
    (while (search-forward-regexp "([[:alnum:]*]" nil t)
      (setq symb (thing-at-point 'symbol))
      (with-current-buffer new-buffer
        (insert symb)
        (insert-char ?\n 1)))
    (switch-to-buffer new-buffer)
    (shell-command-on-region (point-min) (point-max) "sort -u" nil t)
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "mode groups")

(defmacro my-defun-rename-symb-tree (name doc func)
  "Travel by TREE and applies FUNC to each symbol."
  `(defun ,name (tree)
     ,doc
     (cond
      ((symbolp tree)
       (,func tree)
       )
      ((listp tree)
       (mapcar ',name tree)
       )
      (t (error "Only tree of symbols allowed"))
      )))

(my-defun-rename-symb-tree
 my-feature2mode
 "Convert TREE of features to TREE of modes for these features. Single symbol allowed."
 (lambda (symb) (intern (concat (symbol-name symb) "-mode"))))

(my-defun-rename-symb-tree
 my-mode2hook
 "Convert TREE of modes to TREE of hooks for these modes. Single symbol allowed."
 (lambda (symb) (intern (concat (symbol-name symb) "-hook")))
 )

(my-defun-rename-symb-tree
 my-mode2modemap
 "Convert TREE of modes to TREE of keymaps for these modes. Single symbol allowed."
 (lambda (symb) (intern (concat (symbol-name symb) "-map")))
 )

(defvar my-prog-mode-list
  '(nsis-mode
    html-mode nxml-mode wesnoth-mode
    LilyPond-mode
    texinfo-mode
    gadict-mode)
  "List of development modes.")

(defvar my-prog-hook-list
   (my-mode2hook my-prog-mode-list)
  "List of development mode hooks.")

(defvar my-text-mode-list
  '(text-mode
    outline-mode
    rst-mode
    diff-mode
    magit-revision-mode
    dict-c5-mode)
  "List of text modes.")

(defvar my-text-mode-hook-list
  (my-mode2hook my-text-mode-list)
  "List of text mode hooks.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "MS Windows, w32, win32")

;; To remap CapsLock to ScrollLock:
;; Windows Registry Editor Version 5.00
;; [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
;; ; CapsLock (3a,00) => LWin (5b,e0); LWin (5b,e0) => Apps (5d,e0)
;; "Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,5b,e0,3a,00,5d,e0,5b,e0,00,00,00,00
(when (eq window-system 'w32)
  (setq w32-apps-modifier 'super))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "appearance")

;; To maximize frame on full screen, not work with Windows Emacs 21.4.
;; And maked different height with Emacs 22.3 and 23.1.
;; (setq initial-frame-alist '((fullscreen . fullboth)))

(cl-eval-when (compile) (load-library "window"))

(setq display-buffer-reuse-frames t)

(defun my-maximize ()
  ;; Next code work with Emacs 21.4, 22.3, 23.1.
  (let (
        (px (display-pixel-width))
        (py (display-pixel-height))
        (fx (frame-char-width))
        (fy (frame-char-height))
        tx ty
        )
    ;; Next formulas discovered empiric on Windows host with default font.
    (setq tx (- (/ px fx) 7))
    (setq ty (- (/ py fy) 4))
    (setq initial-frame-alist '((top . 2) (left . 2)))
    (add-to-list 'initial-frame-alist (cons 'width tx))
    (add-to-list 'initial-frame-alist (cons 'height ty)) ))

(when window-system
  (if (fboundp 'toggle-frame-maximized)
      (toggle-frame-maximized)
    (my-maximize) )
  (add-to-list 'default-frame-alist '(fullscreen . maximized)))

(menu-bar-mode -1)
(when window-system
  (mouse-avoidance-mode 'animate)
  (scroll-bar-mode 1)
  (tool-bar-mode -1)
  (tooltip-mode -1)
  (setq-default line-spacing nil)
  (defun my-popup-menu ()
    "Menu from keyboard by emulating mouse event."
    (interactive)
    (mouse-popup-menubar
     (list (list (/ (display-pixel-width) 2) 10) (get-buffer-window (buffer-name)))
     nil) )
  (global-set-key [f10] 'my-popup-menu)
  (global-set-key [apps] 'my-popup-menu)
  (global-set-key [menu] 'my-popup-menu) )

;; Prefer horizontal windows splitting.
(when (>= emacs-major-version 23)
  (setq split-height-threshold nil)
  (setq split-width-threshold nil)
  )

(setq frame-title-format '("EMACS " system-name ": %b"))
(setq icon-title-format '("EMACS " system-name ": %b"))

;; Deprecated: `default-header-line-format', `default-mode-line-format'.
;; For `mode-line-format' default value was used.
(setq-default header-line-format nil)

(setq-default left-fringe-width nil)
(setq-default right-fringe-width nil)
(setq-default left-margin-width nil)
(setq-default right-margin-width nil)

(if (< emacs-major-version 24)
    (setq default-truncate-lines nil)
  (setq-default truncate-lines nil))
(setq truncate-partial-width-windows nil)

(setq large-file-warning-threshold (* 12 1000 1000)) ; Greater then 10 MiB in order to open logs without warnings.

;; show column & line numbers in status bar
(setq column-number-mode t)
(setq line-number-mode t)
(setq size-indication-mode t)
(setq line-number-display-limit large-file-warning-threshold)
(setq line-number-display-limit-width 200)
;; (linum-mode 1)
;; (global-linum-mode 1)

(when window-system
  (set-background-color "white")
  (set-foreground-color "black")
  (set-cursor-color "brown")
  ;; (set-mouse-color "white")
  (setq cursor-type 'box)           ; box, hollow, bar, hbar
  ;;(setq blink-matching-delay 0.01)
  (blink-cursor-mode 1)
  (setq use-file-dialog t)
  (setq use-dialog-box t)
  ;; (set-face-font 'default "7x14")
  )

;; See what I am typing immediately (for keystroke in minibuffer).
(setq echo-keystrokes 0.2)

(defun my-dpi ()
  (let* ((attrs (car (display-monitor-attributes-list)))
         (size (assoc 'mm-size attrs))
         (sizex (cadr size))
         (res (cdr (assoc 'geometry attrs)))
         (resx (- (caddr res) (car res)))
         dpi)
    (catch 'exit
      ;; in terminal
      (unless sizex
        (throw 'exit 10))
      ;; on big screen
      (when (> sizex 1000)
        (throw 'exit 10))
      ;; DPI
      (* (/ (float resx) sizex) 25.4))))

(defun my-preferred-font-size ()
  (let ( (dpi (my-dpi)) )
  (cond
    ((< dpi 110) 10)
    ((< dpi 130) 11)
    ((< dpi 160) 12)
    (t 12))))

(defvar my-preferred-font-size (my-preferred-font-size))

(defvar my-regular-font
  (cond
   ((eq window-system 'x) (format "DejaVu Sans Mono-%d:weight=normal" my-preferred-font-size))
   ((eq window-system 'w32) (format "Courier New-%d:antialias=none" my-preferred-font-size))))
(defvar my-symbol-font
  (cond
   ((eq window-system 'x) (format "DejaVu Sans Mono-%d:weight=normal" my-preferred-font-size))
   ((eq window-system 'w32) (format "DejaVu Sans Mono-%d:antialias=none" my-preferred-font-size))))

(cond
 ((eq window-system 'x)
  (if (and (fboundp 'find-font) (find-font (font-spec :name my-regular-font)))
      (set-frame-font my-regular-font)
    (set-frame-font "7x14")))
 ((eq window-system 'w32)
  (set-frame-font my-regular-font)
  ;; (set-default-font my-regular-font)
  (add-to-list 'default-frame-alist
               (cons 'font my-regular-font))
  (set-fontset-font nil 'cyrillic my-regular-font)
  (set-fontset-font nil 'greek my-regular-font)
  (set-fontset-font nil 'phonetic my-regular-font)
  (set-fontset-font nil 'symbol my-symbol-font)))

(fset 'yes-or-no-p 'y-or-n-p)

(when (boundp 'confirm-kill-emacs)
  (setq confirm-kill-emacs 'y-or-n-p))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "date, time")

(require 'time)

;; Also useful such format: (setq display-time-format " %H:%M %d-%m-%y ")
(setq display-time-24hr-format t)
(setq display-time-day-and-date nil)
(setq display-time-default-load-average nil)
(display-time)                          ; display-time-mode

;; For (display-time-world).
(setq display-time-world-time-format "%A %d %B %R %z %Z")
(setq display-time-world-list
      '(("Europe/London" "London")
        ("EET" "Eastern European")
        ("Europe/Moscow" "Moscow")
        ("Asia/Tel_Aviv" "Tel Aviv")
        ("America/Chicago" "Chicago/US Central")
        ("America/Los_Angeles" "Los Angeles")
        ("America/New_York" "New York")
        ("Asia/Tokyo" "Tokyo")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "shell, bash, Cygwin, MSYS")

(cl-eval-when (compile) (require 'shell))

(defvar my-use-windows-shell nil
  "If t 'cmdproxy.exe' will be used as shell.
Affect on \\[shell] like commands. If nil, 'sh' will be used." )

(defun follow-cygwin-symlink ()
  "Follow new-style (and also UCS-16) Cygwin symlinks."
  (save-excursion
    (goto-char 0)
    (when (looking-at "!<symlink>\xff\xfe")
      (find-alternate-file
       (substring
        (decode-coding-string
         (buffer-substring (match-end 0) (point-max))
         'utf-16-le)
        0 -1)                           ; -1 for stripping final \0.
       ))))

(defvar cygwin-mount-table--internal)
(defun my-dos2cygwin-path (path)
  "Convert DOS path to Cygwin according to current mount table."
  (interactive (list (read-directory-name "Enter DOS path: ")))
  (setq path (replace-regexp-in-string "\\\\" "/" (expand-file-name path)))
  (let ( (table cygwin-mount-table--internal) item prefix )
    (while table
      (setq item (car table))
      (setq prefix (concat "\\`" (regexp-quote (car item))))
      (setq table (cdr table))
      (when (string-match prefix path)
        (setq path (replace-regexp-in-string prefix (cdr item) path))
        (setq table nil)
        ) )
    path
    ))

(defun my-shell-quote-argument (arg)
  (cond
   ((string-match "[<>&|* \"()[]" arg)
    (concat "'" arg "'"))
   ((string-match "'" arg)
    (concat "\"" arg "\""))
   (t
    arg)))

;; Activate Cygwin for native Windows Emacs if available.
(when (eq system-type 'windows-nt)
  (ignore-errors
    (require 'cygwin-mount)
    (cygwin-mount-activate))
  (add-hook 'find-file-hook 'follow-cygwin-symlink)
  ;; Workaround for Cygwin shell, when set 'CYGWIN=noglob'. By default 'shell-quote-argument'
  ;; quoted by double '\' chars this cause failure.
  (advice-add #'shell-quote-argument :override #'my-shell-quote-argument)
  ;; Workaround for Cygwin when 'shell-file-name' is 'bash'.
  (setq null-device "/dev/null")
  ;; Use shell from Cygwin/MinGW.
  (setq shell-file-name "bash")
  (setenv "SHELL" "/bin/bash")
  ;; (modify-coding-system-alist 'process "bash" '(cp1251-unix . cp1251-unix))
  )

(when (eq system-type 'windows-nt)
  ;; Fix 'starttls.el' on native Windows Emacs with gnutls-cli from Cygwin.
  ;; 'gnutls-cli' run with '-s' opt and process wait for SIGALRM.
  ;; But build-in native Emacs 'kill' command can not send such Cygwin
  ;; specific sygnal. So 'starttls-negotiate-gnutls' function infinitely
  ;; wait for 'gnutls-cli' output.
  (defadvice signal-process (around cygwin (process sigcode))
    "Use 'kill.exe' instead build-in Emacs 'kill'."
    (if (eq sigcode 'SIGALRM)
        (shell-command
         (format "kill.exe -s SIGALRM %d"
                 (if (processp process) (process-id process) process)))
      ad-do-it
      ))
  (ad-activate 'signal-process)
  (modify-coding-system-alist 'process "gnutls-cli" '(binary . binary))
  )

(when (eq system-type 'windows-nt)
  (add-to-list 'exec-suffixes ".py")
  (add-to-list 'exec-suffixes ".sh")
  (defun executable-find (command) (locate-file command exec-path exec-suffixes))
  )

(ansi-color-for-comint-mode-on)

(defun my-ansi-color (&optional beg end)
  "Interpret ANSI color esacape sequence by colorifying cotent.
Operate on selected region on whole buffer."
  (interactive
   (if (use-region-p)
       (list (region-beginning) (region-end))
     (list (point-min) (point-max))))
  (ansi-color-apply-on-region beg end))

(setq explicit-bash-args '("-i"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "term")

(cl-eval-when (compile) (require 'term))

(when (eq system-type 'cygwin)
  (setq explicit-shell-file-name "bash"))

(setq term-buffer-maximum-size (lsh 1 14))

(setq term-scroll-show-maximum-output t)

(my--eval-after-load term
  ;; (define-key term-raw-map [S-insert] 'term-paste) - defined inside mode!
  (define-key term-mode-map [?\t] #'term-dynamic-complete)
  (defun my-term-send-delete-word-forward () (interactive) (term-send-raw-string "\ed"))
  (defun my-term-send-delete-word-backward () (interactive) (term-send-raw-string "\e\C-h"))
  (define-key term-raw-map [C-delete] 'my-term-send-delete-word-forward)
  (define-key term-raw-map [C-backspace] 'my-term-send-delete-word-backward)
  (defun my-term-send-forward-word () (interactive) (term-send-raw-string "\ef"))
  (defun my-term-send-backward-word () (interactive) (term-send-raw-string "\eb"))
  (define-key term-raw-map [C-left] 'my-term-send-backward-word)
  (define-key term-raw-map [C-right] 'my-term-send-forward-word)
  (defun my-term-send-m-right () (interactive) (term-send-raw-string "\e[1;3C"))
  (defun my-term-send-m-left () (interactive) (term-send-raw-string "\e[1;3D"))
  (define-key term-raw-map [M-right] 'my-term-send-m-right)
  (define-key term-raw-map [M-left] 'my-term-send-m-left) )

(defun my-term-mode-hook ()
  (goto-address-mode 1))
(add-hook 'term-mode-hook #'my-term-mode-hook)

(setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "proced")

(setq-default proced-format 'medium)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "whitespaces")

(cl-eval-when (compile) (require 'whitespace))

(setq-default indicate-empty-lines t)
(setq-default indicate-buffer-boundaries 'left)

;; Old trailing whitespace highlighter built-in into Emacs engine, until global-whitespace-mode is fixed.
(setq-default show-trailing-whitespace t)
(set-face-attribute 'trailing-whitespace nil :background "magenta")

;; whitespace-style "face" causes double quoted strings to be highlighted by font-lock-string-face.
;; https://emacs.stackexchange.com/questions/61770/whitespace-style-face-activats-highlighting-of-quoted-string-in-fundamental-mo
;; (setq whitespace-style '(face trailing tabs))
;; (setq whitespace-global-modes t)
;; (ignore-errors
;;   (require 'whitespace)
;;   (global-whitespace-mode -1))

(setq next-line-add-newlines nil)

;; See also 'mode-require-final-newline'.
(add-hook 'text-mode-hook (lambda () (setq require-final-newline nil)))

(when (fboundp 'cycle-spacing)
  (global-set-key (kbd "M-SPC") 'cycle-spacing))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "server")

(cl-eval-when (compile) (require 'server))

(when (equal window-system 'w32)
  ;; including cygwin here as socket in /tmp directory is a subject of cleanup...
  (setq server-use-tcp t))
(when (and (>= emacs-major-version 22))
  (require 'server)
  (when server-use-tcp
    (unless (file-directory-p server-auth-dir)
      (mkdir server-auth-dir)))
  (when (and (>= emacs-major-version 23) (equal window-system 'w32))
    (defun server-ensure-safe-dir (dir) "Noop" t)) ; Suppress error directory ~/.emacs.d/server is unsafe on windows.
  (when (or (= emacs-major-version 22) (not (eq (server-running-p server-name) t)))
    (server-start)) )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "standart/general settings")

;; Try to speed things up, especially in VM.
(setq gc-cons-threshold 2000000)

;; Default 'command-history' length too short (in Emacs 23.2 is 30).
(setq history-length 200)
(setq history-delete-duplicates t)

;; Don't beep in my headphones!
(setq ring-bell-function '(lambda () "Empty ring-bell-function." nil))
(setq visible-bell t) ; With default ring-bell-function in text terminal
                      ; revert screen if press [end] or [home]
(setq track-eol nil)

(setq enable-recursive-minibuffers t)

;; Prompt before evaluating local bits of lisp.  This stops people
;; putting things at the end of files which delete all your files!
(setq enable-local-variables :safe
      enable-local-eval      1)

(setq kill-whole-line t)

;; Disable because of bug with gettext.el. See
;;   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=287261
;; (setq view-read-only t)

(setq read-quoted-char-radix 16)

;; https://emacs.stackexchange.com/questions/33117/showing-bytes-as-hexadecimal-escapes-rather-than-octal-escapes
(cond
 ((>= emacs-major-version 26)
  (setq display-raw-bytes-as-hex t))
 ((and (>= emacs-major-version 22) (not (eq system-type 'darwin)))
  (setq standard-display-table (make-display-table))
  (let ( (i ?\x80) hex hi low )
    (while (<= i ?\xff)
      (aset standard-display-table (unibyte-char-to-multibyte i)
            (cl-map 'vector
                    (lambda (c) (make-glyph-code c 'escape-glyph))
                    (format "\\%02x" i)))
      (setq i (1+ i))))))

(defun my--get-char (name)
  "Get character by Unicode `name'."
  (cond
   ((<= 26 emacs-major-version)
    (gethash name (ucs-names)))
   ((<= 23 emacs-major-version)
    (cdr (assoc-string name (ucs-names))))
   (t (error "Emacs version is too old and lacks Unicode support..."))))

(when (>= emacs-major-version 23)
  (define-key global-map "\C-x8g" (lambda nil (interactive) (insert-char (my--get-char "HRYVNIA SIGN"))))
  (define-key global-map "\C-x8e" (lambda nil (interactive) (insert-char (my--get-char "EURO SIGN")))) )

;; generic-define-* before (require 'generic-x) allow load all useful extra modes.
(defvar generic-define-mswindows-modes t)
(defvar generic-define-unix-modes t)

(setq generic-extras-enable-list
      '(apache-conf-generic-mode apache-log-generic-mode hosts-generic-mode java-manifest-generic-mode java-properties-generic-mode
        ;; javascript-generic-mode ansible-inventory-generic-mode
       show-tabs-generic-mode vrml-generic-mode bat-generic-mode inf-generic-mode ini-generic-mode rc-generic-mode reg-generic-mode
       rul-generic-mode alias-generic-mode
       etc-fstab-generic-mode etc-modules-conf-generic-mode etc-passwd-generic-mode etc-services-generic-mode etc-sudoers-generic-mode
       fvwm-generic-mode inetd-conf-generic-mode mailagent-rules-generic-mode mailrc-generic-mode named-boot-generic-mode named-database-generic-mode
       prototype-generic-mode resolve-conf-generic-mode samba-generic-mode x-resource-generic-mode xmodmap-generic-mode))

(require 'generic-x)

;; The following commands are usually disabled by default. Enable them...
(put 'eval-expression  'disabled nil)
(put 'downcase-region  'disabled nil)
(put 'upcase-region    'disabled nil)
(put 'narrow-to-page   'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'scroll-left      'disabled nil)
(put 'set-goal-column  'disabled nil)

(setq
 use-dialog-box t
 x-gtk-show-hidden-files t
 )

(defun my-prevent-kill-buffer ()
  (if (member (buffer-name) '("*scratch*" "NOTE.org")) nil t))
(add-to-list 'kill-buffer-query-functions 'my-prevent-kill-buffer)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "scrolling")

(defvar my-scroll-margin 4)

(setq-default
 ;; Set to zero as this recommend documentation.
 scroll-step 0
 ;; If the value is greater than 100, redisplay will never recenter point, but
 ;; will always scroll just enough text to bring point into view
 scroll-conservatively 1000
 scroll-preserve-screen-position t
 )

(defvar my-scroll-margin-mode-list
  '(vc-dir-mode
    recentf-dialog-mode
    org-agenda-grid-mode           ; XXX for this item not worked!
    log-view-mode
    dired-mode
    compilation-mode
    conf-mode)
  "List of modes for enabling scroll margin.")

;; Set margin only for desired modes! Do not frustrate calendar any more.
(make-variable-buffer-local 'scroll-margin)
(defun my-set-scroll-margin () (setq scroll-margin my-scroll-margin))
(mapc (lambda (hook) (add-hook hook #'my-set-scroll-margin))
      (delete-dups (append my-text-mode-hook-list
                           my-prog-hook-list
                           (my-mode2hook my-scroll-margin-mode-list)
                           '(prog-mode-hook))) )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "chars, unicode")

(defun my-print-unicode (&optional start end)
  "Print UNICODE table."
  (interactive "nstart: \nnend: ")
  (switch-to-buffer (get-buffer-create "*UNICODE*"))
  (erase-buffer)
  (let ( (i start) )
    (while (<= i end)
      (insert (format "%s: U+%04x, %s\n" (char-to-string i) i (get-char-code-property i 'name)))
      (setq i (1+ i))
      )))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "search, isearch, occur")

(setq-default case-fold-search t)

(setq query-replace-highlight t)        ; highlight during query
(setq search-highlight t)               ; highlight incremental search

;; Make old Emacs key binding like in Emacs 23.x.
(when (< emacs-major-version 23)
  (global-set-key (kbd "M-s o") 'occur)
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "grep, find, ack, ag")

(cl-eval-when (compile) (require 'find-dired))

;; -ls produce very noisy output:
;; (setq find-ls-option '("-ls" . ""))
;; So I use next expression, which work with GNU find, I replace %s with '0'
;; to avoid unnecessary sys calls and this make output aligned by column:
(setq find-ls-option '("-printf ' -rw-rw-rw- %9s %AY-%Am-%Ad %AH:%AM %p\n'" . ""))

(cl-eval-when (compile) (require 'grep))

;; Do not set t because some grep do not has --color options.
(setq grep-highlight-matches nil)
(setq grep-use-null-device nil)

(my--eval-after-load grep
  (add-to-list 'grep-find-ignored-directories "build" t)
  (add-to-list 'grep-find-ignored-directories "dist" t)
  (add-to-list 'grep-find-ignored-directories "lib" t)
  (add-to-list 'grep-find-ignored-directories "_build" t)
  (add-to-list 'grep-find-ignored-directories "_dist" t)
  (add-to-list 'grep-find-ignored-directories "_lib" t)
  (when (boundp 'grep-find-ignored-files)
    (add-to-list 'grep-find-ignored-files "*TAGS")
    (add-to-list 'grep-find-ignored-files "GPATH")) )

(global-set-key [M-f7] 'rgrep)

(global-set-key [f7] 'my-ag)
(global-set-key [S-f7] 'my-ag-default-directory)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "highlighting")

;; Increase scrolling speed by defer consuming operation.
;; I disable this due to bugs in Emacs (it doesn't highlight at all until you
;; press any key).
;; (setq jit-lock-defer-time 0.01)

(setq font-lock-maximum-decoration t)
(global-font-lock-mode 1)

;; http://debbugs.gnu.org/cgi/bugreport.cgi?archive=yes&bug=22620
;; 24.5; "(global-hi-lock-mode 1)" broke "C-x" key bindings inside "M-x term", especially for "emacs -nw" (Emacs inside Emacs).
; (global-hi-lock-mode -1)

(when window-system
  (set-face-attribute 'shadow nil :foreground "gray60")) ;; tan, gray70

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "highlight selected text")

(delete-selection-mode 1)

(defvar pc-select-selection-keys-only)
(defvar pc-select-meta-moves-sexps)
(when (<= emacs-major-version 23)
  ;; 1/-1, when the mark is active, the region is highlighted.
  (transient-mark-mode 1)
  ;; Order of next items is important, (assignment must done before pc-selection-mode enabled).
  (require 'pc-select)
  (setq pc-select-selection-keys-only t)  ; To avoid some key bindings as F6, etc.
  (setq pc-select-meta-moves-sexps t)
  (pc-selection-mode 1) )

(when window-system
  (set-face-attribute 'region nil :background "light blue"))

(when (eq window-system 'x)
  (setq x-select-enable-clipboard t))

(when (fboundp 'er/expand-region)
  (global-set-key (kbd "s-=") 'er/expand-region))

(defun my-mark-line ()
  "Mark current line."
  (forward-line 0)
  (set-mark (point))
  (forward-line 1)
  (exchange-point-and-mark))

(setq-default er/try-expand-list '(er/mark-word er/mark-symbol er/mark-inside-quotes er/mark-outside-quotes er/mark-inside-pairs er/mark-outside-pairs my-mark-line))

(my--eval-after-load text-mode-expansions
  (add-to-list 'expand-region-exclude-text-mode-expansions 'org-mode)
  (add-to-list 'expand-region-exclude-text-mode-expansions 'rst-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "highlighting current line")

(require 'hl-line)

(defun my-hl-line-range-function ()
  (cons (line-end-position) (line-beginning-position 2)))
(setq hl-line-range-function #'my-hl-line-range-function)

(set-face-attribute 'hl-line nil :inherit nil :background "light yellow")
(setq global-hl-line-sticky-flag t)
(global-hl-line-mode 1)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "paren, braces")

(require 'paren)

(when window-system
  (face-spec-set 'show-paren-match '((t :background "wheat"))))
;; parenthesis, expression, mixed
(setq show-paren-style 'expression)

;; show-paren-mode is global, to override have to be local variable.
(make-variable-buffer-local 'show-paren-mode)
(show-paren-mode 1)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "input method")

(setq mouse-yank-at-point t)

;; (pc-bindings-mode) ; I define own keybinding...

;; cyrillic-jis-russian  for 567 is :,.
;; cyrillic-jcuken  for SHIFT 567 is :,.
;; russian-computer for SHIFT 567 is %^&
(setq default-input-method 'russian-computer)

(defun my-toggle-input-method (&optional arg)
  (interactive "P")
  (if (numberp arg)
      (cond
       ((eq arg 1)
        (activate-input-method nil))
       ((eq arg 2)
        (activate-input-method 'russian-computer))
       ((eq arg 3)
        (activate-input-method 'ukrainian-computer))
       ((eq arg 4)
        (activate-input-method 'greek))
       ((eq arg 5)
        (activate-input-method 'ipa-x-sampa))
       ((eq arg 6)
        (activate-input-method 'TeX))
       ((eq arg 7)
        (activate-input-method 'rfc1345)) )
    (toggle-input-method arg)) )

(global-set-key (kbd "C-\\") 'my-toggle-input-method)

;; I found this more quick method to allow `forward-word' across pronunciation
;; as a whole word.
(defconst my-ipa-chars (list ?ˈ ?ˌ ?ː ?ǁ ?ʲ ?θ ?ð ?ŋ ?ɡ ?ʒ ?ʃ ?ʧ ?ə ?ɜ ?ɛ ?ʌ ?ɒ ?ɔ ?ɑ ?æ ?ʊ ?ɪ))
(when (boundp 'char-script-table)       ; Absent in Emacs 22.
  (mapc (lambda (ch)
          (aset char-script-table ch 'latin)
          (modify-syntax-entry ch "w"))
        my-ipa-chars))
;; Another option is to invent new category:
;;
;; (defconst my-ipa-chars (list ?ˈ ?ˌ ?ː ?ǁ ?ʲ ?θ ?ð ?ŋ ?ɡ ?ʒ ?ʃ ?ʧ ?ə ?ɜ ?ɛ ?ʌ ?ɒ ?ɔ ?ɑ ?æ ?ʊ ?ɪ))
;; (define-category ?p "Phonetic")
;; (mapc (lambda (ch)
;;         (cond
;;          ((eq (aref char-script-table ch) 'phonetic)
;;           (modify-category-entry ch ?p)
;;           (modify-category-entry ch ?l nil t))
;;          ((eq (aref char-script-table ch) 'latin)   ; (aref char-script-table ?ˌ) is 'latin but (char-category-set ?ˌ) is ".j"
;;           (modify-category-entry ch ?l))))
;;       my-ipa-chars)
;; (add-to-list 'word-combining-categories '(?p . ?l))
;; (add-to-list 'word-combining-categories '(?l . ?p))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "mouse")

;; Scroll Bar gets dragged by mouse butn 1
(global-set-key [vertical-scroll-bar down-mouse-1] 'scroll-bar-drag)
;; Paste at point NOT at cursor
(setq mouse-yank-at-point t)
(when window-system
  (mouse-wheel-mode 1))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "key binding, short-keys")

(defun my--smart-beginning-of-line ()
  "Move point to `beginning-of-line'. If repeat command it cycle
position between `back-to-indentation' and `beginning-of-line'."
  (interactive "^")
  (if (and (eq last-command 'my--smart-beginning-of-line)
           (= (line-beginning-position) (point)))
      (back-to-indentation)
    (beginning-of-line)))

(defun my--smart-end-of-line ()
  "Move point to `end-of-line'. If repeat command it cycle
position between last non-whitespace and `end-of-line'."
  (interactive "^")
  (if (and (eq last-command 'my--smart-end-of-line)
           (= (line-end-position) (point)))
      (skip-syntax-backward " " (line-beginning-position))
    (end-of-line)))

(global-set-key [home]     'my--smart-beginning-of-line)
(global-set-key [end]      'my--smart-end-of-line)
(global-set-key [C-home]   'beginning-of-buffer)
(global-set-key [C-end]    'end-of-buffer)
(global-set-key [C-delete] 'kill-word)
(global-set-key [delete]   'delete-char)
;; (global-set-key [backspace]  'backward-delete-char-untabify) ; not work properly in *info* mode

(global-set-key [f2]    'save-buffer)
(global-set-key [S-f6]  'rename-buffer)
(global-set-key [M-f4]  'save-buffers-kill-emacs)
(global-set-key [f6]    'toggle-truncate-lines)
(global-set-key [s-tab] 'other-window)

;; Disable suspend. It is ugly.
(when window-system
  (global-set-key (kbd "C-z") nil))
(global-set-key (kbd "C-x C-z") nil)

;; (global-set-key [language-change] 'ignore)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "coding system, charset, locale, lang")

;; Comment because prefer-coding-system will be ignored.
;; (setq-default coding-system-for-read  'cp1251-dos)
;; (setq-default coding-system-for-write 'cp1251-dos)

;; (setq locale-coding-system  'cp1251-dos)
;; (set-language-environment 'UTF-8)
;; (set-terminal-coding-system 'cp1251)
;; (set-keyboard-coding-system 'cp1251)

(modify-coding-system-alist 'file "\\.el" 'iso-2022-7bit)
(cond
 ((equal window-system 'w32)          ; also (string-equal system-type "windows-nt")
  ;; (set-selection-coding-system 'utf-16-le-dos)
  ;; (setq-default buffer-file-coding-system 'cp1251)
  ;; (setq default-file-name-coding-system 'cp1251)
  ;; (setq default-process-coding-system '(cp1251 . cp1251))
  (setq default-process-coding-system '(utf-8-dos . utf-8-unix))
  )
 ((equal window-system 'x)
  (prefer-coding-system 'utf-8-unix)
  (setq selection-coding-system nil)
  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
  (modify-coding-system-alist 'process ".*" 'utf-8-unix)
  )
 ((eq system-type 'cygwin)
  (when (and (getenv "LANG") (string-match "1251\\'" (getenv "LANG")))
    ;; (prefer-coding-system 'cp1251-unix)
    (prefer-coding-system 'utf-8-unix)
    ;; (modify-coding-system-alist 'process ".*" 'cp1251-unix)
    )
  )
 ((eq system-type 'darwin)
  nil
  )
 )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "ibuffer")

;; buffer-menu better then buffer-list, but ibuffer much better.
(global-set-key "\C-x\C-b" 'ibuffer)
(global-set-key [s-insert] 'ibuffer)

(setq ibuffer-expert t)
(setq ibuffer-use-other-window nil)
(setq ibuffer-default-shrink-to-minimum-size nil)
(setq ibuffer-truncate-lines t)
(setq ibuffer-default-sorting-mode 'recency)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "selecting/switching, creating/killing buffers, open file")
(message "ivy, ido, ffap")

;; (add-hook 'find-file-hook #'make-frame-visible)

(require 'ffap)
(cl-eval-when (compile) (require 'ido nil t))

;; Ido makes appropriate binding.
;(ffap-bindings)
;; C-u C-x C-f finds the file at point
;(setq ffap-require-prefix t)
;; browse urls at point via w3m
;(setq ffap-url-fetcher 'w3m-browse-url)

(setq find-file-existing-other-name t)

(setq ivy-use-virtual-buffers t)

(setq ido-enable-flex-matching t)

(setq ido-use-filename-at-point 'guess)
(setq ido-use-url-at-point t)
(setq ido-auto-merge-work-directories-length -1)
(setq ido-enable-tramp-completion t)
(setq ido-use-virtual-buffers t)
(setq ido-max-prospects 16)
(setq ido-max-work-directory-list 100)

(setq ido-create-new-buffer 'always)

(setq ido-file-extensions-order '(".java" ".c" ".py" ".xml" ".txt" ".el" ".ini" ".cfg" ".cnf" ".log"))

(setq ido-ignore-buffers '("\\` "))
(setq ido-ignore-extensions nil)        ; From completion-ignored-extensions.
(setq ido-case-fold t)
;; ido-ignore-directories
;; ido-ignore-files

(unless
    (ignore-errors
      (require 'ido)
      (ido-mode 1)                      ; (ido-everywhere 'both)
      (global-set-key [?\s-d] #'ido-dired)
      (global-set-key [?\s-f] #'ido-find-file)
      t)
  (global-set-key [?\s-d] #'dired)
  (global-set-key [?\s-f] #'find-file))

(when (package-installed-p 'ivy)
  (global-set-key (kbd "C-x b") #'ivy-switch-buffer))

(global-set-key [?\C-x right] 'next-buffer)
(global-set-key [?\C-x left]  'previous-buffer)
(global-set-key [s-right] 'next-buffer)
(global-set-key [s-left]  'previous-buffer)
(defun my--kill-this-buffer-maybe-switch-to-next ()
  "Kill current buffer. Switch to next buffer if previous command
was switching to next buffer or this command itself allowing
sequential closing of uninteresting buffers."
  (interactive)
  (let ( (cmd last-command) )
    (kill-buffer (current-buffer))
    (when (memq cmd (list 'next-buffer this-command))
      (next-buffer))))
(global-set-key [?\C-x deletechar] 'my--kill-this-buffer-maybe-switch-to-next)
(global-set-key [s-delete] 'my--kill-this-buffer-maybe-switch-to-next)
(defun my--backward-other-window ()
  (interactive)
  (other-window -1))
(global-set-key [?\C-x up] #'my--backward-other-window)
(global-set-key [?\C-x down] #'other-window)
(global-set-key [s-up] #'my--backward-other-window)
(global-set-key [s-down] #'other-window)

(defun my--erase-buffer ()
  (interactive)
  (advice-add #'ask-user-about-supersession-threat :override #'identity)
  (erase-buffer)
  (when (buffer-file-name)
    (basic-save-buffer-1)
    (revert-buffer))
  (advice-remove #'ask-user-about-supersession-threat #'identity))
(global-set-key [s-backspace] #'my--erase-buffer)

(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward)
(setq uniquify-separator "|")
(setq uniquify-after-kill-buffer-p t)
(setq uniquify-strip-common-suffix t)

(setq read-buffer-completion-ignore-case t)
(setq read-file-name-completion-ignore-case t)

(unless (featurep 'smex)
  (require 'icomplete)
  (icomplete-mode 1))
(setq icomplete-with-completion-tables t)

;; It remembers stack of windows (not buffers) configurations and allows navigate with C-c LEFT / RIGHT.
;; I don't find it useful as I always work only with 1 or 2 windows opened.
;; (winner-mode 1)

(defun my--large-file-p ()
  "If buffer too large and my cause performance issue."
  (< large-file-warning-threshold (buffer-size)))

;; http://git.savannah.nongnu.org/cgit/so-long.git/tree/so-long.el is part of Emacs 27.1
;; https://emacs.stackexchange.com/questions/598/how-do-i-prevent-extremely-long-lines-making-emacs-slow
;; (make-variable-buffer-local 'mode-line-format)
;; (setq mode-line-format (delq 'mode-line-position 'mode-line-format))
(define-derived-mode my-large-file-mode fundamental-mode "LargeFile"
  "Fixes performance issues in Emacs for large files."
  ;; (setq buffer-read-only t)
  (setq bidi-display-reordering nil)
  (setq bidi-paragraph-direction 'left-to-right)
  (font-lock-mode -1)
  (jit-lock-mode nil)
  (buffer-disable-undo)
  (setq-local show-paren-mode nil)
  (auto-revert-tail-mode -1)
  (set (make-local-variable 'global-hl-line-mode) nil)
  (set (make-local-variable 'line-number-mode) nil)
  (set (make-local-variable 'column-number-mode) nil)
  (size-indication-mode -1))

(add-to-list 'magic-mode-alist (cons #'my--large-file-p #'my-large-file-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "helm")

(cl-eval-when (compile)
  (require 'helm-locate nil t))

(setq helm-locate-command "locate %s -e %s")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "company")

(setq company-tooltip-align-annotations t)

(setq company-dabbrev-other-buffers 'all) ; or `t' or `nil'
;; (setq company-dabbrev-time-limit 0.1)
(setq company-dabbrev-downcase nil)
(setq company-dabbrev-ignore-case nil)

;; (setq company-backends (delete 'company-dabbrev company-backends))

(defun my-company-filter-out-numbers (lst)
  (cl-remove-if (lambda (str) (string-match-p "^[0-9]" str)) lst))

(when (featurep 'company)
  (add-hook 'company-transformers #'my-company-filter-out-numbers))

(defun company-executable (command &optional arg &rest ignored)
  "Company completion for executable in PATH."
  (interactive (list 'interactive))
  (cl-case command
    (interactive (company-begin-backend 'company-executable))
    (prefix (thing-at-point 'filename))
    (candidates (locate-file-completion-table exec-path exec-suffixes (thing-at-point 'filename) 'identity t))
    ;; (annotation (concat " " (locate-file arg exec-path exec-suffixes)))
    (meta (concat "Full path: " (locate-file arg exec-path exec-suffixes)))))

(defun my-company-text-setup ()
  (setq-local company-backends '((company-dabbrev company-files)))
  (company-mode 1))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "bookmark")

;; (require 'autobm)
(global-set-key (kbd "C-x r m") 'autobm)

(setq set-mark-command-repeat-pop 't)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "completion")

(setq suggest-key-bindings t)

;; I remove partial-completion-mode because it depricated in Emacs 24.0.
;; Completion controled by 'completion-styles' variable.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "dired")

(require 'dired)

(setq dired-dwim-target t)
;; dangerous
;; (setq
;;  dired-recursive-copies 'top
;;  dired-recursive-deletes 'top)

(defun my-dired-up-dir ()
  "'Reuse' buffer if enter to dir or open new buffer if enter to file."
  (interactive)
  ;; (dired-current-directory) always end with trailing '/' char.
  (let* ( (dir (dired-current-directory)) (i (- (length dir) 2)) upperdir )
    (while (and
            (>= i 0)
            (not (equal (aref dir i) ?/)) )
      (setq i (- i 1))
      )
    (setq upperdir (substring dir 0 (+ i 1)))
    (when (file-directory-p upperdir)
      (find-alternate-file upperdir)
      (dired-goto-file dir)
      )
    ))
(define-key dired-mode-map (kbd "<backspace>") 'my-dired-up-dir)

(defun my-dired-enter-to-dir ()
  "'Reuse' buffer if enter to dir or open new buffer if enter to file."
  (interactive)
  (let ( (file (dired-get-file-for-visit)) )
    (if (file-directory-p file)
        (find-alternate-file file)
      (find-file file)
      )))
(define-key dired-mode-map (kbd "<return>")
  'my-dired-enter-to-dir)

;; Make behaviour same as in GUI.
(unless window-system
  (define-key dired-mode-map (kbd "DEL") 'my-dired-up-dir)
  (define-key dired-mode-map (kbd "RET") 'my-dired-enter-to-dir))

;; Enable 'a' command.
(put 'dired-find-alternate-file 'disabled nil)

(defvar my--file-name-tmp-refex
  (concat
   "\\(?:^#.*#"
   "\\|~"
   "\\|\\." (regexp-opt '("base" "local" "orig" "other" "rej" "diff" "log" "stackdump" "pyc" "pyo"))
   "\\|\\.log\\.[0-9]+"
   "\\)\\'")
  "Rule to detect temp/backup files.")

(defun my--file-name-tmp-p (file)
  (string-match my--file-name-tmp-refex
                (or (and (file-directory-p file) "") (file-name-nondirectory file))))

(defun my--dired-flag-tmp-files ()
  "Flag all temporary files for deletion."
  (interactive)
  (dired-mark-if
   (let ( (fn (dired-get-filename 'verbatim t)) )
     (and fn (my--file-name-tmp-p fn)) )
   "backup file"))

(define-key dired-mode-map (kbd "`") 'my--dired-flag-tmp-files)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "ls-lisp, dired ls")

(require 'ls-lisp)

;; If non-nil - use 'insert-directory-program', means directory sorting and
;; other options for `ls-lisp' do not have effect.
(setq ls-lisp-use-insert-directory-program nil)
(setq ls-lisp-ignore-case t)
(setq ls-lisp-dirs-first t)
(if (memq system-type '(windows-nt cygwin))
    (setq ls-lisp-verbosity nil)
  (setq ls-lisp-verbosity '(links uid gid)))

;; On Cygwin use actual "ls" executable. List implementation fails with:
;;   ls-lisp-insert-directory: Getting attributes: Input/output error, lock
;; for some files, making it impossible to see directory contend in Dired even
;; if only some files are problmatic (accessing special files from WSL P9 file system).
(when (eq system-type 'cygwin)
  (setq my-ls-dir-switches '("-a" "-g" "--no-group" "--dired" "--group-directories-first"))
  (setq ls-lisp-use-insert-directory-program t)
  (setq list-directory-verbose-switches my-ls-dir-switches)
  (setq dired-listing-switches (mapconcat #'identity my-ls-dir-switches " ")))
;; Force use 'ls-lisp-format-time-list'.
(setq ls-lisp-use-localized-time-format t)
(setq ls-lisp-format-time-list
      '("%Y-%m-%d %H:%M:%S"
        "%Y-%m-%d %H:%M   "))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "compression, archive")

(require 'jka-compr) ; Automatic decompression, hooks for tar-mode.
(when (fboundp 'auto-compression-mode)
  (auto-compression-mode 1))

(modify-coding-system-alist 'file "\\.\\(war\\|ear\\|sar\\|egg\\)\\'" 'no-conversion)

(add-to-list 'auto-mode-alist '("\\.\\(war\\|ear\\|sar\\|egg\\)\\'" . archive-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "image, png, svg")

(when (fboundp 'auto-image-file-mode)
  (auto-image-file-mode 1))
(my--eval-after-load image-file
  ;; Exclude .svg image from supported image list, as Emacs doesn't come
  ;; with SVG shared library.
  (setq image-file-name-extensions (remove "svg" image-file-name-extensions))
  ;; Re-initialize the image-file handler.
  (auto-image-file-mode t) )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "url")

;; http://tools.ietf.org/html/rfc3986
;; http://en.wikipedia.org/wiki/Percent-encoding
(defun my-percent-decode (str)
  (decode-coding-string
   (let* ( (s (split-string str "%")) )
     (my-fold
      'concat
      (car s)
      (mapcar
       (lambda (x)
         (concat (unibyte-string (string-to-number (substring x 0 2) 16)) (substring x 2)))
       (cdr s))
      )) 'utf-8))

(defun my-percent-decode-region (beg end &optional arg)
  "Convert percent encoded string to native."
  (interactive "r\nP")
  (let ( (result (my-percent-decode (buffer-substring-no-properties beg end))) )
    (if (not arg)
        result
      (delete-region beg end)
      (insert result))
    ) )

(defun my-percent-encode (str)
  (apply 'concat
         (mapcar
          (lambda (ch) (if (or (and (<= ?a ch) (>= ?z ch))
                          (and (<= ?A ch) (>= ?Z ch))
                          (memq ch '(?- ?_ ?. ?~)))
                      (char-to-string ch)
                    (format "%%%02X" ch)))
          (encode-coding-string str 'utf-8) )))

(defun my-percent-encode-region (beg end &optional arg)
  "Encode string to percent encoding."
  (interactive "r\nP")
  (let ( (result (my-percent-encode (buffer-substring-no-properties beg end))) )
    (if (not arg)
        result
      (delete-region beg end)
      (insert result))
    ) )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "browser")

(defun my--browse-url-cygwin-firefox (url &optional _new-window)
  (call-process "cygstart" nil nil nil "firefox" url))

(cond
 ((eq system-type 'cygwin)
  (setq browse-url-browser-function 'my--browse-url-cygwin-firefox))
 ((equal window-system 'w32)
  (setq browse-url-browser-function 'browse-url-default-windows-browser))
 ((boundp 'debian-emacs-flavor)
  (setq browse-url-browser-function 'browse-url-firefox))
 (t
  (setq browse-url-browser-function 'browse-url-mozilla)))

(defun my-cygwin-search (str)
  "Search for Cygwin package on-line."
  (interactive (list (read-string "Search for Cygwin package on-line: ")))
  (browse-url (format "http://cygwin.com/cgi-bin2/package-grep.cgi?grep=%s" str))
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "ide, netbeans, idea")

(defun ide-netbeans-find-command ()
  "Search for NetBeans executable in PATH, later in '/opt/netbeans*/bin/'."
  (or
   (executable-find "netbeans")
   (car (last (sort (file-expand-wildcards "/opt/[Nn]etbeans*/bin/netbeans" t) 'equal))) ))
(defvar ide-netbeans-program (ide-netbeans-find-command)
  "Command to run NetBeans.")

(defconst ide-netbeans-process-bufname "*ide-netbeans*"
  "Name used in `start-process'")
(defun ide-netbeans-open-file (file &optional line)
  "Open FILE on LINE in NetBeans."
  (unless ide-netbeans-program
    (error "'ide-netbeans-program' is not set"))
  ;; https://www.jetbrains.com/help/idea/2016.3/opening-files-from-command-line.html
  (let ( (default-directory (file-name-directory file)) (fname (file-name-nondirectory file)) )
    (if (integerp line)
        (start-process ide-netbeans-process-bufname nil ide-netbeans-program "--open" (format "%s:%d" fname line))
      (start-process ide-netbeans-process-bufname nil ide-netbeans-program "--open" fname))))
(defun ide-netbeans-open-this-buffer ()
  "Open current buffer in NetBeans."
  (interactive)
  (unless (and (stringp (buffer-file-name)) (file-regular-p (buffer-file-name)))
    (error "Buffer have no association with a file"))
  (ide-netbeans-open-file (buffer-file-name) (line-number-at-pos)))

(defvar ide-idea-program nil
  "Idea executable or full path, like 'idea64.exe'")

(defconst ide-idea-process-bufname "*ide-idea*"
  "Name used in `start-process'")
(defun ide-idea-open-file (file &optional line)
  "Open FILE on LINE in Intellij Idea."
  (unless ide-idea-program
    (error "'ide-idea-program' is not set"))
  (let ( (default-directory (file-name-directory file)) (fname (file-name-nondirectory file)) )
    (if (integerp line)
        (start-process ide-idea-process-bufname nil ide-idea-program "--line" (int-to-string line) fname)
      (start-process ide-idea-process-bufname nil ide-idea-program fname))))
(defun ide-idea-open-this-buffer ()
  "Open current buffer in Intellij Idea."
  (interactive)
  (unless (and (stringp (buffer-file-name)) (file-regular-p (buffer-file-name)))
    (error "Buffer have no association with a file"))
  (ide-idea-open-file (buffer-file-name) (line-number-at-pos)))

(define-key global-map [?\s-n] 'ide-netbeans-open-this-buffer)
(define-key global-map [?\s-i] 'ide-idea-open-this-buffer)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "calendar")

(cl-eval-when (compile) (require 'calendar))

;; (setq mark-holidays-in-calendar t)
;; (setq all-christian-calendar-holidays t)
;; (setq calendar-date-display-form (quote ((format "%04s-%02d-%02d" year (string-to-number month) (string-to-number day)))))
;; (setq calendar-time-display-form (quote (24-hours ":" minutes (if time-zone " (") time-zone (if time-zone ")"))))
(setq calendar-week-start-day 1)
(setq calendar-date-style 'iso)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "standard hooks")

(add-hook 'write-file-hooks 'time-stamp)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "logging, logs")

(defun my-auto-revert-tail-mode-hook ()
  (when (string-match "/logs?/\\|\\.\\(?:log\\|out\\|log\\.[0-9]\\)\\'\\|/.xsession-errors\\'"
                      (buffer-file-name (current-buffer)))
    (fundamental-mode)
    (auto-revert-tail-mode 1)
    (log4-hi-mode 1)
    (setq scroll-margin my-scroll-margin)
    ))
(add-hook 'find-file-hook 'my-auto-revert-tail-mode-hook)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "auto-fill")

(setq-default fill-column 78)

(defvar my-fill-column 100
  "I use greater value then 78 for comment in prog source.")

;; By default used American convention - sentence and with two spaces. Change
;; it to one space. Has affect on filling and M-a, M-e commands.
(setq sentence-end-double-space nil)

;; Turn on auto-fill mode
;; (add-hook 'html-mode-hook 'turn-on-auto-fill)
;; (add-hook 'text-mode-hook 'turn-on-auto-fill)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "cacl, calculator")

(setq-default calc-group-digits t)
(setq-default calc-group-char "'")

(defun my-calc-region (arg beg end)
  "Calculate the region and display the result in the echo area.
With prefix ARG non-nil, insert the result at the end of region."
  (interactive "P\nr")
  (require 'calc)
  (let* ((expr (buffer-substring-no-properties beg end))
         (result (calc-eval expr)))
    (if (null arg)
        (message "%s = %s" expr result)
      (goto-char end)
      (save-excursion
        (insert result)))))

(defun my-calc-line (arg)
  "Evaluate expression in current line and display the result in
the echo area by skipping final '=' sign. With prefix ARG
non-nil, insert the result at the end of line and space if
necessary for delimiting."
  (interactive "P")
  (require 'calc)
  (save-excursion
    (let (beg end expr result)
      (beginning-of-line)
      (setq beg (point))
      (end-of-line)
      (search-backward "=" beg t)
      (setq end (point))
      (setq expr (buffer-substring-no-properties beg end))
      (setq result (calc-eval expr))
      (if (null arg)
          (message "%s = %s" expr result)
        (end-of-line)
        (unless (eq (char-before) ?\ )
          (insert ?\ ))
        (insert result)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "rst, reStructuredText")

;; Maintaining the table of contents up-to-date.
(add-hook 'rst-adjust-hook 'rst-toc-update)

(if (coding-system-p 'prefer-utf-8-unix)
    (modify-coding-system-alist 'file "\\.rst\\'" 'prefer-utf-8-unix)
  (modify-coding-system-alist 'file "\\.rst\\'" 'utf-8-unix))

(unless window-system
  (my--eval-after-load rst
    (custom-set-faces
     '(rst-level-1-face ((t (:background "yellow"))) t)
     '(rst-level-2-face ((t (:background "yellow"))) t)
     '(rst-level-3-face ((t (:background "yellow"))) t)
     '(rst-level-4-face ((t (:background "yellow"))) t)
     '(rst-level-5-face ((t (:background "yellow"))) t)
     '(rst-level-6face ((t (:background "yellow"))) t)
     ) ) )

(when (featurep 'flyspell)
  (add-hook 'rst-mode-hook #'flyspell-mode))

(when (featurep 'company)
  (add-hook 'rst-mode-hook #'my-company-text-setup))

;; (add-hook 'rst-mode-hook #'abbrev-mode)
;; (remove-hook 'rst-mode-hook #'abbrev-mode)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "adoc, asciidoc")

(when (fboundp 'adoc-mode)
  (add-to-list 'auto-mode-alist '("\\.adoc$" . adoc-mode)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "md, markdown")

(my--eval-after-load markdown-mode
  ;; (add-hook 'markdown-mode-hook #'whitespace-mode)
  (add-hook 'markdown-mode-hook #'outline-minor-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "TeX, LaTeX")

(setq tex-run-command "initex")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "AUC TeX")

;(add-hook 'LaTeX-mode-hook 'LaTeX-install-toolbar)
;; (setq TeX-parse-self t)             ; Enable parse on load.
;; (setq TeX-auto-save t)              ; Enable parse on save.
;; Query for master file. If you often use \include or \input, you should make AUCTEX aware of the
;; multi-file document structure.
(setq-default TeX-master nil)

;(setq TeX-PDF-mode t)
;(setq TeX-interactive-mode t)
;(setq TeX-source-specials-mode 1)

;;; some more menu entries in the command list:
;;; see tex-mik.el from package auctex: %v is defined in tex-mik.el
;;; other variables are defined in tex.el from auctex
;;; the meaning of some auctex-varibles:
        ;symbols defined in tex.el and tex-mik.el:
        ;%b name slave tex-file  %t name master tex-file
        ;%d dvi-file  %f ps-file
        ;%l "latex --src-specials"
        ;%n line number  %p printcommand  %q "lpq"
        ;%r (TeX-style-check TeX-print-style)
        ;%s master-file-name without extention
        ;%v yap command view line
;; (my--eval-after-load tex
;;   (add-to-list 'TeX-command-list
;;                (list "->PS landscape for pdf"
;;                      "dvips %d -N0 -Ppdf -G0 -T 297mm,210mm -o %f "
;;                      'TeX-run-command nil t))
;;   (add-to-list 'TeX-command-list
;;                (list "All Texify run-viewer"
;;                      "texify --tex-opt=--src --run-viewer --clean %s.tex"
;;                      'TeX-run-command nil t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "reftex")

;; Reftex is included with Emacs 21.1.

;; (autoload 'reftex-mode     "reftex" "RefTeX Minor Mode" t)
;; (autoload 'turn-on-reftex  "reftex" "RefTeX Minor Mode" nil)
;; (autoload 'reftex-citation "reftex-cite" "Make citation" nil)
;; (autoload 'reftex-index-phrase-mode "reftex-index" "Phrase mode" t)
;; (add-hook 'LaTeX-mode-hook 'turn-on-reftex)   ; with AUCTeX LaTeX mode
;; (add-hook 'latex-mode-hook 'turn-on-reftex)   ; with Emacs latex mode

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "PreviewLatex")

;(load "preview-latex.el" nil t t)

;(add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
;(autoload 'LaTeX-preview-setup "preview")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "info")

(unless (getenv "INFOPATH")
  (if (eq system-type 'windows-nt)
      (setenv "INFOPATH" (concat (expand-file-name "~/usr/share/info") ":/usr/share/info:"))
    (setenv "INFOPATH" (expand-file-name "~/usr/share/info:"))))

;; Assume that cygwin-mount already activated.
(when (featurep 'cygwin-mount)
  (setenv "INFOPATH" "/usr/share/info/:~/usr/share/info/:")
  ;; Redefine path-separator to UNIX to update Info-directory-list.
  (let ( (path-separator ":") )
    (require 'info)
    (info-initialize) ))

;; Info index nodes for automake under Debian.
(defvar my-fix-for-automake-info-lookup
  '(("(automake-1.11)Macro Index" nil
     "^`" "['(]")
    ("(automake-1.11)Variable Index" nil
     "^`" "['(]")
    ("(automake-1.11)General Index" nil
     "^`" "['(]")))

;; Add `my-fix-for-automake-info-lookup' entries to the end of doc-spec for
;; some modes.
(my--eval-after-load info-look
  (mapc
   (lambda (mode)
     (let ( (doc-spec (info-lookup->doc-spec 'symbol mode)) )
       (mapc
        (lambda (doc-spec-item)
          (setcdr (last doc-spec) (list doc-spec-item)))
        my-fix-for-automake-info-lookup)))
   '(makefile-mode autoconf-mode))
  (info-lookup-maybe-add-help
   :mode 'makefile-gmake-mode
   :other-modes '(makefile-mode)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "man, woman")

(cl-eval-when (compile) (require 'woman))

(when (featurep 'cygwin-mount)
  (let ( (path (expand-file-name "~")) )
    (when (string-match "\\([c-z]\\):/" path)
      (setenv "MANPATH" (concat "/cygdrive/" (substring path 0 1) "/" (substring path 3) "/usr/share/man/:"))
      ) ))

(setq woman-use-own-frame nil)
(setq woman-fill-frame t)

(with-eval-after-load 'man
  ;; Default sed filter failed with syntax error in native Emacs and Cygwin.
  (when (eq system-type 'windows-nt)
    (setq Man-filter-list nil)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "comint")

;; If non-nil, add a `/' to completed directories, ` ' to file names.
(setq comint-completion-addsuffix t)
;; Non-nil means go to the end of the line before sending input.
(setq comint-eol-on-send t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "spell, ispell, aspell, flyspell")

;; Settings for spelling done in '.emacs-autogen'.

(add-hook 'log-edit-mode-hook 'flyspell-mode)

;; (setq-default ispell-extra-args  '("--sug-mode=ultra"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "dict, dictd, dictionary, gadict, gaphrase, gadialog")

(defun my-gedict-enable-whitespace ()
  (setq show-trailing-whitespace nil)
  (setq-local whitespace-style '(face trailing))
  (whitespace-mode 1))

(when (fboundp 'gadict-mode)
  (add-to-list 'auto-mode-alist '("\\.gadict$" . gadict-mode)) )
(add-hook 'gadict-mode-hook 'my-gedict-enable-whitespace)

(when (fboundp 'gaphrase-mode)
  (add-to-list 'auto-mode-alist '("\\.gaphrase$" . gaphrase-mode)) )
(add-hook 'gaphrase-mode-hook 'my-gedict-enable-whitespace)

(when (fboundp 'gadialog-mode)
  (add-to-list 'auto-mode-alist '("\\.gadialog$" . gadialog-mode)) )
(add-hook 'gadialog-mode-hook 'my-gedict-enable-whitespace)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "figlet")

(defun my-figlet-region (&optional b e)
  (interactive "r")
  (shell-command-on-region b e "figlet" (current-buffer) t)
  (comment-region (mark) (point)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "org-mode, GTD, PIM, organize, todo")

(require 'org)
;; For "<s TAB". See `org-structure-template-alist'.
(require 'org-tempo)
;; (require 'ob-shell)
;; (require 'ob-python)
(require 'org-capture nil t)

(cl-eval-when (compile)
  (require 'org-agenda)
  (require 'org-archive))

;; XXX org-todo-keywords '((sequence "TODO" "START" "|" "DONE")) for org-version 4.67c
(add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
(setq org-directory "~/my/gtd")
(setq
 org-agenda-ndays 31
 org-deadline-warning-days 7
 org-agenda-show-all-dates t
 org-agenda-format-date "%Y-%m-%d, %A %e %B"
 org-agenda-skip-deadline-if-done t
 org-agenda-skip-scheduled-if-done t
 org-agenda-start-on-weekday nil
 org-reverse-note-order t
 org-hide-leading-stars t
 org-tags-column 64
 org-archive-save-context-info '(time file olpath todo itags)
 org-cycle-emulate-tab nil
 )
(defvar my-org-agenda-todo-file (concat org-directory "/TODO.org"))
(defvar my-org-agenda-note-file (concat org-directory "/NOTE.org"))
(setq org-agenda-file-regexp "\\`[^.#].*[^_]\\.org\\'"
      org-agenda-files (list org-directory))
;; (setq my-org-agenda-learning-file (concat org-directory "/LEARNING.org"))
;; (setq org-agenda-files `(,my-org-agenda-todo-file ,my-org-agenda-note-file ,my-org-agenda-learning-file))
(define-key global-map "\C-va" 'org-agenda)
(define-key global-map "\C-ve" (lambda nil (interactive) (find-file my-org-agenda-note-file)))

(setq org-todo-keywords '("|" "DONE"))

;; My tags for remember buffer.
(setq org-tag-alist
      '(
        ("ADMIN" . ?a)
        ("BLOG" . ?b)
        ("DEVEL" . ?d)
        ("HOME" . ?h)
        ("GET" . ?g)
        ("LIFE" . ?l)
        ("MAIL" . ?m)
        ("JOB" . ?j)
        ("QUESTION" . ?q)
        ("PROJECT" . ?p)
        ("READ" . ?r)
        ("SEE" . ?s)
        ))
;; With this variable tags duplicated in *Org Tags* menu. I use
;; `org-tag-alist' instead until bug fixed.
(setq org-tag-persistent-alist nil)

(setq org-support-shift-select t)

(setq org-default-notes-file my-org-agenda-todo-file)
(setq org-capture-templates
      '(("t" "Todo" entry (file my-org-agenda-todo-file) "* %?\n  SCHEDULED: %T")))
(define-key global-map "\C-vr"
  (lambda () (interactive) (org-capture nil "t")))

(when (featurep 'company)
  (add-hook 'org-mode-hook #'my-company-text-setup))
(add-hook 'org-mode-hook #'mypasshide-mode)

(defun my-org-archive-location (path)
  "For given PATH make path to archive. Currently add undescore
before file extention. If file name doesn't match
`org-agenda-file-regexp' or have no extention return `nil'."
  (if (and (file-name-extension path)
           (string-match org-agenda-file-regexp (file-name-nondirectory path)))
      (concat (file-name-sans-extension path) "_." (file-name-extension path))
    nil))

(defun my-org-archive-file (path)
  "Move marked by `org-done-keywords' entries to archive file.
.
Archive file name constructed by `my-org-archive-location'."
  (let ( (archive (my-org-archive-location path))
         entry-re entry-done-re
         entry-beg entry-end )
    (unless archive
      (error "'%s' looks like a non-org file..." path))
    (save-excursion
      (with-current-buffer (find-file-noselect path)
        (org-set-regexps-and-options)
        (setq entry-re "^\\* "
              entry-done-re (concat "^\\* *" (mapconcat 'regexp-quote org-done-keywords "\\|") " "))
        (kill-new "")
        (goto-char (point-min))
        (while (re-search-forward entry-done-re nil t)
          (setq entry-beg (line-beginning-position))
          (if (re-search-forward entry-re nil t)
              (beginning-of-line)
            (goto-char (point-max)))
          (setq entry-end (point))
          (let ( (last-command 'kill-region) )
            (kill-region entry-beg entry-end))
          )
        (when (> (length (car kill-ring)) 0)
          (with-current-buffer (find-file-noselect archive)
            (goto-char (point-max))
            (insert ?\n)
            (yank)
            (save-buffer))
          (save-buffer) )))))

(defun my-org-archive (&optional prefix)
  "Move all entries marked by `org-done-keywords' to archive
files with name mangled by `my-org-archive-location'.
.
Without prefix work on current file. With prefix work on
`org-agenda-files'."
  (interactive "P")
  (cl-loop for file in (if prefix (org-agenda-files) (list (buffer-file-name))) do
        (my-org-archive-file file)))

(setq org-agenda-include-diary nil)

(defun my-org-kill-by-tag (tag)
  "Put all entries that matches TAG from current org-file to `kill-ring'."
  (interactive (list (completing-read "Enter tag: " (org-get-buffer-tags))))
  (let ( rs (last-command 'kill-region) )
    (setq rs (org-scan-tags
              (lambda ()
                (org-mark-subtree)
                (list (point) (mark)))
              '(member tag tags-list) nil))
    (kill-new "")
    (dolist (r (reverse rs))            ; Kill from the end so upcoming regions still valid.
      (apply #'kill-region r))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "TODO, XXX, FIXME highlight")

(defvar my-todo-words '("TODO" "FIXME" "XXX" "HACK" "TBD" "BUG" "DELME" "EDITED"))

(defun my-todo (&optional mode)
  (interactive)
  (font-lock-add-keywords
   mode
   (list (list (concat "\\<" (regexp-opt my-todo-words) "\\>") 0 'font-lock-warning-face t))))

(add-hook 'text-mode-hook 'my-todo)
(add-hook 'prog-mode-hook 'my-todo)
(add-hook 'conf-mode-hook 'my-todo)
(add-hook 'yaml-mode-hook 'my-todo)
(with-eval-after-load 'generic-x
  (mapc (lambda (mode) (add-hook (intern (concat mode "-hook")) 'my-todo)) generic-mode-list))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "mail, message")

(cl-eval-when (compile) (require 'message))

(setq mail-user-agent 'message-user-agent)

(defun my-compose-mail ()
  (interactive)
  (compose-mail nil nil `(("Organization" . ,(getenv "ORGANIZATION")))))
(global-set-key (kbd "C-x m") #'my-compose-mail)

(setq message-citation-line-format "On %Y-%m-%d, %N wrote:
")
(setq message-citation-line-function 'message-insert-formatted-citation-line)

(setq mail-signature t)
(setq mail-signature-file "~/.signature")
;; (add-hook 'mail-setup-hook 'fortune-to-signature)

;; (setq mail-from-style 'angles)

(setq mail-personal-alias-file "~/.mailrc")
;; Initialize from your mail aliases file...
(setq mail-aliases t)
(require 'ecomplete nil t)              ; Absent in Emacs 22.
(setq message-mail-alias-type '(abbrev ecomplete))

(my--eval-after-load message
  (require 'mailabbrev)
  (define-key message-mode-map "\e\t" 'mail-abbrev-complete-alias))

(defun my-message-mode-hook ()
  (setq fill-column 78)
  (turn-on-auto-fill)
  (flyspell-mode 1))
(add-hook 'message-mode-hook 'my-message-mode-hook)

;; Mark all my messages by "common" string in "Message-Id" field to simplify
;; lookup for followups to me.
(setq message-user-fqdn "gavenkoa.example.com")

;; Kill message buffer after mail send. You always can use C-c C-s to preserve it.
(setq message-kill-buffer-on-exit t)

(defconst my--message-safe-filename-regex "[[:alnum:]-_!.@]"
  "Safe file names.")

(defun my--message-refine-filename (filename)
  (mapconcat
   (lambda (ch) (or (when (string-match my--message-safe-filename-regex (char-to-string ch)) (char-to-string ch)) "-"))
   filename "") )

(cl-eval-when (compile) (require 'gnus))

(defun my--message-save ()
  "Store message in `gnus-article-save-directory' after
successful sending. It is possible that mail rejected and I lost
it completely, this func save it for me."
  (unless (eq major-mode 'message-mode)
    (error "Attempt to call my--message-save in non message-mode buffer"))
  (make-directory gnus-article-save-directory t)
  (let ( (buf (current-buffer))
         (field-to (my--message-refine-filename (or (message-fetch-field "Newsgroups") (message-fetch-field "To"))))
         (field-subject (my--message-refine-filename (message-fetch-field "Subject")))
         file )
    (when (> (length field-to) 32)
      (setq field-to (substring field-to 0 32)))
    (when (> (length field-subject) 64)
      (setq field-subject (substring field-subject 0 64)))
    (setq file (concat gnus-article-save-directory "/" (format-time-string "%F_%H-%M-%S") "_" field-to "_" field-subject))
    (with-temp-file file
      (insert-buffer-substring buf)
      )) )
(add-hook 'message-sent-hook 'my--message-save)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "smtp, smtpmail")

(when (and (not (eq system-type 'gnu/linux)) (boundp 'smtpmail-smtp-server))
  (require 'smtpmail)
  (setq
   ;; If you use the default mail user agent.
   send-mail-function 'smtpmail-send-it
   ;; If you use Message or Gnus.
   message-send-mail-function 'smtpmail-send-it
   )
  )
;; (setq smtpmail-debug-verb t)
;; (setq smtpmail-debug-info t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "gnus, mh-e")

(cl-eval-when (compile)
  (require 'gnus)
  (require 'gnus-agent)
  (require 'gnus-start)
  (require 'gnus-score)
  (require 'gnus-topic)
  (require 'gnus-spec)
  (require 'spam))

;; (setq gnus-verbose 10)

(setq gnus-site-init-file "~/.gnus.el")

(setq
 gnus-read-newsrc-file nil
 gnus-save-newsrc-file nil
 gnus-backup-startup-file t
 gnus-use-dribble-file t
 gnus-save-killed-list t
 )

(defun my-kill-gnus ()
  "Kill Gnus when exiting Emacs."
  (let ( (gnus-interactive-exit nil) )
    (gnus-group-exit)
    ))
(my--eval-after-load gnus
  (add-hook 'kill-emacs-hook 'my-kill-gnus))

(my--eval-after-load gnus-art
  (setq gnus-visible-headers (concat gnus-visible-headers "\\|^Archived-At:\\|^List-URL:\\|^Message-Id:")))

;; Store gnus specific files to '~/.gnus'.
(setq
 gnus-directory "~/.gnus"
 gnus-agent-directory "~/.gnus/agent/"
 gnus-article-save-directory "~/.gnus/saved"
 gnus-kill-files-directory "~/.gnus/scores"
 gnus-cache-directory "~/.gnus/cache"
 mail-source-directory "~/.gnus/mail"
 message-directory "~/.gnus/mail"
 message-auto-save-directory "~/.gnus/autosave"
 ;; message-signature-directory
 mailcap-download-directory  "~/.gnus/mailcap"
 ;; nnml-directory "~/.gnus/nnml-mail"
 spam-directory "~/.gnus/spam/"
 smime-certificate-directory "~/.gnus/certs/"
 ;; nnfolder-directory "~/.gnus/archive"
 ;; nnfolder-active-file "~/.gnus/archive/active"
 )

;; Remove gnus-ignored-newsgroups to show all GMail folders.
(setq gnus-ignored-newsgroups "some-non-existing")

(my--eval-after-load gnus
  (require 'spam)
  (spam-initialize)
  (setq gnus-spam-process-newsgroups
        '(("^gmane\\." ((spam spam-use-gmane))))))

(setq
 gnus-novice-user nil
 gnus-expert-user nil
 gnus-interactive-catchup t
 gnus-interactive-exit t)

(setq
 gnus-read-active-file nil
 gnus-check-new-newsgroups nil
 gnus-check-bogus-newsgroups nil)

(setq nntp-connection-timeout 10)

(setq gnus-large-newsgroup 800)
(setq gnus-large-ephemeral-newsgroup 600)
(setq gnus-group-listing-limit 1000)

(setq
 gnus-group-goto-unread t
 gnus-summary-next-group-on-exit nil)

(setq
 gnus-permanently-visible-groups ".*"
 gnus-topic-display-empty-topics t)

;; (setq 'gnus-use-cache t)
(setq gnus-use-long-file-name t)
(setq gnus-cache-remove-articles '(read))

;; If you're spooling in overlapping mbox folders, you probably want to delete
;; all messages with duplicate message IDs.
(setq nnmail-treat-duplicates 'delete)

;; To disable html part of a message:
;; (setq mm-discouraged-alternatives '("text/html" "text/richtext"))
;; I manage to open link in external browser and fix navigation command so pretty ok with HTML parts.
(setq mm-discouraged-alternatives '("text/richtext"))
(setq gnus-buttonized-mime-types '("text/html"))

(setq mm-text-html-renderer 'shr)

(cl-eval-when (compile)
  (ignore-errors
    ;; w3m-anchor is macros in newer Emacs, need definition during byte-compilation.
    (require 'w3m-util)))

(defun my-w3m-view-url ()
  (interactive)
  (browse-url (w3m-anchor)))

(my--eval-after-load w3m
  (define-key w3m-minor-mode-map (kbd "RET") #'my-w3m-view-url)
  (define-key w3m-minor-mode-map (kbd "S-RET") #'w3m-safe-view-this-url)
  (define-key w3m-minor-mode-map (kbd "<left>") #'backward-char)
  (define-key w3m-minor-mode-map (kbd "<right>") #'forward-char)
  (define-key w3m-minor-mode-map (kbd "<up>") #'previous-line)
  (define-key w3m-minor-mode-map (kbd "<down>") #'next-line))

(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

(my--eval-after-load gnus
  (gnus-demon-add-handler 'gnus-demon-scan-news 10 t))

;; Show prefix and 'To' field instead 'From' for my mails.
(setq gnus-summary-to-prefix (if window-system "▒ " "==> "))
(setq gnus-summary-newsgroup-prefix (if window-system "▒ " "==> "))
(setq gnus-ignored-from-addresses (list (regexp-quote user-mail-address) (regexp-quote user-full-name)))

(setq gnus-posting-styles
      '((".*"
         (organization (getenv "ORGANIZATION"))
         (signature-file "~/.signature"))))

(my--eval-after-load gnus
  (gnus-add-configuration
   '(article (vertical 1.0 (summary .30 point) (article 1.0)))))

(setq gnus-summary-display-arrow t)

;; `gnus-summary-line-format',
;; `gnus-server-line-format', `gnus-topic-line-format',
;; `gnus-group-mode-line-format', `gnus-summary-mode-line-format',
;; `gnus-article-mode-line-format', `gnus-server-mode-line-format',
;; `gnus-summary-pick-line-format'.

(when window-system
  (setq
   gnus-sum-thread-tree-root "● "
   gnus-sum-thread-tree-false-root " © "
   gnus-sum-thread-tree-indent " "
   gnus-sum-thread-tree-single-indent "• "
   gnus-sum-thread-tree-leaf-with-other "├○ "
   gnus-sum-thread-tree-single-leaf "└○ "
   gnus-sum-thread-tree-vertical "│"
   ))

(setq gnus-user-date-format-alist '((t . "%Y-%m-%d %H:%M")))
(setq gnus-summary-line-format "%U%R%z %&user-date; %B %[%-22,22f%] %s\n")
(setq gnus-summary-mode-line-format "Gnus: %p %Z")

(setq gnus-article-time-format "%Y-%m-%d %T%z %a")
(setq gnus-article-date-headers '(combined-lapsed user-defined))

;; Remember when I visit group last time.
(add-hook 'gnus-select-group-hook 'gnus-group-set-timestamp)

(defvar gnus-tmp-group)
(defun gnus-user-format-function-d (header)
  (let ((time (gnus-group-timestamp gnus-tmp-group)))
    (if (and time (time-less-p (time-subtract (current-time) time) (seconds-to-time (* 3600 24 7 30 2))))
        (format-time-string "%Y-%m-%d %H:%M" time)
      "")))
;; %d (or with user defined format %ud) shown when I visit group last time in
;; %*Group* buffer.
(setq gnus-group-line-format "%M%S%p%P%6y:%B%(%-50,50G%)%3O %ud\n")

;; gnus-visible-headers gnus-extra-headers
(setq
 gnus-sorted-header-list
 '(
   "^From:"
   "^Subject:"
   "^Summary:"
   "^Keywords:"
   "^Newsgroups:"
   "^Followup-To:"
   "^To:"
   "^Cc:"
   "^Organization:"
   "^Date:"
   "^User-Agent:"
   "^X-Mailer:"
   "^X-Newsreader:"
   ))

(setq
 gnus-show-threads t
 gnus-thread-sort-functions '(gnus-thread-sort-by-date gnus-thread-sort-by-total-score)
 gnus-summary-thread-gathering-function 'gnus-gather-threads-by-subject
 gnus-summary-gather-subject-limit 'fuzzy
 gnus-thread-hide-killed t
 gnus-thread-ignore-subject t
 )

;; gnus-summary-mark-below gnus-summary-default-score gnus-summary-default-high-score gnus-summary-default-low-score

;; Scoring.
(setq
 gnus-use-scoring t
 gnus-save-score t
 gnus-score-expiry-days 60
 ;; gnus-decay-scores t
 gnus-score-decay-constant 3
 )

(setq gnus-score-interactive-default-score 100)

;; These variables are local to each summary buffer and usually set by the
;; score file: gnus-summary-mark-below, gnus-summary-expunge-below, gnus-thread-expunge-below

(setq gnus-use-adaptive-scoring t)
;; I use 100 for replay to me and 200 for essential mails, and -50 for bad mails.
(setq gnus-default-adaptive-score-alist
      '(
        (gnus-unread-mark)
        (gnus-ticked-mark (followup 100))
        (gnus-dormant-mark (followup 100))
        ;; (gnus-read-mark (followup -50))
        ;; (gnus-catchup-mark (subject -50))
        (gnus-del-mark (followup -50))
        (gnus-killed-mark (followup -50))
        (gnus-kill-file-mark (from -9999))
        ))

;; Increase the score for followups to a sent article.
(my--eval-after-load gnus-score
  ;; (add-hook 'message-sent-hook 'gnus-score-followup-article)
  (add-hook 'message-sent-hook 'gnus-score-followup-thread))

(defvar my-gnus-summary-kill-same-subject-min-len 8
  "Minimal length of subject string to ignore this subject.")
(defun my-gnus-summary-kill-same-subject (&optional unmark)
  "Add negative scores for all articles with same subject."
  (interactive "P")
  (when (or (not (integerp unmark)) (< 0 unmark))
    (let ( (subj (gnus-simplify-subject-fuzzy (gnus-summary-article-subject))) )
      (when (<= (length subj) my-gnus-summary-kill-same-subject-min-len)
        (gnus-summary-score-entry
         "subject" subj
         's (- gnus-score-interactive-default-score) (current-time-string)))))
  (gnus-summary-kill-same-subject unmark))
(my--eval-after-load gnus-sum
  (define-key gnus-summary-mode-map (kbd "C-k") #'my-gnus-summary-kill-same-subject))

(defun my-gnus-mark-thread-as-read ()
  "Mark unmarked articles in current thread as read and move to
next thread without selecting article."
  (interactive)
  (gnus-summary-top-thread)
  (catch 'exit
    (while t
      (when (eq (gnus-summary-article-mark (gnus-summary-article-number)) gnus-unread-mark)
        (gnus-summary-mark-article (gnus-summary-article-number) gnus-del-mark))
      (when (or (not (gnus-summary-search-forward)) (eq (gnus-summary-thread-level) 0))
        (throw 'exit nil)) )))
(my--eval-after-load gnus-sum
  (define-key gnus-summary-mode-map (kbd "H-k") #'my-gnus-mark-thread-as-read))

(defun my-gnus-thread-score-function (&rest scores)
  "If any followup have positive score assign greater available
score to thread, else assign lesser available score."
  (let ( (max (apply 'max scores)) (min (apply 'min scores)) )
    (if (< 0 max) max min)))
(setq gnus-thread-score-function #'my-gnus-thread-score-function)
(defun my-gnus-thread-total-score ()
  "Helper to debug `gnus-thread-score-function' function."
  (interactive)
  (message
   (int-to-string
    (gnus-thread-total-score
     (gnus-id-to-thread (mail-header-id (gnus-summary-article-header)))))))

;; Especially highlight my message and replays to me.
(my--eval-after-load gnus-sum
  (defface my-gnus-own-unread-face nil
    "Use this face to display own postings in Summary Buffer"
    :group 'my-gnus)
  (copy-face 'gnus-summary-high-unread 'my-gnus-own-unread-face)
  (set-face-background 'my-gnus-own-unread-face "linen")
  (add-to-list 'gnus-summary-highlight
               '((and (> score 190) (eq mark gnus-unread-mark)) . my-gnus-own-unread-face))
  (defface my-gnus-own-ancient-face nil
    "Use this face to display own postings in Summary Buffer"
    :group 'my-gnus)
  (copy-face 'gnus-summary-high-ancient 'my-gnus-own-ancient-face)
  (set-face-background 'my-gnus-own-ancient-face "linen")
  (add-to-list 'gnus-summary-highlight
               '((and (> score 190) (eq mark gnus-ancient-mark)) . my-gnus-own-ancient-face))
  (defface my-gnus-own-ticked-face nil
    "Use this face to display own postings in Summary Buffer"
    :group 'my-gnus)
  (copy-face 'gnus-summary-high-ticked 'my-gnus-own-ticked-face)
  (set-face-background 'my-gnus-own-ticked-face "linen")
  (add-to-list 'gnus-summary-highlight
               '((and (> score 190) (or (eq mark gnus-dormant-mark) (eq mark gnus-ticked-mark))) . my-gnus-own-ticked-face))
  (defface my-gnus-fup-face nil
    "Use this face to display direct fups to my postings."
    :group 'my-gnus)
  (copy-face 'gnus-summary-high-unread 'my-gnus-fup-face)
  (set-face-background 'my-gnus-fup-face "honeydew")
  (add-to-list 'gnus-summary-highlight
               '((and (<= 90 score) (<= score 110) (eq mark gnus-unread-mark)) . my-gnus-fup-face)) )

;; (setq gnus-home-score-file
;;       ;; All groups that match the regexp `"\\.emacs"'
;;       '(("\\.emacs" "emacs.SCORE")
;;         ;; All the comp groups in one score file
;;         ("^comp" "comp.SCORE")))

;; Make C-Up, C-Down more like across paragraph moving.
(my--eval-after-load gnus
  (define-key gnus-summary-mode-map [(meta up)] '(lambda() (interactive) (scroll-other-window -1)))
  (define-key gnus-summary-mode-map [(meta down)] '(lambda() (interactive) (scroll-other-window 1)))
  (define-key gnus-summary-mode-map [(control down)] 'gnus-summary-next-thread)
  (define-key gnus-summary-mode-map [(control up)] 'gnus-summary-prev-thread))

(defun my-gnus-search-web-by-message-id ()
  "Search for article archive by Message-Id in Google."
  (interactive)
  (let ( (msgid (message-fetch-field "Message-Id")) (subj (message-fetch-field "Subject")) )
    (setq msgid (replace-regexp-in-string "[<>]" "" msgid))
    (setq subj (replace-regexp-in-string "[\"#]" " " subj))
    (browse-url (format "https://www.google.com.ua/search?q=%s" (url-encode-url (format "%s OR \"%s\"" msgid subj))))
    (browse-url (format "http://mid.mail-archive.com/%s" (url-encode-url msgid)))))

(my--eval-after-load gnus-art
  (define-key gnus-article-mode-map [(control return)] #'my-gnus-search-web-by-message-id))

;; (setq imap-log t)

;; (setq mail-user-agent 'mh-e-user-agent)

(custom-set-faces
 '(gnus-summary-cancelled ((t (:foreground "plum" :background nil))))
 '(gnus-signature-face ((t (:foreground "grey"))))
 )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "jabber")

(cl-eval-when (compile) (require 'jabber nil t))

(setq jabber-history-dir (concat user-emacs-directory ".jabber"))

(autoload 'jabber-connect-all "jabber")

(setq
 jabber-history-enabled t
 jabber-history-muc-enabled t
 jabber-use-global-history nil
 jabber-backlog-number 40
 jabber-backlog-days 30
 jabber-alert-presence-message-function (lambda (who oldstatus newstatus statustext) nil)
 )

(my--eval-after-load jabber
  ;; Redefine standard binding for sending message form RET to C-RET.
  (define-key jabber-chat-mode-map (kbd "RET") 'newline)
  (define-key jabber-chat-mode-map [C-return] 'jabber-chat-buffer-send)
  ;; fsm used in emacs jabber
  (when (featurep 'fsm)
    (setq fsm-debug nil))               ; Disable *fsm-debug* buffer.
  ;; Handle Emacs exit.
  (add-hook 'kill-emacs-hook 'jabber-disconnect))

(defvar my-chat-prompt "[%t] %n>\n")
(setq
 jabber-chat-foreign-prompt-format my-chat-prompt
 jabber-chat-local-prompt-format my-chat-prompt
 jabber-groupchat-prompt-format my-chat-prompt
 jabber-muc-private-foreign-prompt-format "[%t] %g/%n>\n")

(let ( (mgs-list '("Я тутачки, а где Вы меня ожидали?"
                   "Software Development == Church Development. Step 1. Build it. Step 2. Pray."
                   "Great books aren't written – they're rewritten."
                   "А любит Б, Б любит С, что делать A? Найти другую Б!")) )
  (random t)
  (setq jabber-default-show (nth (random (length mgs-list)) mgs-list))
  (setq jabber-default-status (nth (random (length mgs-list)) mgs-list))
  )

(defvar my-jabber-users nil
  "Assoc list of jabber user group. Keys are strings, values are lists of JIDs.")

(defun my-jabber-send (group)
  "GROUP is keys from `my-jabber-users'"
  (interactive
   (list (completing-read "Select group: " my-jabber-users))
   )
  (let (
        (msg (if (use-region-p)
                 (buffer-substring (region-beginning) (region-end))
               (buffer-string)))
        (jc (jabber-read-account))
        )
    (deactivate-mark)
    (mapc
     (lambda (user)
       (jabber-send-message jc user "" msg "normal")
       )
     (cdr (assoc group my-jabber-users))
     )
    )
  )

(global-set-key (kbd "C-x C-j C-s") 'my-jabber-send)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "erc")

(cl-eval-when (compile)
  (require 'erc)
  (require 'erc-log))

;; (add-to-list 'erc-modules 'notify)
;; (setq erc-notify-list '(""))

;; Take off noise message.
(setq erc-track-exclude-types '("JOIN" "PART" "QUIT" "NICK" "MODE"))

(setq erc-current-nick-highlight-type 'nick-or-keyword)
(setq erc-track-use-faces t)

(setq erc-server-coding-system 'utf-8)
(setq erc-encoding-coding-alist
      '(
        ("^icq-" . cp1251)
        ("#debian-russian" . koi8-r)
        ))

;; (setq erc-autojoin-channels-alist '(("freenode.net" "#emacs")))

(setq
 erc-server-auto-reconnect t
 erc-server-reconnect-timeout 60
 erc-server-reconnect-attempts 2)

(setq
 erc-log-channels-directory "~/.emacs.d/.irc"
 erc-log-file-coding-system 'utf-8-unix)
(my--eval-after-load erc
  (require 'erc-log)
  (mkdir erc-log-channels-directory t))

;; Kill buffers for channels after /part
;; (setq erc-kill-buffer-on-part t)
;; Kill buffers for private queries after quitting the server
;; (setq erc-kill-queries-on-quit t)
;; Kill buffers for server messages after quitting the server
;; (setq erc-kill-server-buffer-on-quit t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "devel, programming")

(which-func-mode 1)

(add-to-list 'auto-mode-alist '("\\.cu$" . c-mode))

(defun my--c++-header-file-p ()
  "Return non-nil, if in a C++ header."
  (and (string-match "\\.h$"
                     (or (buffer-file-name)
                         (buffer-name)))
       (save-excursion
         (re-search-forward "\\_<class\\_>" nil t))))

(add-to-list 'magic-mode-alist '(my--c++-header-file-p . c++-mode))

(setq-default comment-style (quote indent))
(setq-default comment-column 44)
(setq-default comment-fill-column my-fill-column)

(setq-default fill-column my-fill-column)

(add-hook 'prog-mode-hook #'hs-minor-mode)

(defun my-company-prog-mode-setup ()
  (setq-local company-dabbrev-code-other-buffers 'code)
  (setq-local company-backends '((company-capf company-dabbrev-code company-files)))
  (company-mode 1))

(when (featurep 'company)
  (add-hook 'prog-mode-hook #'my-company-prog-mode-setup))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "diff, patch, ediff, emerge")

(cl-eval-when (compile) (require 'ediff))

(setq diff-switches "-u")

(setq ediff-diff-options "")
(setq ediff-custom-diff-options "-u")
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(setq ediff-split-window-function 'split-window-vertically)

;; Disable: sometimes it take a long time to process large hunks.
;; Use C-c C-b on hunk by own.
;; (defun my-diff-auto-refine-mode-on () (diff-auto-refine-mode 1))
;; (add-hook 'diff-mode-hook 'my-diff-auto-refine-mode-on)

;; Since 27.1 it is enabled during font-lock. Need to disable explicitly.
(setq diff-refine nil)
;; https://emacs.stackexchange.com/questions/61760/lags-when-navigating-vc-root-diff-buffer/
(setq diff-font-lock-syntax 'hunk-only)

(when (and window-system (< emacs-major-version 26))
  (my--eval-after-load diff-mode
    (set-face-foreground 'diff-added "DarkGreen")
    (set-face-foreground 'diff-removed "DarkRed")
    (set-face-background 'diff-refine-changed "LightBlue1")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "vc-mode, VCS, version control, cvs, svn, mercurial, hg, bazaar, bzr, git, fossil")

(cl-eval-when (compile)
  (require 'vc)
  (require 'vc-hooks)
  (require 'vc-annotate)
  (require 'vc-svn))

(defun my-vc-show-rev (rev)
  "Show diff for REV."
  (interactive "sRevision: ")
  (let ((backend (vc-responsible-backend default-directory)))
    (when backend
      (let ((rev-from (vc-call-backend backend 'previous-revision nil rev)))
        (when rev-from
          (vc-diff-internal t (list backend nil) rev-from rev))))))

(global-set-key (kbd "C-x v R") 'my-vc-show-rev)

;; `-b' switch to ignore changes in whitespaces.
;; (setq vc-git-diff-switches "-b")
;; (setq vc-diff-switches "-b")

(defun my-vc-root-diff (prefix)
  "Same as `vc-root-diff' but for Hg with C-u show latest MQ patch and
with C-u C-u show MQ patch and local changes."
  (interactive "P")
  (when (eq 'non-hg-mq
            (catch 'break
              (unless (and prefix (eq (vc-deduce-backend) 'Hg))
                (throw 'break 'non-hg-mq))
              (let* ( (rootdir (vc-call-backend 'Hg 'root default-directory)) (default-directory rootdir) )
                (unless (eq (vc-hg-command nil t rootdir "log" "-r" "qtip") 0)
                  (throw 'break 'non-hg-mq))
                (cond
                 ((equal prefix '(4))
                  (vc-diff-internal t (list 'Hg (list rootdir)) "qparent" "qtip"))
                 ((equal prefix '(16))
                  (vc-diff-internal t (list 'Hg (list rootdir)) "qparent" nil)) ))))
    (call-interactively 'vc-root-diff nil) ))

(global-set-key (kbd "C-x v D") 'my-vc-root-diff)

(setq vc-hg-diff-switches (list "-U" "7"))
;; More context (7 lines) and better rename detection (30% similarity).
(setq vc-git-diff-switches (list "-U7" "-M3"))

(setq vc-git-print-log-follow t)

(when window-system
  (setq
   vc-annotate-very-old-color "#0b5b20"
   vc-annotate-background "white"
   vc-annotate-color-map
   '(
     (20 .  "#EE0000")
     (40 .  "#E0800D")
     (60 .  "#D3001A")
     (80 .  "#C68027")
     (100 . "#B90034")
     (120 . "#AB8042")
     (140 . "#9E004F")
     (160 . "#91805C")
     (180 . "#840069")
     (200 . "#778077")
     (220 . "#690084")
     (240 . "#5C8091")
     (260 . "#4F009E")
     (280 . "#4280AB")
     (300 . "#3400B9")
     (320 . "#2780C6")
     (340 . "#1A00D3")
     (360 . "#0D80E0")))
  )

(defun my-log-edit-mode-hook ()
  (setq fill-column 78)
  )
(add-hook 'log-edit-mode-hook 'my-log-edit-mode-hook t)

(with-eval-after-load 'log-edit
  (remove-hook 'log-edit-hook 'log-edit-insert-message-template))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "magit")

(when (eq window-system 'w32)
  (setq magit-refresh-status-buffer nil))

(with-eval-after-load 'magit-mode
  (setq magit-log-margin '(t "%F %H:%M" magit-log-margin-width t 18))
  (define-key magit-mode-map [s-tab] nil))

;; No only it is slow in Cygwin it is also fails on some hunks...
(setq magit-diff-refine-hunk nil)

(with-eval-after-load 'magit-branch
  (remove-hook 'find-file-hook 'magit-edit-branch*description-check-buffers))
(with-eval-after-load 'magit-autorevert
  (remove-hook 'find-file-hook 'magit-auto-revert-mode-check-buffers)
  (remove-hook 'after-change-major-mode-hook 'magit-auto-revert-mode-enable-in-buffers))
(with-eval-after-load 'git-commit
  (remove-hook 'find-file-hook 'git-commit-setup-check-buffer)
  (remove-hook 'after-change-major-mode-hook 'git-commit-setup-font-lock-in-buffer))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "indenting")

(cl-eval-when (compile) (require 'cc-mode))

(setq standard-indent 4)
(setq c-basic-offset 4)

(when (fboundp 'electric-indent-mode)
  (electric-indent-mode -1))

;; TAB (tab settings)
(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)     ; spaces instead of tabs by default
(setq tab-always-indent t)
(setq c-tab-always-indent t)
(let ( (line-width 400) i )
  (setq i (* (ceiling line-width 4) 4))
  (setq tab-stop-list nil)
  (while (>= i 0)
    (setq tab-stop-list (cons i tab-stop-list))
    (setq i (- i 4))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "compile")

;; Prompt for compilation command.
(setq compilation-read-command 1)
(setq compile-command "mymake ")
(when (eq system-type 'berkeley-unix)
  (setq compile-command "gmake "))
;; With '1' compilation window shall scroll down, with `first-error' stops scrolling at the first error.
(setq compilation-scroll-output 1)
(setq compilation-ask-about-save t)

;; Show error in EN locale to easy search how fix problem in docs and Internet.
;; (setq compilation-environment '("LANG=C"))

(my--eval-after-load compile
  ;; My funny error messages.
  (add-to-list 'compilation-error-regexp-alist-alist '(nant "^\\( +\\[csc\\] \\|\\)\\(.*\\)(\\([0-9]*\\),\\([0-9]*\\)):" 2 3 4))
  (add-to-list 'compilation-error-regexp-alist 'nant)
  (add-to-list 'compilation-error-regexp-alist-alist '(msvc "^ *\\(.*\\)(\\([0-9]*\\)) +:" 1 2))
  (add-to-list 'compilation-error-regexp-alist 'msvc)
  (add-to-list 'compilation-error-regexp-alist-alist '(keil "^\"?\\([^\"]*\\)\"?,\\([0-9]*\\) .*\\[.*\\]: " 1 2))
  (add-to-list 'compilation-error-regexp-alist 'keil)
  (add-to-list 'compilation-error-regexp-alist-alist '(maven "\\[ERROR\\] \\(.*\\.java\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\]" 1 2 3))
  (add-to-list 'compilation-error-regexp-alist 'maven)
  (add-to-list 'compilation-error-regexp-alist-alist '(asciidoc "^asciidoc: \\(?:ERROR\\|WARNING\\): \\([^\n:]+\\): line \\([0-9]+\\):" 1 2))
  (add-to-list 'compilation-error-regexp-alist 'asciidoc)
  (when (boundp 'compilation-mode-font-lock-keywords)
    (add-to-list 'compilation-mode-font-lock-keywords '("\\(/[Oo][Uu][Tt]:[^[:blank:]]+\\)" . 1))
    (add-to-list 'compilation-mode-font-lock-keywords '("[[:blank:]]\\(/F[oe][^[:blank:]]+\\)" . 1))))

(ignore-errors
  (require 'ansi-color)
  (defun my-colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  (add-hook 'compilation-filter-hook 'my-colorize-compilation-buffer))

(defvar my-comint-send-hist-list nil
  "History list for `my-comint-send-string'."
  )
(defun my-comint-send-string (string)
  "Send string to comint buffers. Useful for *compilation* read-only buffer.
Automaticaly append final newline."
  (interactive
   (list (read-string "Type string: " nil 'my-comint-send-hist-list))
   )
  (comint-send-string (get-buffer-process (current-buffer)) (concat string "\n"))
  )
(my--eval-after-load compile
  (define-key compilation-mode-map [C-return] 'my-comint-send-string))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "scons")

(add-to-list 'auto-mode-alist '("SConstruct\\'" . python-mode))
(add-to-list 'auto-mode-alist '("SConscript\\'" . python-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "gdb, gud")
;; Use C-x SPACE to set breakpoint in source file.

(cl-eval-when (compile) (require 'gdb-mi nil t))

(setq gdb-show-main t)                  ; See also (gdb-many-windows)

(setq gud-pdb-command-name "python3 -m pdb")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "completion, abbrev")

(setq completion-ignore-case t)

(setq abbrev-file-name (concat user-emacs-directory ".abbrev"))
;; (quietly-read-abbrev-file)
;; (setq default-abbrev-mode t)
;; (setq save-abbrevs t)

(global-set-key (kbd "M-/") 'hippie-expand)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "TAGS, etags, ctags, GNU GLOBAL")

;; One of 'tags-table-list' or 'tags-file-name' control which TAGS files to
;; use.

(ignore-errors
  (require 'etags-table)
  (setq etags-table-search-up-depth 8)
  (require 'etags-select)
  (global-set-key "\M-." 'etags-select-find-tag)
  )

(setq tags-add-tables t)

(defvar my-ido-tag-history nil
  "History of tags selected using `my-ido-complete-tag'.")
(defun my-ido-complete-tag (&optional substr)
  "Find a tag using ido."
  (tags-completion-table)
  (let ( tag-names )
    (mapatoms (lambda (x) (push (symbol-name x) tag-names)) tags-completion-table)
    (ido-completing-read "Tag: " tag-names nil t substr 'my-ido-tag-history)))
(defun my-complete-tag (prefix point)
  (interactive "P\nd")
  (if prefix
      (funcall #'complete-tag)
    (let ( (bounds (find-tag-default-bounds)) tag )
      (if (or (not bounds) (< point (car bounds)) (< (cdr bounds) point))
          (setq tag (my-ido-complete-tag))
        (setq tag (my-ido-complete-tag (buffer-substring (car bounds) (cdr bounds))))
        (delete-region (car bounds) (cdr bounds)))
      (insert tag))))

(global-set-key [M-return] #'my-complete-tag)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "imenu")

(require 'imenu)

(defun my-imenu-to-menubar ()
  "Force imenu building when (menu-bar-mode -1)."
  (when imenu-generic-expression
    (imenu-add-menubar-index)
    (run-hooks 'menu-bar-update-hook) ))
(add-hook 'prog-mode-hook 'my-imenu-to-menubar)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "windows inf files for driver installin")

(add-to-list 'auto-mode-alist '("\\.inf\\'" . conf-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "fvwm-mode")

(my--eval-after-load fvwm-mode
  (setq fvwm-fvwmcommand-path (executable-find "FvwmCommand")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "makefile, make")

(add-to-list 'auto-mode-alist '("\\(Makefile\\|Makefile\\..+\\)\\'" . makefile-gmake-mode) t)

(defun my-makefile-setup ()
  (add-hook 'completion-at-point-functions 'comint-filename-completion nil t))

(add-hook 'makefile-mode-hook #'my-makefile-setup)

(defun my-makefile-company-setup ()
  "Limit search for symbols to Makefiles."
  (setq-local company-dabbrev-code-other-buffers t)
  (setq-local company-backends '((company-capf company-dabbrev-code company-files company-executable)))
  (company-mode 1))

(when (featurep 'company)
  (add-hook 'makefile-mode-hook #'my-makefile-company-setup))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "asm, assembler")

;; (setq-default asm-comment-char 59)
(add-hook 'asm-mode-hook '(lambda () (setq comment-start "/*") (setq comment-end "*/")) t)

(add-to-list 'auto-mode-alist '("\\.\\([sS]79\\|[sS]\\)\\'" . asm-mode))

;; (add-hook 'asm-mode-hook '(lambda () (local-unset-key ":")))
;; (add-hook 'asm-mode-hook '(lambda () (local-set-key ":" ":")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "linker")

(when (fboundp 'iar-linker-config-mode)
  (add-to-list 'auto-mode-alist '("\\.icf\\'" . iar-linker-config-mode))
  )
(when (fboundp 'iar4-linker-config-mode)
  (add-to-list 'auto-mode-alist '("\\.xcl\\'" . iar4-linker-config-mode))
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "c-mode, cc-mode, c++-mode")

(cl-eval-when (compile) (require 'cc-mode))

;; Minor mode that highlights suspicious C and C++ constructions.
(global-cwarn-mode 1)

(setq c-echo-syntactic-information-p t)

(defun my-c-mode-common-hook ()
  ;; Automatically inserte newlines after special characters such as brace, comma, semi-colon, and colon.
  (c-toggle-auto-newline -1)
  ;; Delete all preceding whitespace by DEL.
  (c-toggle-hungry-state -1)
  ;; Auto indent after typing colon according to `c-hanging-colons-alist'.
  (c-toggle-electric-state 1)
  )
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

(defconst my-c-style
  '((c-tab-always-indent . t)
    (c-comment-only-line-offset . 4)
    (c-hanging-braces-alist
     . (
        (brace-list-open)
        (substatement-open after)
        ))
    (c-hanging-colons-alist
     . (
        (access-label after)
        (case-label after)
        (inher-intro)
        (label after)
        (member-init-intro before)
        ))
    (c-cleanup-list
     . (
        defun-close-semi
        empty-defun-braces
        scope-operator
        ))
    (c-offsets-alist
     . (
        (access-label . -)
        (arglist-intro . ++)
        (arglist-cont-nonempty . ++)
        (arglist-close . ++)
        (block-open . 0)
        (case-label . 0)
        (cpp-define-intro . 0)
        (comment-intro . 0)
        (func-decl-cont . ++)
        (inexpr-class . 0)
        (inline-open . 0)
        (knr-argdecl-intro . -)
        (label . 0)
        (statement-block-intro . +)
        (statement-cont . ++)
        (substatement-open . 0)
        (inextern-lang . 0)
        ))
    ;; Certain syntactic errors are reported (like wrong indent).
    (c-report-syntactic-errors . t)
    ;; Echo syntactic information on TAB in message buffer.
    (c-echo-syntactic-information-p . t))
  "My C Programming Style")

(defun my-c-mode-style-hook ()
  (c-add-style "my" my-c-style t)
  ;; If set 'c-default-style' before 'c-add-style'
  ;; "Undefined style: my" error occured from 'c-get-style-variables'.
  (setq c-default-style
        '(
          (java-mode . "my") (c-mode . "my") (csharp-mode . "my") (c++-mode . "my") (objc-mode . "my")
          (idl-mode . "my")
          (awk-mode . "awk")
          (other . "my")
          ))
  )
(add-hook 'c-mode-common-hook 'my-c-mode-style-hook)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "python, python-mode")

(cl-eval-when (compile)
  (require 'python))

(setq python-shell-interpreter "python3")
(setq python-shell-interpreter-args "-i")

(setq python-indent-offset 4)

(defun my-python/describe-at-point (symbol process prefix)
  "Show full docs for symbol at point using Python's help() built-in.

With argument 1 uses Python's type() built-in.
With argument 2 uses Python's repr() built-in.
With argument 1 uses Python's dir() built-in.
With argument 1 uses Python's vars() built-in."
  (interactive (list (python-info-current-symbol)
                     (python-shell-get-process)
                     current-prefix-arg))
  (let ( (cmd
          (cond
           ((eq 1 prefix) (concat "help(type(" symbol "))\n"))
           ((eq 2 prefix) (concat "repr(" symbol ")\n"))
           ((eq 3 prefix) (concat "print('\\n'.join(dir(" symbol ")))\n"))
           ((eq 4 prefix) (concat "vars(" symbol ")\n"))
           ((not prefix) (concat "help('" symbol "')\n"))
           (t (concat "dir(" symbol ")\n")))) )
    (switch-to-buffer (get-buffer-create (format "*pydoc: %s*" symbol)))
    (fundamental-mode)
    (read-only-mode -1)
    (buffer-disable-undo)
    (erase-buffer)
    (insert (python-shell-send-string-no-output cmd process))
    (setq-local delete-trailing-lines t)
    (delete-trailing-whitespace)
    (read-only-mode 1)
    (goto-char (point-min))))

(defun my-python/send-paragraph ()
  (interactive)
  (save-excursion
    (let ( end )
      (forward-paragraph)
      (setq end (point))
      (backward-paragraph)
      (python-shell-send-region (point) end))))

;; For built-in python.el
(my--eval-after-load python
  ;; Shadows primitive built-in `python-describe-at-point'.
  (define-key python-mode-map "\C-c\C-d" 'my-python/describe-at-point)
  (define-key python-mode-map [?\C-c ?\C-h] 'my-python/send-paragraph))

(defgroup my-python nil
  "My Python extentions in Emacs."
  :group 'python)

(defvar my-python/pylint-command "pylint"
  "Command to run pylint executable.")
(defvar my-python/pylint-args "-f parseable --disable=C0301,C0325"
  "Arguments to pass to pylint executable.")

(defvar my-python/pep8-command "pep8"
  "Command to run pep8 executable.")
(defvar my-python/pep8-args ""
  "Arguments to pass to pep8 executable.")

(defvar my-python/pyflakes-command "pyflakes"
  "Command to run pyflakes executable.")
(defvar my-python/pyflakes-args ""
  "Arguments to pass to pyflakes executable.")

(defvar my-python/pyflakes3-command "pyflakes3"
  "Command to run pyflakes3 executable.")
(defvar my-python/pyflakes3-args ""
  "Arguments to pass to pyflakes3 executable.")

(defvar my-python/checker-alist
  '((pylint . (my-python/pylint-command my-python/pylint-args))
    (pep8 . (my-python/pep8-command my-python/pep8-args))
    (pyflakes . (my-python/pyflakes-command my-python/pyflakes-args))
    (pyflakes3 . (my-python/pyflakes3-command my-python/pyflakes3-args)))
  "Known Python source code checkers.")

(defcustom my-python/default-checker
  (cond
   ((eq system-type 'cygwin) 'pylint)
   (t 'pyflakes))
  "Default Python source code checker. See `my-python/checker-alist' for full alist."
  :group 'my-python
  :type (cons 'choice (mapcar (lambda (e) (cons 'const e)) my-python/checker-alist)))

(defvar my-python/check-history nil)

(defun my-python/check (&optional checker)
  (interactive
   (list
    (completing-read "Select cheker: " (mapcar (lambda (e) (car e)) my-python/checker-alist) nil t (symbol-name my-python/default-checker) 'my-python/check-history)))
  (let ( entry )
    (unless (setq entry (cdr (assoc (intern-soft checker) my-python/checker-alist)))
      (error "Unknown checker..."))
    (compilation-start (format "%s %s %s" (symbol-value (car entry)) (symbol-value (cadr entry)) (shell-quote-argument (buffer-file-name))))))

(my--eval-after-load python
  (define-key python-mode-map [?\C-c ?\C-v] #'my-python/check))

;; For 3rd party python-mode.el.
(my--eval-after-load python-mode
  (when (and (boundp 'py-version) (equal py-version "5.1.0"))
    ;; (py-toggle-shells 'cpython)
    (setq-default py-which-shell py-python-command))
  (when (boundp 'py-version)
    (define-key python-mode-map [C-backspace] 'backward-kill-word)
    (define-key python-mode-map [?\C-c ?p] 'py-execute-paragraph)
    (define-key python-mode-map [?\C-c ?r] 'py-execute-region)
    (define-key inferior-python-mode-map "\C-c\C-f" 'python-describe-symbol)))

;; Enable "M-/", "C-c g", "C-c d", "C-c f" shortcuts.
(setq ropemacs-enable-shortcuts t)
(ignore-errors
  ;; (require 'pymacs)
  ;; (pymacs-load "ropemacs" "rope-")
  )
;; Automatically save project python buffers before refactorings
(setq ropemacs-confirm-saving 'nil)

(defun my-python-add-to-path (path)
  (interactive (list (read-directory-name "Enter new path for PYTHONPATH: ")))
  (when (featurep 'cygwin-mount)
    (setq path (my-dos2cygwin-path path)))
  (python-send-string (format "import sys; sys.path.append(\"%s\")" (expand-file-name path))) )

(defun my-python-django-fix (path)
  "XXX not work on Cygwin + naive Emacs."
  (interactive (list (read-directory-name "Enter new path for PYTHONPATH: ")))
  (when (featurep 'cygwin-mount)
    (setq path (my-dos2cygwin-path path))
    )
  (let ((file (concat path "manage.py")))
    (if (file-exists-p file)
        (python-send-string (format "import os; os.chdir(\"%s\"); execfile(\"%s\")" path file))
      (error (format "file '%s' does not exist" file))
      )))

;; Disable in flavor of Semantic and perfomance reason.
;; (when (>= emacs-major-version 22)
;;   (add-hook 'python-mode-hook 'turn-on-eldoc-mode)

(defun my-python-mode-hook ()
  (when (and (eq window-system 'w32) (fboundp 'prettify-symbols-mode))
    (prettify-symbols-mode -1)))
(add-hook 'python-mode-hook 'my-python-mode-hook)

;; (when (equal window-system 'w32)
;;   (add-to-list 'process-coding-system-alist '("python" cp1251-unix . cp1251-unix)))

(add-to-list 'auto-mode-alist '("/requirements.txt\\'" . conf-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "perl, cperl")

(cl-eval-when (compile) (require 'cperl-mode))

;; Use cperl instead perl mode.
(mapc
 (lambda (pair)
   (if (eq (cdr pair) 'perl-mode)
       (setcdr pair 'cperl-mode)))
 (append auto-mode-alist interpreter-mode-alist))
;; Don't show all man page. I set man switches to "-a"...
(add-hook
 'cperl-mode-hook
 '(lambda ()
    (make-local-variable 'Man-switches)
    (setq Man-switches nil)))

;; Expands for keywords such as foreach, while, etc...
(setq cperl-electric-keywords t)

(setq
 cperl-indent-level 2
 cperl-close-paren-offset -2
 cperl-continued-statement-offset 2
 cperl-indent-parens-as-block t
 cperl-tab-always-indent t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "r, ess-mode")

(setq ess-indent-offset 2)

(my--eval-after-load ess-inf
  (define-key inferior-ess-mode-map [home] 'comint-bol))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "SML, Standard ML")

(my--eval-after-load sml
  (define-key sml-mode-map (kbd "C-c C-p") 'sml-send-function))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "javascript, js, typescript")

(if (>= emacs-major-version 23)
    (add-to-list 'auto-mode-alist '("\\.js$" . js-mode))
  (add-to-list 'auto-mode-alist '("\\.js$" . javascript-generic-mode))
  )

(my--eval-after-load js
  (modify-syntax-entry ?$ "w" js-mode-syntax-table))

(setq js-indent-level 4)
;; js-curly-indent-offset, js-expr-indent-offset, js-paren-indent-offset, 	js-square-indent-offset, js-switch-indent-offset

;; BUG: all single char comments do not stop highlighting on end of line but
;; go to end of buffer. To fix use code:
;; (setq auto-mode-alist (rassq-delete-all 'js-mode auto-mode-alist))
;; (add-to-list 'auto-mode-alist '("\\.js$" . c++-mode))

(my--eval-after-load typescript-mode
  (add-to-list 'auto-mode-alist '("\\.tsx?$" . typescript-mode)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "json")

(defun my-json-mode-hook ()
  (set (make-local-variable 'js-indent-level) 2))
(add-hook 'json-mode-hook #'my-json-mode-hook)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "yaml, yml")

(my--eval-after-load yaml-mode
  (add-to-list 'auto-mode-alist '("\\.ya?ml\\.j2\\'" . yaml-mode)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "bat file, batch")

;; loaded from 'generic-x.el'

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "csharp, c-sharp")

(autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t)
(add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "java")

(when (fboundp 'subword-mode)
  (add-hook 'java-mode-hook #'subword-mode))

(add-hook 'java-mode-hook #'auto-revert-mode)

(defun my-company-java-setup ()
  (setq-local company-dabbrev-code-other-buffers t)
  (setq-local company-backends '((company-semantic company-capf company-dabbrev-code)))
  (company-mode 1))
(when (and (featurep 'semantic) (featurep 'company))
  (add-hook 'java-mode-hook #'my-company-java-setup))

(defvar my-java-exeption-dirs nil
  "List of dirs to look by `my-java-exeption'.")

(defun my-java-exeption ()
  "Look at current line if it like Java exaption and try find file using `my-java-exeption-dirs'"
  (interactive)
  (save-excursion
    (let ( path file line end )
      (forward-line 1)
      (backward-char 1)
      (setq end (point))
      (forward-line 0)
      (if (not (re-search-forward "^\\s-+at \\([a-zA-Z0-9.$]+\\)(\\([^.]+\\)\\.java:\\([1-9][0-9]*\\))" end t))
          (message "Current line doesn't look like Java exeption or lack necessary information...")
        (setq file (match-string 2))
        (setq line (match-string 3))
        (setq path (match-string 1))
        (setq path (replace-regexp-in-string (concat "\\." file ".*") "" path))
        (setq path (replace-regexp-in-string "\\." "/" path))
        (setq path (cl-some (lambda (dir)
                              (let ((full-path (format "%s/%s/%s.java" dir path file)))
                                (when (file-exists-p full-path) full-path)))
                            my-java-exeption-dirs))
        (if (not path)
            (message "Can't find file %s.java" file)
          (find-file-other-window path)
          (forward-line (string-to-number line)))))))

(my--eval-after-load log4-hi-mode
  (define-key log4-hi-mode-map [C-return] #'my-java-exeption))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "cfengine")

(add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine3-mode))

;; Problems with hunging on re-display when symbols is used on Windows can be solved by:
;;   (setq inhibit-compacting-font-caches t)
;; or choosing "DejaVu Sans Mono" font.
;; (my--eval-after-load cfengine3
;;   (defconst cfengine3--prettify-symbols-alist
;;     '(("->"  . ?→)
;;       ("=>"  . ?⇛))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "Pascal")

(cl-eval-when (compile) (require 'pascal))

(setq
 pascal-indent-level 4
 pascal-case-indent 2
 pascal-auto-newline t
 pascal-tab-always-indent t
 ;; pascal-toggle-completions t
 ;; pascal-auto-lineup nil
 pascal-auto-endcomments t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "nsis-mode")

(when (fboundp 'nsis-mode)
  (add-to-list 'auto-mode-alist '("\\.\\(nsi\\|nsh\\)\\'" . nsis-mode))
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "wesnoth-mode")

(ignore-errors
  (require 'wesnoth-mode)
  (add-to-list 'auto-mode-alist '("wesnoth.*\\.cfg\\'" . wesnoth-mode)) )

(defvar wesnoth-base-indent)
(setq wesnoth-base-indent 2)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "css")

(cl-eval-when (compile) (require 'css-mode))

(setq css-indent-offset 4)

;; (package-install 'css-eldoc)

(my--eval-after-load css-mode
  (when (fboundp 'css-eldoc-enable)
    (css-eldoc-enable)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "htmlize")

(cl-eval-when (compile) (require 'htmlize nil t))

(setq
 htmlize-html-charset "utf-8"
 htmlize-output-type 'inline-css
 htmlize-html-major-mode 'html-mode
 htmlize-convert-nonascii-to-entities nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "html")

(defun my-html-charref-escape-region (start end)
  (interactive "r")
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (while (search-forward "&" nil t) (replace-match "&amp;"))
      (goto-char (point-min))
      (while (search-forward "<" nil t) (replace-match "&lt;"))
      (goto-char (point-min))
      (while (search-forward ">" nil t) (replace-match "&gt;"))
      )))

(defun my-html-charref-from-char (char)
  (format "&#%d;" char)
  )

(defun my-html-charref-from-string (string)
  (let ((res ""))
    (mapc
     (lambda (char) (setq res (concat res (my-html-charref-from-char char))))
     string)
    res
    ) )

(defun my-html-charref-escape-region2 (begin end &optional prefix)
  (interactive "r\nP")
  (if prefix
      (save-excursion
        (goto-char begin)
        (insert (my-html-charref-from-string (delete-and-extract-region begin end))))
    (my-html-charref-from-string (buffer-substring begin end))
    ))

(defun my-html-charref-to-string (html)
  "Return string with replaced decimal/hex and string charrefs by
correcponding UTF-8 symbol."
  (let (str)
    (with-temp-buffer
      (insert html)
      (goto-char (point-min))
      (while (search-forward-regexp "&\\(?:#\\([[:digit:]]+\\)\\|#x\\([[:xdigit:]]+\\)\\|\\(lt\\|gt\\|amp\\|quot\\)\\);" nil t)
        (setq str (or (match-string 1) (match-string 2) (match-string 3)))
        (cond
         ((match-string 1)
          (when (> (string-to-number str 10) 0)
            (replace-match (string (string-to-number str 10)) t t)))
         ((match-string 2)
          (when (> (string-to-number str 16) 0)
            (replace-match (string (string-to-number str 16)) t t)))
         (t
          (cond
           ((equal str "lt")
            (replace-match "<" t t))
           ((equal str "gt")
            (replace-match ">" t t))
           ((equal str "quot")
            (replace-match "\"" t t))
           ((equal str "amp")
            (replace-match "&" t t)))) ))
      (buffer-string))))

(defun my-html-charref-unescape-region (begin end &optional prefix)
  (interactive "r\nP")
  (if prefix
      (save-excursion
        (goto-char begin)
        (insert (my-html-charref-to-string (delete-and-extract-region begin end))))
    (my-html-charref-to-string (buffer-substring begin end))
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "nxml")

(cl-eval-when (compile) (require 'nxml-mode))

(setq nxml-sexp-element-flag t)
(setq nxml-child-indent 2)
(setq nxml-attribute-indent 4)

(add-to-list 'auto-mode-alist '("\\.pom\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.xsd\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.rng\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.xul\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.xslt\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.svg\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.rss\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.atom\\'" . nxml-mode))

(my--eval-after-load nxml-mode
  (if (<= emacs-major-version 25)
      (define-key nxml-mode-map [C-return] 'nxml-complete)
    (define-key nxml-mode-map [C-return] 'completion-at-point))
  (define-key nxml-mode-map [S-tab] 'hs-toggle-hiding))

(defun my-nxml-pp ()
  "Pretty-print XML."
  (interactive)
  (goto-char (point-min))
  (while (re-search-forward ">[ \t\n\r]+<" nil t)
    (replace-match ">\n<"))
  (goto-char (point-min))
  (while (re-search-forward "><" nil t)
    (replace-match ">\n<"))
  (indent-region (point-min) (point-max))
  (goto-char (point-min)))

(defun my-nxml-where (&optional prefix)
  "Display the hierarchy of XML elements the point is on as a path."
  (interactive "P")
  (let (path)
    (save-excursion
      (save-restriction
        (widen)
        (while (and (< (point-min) (point))
                    (condition-case nil
                        (progn
                          (nxml-backward-up-element)
                          t)
                      (error nil)))
          (setq path (cons (xmltok-start-tag-local-name) path)))
        (setq path (mapconcat 'identity path "/"))
        (when prefix
          (kill-new path))
        (if (called-interactively-p t)
            (message "%s" path)
          path)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "relax ng, rng")

(my--eval-after-load rng-loc
  (add-to-list 'rng-schema-locating-files "~/.emacs.d/rnc/schemas.xml"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "web-mode")

(require 'web-mode nil t)
(cl-eval-when (compile) (require 'web-mode nil t))

(setq web-mode-markup-indent-offset 2
      web-mode-css-indent-offset 2
      web-mode-code-indent-offset 2
      web-mode-script-padding 2
      web-mode-style-padding 2)

(setq web-mode-enable-comment-keywords t)

(setq web-mode-enable-auto-indentation nil)

(ignore-errors (require 'web-mode))

(when (featurep 'web-mode)
  ;; Replace html-mode  with web-mode.
  (when (cl-some (lambda (spec) (eq (cdr spec) 'html-mode))
                 magic-fallback-mode-alist)
    (setq magic-fallback-mode-alist (copy-tree magic-fallback-mode-alist))
    (mapc (lambda (spec) (when (eq (cdr spec) 'html-mode) (setcdr spec 'web-mode)))
          magic-fallback-mode-alist))
  (setq web-mode-engine-file-regexps (delq (assoc "jsp" web-mode-engine-file-regexps) web-mode-engine-file-regexps))
  (mapc (lambda (i) (add-to-list 'web-mode-engine-file-regexps i))
          '(("jsp" . "\\.tagf?\\'")
            ("jsp" . "\\.jspf?\\'")))
  (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.php\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.jspf?\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("/WEB-INF/tags/.*\\.tagf?\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)) )

(face-spec-set 'web-mode-html-tag-face
               '((((class color) (min-colors 16)) :foreground "blue")
                 (((type tty) (class mono)) :inverse-video t)))
(face-spec-set 'web-mode-html-tag-custom-face
               '((((class color) (min-colors 16)) :foreground "red")
                 (((type tty) (class mono)) :inverse-video t)))
(face-spec-set 'web-mode-html-tag-custom-face
               '((((class color) (min-colors 16)) :foreground "red")
                 (((type tty) (class mono)) :inverse-video t)))
(face-spec-set 'web-mode-html-tag-bracket-face
               '((((background dark)) . (:foreground "white"))
                 (((background light)) . (:foreground "black"))))
(copy-face 'font-lock-variable-name-face 'web-mode-html-attr-name-face)
(copy-face 'web-mode-html-tag-bracket-face 'web-mode-html-attr-equal-face)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "sgml")

(cl-eval-when (compile) (require 'sgml-mode))

(setq sgml-basic-offset 4)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "psgml")

(cl-eval-when (compile) (require 'psgml nil t))

(defvar my-html-template
      '("html"
        (nil
         "\n<head>" \n
         "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" (read-string "Charset: ") "\">" \n
         "<title>" (setq str (read-string "Title: ")) "</title>\n"
         "</head>\n"
         "<body>\n<h1>" str "</h1>"
         "\n<address>" \n
         "<a href=\"mailto:" user-mail-address "\">" (user-full-name) "</a>" \n
         "</address>" \n
         "</body>\n"
         )))

(my--eval-after-load sgml-mode
  (unless (featurep 'psgml)
    (setq html-tag-alist
          (cons
           my-html-template
           (my-filter
            (lambda (item) (not (equal (car item) "html")))
            html-tag-alist)))
    (add-to-list 'html-tag-alist '("script" (\n) ("type" "text/javascript") ))
    (add-to-list 'html-tag-alist '("style" (\n) ("type" "text/css") )) ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "jsp")

(defvar jsp-font-lock-syntactic-keywords
  '(("\\(<\\)%--" (1 "< b"))
    ("--%\\(>\\)" (1 "> b"))))

(define-derived-mode jsp-mode html-mode "JSP"
  "JSP editing mode. Redefine HTML comment syntax to JSP."
  (setq comment-start "<%--")
  (setq comment-end "--%>")
  (setq comment-start-skip "<[!%]--[ \t]*")
  (setq comment-end-skip "[ \t]*--[% \t\n]*>")
  (setcdr (assoc 'font-lock-syntactic-keywords font-lock-defaults) 'jsp-font-lock-syntactic-keywords) )

(unless (featurep 'web-mode)
  (add-to-list 'auto-mode-alist '("\\.jspf?\\'" . jsp-mode)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "emmet")

(cl-eval-when (compile) (require 'emmet-mode nil t))

(when (featurep 'emmet-mode)
  (add-hook 'sgml-mode-hook 'emmet-mode))

(when (featurep 'web-mode)
  (add-hook 'web-mode-hook 'emmet-mode))

(setq emmet-move-cursor-between-quotes t)
(setq emmet-move-cursor-after-expanding t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "sh, bash")

(cl-eval-when (compile) (require 'sh-script))

(setq sh-basic-offset 2)

(add-to-list 'auto-mode-alist '("\\.cygport\\'" . shell-script-mode))

(defun my-sh-company-setup ()
  (setq-local company-backends '((company-capf company-files company-dabbrev-code)))
  (setq-local company-dabbrev-code-other-buffers t)
  (company-mode 1))

(when (featurep 'company)
  (add-hook 'sh-mode-hook #'my-sh-company-setup))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "pg, Proof General")

(cl-eval-when (compile) (require 'proof nil t))

(setq proof-splash-enable nil)
;; (setq proof-toolbar-enable nil)

(setq
 isar-display:show-types t
 isar-display:show-sorts t
 isar-display:show-main-goal t
 isar-display:show-brackets t
 ;; Too many output, so commented:
 ;; isar-display:show-consts t
 )

(my--eval-after-load proof
  ;; (proof-maths-menu-toggle 1)
  ;; (unicode-tokens-mode 1)
  ;; (proof-imenu-toggle 1)
  )
(my--eval-after-load isar
  (define-key isar-mode-map (kbd "C-c C-m") 'proof-goto-point))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "printing")

(setq ps-paper-type 'a4)

;; Use Notepad to print plain text files to the default Windows printer
;(setq lpr-command "notepad")
;(setq lpr-headers-switches '("/p"))    ; \ mis-use these
;(setq lpr-switches nil)                ; / two variables
;(setq printer-name nil)        ; notepad takes the default
;(setq lpr-printer-switch "/P") ;; run notepad as batch printer
;;

;; Printing to file.

;(setq printer-name "~/myprint.txt")
;(setq ps-printer-name nil)
;(setq ps-print-header nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "SQL")

(cl-eval-when (compile) (require 'sql))

(setq sql-password "")
(add-to-list 'auto-mode-alist '("\\.plsql\\'" . sql-mode))

;; Disable placeholders substitution in Oracle SQLi by Emacs itself.
;; This enable "define" and "&var" syntax.
(setq sql-oracle-scan-on nil)

(add-hook 'sql-interactive-mode-hook (lambda () (toggle-truncate-lines 1)))

(defun my-sql-explain-paragraph ()
  "Send the current paragraph to the SQL process with \"explain \" keyword.
Works at least for MySql/MariaDB."
  (interactive)
  (let ((start (save-excursion
                 (backward-paragraph)
                 (point)))
        (end (save-excursion
               (forward-paragraph)
               (point))))
    (sql-send-string (concat "explain " (buffer-substring-no-properties start end)))))

(my--eval-after-load sql
  (define-key sql-mode-map (kbd "C-c C-e") 'my-sql-explain-paragraph))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "hideshow")

(require 'hideshow)

(defun my-selective-display-toggle ()
  "Better alternative to 'C-x $' using current column as threshold."
  (interactive)
  (set-selective-display
   (unless selective-display
     (1+ (current-column)))))

(defun my-hs-toggle ()
  (interactive)
  (if hs-minor-mode
      (if (condition-case nil
              (hs-toggle-hiding)
            (error t))
          (hs-show-all))
    (my-selective-display-toggle)))

(define-key global-map (kbd "s--") #'my-hs-toggle)

(add-to-list
 'hs-special-modes-alist
 '(nxml-mode
   "<!--\\|<[^/>][^>]*>" "-->\\|</[^/>]+>" "<!--" nxml-forward-element nil))
(add-hook 'nxml-mode-hook #'hs-minor-mode)
;; (setcdr (assoc 'nxml-mode hs-special-modes-alist) (list "<!--\\|<[^/>][^>]*>" "-->\\|</[^/>]+>" "<!--" #'nxml-forward-element nil))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "prettyprint, pp")

(defun my-pp ()
  (interactive)
  (let ( (fname (buffer-file-name)) )
    (cond
     ((eq major-mode 'nxml-mode)
      (my-nxml-pp))
     ((string-match "\\.json\\'" fname)
       (json-pretty-print-buffer)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "desktop")

;; Save and restore my buffers every time.
(require 'desktop)

(setq desktop-base-file-name ".emacs.desktop")
(setq desktop-base-lock-name ".emacs.desktop.lock")
(setq desktop-dirname user-emacs-directory)

(add-to-list 'desktop-path desktop-dirname)
; Lazy loading of buffer significantly reduces startup time!
(setq desktop-restore-eager 1)
(setq desktop-restore-frames nil)
(unless my-profiler-enabled
  (desktop-save-mode 1))
(setq
 desktop-globals-to-save
 (append
  '((file-name-history . 100)
    (compile-history . 100)
    (command-history . 100)
    (extended-command-history . 100)
    (shell-command-history . 100)
    (search-ring . 20)
    (query-replace-history . 100)
    (regexp-history . 100)
    (grep-history . 100)
    (minibuffer-history . 100)
    tags-file-name
    register-alist)
  desktop-globals-to-save))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "User welcome msg")

(add-hook 'emacs-startup-hook
          (lambda ()
            (let ( (mgs-list '("Welcome to emacs, the thermonuclear editor."
                               "You enter to Out Space. Emacs on."
                               "Nice day for Emacsing!")) )
              (message (nth (random (length mgs-list)) mgs-list)))))

(switch-to-buffer "*Messages*")
(setq default-directory "~/")
(switch-to-buffer "*scratch*")
(setq default-directory "~/")

;;; End loading...

;; Local variables:
;; mode: outline-minor
;; outline-regexp: "(message \""
;; End: