Files
Tools/config/home/emacs.d/init.el

2573 lines
88 KiB
EmacsLisp
Executable File

;;;; ~/.Emacs.d/init.el
;;;;
;;;; emacs configuration
;;;; br, 2010-2024
;;;;
;;;; all personal variables/defun are prefixed with "my/".
;;
;;
;; TODO
;; paredit: see https://takeokunn.github.io/.emacs.d/
;;
;;; Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; packages/directories setup
(require 'package)
;; (require 'use-package)
(package-initialize)
(setq use-package-always-ensure t)
;; (setq package-check-signature nil)
(use-package delight :ensure t)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
;;(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))
;;(add-to-list 'package-archives '("ox-odt" . "https://kjambunathan.github.io/elpa/"))
;; set package directory & recompile lisp files in user-emacs-directory
(add-to-list 'load-path (concat user-emacs-directory "lisp/"))
(add-to-list 'load-path "~/data/private/")
;; (byte-recompile-directory user-emacs-directory 0 t)
;; need to check
;;(require 'prog-mode)
;; store backup and auto-saved buffers (file~ and .#file#) in ~/tmp/emacs
(defconst my/emacs-tmpdir "~/tmp/emacs"
"Directory where to store all temp and backup files.")
(setq backup-directory (concat my/emacs-tmpdir "/backups/")
save-directory (concat my/emacs-tmpdir "/autosave/")
auto-save-list-file-prefix (concat my/emacs-tmpdir "/autosave-list/"))
;; create dirs if necessary
(dolist (dir (list backup-directory save-directory auto-save-list-file-prefix))
(if (not (file-exists-p dir))
(make-directory dir t)))
;; backup settings
(setq backup-directory-alist `(("." . ,backup-directory))
make-backup-file t ; make backup when first saving
delete-old-versions t ; removes old versions silently
kept-old-versions 10 ; how many to keep (oldest)
kept-new-versions 10 ; how many to keep (newest)
backup-by-copying 1 ; to avoid link issues, backups are copied
version-control t ; numbered backups
)
;; auto-save settings
(setq auto-save-file-name-transforms `((".*" ,save-directory t))
auto-save-timeout 60 ; seconds idle before auto-save
auto-save-interval 200 ; keystrokes between auto-saves
)
;; backup tramp files locally
(add-to-list 'backup-directory-alist
(cons tramp-file-name-regexp backup-directory))
;; disable lockfiles
(setq create-lockfiles nil)
;; external editing in firefox
(require 'atomic-chrome)
(atomic-chrome-start-server)
;; *scratch* & *Messages* are immortal
(add-hook 'kill-buffer-query-functions
(lambda () (not (member (buffer-name)
'("*scratch*" "*Messages*")))))
;; allow remembering risky variables
(defun risky-local-variable-p (sym &optional _ignored) "Zoba SYM." nil)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; swap modifier keysyms (japanese keyboard)
;; Done in .xmodmap
;;
;; windows key (super) becomes hyper
;;(setq x-super-keysym 'hyper)
;; alt key (meta) becomes super
;;(setq x-meta-keysym 'super)
;; muhenkan key (hyper) becomes meta
;;(setq x-hyper-keysym 'meta)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; crontabs handling
;; The idea: copy crontab entries to temp buffer, and
;; send back current buffer to "crontab"
(defun my/edit-root-crontab ()
"Edit root crontab."
(interactive)
(with-editor-async-shell-command "crontab -e"))
(defvar my/crontabs-dir
(concat my/emacs-tmpdir "/crontabs/" (number-to-string (user-uid)))
"The directory in which to place the crontabs.")
;;(format "%s/emacs-cron" (or (getenv "TMPDIR") "/tmp") (user-uid)))
(defun my/edit-crontab ()
"Edit current user crontab."
(interactive)
(setq cronBuf (get-buffer "br-crontab"))
(when (not
(and cronBuf
(buffer-live-p cronBuf)))
;;(not cronBuf)
;;()
(message "creating br-crontab")
(setq cronBuf (get-buffer-create "br-crontab"))
(set-buffer cronBuf)
(crontab-mode)
(insert (shell-command-to-string "crontab -l"))
(set-buffer-modified-p nil)
(goto-char (point-min)))
(pop-to-buffer-same-window cronBuf))
(defun my/crontab-e ()
"Run `crontab -e' in an Emacs buffer. Use 'kill-buffer' on crontab window to validate."
(interactive)
(with-editor-async-shell-command "crontab -e"))
(defun my/root-crontab-e ()
"Run `crontab -e -u root' in an Emacs buffer. Use 'kill-buffer' on crontab window to validate."
(interactive)
(with-editor-async-shell-command "sudo -E crontab -e -u root"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; lisp tools
(defun my/append-to-list (list-var elements)
"Append ELEMENTS to the end of LIST-VAR. Return new LIST-VAR value."
(unless (consp elements)
(error "ELEMENTS must be a list"))
(let ((list (symbol-value list-var)))
(if list
(setcdr (last list) elements)
(set list-var elements)))
(symbol-value list-var))
(defun my/add-to-list (list-var elements &optional uniq)
"Add ELEMENTS to the beginning LIST-VAR, remove duplicates if UNIQ is true.
Return new LIST-VAR value."
(unless (consp elements)
(error "ELEMENTS must be a list"))
(set list-var (append elements (symbol-value list-var)))
(and uniq
(delete-dups (symbol-value list-var)))
(symbol-value list-var))
;; don't remember what it was about. Saturday night wine idea ?
(defun my/str-replace-all (str alist)
"Given an ALIST of the form '((a1 . a2)(b1 . b2)), will return a1 or b1 if STR equals a2 or b2."
(if (null alist)
str
(let* ((elem (car alist))
(lhs (car elem))
(rhs (cdr elem)))
;;(message str)
;;(message lhs)
;;(message rhs)
;;(message "+++++++")
(replace-regexp-in-string rhs lhs (my/str-replace-all str (cdr alist))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; buffer names
;; shorten tramp sudo
;;(my/add-to-list
;; 'directory-abbrev-alist
;; '(("^root:/" . "/ssh:arwen:/home/br/www/cf.bodi/seven/")
;; ("arwen:rebels:/" . "/ssh:arwen:/home/br/www/cf.bodi/rebels21/")
;; ("arwen:strats:/" . "/ssh:arwen:/home/br/www/cf.bodi/strat-dom/")))
;; Buffer name in status bar
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward ; display finename as dir1/dir2/file
uniquify-min-dir-content 0 ; minimum # of dirs in name
uniquify-strip-common-suffix t ; strip dirs suffixes if conflict
)
;; set main frame title
(set-frame-name "GNU Emacs")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ibuffer -- NOT USED: Using Helm
(defun my/ibuffer-hook ()
"br ibuffer-hook."
(interactive)
(ibuffer-tramp-set-filter-groups-by-tramp-connection)
(ibuffer-do-sort-by-alphabetic))
(define-ibuffer-column dirname
(:name "Directory"
:inline nil)
(message (buffer-file-name buffer))
(if (buffer-file-name buffer)
(my/str-replace-all
(file-name-directory
(buffer-file-name buffer))
directory-abbrev-alist)
(or dired-directory
"")))
;; (global-set-key (kbd "C-x C-b") 'ibuffer)
;; (global-set-key (kbd "C-x b") 'ibuffer)
;; original value
;; (setq ibuffer-formats
;; '((mark modified read-only " "
;; (name 18 18 :left :elide)
;; " "
;; (size 9 -1 :right)
;; " "
;; (mode 16 16 :left :elide)
;; " " filename-and-process)
;; (mark " "
;; (name 16 -1)
;; " " filename)))
(setq ibuffer-formats
'((mark modified " "
(name 18 18 :right :elide)
" "
(size 9 -1 :right)
" "
(mode 16 16 :left :elide)
" " filename-and-process)
(mark " "
(name 16 -1)
" " filename
)
(mark modified read-only " "
(name 30 30 :left :elide)
" "
(size 9 -1 :right)
" " dirname)
))
(add-hook 'ibuffer-hook 'my/ibuffer-hook)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; package auto update
(use-package auto-package-update
:if (not (daemonp))
:custom
(auto-package-update-interval 7) ; in days
(auto-package-update-prompt-before-update t)
(auto-package-update-delete-old-versions t)
(auto-package-update-hide-results t)
:config
(auto-package-update-maybe))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; command-log-mode
;;(use-package command-log-mode
;; :straight t
;; :defer t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ggtags
(use-package ggtags
:ensure t
:diminish "gg"
:disabled t
;; :defer t
:after cc-mode
:init
(setq ggtags-global-window-height 28
ggtags-enable-navigation-keys nil)
(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
(ggtags-mode 1))))
;;(after cc-mode (add-hook 'c-mode-common-hook #'ggtags-mode))
:config
(bind-keys :map ggtags-mode-map
;;("C-c g s" . ggtags-find-other-symbol)
;;("C-c g h" . ggtags-view-tag-history)
;;("C-c g r" . ggtags-find-reference)
;;("C-c g f" . ggtags-find-file)
;;("C-c g c" . ggtags-create-tags)
;;("C-c g u" . ggtags-update-tags)
("H-g s" . ggtags-find-other-symbol)
("H-g h" . ggtags-view-tag-history)
("H-g r" . ggtags-find-reference)
("H-g f" . ggtags-find-file)
("H-g c" . ggtags-create-tags)
("H-g u" . ggtags-update-tags)
("M-," 'pop-tag-mark)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; projectile
;; default config from developer
(use-package projectile
;;:diminish projectile-mode
:diminish " prj"
;; :delight
:ensure t
:config
;;(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
;;(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(setq projectile-enable-caching t
;;projectile-indexing-method 'alien ;; does not use ".projectile"
projectile-indexing-method 'hybrid
;;projectile-indexing-method 'native
projectile-completion-system 'auto
projectile-tags-backend 'ggtags)
(add-to-list 'projectile-globally-ignored-files "*.png")
(projectile-mode +1))
;; (add-to-list 'projectile-globally-ignored-files "node-modules")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; git
;; (use-package forge
;; :after magit)
(use-package magit
:ensure t
:config
(setq magit-delete-by-moving-to-trash nil
magit-clone-default-directory "~/dev/")
(magit-auto-revert-mode -1)
:bind
(("C-c g" . magit-file-dispatch)
("C-x g" . magit-status)))
(use-package git-gutter
:diminish
:config
(global-git-gutter-mode +1))
;; (use-package magithub
;; :after magit
;; ;;:ensure t
;; :config
;; (progn
;; (magithub-feature-autoinject t)
;; ;; (magithub-feature-autoinject '(commit-browse completion))
;; (setq
;; magithub-clone-default-directory "~/dev")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; delight
(use-package autorevert
:delight auto-revert-mode)
(use-package whole-line-or-region
:delight whole-line-or-region-local-mode)
;;(use-package abbrev
;; :delight abbrev-mode)
(use-package emacs
:delight
;; (auto-fill-function " AF")
(auto-fill-function)
(abbrev-mode)
(visual-line-mode))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; tramp
(setq tramp-default-method "ssh" ; faster than default scp
enable-remote-dir-locals t
tramp-verbose 1)
;; (customize-set-variable 'tramp-syntax 'simplified)
;; Emacs 29.1 ?
;;(autoload #'tramp-register-crypt-file-name-handler "tramp-crypt")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; conf mode
;; strangely ".cnf" is not here...
(use-package conf-mode
:hook
(conf-mode . my/conf-mode-hook)
:mode
(("\\.cnf\\'" . conf-mode)
("/auto\\." . conf-mode))
:config
(defun my/conf-mode-hook ()
(message "calling my/conf-mode-hook")
(setq-local comment-column 50)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ssh config
(use-package ssh-config-mode
:ensure t
:init
(autoload 'ssh-config-mode "ssh-config-mode" t)
:mode
(("/\\.ssh/config\\'" . ssh-config-mode)
("/sshd?_config\\'" . ssh-config-mode)
("/known_hosts\\'" . ssh-known-hosts-mode)
("/authorized_keys2?\\'" . ssh-authorized-keys-mode))
:hook
(ssh-config-mode . turn-on-font-lock))
;; (autoload 'ssh-config-mode "ssh-config-mode" t)
;; (add-to-list 'auto-mode-alist
;; '("/\\.ssh/config\\'" . ssh-config-mode))
;; (add-to-list 'auto-mode-alist
;; '("/sshd?_config\\'" . ssh-config-mode))
;; (add-to-list 'auto-mode-alist
;; '("/knownhosts\\'" . ssh-known-hosts-mode))
;; (add-to-list 'auto-mode-alist
;; '("/authorized_keys2?\\'" . ssh-authorized-keys-mode))
;; (add-hook 'ssh-config-mode-hook 'turn-on-font-lock)
;; following does not work
;;(set-default 'tramp-default-proxies-alist
;; '("arwen" "root" "/ssh:arwen:"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; which-key
(use-package which-key
:diminish which-key-mode
:init
(which-key-mode)
:config
(which-key-setup-side-window-right-bottom)
(setq which-key-sort-order 'which-key-key-order-alpha
which-key-side-window-max-width 0.33
which-key-idle-delay 1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; flycheck
(use-package flycheck
:ensure t
:init
(require 'projectile)
(global-flycheck-mode)
:config
(setq-default flycheck-sh-bash-args '("-O" "extglob")
flycheck-disabled-checkers '(c/c++-clang c/c++-cppcheck c/c++-gcc))
;;(flycheck-add-mode 'sh-shellcheck 'bats-mode)
:bind
(("H-n" . flycheck-next-error)
("H-p" . flycheck-previous-error)
("H-l" . flycheck-list-errors)
("M-n" . flycheck-next-error)
("M-p" . flycheck-previous-error)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; subversion
;;(require 'psvn)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Japanese/iBus: works out of the box now
;; ibus-mode
;;(require 'ibus)
;; Turn on ibus-mode automatically after loading .emacs
;;(add-hook 'after-init-hook 'ibus-mode-on)
;; Use C-SPC for Set Mark command
;;(ibus-define-common-key ?\C-\s nil)
;; Use C-/ for Undo command
;;(ibus-define-common-key ?\C-/ nil)
;; Change cursor color depending on IBus status
;;(setq ibus-cursor-color '("red" "blue" "limegreen"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Some useful setups
;; mouse
;; does not change point when getting focus - DOES NOT WORK
;; (setq x-mouse-click-focus-ignore-position t)
;;focus-follows-mouse nil ; must reflect WM settings
;;mouse-autoselect-window nil ; pointer does not select window
(global-set-key (kbd "C-h c") 'describe-char)
(global-set-key (kbd "C-x 4 C-b") 'switch-to-buffer-other-window)
(global-unset-key [mode-line mouse-3]) ; disabble annoying modeline mouse-3
;; compilation buffer in different frame
;; https://emacs.stackexchange.com/a/21393/23591
;; (push "*compilation*" special-display-buffer-names)
;; https://emacs.stackexchange.com/a/75534/23591
(add-to-list 'display-buffer-alist
(cons (rx string-start "*compilation*" string-end)
(cons 'display-buffer-reuse-window
'((reusable-frames . visible)
(inhibit-switch-frames . nil)))))
;; next example maps C-x C-x to the same as C-c
;; (global-set-key (kbd "C-x C-x") (lookup-key global-map (kbd "C-c")))
(setq inhibit-splash-screen t ; no spash screen
column-number-mode t ; displays line/column positions
kill-whole-line t ; C-k kills whole line
;; tab indents first, if indented, tries to autocomplete
;; TOO DANGEROUS (it completes without asking!)...
;; tab-always-indent t ; TAB always indent
tab-always-indent 'complete
completions-format 'vertical ; sort completions vertically
;; Removed: Use smartparens instead.
;; show matching brace/paren
;;show-paren-mode t
;; style: parenthesis, expression, mixed
;;show-paren-style 'parenthesis
sentence-end-double-space nil ; who decided sentences should
; end with two spaces ??
;; global-hl-line-sticky-flag t ; highlight line
tab-width 2 ; default tab width
)
(setq-default indent-tabs-mode nil) ; no tabs
(icomplete-mode 0) ; minibuffer completion
; soooo sloooow
;; (global-hl-line-mode) ; line highlight
(delete-selection-mode 1) ; replace region when inserting text
;; fix mess with bidirectional (arabic/hebrew)
(setq-default bidi-display-reordering nil
bidi-paragraph-direction 'left-to-right)
(setq display-time-24hr-format t) ; time format
(display-time-mode 0) ; disable time in the mode-line
(if (< emacs-major-version 29) ; just 'y' or 'n' instead of yes/no
(defalias 'yes-or-no-p 'y-or-n-p)
(setopt use-short-answers t))
(setq duplicate-line-final-position -1) ; point on last new line
(mouse-avoidance-mode 'exile) ; Avoid collision of mouse with point
;;(menu-bar-mode 0) ; Disable the menu bar
;;(put 'downcase-region 'disabled nil) ; Enable downcase-region
;;(put 'upcase-region 'disabled nil) ; Enable upcase-region
;;(global-subword-mode 1) ; Iterate through CamelCase words
;;(fringe-mode 0) ; Disable fringes
(set-default-coding-systems 'utf-8) ; default encoding - obviously utf-8
;; enable recursive minibuffer
(minibuffer-depth-indicate-mode)
(setq enable-recursive-minibuffers t)
;; copy from point to end of line (including '\n')
(defun my/mark-from-point-to-end-of-line ()
"Copy text from point to end of line."
(interactive)
(set-mark (+ (line-end-position) 1))
(kill-ring-save nil nil t))
(global-set-key (kbd "M-k") 'my/mark-from-point-to-end-of-line)
;; (global-set-key (kbd "C-k") 'kill-line)
;; minions: minor modes menu instead of (long) list on modeline
;;(use-package minions
;; :config (minions-mode 1))
;;(defun caadr (a)
;; (car(car(cdr a))))
;;(defun mouse-set-point-2 (event)
;; (interactive "e")
;; (mouse-minibuffer-check event)
;; (let ((event-target-window (caadr event)))
;; (if (eql event-target-window (frame-selected-window))
;; (posn-set-point (event-end event))
;; (set-frame-selected-window nil event-target-window))))
;;
;;(global-set-key [mouse-1] 'mouse-set-point-2)
;;
;;(global-unset-key [down-mouse-1])
;;(defadvice mouse-set-point (around cv/mouse-set-point (event) activate)
;; (let ((event-name (car event))
;; (event-target-window (posn-window (event-start event))))
;; (if (and (eql 'down-mouse-1 event-name)
;; (eql event-target-window (selected-window)))
;; ad-do-it
;; (select-window event-target-window))))
;; (defadvice mouse-drag-region (around cv/mouse-drag-region (event) activate)
;; (let ((event-target-window (posn-window (event-start event))))
;; ; (if (eql event-target-window (selected-window))
;; ; ad-do-it
;; ; (select-window event-target-window))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; local functions
(defun my/indent-whole-buffer ()
"Indent whole buffer. TODO: indent comments."
(interactive)
;; (delete-trailing-whitespace)
;; (untabify (point-min) (point-max))
(indent-region (point-min) (point-max) nil))
(global-set-key (kbd "H-;") 'my/indent-whole-buffer)
(global-set-key (kbd "H-\\") 'my/indent-whole-buffer)
(defvar my/temp-buffer-count 0)
(defun my/make-temp-buffer (&optional mode)
"Create new temporary buffer named '*temp-digit*' with MODE mode (default: text)."
(interactive)
(let ((tmp (format "*temp-%d*" my/temp-buffer-count))
(dir (concat my/emacs-tmpdir "/tmpbufs/")))
(switch-to-buffer tmp)
(cd dir)
(if mode
(mode)
(text-mode))
(message "New temp buffer (%s) created." tmp))
(setq my/temp-buffer-count (1+ my/temp-buffer-count)))
(global-set-key (kbd "C-c t") 'my/make-temp-buffer)
(defun my/write-visit-file ()
"Write current buffer/region to file, and visit it."
(interactive)
(let ((thefile (read-file-name
"Copy/visit file: " nil nil nil)))
(if (use-region-p)
(write-region (region-beginning) (region-end) thefile nil nil nil t)
(save-restriction
(widen)
(write-region (point-min) (point-max) thefile nil nil nil t)))
(find-file-noselect thefile)))
(global-set-key (kbd "C-c w") 'my/write-visit-file)
(defun my/before-save ()
"Remove trailing spaces, remove 'org-mode' results blocks."
(delete-trailing-whitespace)
(when (derived-mode-p 'org-mode)
(org-babel-map-src-blocks nil (org-babel-remove-result))))
(add-hook 'before-save-hook 'my/before-save)
;;(global-set-key (kbd "C-c w") 'my/write-visit-file)
;;; from https://github.com/zilongshanren/prelude/blob/master/core/prelude-core.el
(defun my/delete-buffer-and-file ()
"Kill the current buffer and deletes the file it is visiting."
(interactive)
(let ((filename (buffer-file-name)))
(when filename
(if (vc-backend filename)
(vc-delete-file filename)
(when (y-or-n-p (format "Are you sure you want to delete %s? " filename))
(delete-file filename)
(message "Deleted file %s" filename)
(kill-buffer))))))
(global-set-key (kbd "s-d") 'my/delete-buffer-and-file)
;; from https://pages.sachachua.com/.emacs.d/Sacha.html
(defun my/smarter-move-beginning-of-line (arg)
"Move point back to indentation of beginning of line.
Move point to the first non-whitespace character on this line.
If point is already there, move to the beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.
If ARG is not nil or 1, move forward ARG - 1 lines first. If
point reaches the beginning or end of the buffer, stop there."
(interactive "^p")
(setq arg (or arg 1))
;; Move lines first
(when (/= arg 1)
(let ((line-move-visual nil))
(forward-line (1- arg))))
(let ((orig-point (point)))
(back-to-indentation)
(when (= orig-point (point))
(move-beginning-of-line 1))))
;; remap C-a to `smarter-move-beginning-of-line'
(global-set-key [remap move-beginning-of-line]
'my/smarter-move-beginning-of-line)
;;(defun my/upcase-word()
;; "Upcase current word."
;; (interactive)
;; (save-excursion
;; (let* ((bounds (bounds-of-thing-at-point 'word))
;; (beg (car bounds))
;; (end (cdr bounds)))
;; (upcase-region beg end))))
;; redefine upcase/downcase-word to really do it.
(defun my/upcase-word()
"Upcase current word."
(interactive)
(save-excursion
(beginning-of-thing 'word)
(upcase-word 1)))
(defun my/downcase-word()
"Downcase current word."
(interactive)
(save-excursion
(beginning-of-thing 'word)
(downcase-word 1)))
(global-set-key (kbd "M-u") 'my/upcase-word)
(global-set-key (kbd "M-l") 'my/downcase-word)
(global-set-key (kbd "H-y") 'duplicate-dwim)
;; rewrite comment-kill to avoid filling kill-ring
;; From: https://emacs.stackexchange.com/a/5445/23591
;; https://emacs.stackexchange.com/questions/5441/function-to-delete-all-comments-from-a-buffer-without-moving-them-to-kill-ring
(defun my/comment-delete (arg)
"Delete the first comment on this line, if any. Don't touch the kill ring.
With prefix ARG, delete comments on that many lines starting with this one."
(interactive "P")
(comment-normalize-vars)
(dotimes (_i (prefix-numeric-value arg))
(save-excursion
(beginning-of-line)
(let ((cs (comment-search-forward (line-end-position) t)))
(when cs
(goto-char cs)
(skip-syntax-backward " ")
(setq cs (point))
(comment-forward)
;; (kill-region cs (if (bolp) (1- (point)) (point))) ; original
(delete-region cs (if (bolp) (1- (point)) (point))) ; change to delete-region
(indent-according-to-mode))))
(if arg (forward-line 1))))
(defun my/comment-delete-dwim (beg end arg)
"Delete comments without touching the kill ring.
With active region, delete comments in region. With prefix, delete comments
in whole buffer. With neither, delete comments on current line."
(interactive "r\nP")
(let ((lines (cond (arg
(count-lines (point-min) (point-max)))
((region-active-p)
(count-lines beg end)))))
(save-excursion
(when lines
(goto-char (if arg (point-min) beg)))
(my/comment-delete (or lines 1)))))
;; kill remove all consecutive blank lines (keep one only).
(defun my/single-blank-lines ()
"Keep only one blank lines in buffer, keep one when multiple ones."
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\\(^[[:space:]\n]+\\)\n" nil t)
(replace-match "\n"))))
(defun my/collapse-blank-lines (beg end)
"Delete all consecutive `blank' lines in region or buffer, keeping one only."
(interactive "r")
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\\(^[[:space:]\n]+\\)\n" nil t)
(replace-match "\n"))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; multiple cursors
(use-package multiple-cursors
:bind
(("C-c m t" . mc/mark-all-like-this)
("C-c m m" . mc/mark-all-like-this-dwim)
("C-c m l" . mc/edit-lines)
("C-c m e" . mc/edit-ends-of-lines)
("C-c m a" . mc/edit-beginnings-of-lines)
("C-c m n" . mc/mark-next-like-this)
("C-c m p" . mc/mark-previous-like-this)
("C-c m s" . mc/mark-sgml-tag-pair)
("C-c m d" . mc/mark-all-like-this-in-defun)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-S-<mouse-1>" . mc/add-cursor-on-click)
("C-M-m" . mc/mark-all-dwim)))
(use-package phi-search)
(use-package phi-search-mc :config (phi-search-mc/setup-keys))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; shell, eshell modes
;; will tell e-shell to run in visual mode
'(eshell-visual-commands
(quote
("vi" "screen" "top" "less" "more")))
;; ignore duplicate input in shell-mode
(use-package shell
:config
(progn
(setq comint-input-ignoredups t)))
;; https://www.emacswiki.org/emacs/SwitchingBuffers
(defun my/switch-buffers ()
"Switch the buffers between the two last frames."
(interactive)
(let ((this-frame-buffer nil)
(other-frame-buffer nil))
(setq this-frame-buffer (car (frame-parameter nil 'buffer-list)))
(other-frame 1)
(setq other-frame-buffer (car (frame-parameter nil 'buffer-list)))
(switch-to-buffer this-frame-buffer)
(other-frame 1)
(switch-to-buffer other-frame-buffer)))
(defun my/switch-upper-window ()
"Switch main window and upper one."
(interactive)
(window-swap-states my/main-window my/upper-window))
(defun my/switch-lower-window ()
"Switch main window and lower one."
(interactive)
(window-swap-states my/main-window my/below-window))
(global-set-key (kbd "C-c u") 'my/switch-upper-window)
(global-set-key (kbd "C-c l") 'my/switch-lower-window)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; recent files
(require 'recentf)
(setq recentf-max-saved-items 20
recentf-max-menu-items 10)
(recentf-mode)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; vc-mode modeline
;; inspired from:
;; https://emacs.stackexchange.com/questions/10955
(advice-add #'vc-git-mode-line-string :filter-return #'my/replace-git-status)
(defun my/replace-git-status (tstr)
"Replace git `variable:vc-mode' string with a UTF8 symbol followed by TSTR."
(let* ((tstr (replace-regexp-in-string "Git" "" tstr))
(first-char (substring tstr 0 1))
(rest-chars (substring tstr 1)))
(cond
((string= ":" first-char) ; Modified
(replace-regexp-in-string "^:" "" tstr))
((string= "-" first-char) ; No change
(replace-regexp-in-string "^-" "" tstr))
((string= "@" first-char) ; Added
(replace-regexp-in-string "^@" "" tstr))
(t tstr))))
(setf mode-line-modes
(mapcar (lambda (item)
(if (and (listp item)
(eq :propertize (car item))
(listp (cdr item))
(string= "" (car (cadr item)))
(eq 'mode-name (cadr (cadr item))))
(cl-list* (car item)
'(:eval (if (eq 'sh-mode major-mode)
'("" sh-shell)
'("" mode-name)))
(cddr item))
item))
mode-line-modes))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hippie
;; (setq hippie-expand-try-functions-list
;; '(yas-hippie-try-expand
;; try-expand-all-abbrevs
;; try-complete-file-name-partially
;; try-complete-file-name
;; try-expand-dabbrev
;; try-expand-dabbrev-from-kill
;; try-expand-dabbrev-all-buffers
;; try-expand-list
;; try-expand-line
;; try-complete-lisp-symbol-partially
;; try-complete-lisp-symbol))
;; (use-package yasnippet
;; :diminish yas-minor-mode
;; :init (yas-global-mode)
;; :config
;; (progn
;; (yas-global-mode)
;; (add-hook 'hippie-expand-try-functions-list 'yas-hippie-try-expand)
;; (setq yas-key-syntaxes '("w_" "w_." "^ "))
;; ;;(setq yas-installed-snippets-dir (concat user-emacs-directory "yassnippet"))
;; (setq yas-expand-only-for-last-commands nil)
;; (yas-global-mode 1)
;; (bind-key "\t" 'hippie-expand yas-minor-mode-map)
;; (add-to-list 'yas-prompt-functions 'shk-yas/helm-prompt)))
;; (use-package yasnippet-snippets
;; :after (yasnippet)
;; :defer t
;; :config
;; (yas-global-mode 1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; key Bindings
(global-set-key (kbd "<C-M-tab>") 'my/indent-whole-buffer)
;;(global-set-key (kbd "C-a") 'back-to-indentation)
;; https://github.com/technomancy/better-defaults/blob/master/better-defaults.el#L78
(global-set-key (kbd "M-/") 'hippie-expand)
(global-set-key (kbd "M-z") 'zap-up-to-char)
(global-set-key (kbd "C-s") 'isearch-forward-regexp)
(global-set-key (kbd "C-r") 'isearch-backward-regexp)
;; (global-set-key (kbd "C-M-s") 'isearch-forward) ; conflict with org
;; (global-set-key (kbd "C-M-r") 'isearch-backward)
;; goto-line/goto-char
;; (global-set-key (kbd "C-c g") 'goto-line)
;; (global-set-key (kbd "C-c c") 'goto-char)
(global-set-key (kbd "s-g g") 'goto-line)
(global-set-key (kbd "s-g c") 'goto-char)
(global-set-key (kbd "s-g s-g") 'goto-line)
(global-set-key (kbd "s-g s-c") 'goto-char)
(global-set-key (kbd "C-x w") 'compare-windows)
;; as dot-mode uses <insert>, we allow overwrite-mode with S-<insert>
(global-set-key (kbd "S-<insert>") 'overwrite-mode)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; define my own keymap (s-c)
;; first, define a keymap, with Super-c as prefix.
;; (defvar my/keys-mode-map (make-sparse-keymap)
;; "Keymap for my/keys-mode.")
;; (defvar my/keys-mode-prefix-map (lookup-key global-map (kbd "s-c"))
;; "Keymap for custom key bindings starting with s-c prefix.")
;; ;; (define-key my/keys-mode-map (kbd "s-c") my/keys-mode-prefix-map)
;; (define-minor-mode my/keys-mode
;; "A minor mode for custom key bindings."
;; :lighter "s-c"
;; :keymap 'my/keys-mode-map
;; :global t)
;; (defun my/prioritize-keys
;; (file &optional noerror nomessage nosuffix must-suffix)
;; "Try to ensure that custom key bindings always have priority."
;; (unless (eq (caar minor-mode-map-alist) 'my/keys-mode)
;; (let ((my/keys-mode-map (assq 'my/keys-mode minor-mode-map-alist)))
;; (assq-delete-all 'my/keys-mode minor-mode-map-alist)
;; (add-to-list 'minor-mode-map-alist my/keys-mode-map))))
;; (advice-add 'load :after #'my/prioritize-keys)
;;(global-set-key (kbd "C-c t") #'make-temp-buffer)
;;(define-key my/keys-mode-prefix-map (kbd "r b") #'revert-buffer)
;;(define-key my/keys-mode-prefix-map (kbd "r b") 'revert-buffer)
;;(define-key ctl-x-map ";" 'indent-region)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; helm
;; Partially from http://pages.sachachua.com/.emacs.d/Sacha.html#org480d137
;; and http://tuhdo.github.io/helm-intro.html
(use-package helm
:diminish helm-mode
:init
;;(progn
;; (require 'helm-config)
;; (require 'helm-autoloads)
(require 'pcomplete)
(require 'helm-projectile)
;; (require 'tramp)
(setq
helm-candidate-number-limit 100
;; From https://gist.github.com/antifuchs/9238468
helm-split-window-inside-p t ; open helm buffer in current window
helm-idle-delay 0.0 ; update fast sources immediately (doesn't).
helm-input-idle-delay 0.01 ; this actually updates things
; reeeelatively quickly.
helm-yas-display-key-on-candidate t
helm-quick-update t
helm-M-x-requires-pattern nil
helm-ff-skip-boring-files t
helm-ff-guess-fap-urls nil ; do not use ffap for URL at point
helm-projectile-fuzzy-match nil
helm-buffers-truncate-lines nil ; truncate lines in buffers list
helm-buffer-max-length nil ; buffer name length is longest one
helm-prevent-escaping-from-minibuffer nil ; allow escaping from minibuffer (C-o)
helm-scroll-amount 8 ; scroll 8 lines other window M-<NEXT>
helm-ff-file-name-history-use-recentf t
helm-move-to-line-cycle-in-source nil
;; helm-ff-auto-update-initial-value nil
helm-echo-input-in-header-line t) ; ??
;;)
(helm-mode)
(helm-projectile-on)
;;)
:bind
(("C-c h" . helm-mini)
("C-h a" . helm-apropos)
("C-x C-b" . helm-buffers-list)
("C-x C-f" . helm-find-files)
("C-x b" . helm-buffers-list)
("M-y" . helm-show-kill-ring)
("M-x" . helm-M-x)
("C-x c o" . helm-occur)
("C-x c s" . helm-swoop)
("C-x c y" . helm-yas-complete)
("C-x c Y" . helm-yas-create-snippet-on-region)
;;("C-x c b" . my/helm-do-grep-book-notes)
("C-x c SPC" . helm-all-mark-rings)
:map helm-map
;; rebind tab/C-i to run persistent action
("<tab>" . helm-execute-persistent-action)
("C-i" . helm-execute-persistent-action) ; make TAB works in terminal
("C-z" . helm-select-action) ; list actions using C-z
)
;;("<left>" . helm-previous-source)
;;("<right>" . helm-next-source)
;;:map helm-imenu-map
;;("<left>" . helm-previous-source)
;;("<right>" . helm-next-source)
;;:map helm-find-files-map
;;("<left>" . helm-previous-source)
;;("<right>" . helm-next-source))
:bind*
(:map helm-find-files-map
("<left>" . helm-previous-source)
("<right>" . helm-next-source)))
(use-package helm-swoop
:bind
(("M-i" . helm-swoop)
("M-I" . helm-swoop-back-to-last-point)
("C-c M-i" . helm-multi-swoop)
("C-x M-i" . helm-multi-swoop-all)
)
:config
(progn
(define-key isearch-mode-map (kbd "M-i") 'helm-swoop-from-isearch)
(define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop)))
(use-package helm-flycheck
:requires (helm))
;; Turn off ido mode in case I enabled it accidentally
;; (ido-mode -1)
;; helm will be used to describe bindings
(use-package helm-descbinds
:defer t
:bind (("C-h b" . helm-descbinds)
("C-h w" . helm-descbinds)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; wc-mode
;;(require 'wc-mode)
;;(global-set-key (kbd "C-c C-w") 'wc-mode)
;;(setq wc-modeline-format "WC[%C/%tc]")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; kill/copy line if no region
(use-package whole-line-or-region
:delight whole-line-or-region-local-mode
;;:diminish whole-line-or-region-local-mode
:commands
(whole-line-or-region-global-mode)
:init
(whole-line-or-region-global-mode 1)
;; remove comment remaps
(define-key whole-line-or-region-local-mode-map [remap comment-dwim] nil)
(define-key whole-line-or-region-local-mode-map [remap comment-region] nil)
(define-key whole-line-or-region-local-mode-map [remap uncomment-region] nil)
:config
;;(whole-line-or-region-global-mode 1)
;; remove comment remaps
;;(define-key whole-line-or-region-local-mode-map [remap comment-dwim] nil)
;;(define-key whole-line-or-region-local-mode-map [remap comment-region] nil)
;;(define-key whole-line-or-region-local-mode-map [remap uncomment-region] nil)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; vundo / undo-tree / winner
;; vundo config from :
;; https://www.reddit.com/r/emacs/comments/txwwfi/vundo_is_great_visual_undotree_for_emacs28/
(use-package vundo
:commands (vundo)
:config
;; Take less on-screen space.
(setq vundo-compact-display t)
;; Better contrasting highlight.
(custom-set-faces
'(vundo-node ((t (:foreground "#808080"))))
'(vundo-stem ((t (:foreground "#808080"))))
'(vundo-highlight ((t (:foreground "#FFFF00")))))
;; Use `HJKL` VIM-like motion, also Home/End to jump around.
;; (define-key vundo-mode-map (kbd "l") #'vundo-forward)
(define-key vundo-mode-map (kbd "<right>") #'vundo-forward)
;; (define-key vundo-mode-map (kbd "h") #'vundo-backward)
(define-key vundo-mode-map (kbd "<left>") #'vundo-backward)
;; (define-key vundo-mode-map (kbd "j") #'vundo-next)
(define-key vundo-mode-map (kbd "<down>") #'vundo-next)
;; (define-key vundo-mode-map (kbd "k") #'vundo-previous)
(define-key vundo-mode-map (kbd "<up>") #'vundo-previous)
(define-key vundo-mode-map (kbd "<home>") #'vundo-stem-root)
(define-key vundo-mode-map (kbd "<end>") #'vundo-stem-end)
(define-key vundo-mode-map (kbd "q") #'vundo-confirm)
(define-key vundo-mode-map (kbd "C-g") #'vundo-quit)
(define-key vundo-mode-map (kbd "RET") #'vundo-confirm))
(global-set-key (kbd "C-x u") 'vundo)
;; (use-package undo-tree
;; :diminish undo-tree-mode
;; :defer t
;; :init
;; (progn
;; (defalias 'redo 'undo-tree-redo)
;; (defalias 'undo 'undo-tree-undo)
;; (global-undo-tree-mode 1))
;; :config
;; (progn
;; (setq undo-tree-visualizer-timestamps t
;; undo-tree-visualizer-diff t
;; undo-tree-enable-undo-in-region t
;; ;;undo-tree-auto-save-history t
;; )
;; (let ((undo-dir (concat my/emacs-tmpdir "/undo-tree/")))
;; (setq undo-tree-history-directory-alist
;; `(("." . ,undo-dir)))
;; (unless (file-exists-p undo-dir)
;; (make-directory undo-dir t)))))
;; useful to come back to working window after a buffer has popped up
;; C-c <left> to come back
(use-package winner
:init (winner-mode 1))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; windows navigation
(use-package windmove
:bind (("H-<right>" . windmove-right)
("H-<left>" . windmove-left)
("H-<up>" . windmove-up)
("H-<down>" . windmove-down)
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; auto completion
(use-package company
:diminish "Co"
:defer t
:bind
(:map company-active-map
("RET" . nil)
;; ([return] . nil)
("TAB" . company-complete-selection)
;; ([tab] . company-complete-selection)
;;("<right>" . company-complete-common)
)
:config
;; Too slow !
;; (global-company-mode 1)
(setq-default
company-idle-delay .2
company-minimum-prefix-length 3
company-require-match nil
company-tooltip-align-annotations t)
:hook
(('prog-mode . 'company-mode)))
;;(add-to-list 'company-backends 'company-shell)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dot-mode (vi-like redo)
;; repo: https://github.com/wyrickre/dot-mode
(use-package dot-mode
:diminish
:bind (("<insert>" . dot-mode-execute)
("C-M-<insert>" . dot-mode-override) ; store next keystroke
("C-c <insert>" . dot-mode-copy-to-last-kbd-macro)
("C-." . dot-mode-execute) ; default bindings below
("C-M-." . dot-mode-override)
("C-c ." . dot-mode-copy-to-last-kbd-macro))
:init
(global-dot-mode 1) ; enabled in all buffers
(setq dot-mode-verbose nil
dot-mode-ignore-undo t ; don't consider undos
dot-mode-global-mode t)) ; can redo in different buffer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; change copy/kill region
;; from sacha
(defadvice kill-region (before slick-cut activate compile)
"When called interactively with no active region, kill a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; browse-url / webpaste (pastebin)
(use-package browse-url
:ensure t
:defer t
:bind (( "C-c b" . browse-url )))
(use-package webpaste
:ensure t
:bind (("C-c P b" . webpaste-paste-buffer)
("C-c P r" . webpaste-paste-region))
:hook (webpaste-return-url . my/webpaste-return-url-hook)
:config
(progn
(setq webpaste-provider-priority '("dpaste.org" "gist.github.com" "paste.mozilla.org"
"dpaste.org" "ix.io")
webpaste-paste-confirmation t ; prompts before sending
;; nothing below: We do in webpaste-return-url hook
webpaste-open-in-browser nil ; do not open in browser
webpaste-add-to-killring nil ; do not add url to killring
webpaste-paste-raw-text nil ; try to detect language
))
(defun my/webpaste-return-url-hook (url)
(message "Webpaste: %S" url)
(browse-url-xdg-open url)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; markdown mode
;; https://github.com/jrblevin/markdown-mode/issues/578
(setq native-comp-deferred-compilation-deny-list '("markdown-mode\\.el$"))
;; inspired from: https://github.com/zaeph/.emacs.d/blob/master/init.el
;; doc: https://leanpub.com/markdown-mode/read
(use-package markdown-mode
:ensure t
:init
;;(setq markdown-command "pandoc"
;; markdown-command-needs-filename t)
;; for pandoc:
(setq markdown-command
(concat "pandoc"
" --quiet"
" --from=markdown --to=html"
" --standalone --mathjax --highlight-style=pygments"))
;; https://github.com/jrblevin/markdown-mode/issues/578
;; (setq markdown-nested-imenu-heading-index nil)
:mode
(("\\.md\\'" . gfm-mode)
("\\.markdown\\'" . gfm-mode))
:hook
((markdown-mode . visual-line-mode)
(markdown-mode . flyspell-mode)))
;; markdown-toc mode
;; (require 'dash)
;; drop all H1 titles
(custom-set-variables
'(markdown-toc-user-toc-structure-manipulation-fn
(lambda (toc-structure)
(--map (-let (((level . label) it))
(cons (- level 1) label))
(cdr toc-structure)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; text mode
;; for some reason, I was not able to "use-package".
;;(use-package text-mode
;; :preface (provide 'text-mode)
;; :ensure nil
;; :mode
;; (("\\.txt\\'" . text-mode)
;; ("\\.text\\'" . text-mode))
;; :config
;; (progn
;; (message "I am in text-mode- use-package")
;; (setq visual-line-fringe-indicators '(nil right-curly-arrow))
;; (turn-on-visual-line-mode) ; enable visual-line
;; (auto-fill-mode -1)) ; disable auto-fill
;; )
(defun my/text-mode-hook ()
"X br text mode hook."
(setq visual-line-fringe-indicators '(nil right-curly-arrow))
(turn-on-visual-line-mode) ; enable visual-line
(auto-fill-mode -1)) ; disable auto-fill
(add-hook 'text-mode-hook 'my/text-mode-hook)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; makefile mode
(defun my/makefile-mode-hook ()
"X br makefile mode hook."
;; (message "entering Makefile-mode")
(setq indent-tabs-mode t
tab-width 8
comment-column 60
comment-fill-column 120)
;;(defadvice comment-indent (around indent-to activate)
;; "Disable indent-tab-mode when indenting comment."
;; (lambda (fun &rest args) (let (indent-tabs-mode) (apply fun args))))
)
(add-hook 'makefile-mode-hook 'my/makefile-mode-hook)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org mode
;; mediawiki export
(require 'ox-mediawiki)
(require 'org-tempo)
;;(require 'ox-extra)
(defun my/org-mode-hook ()
"X br org-mode-hook."
(interactive)
(setq fill-column 78
;; show structure at startup
org-startup-folded 'content
truncate-lines nil
org-src-fontify-natively t ; nil: disable coloring in code blocks
org-src-preserve-indentation t
org-src-tab-acts-natively t
org-src-window-setup 'current-window
org-src-block-faces nil
;; org-descriptive-links nil
org-link-descriptive nil
;; no TOC by default in export
;; org-export-with-toc nil
;;org-html-head-include-default-style nil
;;org-src-block-faces '(("emacs-lisp" (:background "#EEE2FF"))
;; ("python" (:background "#E5FFB8")))
org-todo-keywords '((sequence "TODO" "STARTED" "WAITING"
;; "REVIEW(r)" "SUBMIT(m)"
"|" "DONE" "CANCELED"))
;;org-todo-keyword-faces '(("TODO" :foreground "red" :weight bold)
;; ("STARTED" :foreground "cyan" :weight bold)
;; ("WAITING" :foreground "gold" :weight bold)
;; ("DONE" :foreground "sea green" :weight bold)
;; ("LATER" :foreground "dark red" :weight bold)
;; ("CANCELED" :foreground "dark red" :weight bold))
org-support-shift-select t
org-indent-mode-turns-on-hiding-stars nil
org-export-allow-bind-keywords t
visual-line-fringe-indicators '(nil right-curly-arrow)
)
;; change "=" (verbatim) to be different from "~" (code)
(push '(verbatim . "<code class='verbatim'>%s</code>") org-html-text-markup-alist)
;; to allow hiding a headline with :ignore: tag
;;(ox-extras-activate '(ignore-headlines))
;; visual-line mode
(org-indent-mode)
(visual-line-mode)
;;(setq visual-line-fringe-indicators '(nil right-curly-arrow))
(auto-fill-mode 1)
(define-key org-mode-map
(kbd "C-c l") 'my/org-toggle-link-display)
(define-key org-mode-map
(kbd "C-c x") 'org-mw-export-as-mediawiki))
(defun my/org-toggle-link-display ()
"Toggle the literal or descriptive display of links."
(interactive)
(if org-link-descriptive
(progn (remove-from-invisibility-spec '(org-link))
(org-restart-font-lock)
(setq org-link-descriptive nil))
(progn (add-to-invisibility-spec '(org-link))
(org-restart-font-lock)
(setq org-link-descriptive t))))
(add-hook 'org-mode-hook 'my/org-mode-hook)
;; inspired from https://orgmode.org/guide/Introduction.html
(global-set-key (kbd "H-c l") 'org-store-link)
(global-set-key (kbd "H-c a") 'org-agenda)
(global-set-key (kbd "H-c c") 'org-capture)
;; babel languages
(org-babel-do-load-languages
'org-babel-load-languages
'((calc . t)
(emacs-lisp . t)
(sql . t)
(perl . t)
(shell . t)))
;; (plantuml . t)
;; (python . t)
;; (ruby . t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; vimrc mode
(add-hook
'vimrc-mode-hook
(lambda ()
(setq indent-tabs-mode nil ; do not use tabs
comment-column 50)))
(require 'vimrc-mode)
(add-to-list 'auto-mode-alist '("\\.vim\\(rc\\)?\\'" . vimrc-mode))
;;(add-to-list 'auto-mode-alikst '(".vim\\(rc\\)?$" . vimrc-mode))
;;(add-to-list 'auto-mode-alist '(".vim\\(rc\\)?" . vimrc-mode))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; perl (cperl) mode
(defalias 'perl-mode 'cperl-mode)
(add-hook
'perl-lisp-mode-hook
(lambda ()
(setq indent-tabs-mode nil ; do not use tabs
tab-width 2)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Cobol mode
(setq auto-mode-alist
(append
'(("\\.cob\\'" . cobol-mode)
("\\.cbl\\'" . cobol-mode)
("\\.cpy\\'" . cobol-mode))
auto-mode-alist))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; C mode
(defun my/indent-maybe-cpp-directive ()
"Indent c pre-processor line according to my own standard."
(interactive)
(save-excursion
(back-to-indentation)
(when (looking-at "#")
(delete-char 1)
(indent-according-to-mode)
(beginning-of-line)
(when (looking-at " ")
(delete-char 1))
(insert "#")
(beginning-of-line))))
(defun my/c-style ()
"Some general C setup."
(interactive)
(c-set-style "k&r")
(c-set-offset 'knr-argdecl-intro '+)
(c-set-offset 'case-label '+)
(bind-keys :map c-mode-map
("s-;" . my/indent-maybe-cpp-directive)
("<f5>" . projectile-compile-project)
("F" . self-insert-command))
(auto-complete-mode 0)
;;(yas-minor-mode 1)
(flycheck-mode 1)
;;(ggtags-mode 1)
(show-smartparens-mode 1)
(company-mode 1)
(auto-fill-mode 1)
(setq company-backends '((company-dabbrev-code company-gtags))
c-basic-offset 4
comment-column 50
fill-column 100
c-ignore-auto-fill '(string cpp)
comment-auto-fill-only-comments nil
comment-style 'extra-line))
(use-package cc-mode
:ensure nil
:config
(add-hook 'c-mode-common-hook
(lambda ()
;;(when (derived-mode-p 'c-mode 'c++-mode 'java-mode 'asm-mode)
(when (derived-mode-p 'c-mode)
(ggtags-mode 1))))
(add-hook 'c-mode-hook 'my/c-style))
;;;;;;;;;;;;; linux kernel style
(defun c-lineup-arglist-tabs-only (ignored)
"Line up argument lists by tabs, not spaces. fuck flycheck IGNORED."
(let* ((anchor (c-langelem-pos c-syntactic-element))
(column (c-langelem-2nd-pos c-syntactic-element))
(offset (- (1+ column) anchor))
(steps (floor offset c-basic-offset)))
(* (max steps 1)
c-basic-offset)))
;; Eudyptula challenge
(defvar my/eudyptula-dir
(expand-file-name "~/dev/eudyptula")
"Eudyptula challenge directory.")
(defvar my/kernel-dir
(concat my/eudyptula-dir "/linux")
"Kernel tree within Eudyptula challenge.")
(defvar my/kernel-scripts-dir
(concat my/kernel-dir "/scripts")
"Scripts dir within Eudyptula challenge's kernel directory.")
(defvar my/kernel-include-dirs
(list (concat my/kernel-dir "/include")
(concat my/kernel-dir "/arch/x86/include")
(concat my/kernel-dir "/arch/x86/include/generated"))
"Kernel include directory.")
(defvar my/running-kernel-include-dirs
(let ((kernel (concat "/lib/modules/"
(string-trim (shell-command-to-string "uname -r"))
"/build")))
(list (concat kernel "/include")
(concat kernel "/arch/x86/include")))
"Running kernel include directory.")
;; https://stackoverflow.com/questions/29709967/using-flycheck-flymake-on-kernel-source-tree
(flycheck-define-checker my/flycheck-kernel-checker
"Linux source checker"
:command
(
"make" "C=1" "-C" (eval my/kernel-dir)
(eval (concat "M="
(file-name-directory buffer-file-name)))
(eval (concat (file-name-sans-extension (file-name-nondirectory buffer-file-name))
".o"))
)
:error-patterns
((error line-start
(message "In file included from") " " (file-name) ":" line ":"
column ":"
line-end)
(info line-start (file-name) ":" line ":" column
": note: " (message) line-end)
(warning line-start (file-name) ":" line ":" column
": warning: " (message) line-end)
(error line-start (file-name) ":" line ":" column
": " (or "fatal error" "error") ": " (message) line-end))
:modes (c-mode c++-mode))
;; :error-filter
;; (lambda (errors)
;; (let ((errors (flycheck-sanitize-errors errors)))
;; (dolist (err errors)
;; (let* ((fn (flycheck-error-filename err))
;; ;; flycheck-fix-error-filename converted to absolute, revert
;; (rn0 (file-relative-name fn default-directory))
;; ;; make absolute relative to "make -C dir"
;; (rn1 (expand-file-name rn0 my/kernel-dir))
;; ;; relative to source
;; (ef (file-relative-name rn1 default-directory))
;; )
;; (setf (flycheck-error-filename err) ef)
;; )))
;; errors)
;; (defun my/flycheck-mode-hook ()
;; "Flycheck mode hook."
;; (setq flycheck-linux-makefile my/kernel-dir)
;; (flycheck-select-checker 'my/flycheck-kernel-checker)
;; )
(dir-locals-set-class-variables
'linux-kernel
'((c-mode
. ((c-basic-offset . 8)
(c-label-minimum-indentation . 0)
(c-offsets-alist
. ((arglist-close . c-lineup-arglist)
(arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist))
(arglist-intro . +)
(brace-list-intro . +)
(c . c-lineup-C-comments)
(case-label . 0)
(comment-intro . c-lineup-comment)
(cpp-define-intro . +)
(cpp-macro . -1000)
(cpp-macro-cont . +)
(defun-block-intro . +)
(else-clause . 0)
(func-decl-cont . +)
(inclass . +)
(inher-cont . c-lineup-multi-inher)
(knr-argdecl-intro . 0)
(label . -1000)
(statement . 0)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-cont . +)
(substatement . +)))
(indent-tabs-mode . t)
(show-trailing-whitespace . t)
(eval . (flycheck-select-checker 'my/flycheck-kernel-checker)
;; (setq flycheck-gcc-include-path my/kernel-include-dirs)
)
))))
;; (setq flycheck-checkers (delete 'c/c++-clang flycheck-checkers))
;; linux kernel style
(defun my/maybe-linux-style ()
"Apply linux kernel style when buffer path contain 'eudyptula'."
(interactive)
(when (and buffer-file-name
(string-match "eudyptula" buffer-file-name))
(setq flycheck-checkers (delete '(c/c++-clang c/c++-cppcheck) flycheck-checkers)
flycheck-gcc-include-path my/kernel-include-dirs
flycheck-clang-include-path my/kernel-include-dirs)))
;; (add-hook 'c-mode-hook 'my/maybe-linux-style)
(dir-locals-set-directory-class my/eudyptula-dir 'linux-kernel)
;; (add-hook 'flycheck-mode-hook 'my/flycheck-mode-hook)
(defun my/checkpatch (file &optional nointree noterse nofilemode)
"Run checkpatch on FILE, or current buffer if FILE is nil.
If NOTERSE is t, a full report will be done. If NOFILEMODE is t, FILE
is supposed to be a patchfile (otherwise a regular source file).
If NOINTREE is t, check will be done on file outside `my/kernel-dir'"
;;(interactive)
(interactive "FFile name (default: current buffer): ")
(let* ((ckp (concat my/kernel-scripts-dir "checkpatch.pl "))
(fn (or file (buffer-file-name)))
(terse (if noterse "" "--terse "))
(tree (if nointree "--notree " ""))
(fm (if nofilemode "" "--file "))
(opt (concat "--emacs --color=never " terse tree fm)))
(setq my/compile (concat ckp opt fn))
(compile (concat ckp opt fn))))
(defun my/checkstaging ()
"Zobi."
(interactive)
(my/checkpatch "drivers/staging/*/*.[ch]"))
;; add kernel includes
;;(string-trim (shell-command-to-string "uname -r"))
;; to avoid "free variable" warnings at compile
;; (eval-when-compile
;; (require 'cc-defs))
;; (add-hook 'c-mode-common-hook
;; (lambda ()
;; ;; Add kernel style
;; (c-add-style
;; "linux-tabs-only"
;; '("linux" (c-offsets-alist
;; (arglist-cont-nonempty
;; c-lineup-gcc-asm-reg
;; c-lineup-arglist-tabs-only))))))
;; linux kernel style
;; (defun maybe-linux-style ()
;; "Apply linux kernel style when buffer path contains 'linux'."
;; (interactive)
;; (when (and buffer-file-name
;; (string-match "linux" buffer-file-name))
;; (c-set-style "linux")))
;; (add-hook 'c-mode-hook 'maybe-linux-style)
;; ;; (defun br-linux-style ()
;; ;; "Line up argument lists by tabs, not spaces"
;; ;; (interactive)
;; ;; (setq indent-tabs-mode t)
;; ;; (setq show-trailing-whitespace t)
;; ;; (c-set-style "linux-tabs-only"))
;; (add-hook 'c-mode-hook
;; (lambda ()
;; (let ((filename (buffer-file-name)))
;; ;; Enable kernel mode for the appropriate files
;; (when (and filename
;; (or (string-match "dev/eudyptula" filename)
;; (string-match "dev/kernel" filename)))
;; ;;(string-match (expand-file-name "~/dev/Eudyptula")
;; ;; (string-match "Eudyptula" buffer-file-name))
;; ;;(cl-search "eudyptula" buffer-file-name))
;; ;;(setq indent-tabs-mode t)
;; (setq show-trailing-whitespace t)
;; (c-set-style "linux-tabs-only")))))
;; exercism C style
(defvar my/exercism-dir
(expand-file-name "~/dev/exercism-tracks/")
"Exercism challenge directory.")
(dir-locals-set-class-variables
'exercism-style
'((c-mode
. ((c-basic-offset . 3)
(c-label-minimum-indentation . 0)
(c-offsets-alist
. ((arglist-close . c-lineup-arglist)
(arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist))
(arglist-intro . +)
(brace-list-intro . +)
(c . c-lineup-C-comments)
(case-label . 0)
(comment-intro . c-lineup-comment)
(cpp-define-intro . +)
(cpp-macro . -1000)
(cpp-macro-cont . +)
(defun-block-intro . +)
(else-clause . 0)
(func-decl-cont . +)
(inclass . +)
(inher-cont . c-lineup-multi-inher)
(knr-argdecl-intro . 0)
(label . -1000)
(statement . 0)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-cont . +)
(substatement . +)))
(indent-tabs-mode . nil)
(fill-column . 80)
(show-trailing-whitespace . t)
(comment-column . 33)
;;(eval . (flycheck-select-checker 'my/flycheck-kernel-checker)
;; (setq flycheck-gcc-include-path my/kernel-include-dirs)
;;)
))))
(dir-locals-set-directory-class my/exercism-dir 'exercism-style)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; emacs lisp mode
(defun my/emacs-lisp-mode-hook ()
"My Emacs Lisp mode hook."
(interactive)
(setq
indent-tabs-mode nil
tab-width 2
lisp-body-indent 2
;; lisp-indent-offset 2
comment-column 50
fill-column 128
comment-auto-fill-only-comments t
auto-fill-mode t)
(define-key emacs-lisp-mode-map
(kbd "<enter>") 'reindent-then-newline-and-indent))
(add-hook
'lisp-interaction-mode-hook
(lambda ()
(define-key lisp-interaction-mode-map
(kbd "<C-enter>") 'eval-last-sexp)))
(add-hook
'lisp-mode-hook
(lambda ()
(outline-minor-mode)
(make-local-variable 'outline-regexp)
(setq outline-regexp "^(.*")
(ignore-errors (semantic-default-elisp-setup))
(set (make-local-variable lisp-indent-function)
'common-lisp-indent-function)))
(add-hook 'emacs-lisp-mode-hook 'my/emacs-lisp-mode-hook)
;; eldoc - provides minibuffer hints when working in elisp
(use-package "eldoc"
:diminish eldoc-mode
:commands turn-on-eldoc-mode
:defer t
:init
(progn
(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)))
;; aggressive indent
;; (add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode)
;; (add-hook 'css-mode-hook #'aggressive-indent-mode)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; lisp interaction mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; php mode
;;TODO (use-package php
;;
;; )
(defun my/php-send-buffer ()
"Send current buffer to PHP for execution.
The output will appear in the buffer *PHP*."
(interactive)
(php-send-region (if (string-match "\\(^#!.*$\\)" (buffer-string) nil)
(+ 1 (point-min) (match-end 1))
(point-min))
(point-max)))
(defun my/php-mode-hook ()
"Hook for php-mode."
(interactive)
(setq indent-tabs-mode nil
c-basic-offset 4
comment-column 50
fill-column 128
comment-auto-fill-only-comments t
auto-fill-mode t
php-mode-template-compatibility nil)
;;php-executable "php -f")
(paren-toggle-open-paren-context 1)
(php-enable-default-coding-style)
(c-set-offset 'case-label '+)
(define-key php-mode-map
(kbd "C-c f") 'php-search-documentation)
(define-key php-mode-map
(kbd "C-c r") 'my/php-send-buffer)
;;(auto-complete-mode t)
;;(require 'ac-php)
;;(setq ac-sources '(ac-source-php))
(require 'company-php)
(set (make-local-variable 'company-backends)
'((company-ac-php-backend company-dabbrev-code)
company-capf company-files))
)
(use-package phpactor :ensure t)
(use-package company-phpactor :ensure t)
;;(setq lsp-clients-php-server-command '("phpactor" "language-server"))
;; Add lsp or lsp-deferred function call to functions for your php-mode customization
;; https://phpactor.readthedocs.io/en/master/lsp/emacs.html
(defun init-php-mode ()
"Zobi."
(lsp-deferred))
(with-eval-after-load 'php-mode
;; If phpactor command is not installed as global, write the full path
;; (custom-set-variables '(lsp-phpactor-path "/path/to/phpactor"))
(add-hook 'php-mode-hook #'init-php-mode))
;;(company-mode t)
;;(require 'company-php)
;;(set (make-local-variable 'company-backends)
;; '((company-ac-php-backend company-dabbrev-code)
;; company-capf company-files)))
;; (add-to-list 'company-backends 'company-ac-php-backend ))
(add-hook 'php-mode-hook 'my/php-mode-hook)
;; autoload php-html-helper-mode
;;(autoload 'php-html-helper-mode "html-helper-mode" "html-helper-mode" t)
;;(add-to-list 'auto-mode-alist '("\\.inc\\'" . php-html-helper-mode))
;;(add-to-list 'auto-mode-alist '("\\.html\\'" . html-mode))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; go mode
(add-hook
'go-mode-hook
(lambda ()
;; (setq-default)
(setq
indent-tabs-mode nil
tab-width 2
standard-indent 2)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; js mode
(add-hook
'js-mode-hook
(lambda ()
(setq
indent-tabs-mode nil
js-indent-level 3
;; tab-width 3
c-basic-offset 3
comment-column 50
fill-column 128
comment-auto-fill-only-comments t
auto-fill-mode t)
(define-key js-mode-map
(kbd "<kp-enter>") 'reindent-then-newline-and-indent)))
(use-package json-mode
:defer t
:mode "\\.json\\'"
:config
(setq indent-tabs-mode nil
js-indent-level 2)
;; https://github.com/joshwnj/json-mode/issues/72
(setq-default json-mode-syntax-table
(let ((st (make-syntax-table)))
;; Objects
(modify-syntax-entry ?\{ "(}" st)
(modify-syntax-entry ?\} "){" st)
;; Arrays
(modify-syntax-entry ?\[ "(]" st)
(modify-syntax-entry ?\] ")[" st)
;; Strings
(modify-syntax-entry ?\" "\"" st)
;; Comments
(modify-syntax-entry ?\n ">" st)
st))
)
;;(add-hook
;; 'json-mode-hook
;; (lambda ()
;; (setq
;; indent-tabs-mode nil
;; js-indent-level 2)
;; ))
;;(add-to-list 'auto-mode-alist '("\\.js\\'" . my/js-mode-hook))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hideshow mode
(use-package hideshow
:ensure nil
;;:diminish hideshow
:hook
((json-mode . hs-minor-mode)
(web-mode . hs-minor-mode)
(php-mode . hs-minor-mode)
(prog-mode . hs-minor-mode)
(lisp-mode . hs-minor-mode))
:bind
(:map hs-minor-mode-map
("H-<tab>" . hs-toggle-hiding)
("H-h" . hs-hide-block)
("H-s" . hs-show-block)
("H-l" . hs-hide-level)
("H-a" . hs-show-all)
("H-t" . hs-hide-all))
;; :commands hs-toggle-hiding
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; handle large buffers
(defun my/dabbrev-friend-buffer (other-buffer)
"Exclude very large buffers from dabbrev."
(< (buffer-size other-buffer) (* 1 1024 1024)))
(setq dabbrev-friend-buffer-function 'my/dabbrev-friend-buffer)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; multiple cursors
(use-package multiple-cursors
:ensure t
:bind (("C-S-C C-S-C" . mc/edit-lines)
("H-SPC" . set-rectangular-region-anchor)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; sql mode
;;(use-package sql-indent :defer t)
;;(use-package sqlup-mode :defer t)
(use-package sql
:ensure t
:init
;;(setq sql-product 'mysql
;; sqlup-mode t
;;(toggle-truncate-lines 1)
;; connect to a predefined connection (sql-connection-alist)
(defun my/sql-connect-preset (name)
"Connect to a predefined SQL connection listed in `sql-connection-alist'"
(eval `(let ,(cdr (assoc name sql-connection-alist))
(flet ((sql-get-login (&rest what)))
(sql-product-interactive sql-product)))))
(defun my/sql-mode-hook ()
"Hook for SQL mode."
(toggle-truncate-lines 1)
(message "br sql hook"))
(add-hook 'sql-interactive-mode-hook
(lambda ()
(toggle-truncate-lines t)
;;(my/sql-connect-preset)
(setq comint-move-point-for-output "all")))
;; (add-hook 'sql-interactive-mode-hook #'my/sql-mode-hook)
(font-lock-add-keywords 'sql-mode '(("greatest" . font-lock-builtin-face)
("least" . font-lock-builtin-face)))
:config
(toggle-truncate-lines 1)
(sql-set-product-feature 'mysql :prompt-regexp
"^\\(MariaDB\\|MySQL\\) \\[[_a-zA-Z]*\\]> ")
:hook
((sql-mode . sqlind-minor-mode)
(sql-mode . sqlup-mode))
;;(sql . my/sql-mode-hook)
;;(sql-interactive-mode . #'my/sql-mode-hook))
;;(sql-interactive-mode . (toggle-truncate-lines 1)))
)
;;(use-package sqlup-mode
;;:ensure
;;:after sql
;;:init
;;(local-set-key (kbd "C-c u") 'sqlup-capitalize-keywords-in-region)
;;:hook
;;(add-hook 'sql-mode-hook #'sqlup-mode)
;;:config
;;(add-to-list 'sqlup-blacklist "name") ; I use "name" a lot.
;; )
;;(use-package sql-indent
;;:after (sql-mode)
;;:after sql
;;:init
;;:hook
;;((sql . sqlind-minor-mode)))
;; (use-package sql-interactive-mode
;; :ensure
;; :after sql
;; :config
;; (toggle-truncate-lines 0))
;;(add-hook 'sql-mode-hook #'my/sql-mode-hook)
;; When connected to a server within Emacs
;;(add-hook 'sql-interactive-mode-hook #'my/sql-mode-hook)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; html/xml mode
(add-hook
'html-mode-hook
(lambda ()
(setq
indent-tabs-mode nil
;; tab-width 2
sgml-basic-offset 2)))
(defun xml-reformat ()
"Reformats xml to make it readable (respects current selection)."
(interactive)
(save-excursion
(let ((beg (point-min))
(end (point-max)))
(if (and mark-active transient-mark-mode)
(progn
(setq beg (min (point) (mark)))
(setq end (max (point) (mark))))
(widen))
(setq end (copy-marker end t))
(goto-char beg)
(while (re-search-forward ">\\s-*<" end t)
(replace-match ">\n<" t t))
(goto-char beg)
(indent-region beg end nil))))
(add-hook
'nxml-mode-hook
(lambda ()
(setq
indent-tabs-mode nil
;; tab-width 2
sgml-basic-offset 2)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; web mode
(use-package web-mode
;;:demand t
:init
(require 'php-mode)
;; (setq web-mode-enable-current-column-highlight t)
(make-local-variable 'web-mode-code-indent-offset)
(make-local-variable 'web-mode-markup-indent-offset)
(make-local-variable 'web-mode-css-indent-offset)
:mode
("\\.phtml\\'" "\\.html?\\'")
;;(add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
;;(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
:bind
(:map web-mode-map
("C-c f" . php-search-documentation))
;;:hook
;; (('web-mode . php-mode))
:config
(require 'company-php)
(set (make-local-variable 'company-backends)
'((company-ac-php-backend company-dabbrev-code)
company-capf company-files))
(setq web-mode-markup-indent-offset 2
web-mode-enable-auto-pairing nil ; overrides smartparens
web-mode-css-indent-offset 2
web-mode-code-indent-offset 4
web-mode-style-padding 1
web-mode-script-padding 1
web-mode-block-padding 2
web-mode-enable-current-element-highlight t
web-mode-enable-current-column-highlight t
web-mode-sql-indent-offset 2
web-mode-engines-alist '(("php" . "\\.phtml\\'")))
(setq web-mode-ac-sources-alist
'(("css" . (ac-source-css-property))
("html" . (ac-source-words-in-buffer ac-source-abbrev)))
)
;;)
;;(add-hook 'web-mode-hook 'my/web-mode-hook)
;;(eval-after-load "web-mode"
;;'
;;(set-face-background 'web-mode-current-element-highlight-face "red")
(set-face-foreground 'web-mode-current-element-highlight-face "chartreuse")
)
;; (defun my/web-mode-hook ()
;; "br web-mode-hook."
;; (interactive)
;; (setq indent-tabs-mode nil
;; tab-width 2
;; ;; web-mode-attr-indent-offset 2
;; web-mode-enable-auto-pairing nil
;; web-mode-code-indent-offset 2 ; for php, js, etc...
;; web-mode-css-indent-offset 2
;; web-mode-markup-indent-offset 2 ; for html
;; web-mode-sql-indent-offset 2
;; web-mode-enable-current-column-highlight t
;; )
;; (define-key web-mode-map
;; (kbd "C-c f") 'php-search-documentation)
;; (paren-toggle-open-paren-context 1)
;; (c-set-offset 'case-label '+)
;; (setq web-mode-engines-alist
;; '(("php" . "\\.phtml\\'")))
;; (sp-local-pair 'web-mode "<" nil :when '(my/sp-web-mode-is-code-context))
;; )
;; (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
;; (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
;; ;; (add-to-list 'auto-mode-alist '("\\.css\\'" . web-mode))
;; ;; (add-to-list 'auto-mode-alist '("\\.php\\'" . web-mode))
;; (add-hook 'web-mode-hook 'my/web-mode-hook)
;; ;; from FAQ at http://web-mode.org/ for smartparens
;; (defun my/sp-web-mode-is-code-context (id action context)
;; (when (and (eq action 'insert)
;; (not (or (get-text-property (point) 'part-side)
;; (get-text-property (point) 'block-side))))
;; t))
;; (use-package web-mode
;; ;;:mode "\\.html?\\'"
;; :init
;; :hook
;; ((auto-mode-alist .'("\\.php\\'" . web-mode)
;; )
;; :config
;; (progn
;; (setq web-mode-markup-indent-offset 2)
;; (setq web-mode-code-indent-offset 2)
;; (setq web-mode-css-indent-offset 2)
;; (setq web-mode-enable-current-element-highlight t)
;; (setq web-mode-ac-sources-alist
;; '(("css" . (ac-source-css-property))
;; ("html" . (ac-source-words-in-buffer ac-source-abbrev)))
;; )))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; smartparens mode
;; inspired from http://pages.sachachua.com/.emacs.d/Sacha.html#org480d137
(use-package smartparens
:diminish
:ensure t
:config
(progn
(require 'smartparens-config)
(smartparens-global-mode 1)
(show-smartparens-global-mode 1)
;;(add-hook 'emacs-lisp-mode-hook 'smartparens-mode)
(add-hook 'emacs-lisp-mode-hook 'show-smartparens-mode)
(setq sp-navigate-close-if-unbalanced t)
;; keybinding management
;;(define-key smartparens-mode-map (kbd "C-M-k") 'sp-kill-sexp)
;;(define-key smartparens-mode-map (kbd "C-M-w") 'sp-copy-sexp)
(define-key smartparens-mode-map (kbd "s-k") 'sp-kill-hybridsexp)
(define-key smartparens-mode-map (kbd "s-w") 'sp-copy-sexp)
(define-key smartparens-mode-map (kbd "C-c s r n") 'sp-narrow-to-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-f") 'sp-forward-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-b") 'sp-backward-sexp)
(define-key smartparens-mode-map (kbd "s-f") 'sp-forward-sexp)
(define-key smartparens-mode-map (kbd "s-b") 'sp-backward-sexp)
;; (define-key smartparens-mode-map (kbd "C-S-a") 'sp-beginning-of-sexp)
;; (define-key smartparens-mode-map (kbd "C-S-d") 'sp-end-of-sexp)
;; (define-key smartparens-mode-map (kbd "C-S-e") 'sp-end-of-sexp)
(define-key smartparens-mode-map (kbd "s-a") 'sp-beginning-of-sexp)
(define-key smartparens-mode-map (kbd "s-e") 'sp-end-of-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-n") 'sp-next-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-p") 'sp-previous-sexp)
(define-key smartparens-mode-map (kbd "s-n") 'sp-next-sexp)
(define-key smartparens-mode-map (kbd "s-p") 'sp-previous-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-t") 'sp-transpose-sexp)
(define-key smartparens-mode-map (kbd "s-<up>") 'sp-transpose-hybrid-sexp)
(define-key smartparens-mode-map (kbd "s-<down>") 'sp-push-hybrid-sexp)
;; (define-key smartparens-mode-map (kbd "M-D") 'sp-splice-sexp)
(define-key smartparens-mode-map (kbd "s-d") 'sp-splice-sexp)
;; (define-key smartparens-mode-map (kbd "C-<right>") 'sp-forward-slurp-sexp)
;; (define-key smartparens-mode-map (kbd "C-<left>") 'sp-forward-barf-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-<left>") 'sp-backward-slurp-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-<right>") 'sp-backward-barf-sexp)
(define-key smartparens-mode-map (kbd "s-<right>") 'sp-slurp-hybrid-sexp)
(define-key smartparens-mode-map (kbd "s-<left>") 'sp-forward-barf-sexp)
(define-key smartparens-mode-map (kbd "s-S-<left>") 'sp-backward-slurp-sexp)
(define-key smartparens-mode-map (kbd "s-S-<right>") 'sp-backward-barf-sexp)
;; nearly useless in C
;; (define-key smartparens-mode-map (kbd "<kp-enter>") 'sp-up-sexp)
;; (define-key emacs-lisp-mode-map (kbd ")") 'sp-up-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-d") 'sp-down-sexp)
;; (define-key smartparens-mode-map (kbd "C-M-e") 'sp-up-sexp)
(define-key smartparens-mode-map (kbd "C-M-a") 'sp-backward-down-sexp)
(define-key smartparens-mode-map (kbd "C-M-u") 'sp-backward-up-sexp)
(define-key smartparens-mode-map (kbd "M-<delete>")
'sp-unwrap-sexp)
(define-key smartparens-mode-map (kbd "M-<backspace>")
'sp-backward-unwrap-sexp)
(define-key smartparens-mode-map (kbd "C-M-<delete>")
'sp-splice-sexp-killing-forward)
(define-key smartparens-mode-map (kbd "C-M-<backspace>")
'sp-splice-sexp-killing-backward)
(define-key smartparens-mode-map (kbd "C-S-<backspace>")
'sp-splice-sexp-killing-around)
;;(define-key smartparens-mode-map (kbd "C-]") 'sp-select-next-thing-exchange)
;;(define-key smartparens-mode-map (kbd "C-<left_bracket>") 'sp-select-previous-thing)
;;(define-key smartparens-mode-map (kbd "C-M-]") 'sp-select-next-thing)
(define-key smartparens-mode-map (kbd "s-]")
'sp-select-next-thing-exchange)
(define-key smartparens-mode-map (kbd "s-<left_bracket>")
'sp-select-previous-thing-exchange)
;;(define-key smartparens-mode-map (kbd "M-F") 'sp-forward-symbol)
;;(define-key smartparens-mode-map (kbd "M-B") 'sp-backward-symbol)
(define-key smartparens-mode-map (kbd "C-c s t") 'sp-prefix-tag-object)
(define-key smartparens-mode-map (kbd "C-c s p") 'sp-prefix-pair-object)
(define-key smartparens-mode-map (kbd "C-c s c") 'sp-convolute-sexp)
(define-key smartparens-mode-map (kbd "C-c s a") 'sp-absorb-sexp)
(define-key smartparens-mode-map (kbd "C-c s e") 'sp-emit-sexp)
(define-key smartparens-mode-map (kbd "C-c s p") 'sp-add-to-previous-sexp)
(define-key smartparens-mode-map (kbd "C-c s n") 'sp-add-to-next-sexp)
(define-key smartparens-mode-map (kbd "C-c s j") 'sp-join-sexp)
(define-key smartparens-mode-map (kbd "C-c s s") 'sp-split-sexp)
;;;;;;;;;;;;;;;;;;
;; pair management
(sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)
;;; c-mode
(sp-with-modes '(c-mode c++-mode)
(sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET")))
(sp-local-pair "/*" "*/" :post-handlers '(("| " "SPC")
("* ||\n[i]" "RET"))))
;;; markdown-mode
(sp-with-modes '(markdown-mode gfm-mode rst-mode)
(sp-local-pair "*" "*" :bind "C-*")
(sp-local-tag "2" "**" "**")
(sp-local-tag "s" "```scheme" "```")
(sp-local-tag "<" "<_>" "</_>" :transform 'sp-match-sgml-tags))
;;; tex-mode latex-mode
(sp-with-modes '(tex-mode plain-tex-mode latex-mode)
(sp-local-tag "i" "1d5f8e69396c521f645375107197ea4dfbc7b792quot;<" "1d5f8e69396c521f645375107197ea4dfbc7b792quot;>"))
;;; html-mode
(sp-with-modes '(html-mode sgml-mode web-mode)
(sp-local-pair "<" ">"))
;;; web-mode
(defun my/sp-web-mode-is-code-context (id action context)
(when (and (eq action 'insert)
(not (or (get-text-property (point) 'part-side)
(get-text-property (point) 'block-side))))
t))
(sp-local-pair 'web-mode "<" nil :when '(my/sp-web-mode-is-code-context))
;;; lisp modes
(sp-with-modes sp-lisp-modes
(sp-local-pair "(" nil :bind "C-("))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; shell-script mode
(add-hook
'sh-mode-hook
(lambda ()
(setq indent-tabs-mode nil
tab-width 4
sh-basic-offset 4
comment-column 50
comment-auto-fill-only-comments t
fill-column 128
auto-fill-mode t
shfmt-command "~/go/bin/shfmt"
shfmt-arguments '("-i" "4" "-ci"))
(sh-electric-here-document-mode)
(define-key sh-mode-map (kbd "C-c f") 'shfmt-buffer)))
;;(define-key sh-mode-map
;; (kbd "<kp-return>") 'reindent-then-newline-and-indent)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; lsp-mode
(use-package lsp-mode
:ensure t
:diminish "LSP"
:commands (lsp lsp-deferred)
:config
(setq lsp-prefer-flymake nil
lsp-semantic-tokens-enable t
;;lsp-enable-on-type-formatting nil
lsp-enable-snippet nil
lsp-enable-symbol-highlighting t
lsp-lens-enable nil
lsp-headerline-breadcrumb-enable t
lsp-enable-indentation nil
lsp-enable-on-type-formatting nil
lsp-eldoc-enable-hover t
lsp-modeline-diagnostics-enable t
lsp-modeline-code-actions-enable t
lsp-modeline-code-actions-segments '(count icon name)
lsp-signature-render-documentation t)
;;(define-key lsp-mode-map (kbd "<mouse-3>") nil)
;;(define-key lsp-mode-map (kbd "C-S-<mouse-3>") 'lsp-mouse-click)
:hook
((sh-mode . lsp-deferred)
;;(c-mode-common . lsp-deferred)
(lsp-mode . lsp-enable-which-key-integration)))
(use-package lsp-ui
:ensure t
;;:diminish
:config
(setq lsp-ui-doc-show-with-cursor t
lsp-ui-doc-show-with-mouse nil ; breaks isearch
lsp-ui-sideline-enable nil ; too messy
lsp-ui-sideline-show-hover t
lsp-ui-sideline-show-symbol t
lsp-ui-sideline-show-code-actions t
;; lsp-ui-doc-enable nil
;; TRIED 2024/02/26
lsp-ui-doc-enable t
lsp-ui-doc-max-width 80
lsp-ui-doc-max-height 20
lsp-ui-doc-include-signature t ; type signature in doc
lsp-ui-doc-enhanced-markdown t ; looks b0rken (lists...)
lsp-ui-doc-position 'top ; top/bottom/at-point
lsp-ui-doc-alignment 'window)
:commands
(lsp-ui-mode)
:bind-keymap
("s-l" . lsp-command-map))
;;(use-package lsp-lens
;; :diminish)
(use-package helm-lsp
:commands
helm-lsp-workspace-symbol)
;;(use-package eglot
;; :ensure t
;; :diminish "EG")
(use-package ccls
:ensure t
:diminish " ccls"
:init
(setq ccls-initialization-options
'(:index (:comments 2) :completion (:detailedLabel t)))
(setq-default flycheck-disabled-checkers '(c/c++-clang c/c++-cppcheck c/c++-gcc))
(setq ccls-sem-highlight-method 'font-lock)
;; alternatively,
;;(setq ccls-sem-highlight-method 'overlay)
;; For rainbow semantic highlighting
;;(ccls-use-default-rainbow-sem-highlight)
:config
;;(setq projectile-project-root (ccls--suggest-project-root))
:hook
((c-mode) . (lambda () (require 'ccls) (lsp)))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CSS mode
(add-hook
'css-mode-hook
(lambda()
(setq cssm-indent-level 3
cssm-newline-before-closing-bracket t
cssm-indent-function #'cssm-c-style-indenter
cssm-mirror-mode t
css-indent-offset 2
indent-tabs-mode nil)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; additional files to load
;; load different files if they exist in user-emacs-directory directory:
;; emacs custom file, graphical system, system type, and hostname
;; in this order.
;; special case for custom file. Need to do something (maybe use an alist below)
(setq custom-file
(concat user-emacs-directory "custom.el"))
(when (file-exists-p custom-file)
(load custom-file))
;; secret file: all sensitive data
(setq my/secret-file "~/data/private/secret.el")
(when (file-exists-p my/secret-file)
(load my/secret-file)
(message "+++%s" my/secret-file))
;; load graphic/terminal specific file
(let ((filename (concat user-emacs-directory
(if (display-graphic-p)
"graphic"
"term")
".el")))
(when (file-exists-p filename)
(load filename)
(message "+++%s" filename)))
;; host specific file
(let ((filename (concat user-emacs-directory
(system-name)
".el")))
(when (file-exists-p filename)
(load filename)
(message "+++%s" filename)))
;; start server if not running
(require 'server)
(unless (server-running-p)
(server-start)
(message "++++++ emacs server started"))
;; (dolist
;; (filename
;; (list
;; ;; emacs self-generated - TO IMPROVE
;; ;; "custom"
;; ;; graphical system
;; (if (display-graphic-p)
;; "graphic"
;; "term")
;; ;; system type - we need to replace "/" with "!" here, for "gnu/linux"
;; (replace-regexp-in-string "/" "%" (symbol-name system-type))
;; ;; hostname
;; (system-name)))
;; (let ((full-filename (concat user-emacs-directory filename ".el")))
;; ;; load file
;; (message "+++%s" full-filename)
;; (if (file-exists-p full-filename)
;; (load full-filename)
;; )))
(message "++++++ init.el end")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; nothing works in Emacs 25
(defun my/trim-spaces (beg end)
"Trim all blank characters in region to one space, and remove whitespaces
at beginning and end of lines."
(interactive "r")
(save-excursion
(save-restriction
(narrow-to-region beg end)
;; replace multiple spaces in one
(goto-char (point-min))
(while (re-search-forward "[ \t]+" nil t)
(replace-match " "))
;; remove spaces at lines beginning
;;(goto-char (point-min))
;;(while (re-search-forward "^[ \t]+" nil t)
;; (replace-match ""))
;; remove spaces at line start/end
;(delete-trailing-whitespace)
)))
(defun my/align-c-array (beg end)
"Align array declaration on commas between BEG and END."
(interactive "r")
(save-excursion
(save-restriction
(narrow-to-region beg end)
(my/trim-spaces (point-min) (point-max))
(align-regexp (point-min) (point-max) "\\(\\s-[[:alnum:]-_]+,\\)" -1 1 t)
(indent-region (point-min) (point-max) nil))))
(defun my/align (beg end)
"Align columns with spaces."
(interactive "r")
(save-excursion
(save-restriction
(narrow-to-region beg end)
(my/trim-spaces (point-min) (point-max))
(align-regexp (point-min) (point-max) "\\(\\s-*\\)\\s-" 1 0 t)
(delete-trailing-whitespace))))
(defun align-cols (start end max-cols)
"Align text between point and mark as columns.
Columns are separated by whitespace characters.
Prefix arg means align that many columns. (default is all)
Attribution: ?"
(interactive "r\nP")
(save-excursion
(let ((p start)
pos
end-of-line
word
count
(max-cols (if (numberp max-cols) (max 0 (1- max-cols)) nil))
(pos-list nil)
(ref-list nil))
;; find the positions
(goto-char start)
(while (< p end)
(beginning-of-line)
(setq count 0)
(setq end-of-line (save-excursion (end-of-line) (point)))
(re-search-forward "^\\s-*" end-of-line t)
(setq pos (current-column)) ;start of first word
(if (null (car ref-list))
(setq pos-list (list pos))
(setq pos-list (list (max pos (car ref-list))))
(setq ref-list (cdr ref-list)))
(while (and (if max-cols (< count max-cols) t)
(re-search-forward "\\s-+" end-of-line t))
(setq count (1+ count))
(setq word (- (current-column) pos))
;; length of next word including following whitespaces
(setq pos (current-column))
(if (null (car ref-list))
(setq pos-list (cons word pos-list))
(setq pos-list (cons (max word (car ref-list)) pos-list))
(setq ref-list (cdr ref-list))))
(while ref-list
(setq pos-list (cons (car ref-list) pos-list))
(setq ref-list (cdr ref-list)))
(setq ref-list (nreverse pos-list))
(forward-line)
(setq p (point)))
;; align the cols starting with last row
(setq pos-list (copy-sequence ref-list))
(setq start
(save-excursion (goto-char start) (beginning-of-line) (point)))
(goto-char end)
(beginning-of-line)
(while (>= p start)
(beginning-of-line)
(setq count 0)
(setq end-of-line (save-excursion (end-of-line) (point)))
(re-search-forward "^\\s-*" end-of-line t)
(goto-char (match-end 0))
(setq pos (nth count pos-list))
(while (< (current-column) pos)
(insert-char ?\040 1))
(setq end-of-line (save-excursion (end-of-line) (point)))
(while (and (if max-cols (< count max-cols) t)
(re-search-forward "\\s-+" end-of-line t))
(setq count (1+ count))
(setq pos (+ pos (nth count pos-list)))
(goto-char (match-end 0))
(while (< (current-column) pos)
(insert-char ?\040 1))
(setq end-of-line (save-excursion (end-of-line) (point))))
(forward-line -1)
(if (= p (point-min)) (setq p (1- p))
(setq p (point)))))))
;;(setq
;;current-language-environment "UTF-8"
;;(prefer-coding-system 'UTF-8)
;;(set-default-coding-systems 'UTF-8)
;;(set-terminal-coding-system 'UTF-8)
;;(setq-default buffer-file-coding-system 'UTF-8)
;; affichage direct des caractères sur 8 bits
;; (standard-display-european 1)
;; les caractères iso-latin1 qui sont des lettres, des majuscules...
;; (require 'iso-syntax )
;; (rplacd fancy-startup-text
;; `("\nZou are running a customized Emacs configuration. See " :link
;; ("here"
;; #[257 "\300\301!\207"
;; [browse-url-default-browser "http://github.com/izahn/dotemacs/"]
;; 3 "\n\n(fn BUTTON)"]
;; "Open the README file")
;; "\nfor information about these customizations.\n"
;; .
;; (cdr fancy-startup-text)))
;; (rplacd add-to-list 'fancy-startup-text
;; '("\nYou are running a customized Emacs configuration. See " :link
;; ("here"
;; #[257 "\300\301!\207"
;; [browse-url-default-browser "http://github.com/izahn/dotemacs/"]
;; 3 "\n\n(fn BUTTON)"]
;; "Open the README file")
;; "\nfor information about these customizations.\n"))
;; Local Variables:
;; byte-compile-warnings: (not free-vars)
;; End:
(provide 'init)
;;; init.el ends here
(put 'narrow-to-region 'disabled nil)