You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

662 lines
20 KiB
EmacsLisp

;; -*- lexical-binding: t; -*-
(add-to-list 'custom-theme-load-path "~/.workspace/elisp-themes/")
(let ((home (getenv "HOME")))
;; Added by Package.el. This must come before configurations of
;; installed packages. Don't delete this line. If you don't want it,
;; just comment it out by adding a semicolon to the start of the line.
;; You may delete these explanatory comments.
(package-initialize)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
;;(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/"))
;; Where custom config values should be saved
(setq custom-file (concat home "/.custom.el"))
(load custom-file))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;; GLOBAL MODES ;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'flyspell)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
(add-hook 'prog-mode-hook 'linum-mode)
(add-hook 'prog-mode-hook 'show-paren-mode)
(add-hook 'prog-mode-hook 'display-fill-column-indicator-mode)
(defun hugot-delete-trailing-whitespace-hook ()
"Add buffer-local book to delete trailing white space."
(make-variable-buffer-local 'before-save-hook)
(add-hook 'before-save-hook 'delete-trailing-whitespace))
(add-hook 'prog-mode-hook 'hugot-delete-trailing-whitespace-hook)
(add-hook 'yaml-mode 'hugot-delete-trailing-whitespace-hook)
(yas-global-mode)
;; Switch between tabs with C-number
(setq-default tab-bar-select-tab-modifiers '(control))
;; Add a tab bar up top
(tab-bar-mode)
;; enable flycheck everywhere
(global-flycheck-mode)
;; Save minibuffer history between sessions
(savehist-mode 1)
;; Show the current time in the modeline
(display-time-mode 1)
(add-hook 'prog-mode-hook 'abbrev-mode)
;; minimal gui
(when (eq window-system "x")
(require 'emojify)
(global-emojify-mode 1)
(scroll-bar-mode -1))
(tool-bar-mode -1)
(add-hook 'after-init-hook 'global-company-mode)
(xclip-mode 1)
(setq-default fill-column 80)
(setq mouse-wheel-progressive-speed nil) ;; don't accelerate scrolling
(setq epa-pinentry-mode 'loopback)
;; Disable GUI prompt for GPG
(defadvice epg--start (around advice-epg-disable-agent activate)
(let ((agent (getenv "GPG_AGENT_INFO")))
(setenv "GPG_AGENT_INFO" nil)
ad-do-it
(setenv "GPG_AGENT_INFO" agent)))
;; Disable all colours when rendering HTML using shr by replacing its
;; colourize function with a stub.
(advice-add 'shr-colorize-region :around (defun shr-no-colourize-region (&rest ignore)))
;; Let's make sure that lanuage settings are not dependent on the
;; environment
;;(set-language-environment "English")
(setq system-time-locale "en_US.UTF-8")
(setq calendar-week-start-day 1
calendar-day-name-array
["Sunday" "Monday" "Tuesday" "Wednesday"
"Thursday" "Friday" "Saturday"]
calendar-month-name-array
["January" "February" "March" "April" "May"
"June" "Juli" "August" "Septembre"
"October" "November" "December"])
;; Don't ask wether to save abbrevs
(setq save-abbrevs 'silent)
;; ;;Don't auto-save files in the same directory as the file itself
;; (setq auto-save-file-name-transforms
;; `((".*" "~/.emacs-saves/" t)))
(setq show-paren-delay 0)
(fset 'yes-or-no-p 'y-or-n-p)
(setq inhibit-startup-message t inhibit-startup-echo-area-message t)
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq-default tab-bar-tab-hints t)
;; This is very php-specific, it would be nice if this could be
;; modularized more per filetype
(setq grep-find-ignored-directories
'(".cache" "vendor" ".git" ".idea" "vendor" "var"
"web" "node_modules" "httpconf"))
;; Disable request to save open files (because it is annoying)
(setq grep-save-buffers nil)
;; Disable annoying sounds
(setq ring-bell-function 'ignore)
;; Always follow symlinks
(setq vc-follow-symlinks t)
(setq auth-sources '("~/.authinfo.gpg"))
(put 'erase-buffer 'disabled nil)
(setq flycheck-emacs-lisp-load-path 'inherit)
(add-to-list 'load-path "~/projects/phpinspect.el")
(add-to-list 'load-path "~/projects/qtoot")
(add-to-list 'load-path "~/projects/emcn.el")
(add-to-list 'load-path "~/projects/notes-list")
(when (require 'qtoot nil 'noerror)
(setq qtoot-enable-drafts t))
;; END GLOBAL MODES
;;;;;;;;;;;;;;;;;;;;;
;;;;; POWERLINE ;;;;;
;;;;;;;;;;;;;;;;;;;;;
(powerline-default-theme)
(setq powerline-display-buffer-size nil)
(setq display-time-default-load-average nil)
;; END POWERLINE
;;;;;;;;;;;;;;;;;;;;
;;;;; WEB MODE ;;;;;
;;;;;;;;;;;;;;;;;;;;
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
;; When web-mode should be active
(add-to-list 'auto-mode-alist '("\\.cshtml" . web-mode))
(add-to-list 'auto-mode-alist '("\\.twig" . web-mode))
(add-to-list 'auto-mode-alist '("\\.svelte" . web-mode))
(add-to-list 'auto-mode-alist '("\\.java" . java-mode))
;; END WEB MODE
;;;;;;;;;;;;;;;;
;;;;; JAVA ;;;;;
;;;;;;;;;;;;;;;;
(when (require 'lsp-java nil t)
(setq lsp-java-import-gradle-version "7.4.2")
(setq lsp-java-import-gradle-wrapper-enabled nil))
(add-hook 'java-mode-hook 'lsp)
(defun hugot-java-indent-setup ()
(setq c-default-style "java")
(c-set-offset 'arglist-intro '+)
(c-set-offset 'arglist-close '0)
(c-set-offset 'case-label '+))
(add-hook 'java-mode-hook 'hugot-java-indent-setup)
;; END JAVA
;;;;;;;;;;;;;;;;;;;;;;
;;;;; JAVASCRIPT ;;;;;
;;;;;;;;;;;;;;;;;;;;;;
(require 'flycheck)
(add-to-list 'auto-mode-alist '("\\.jsx?$" . web-mode))
(setq web-mode-content-types-alist '(("jsx" . "\\.js[x]?\\'")))
(add-to-list 'flycheck-disabled-checkers 'javascript-jshint)
(add-to-list 'flycheck-disabled-checkers 'json-jsonlist)
(flycheck-add-mode 'javascript-eslint 'web-mode)
(defun hugot-javascript-web-mode-hook ()
(when (or (string-match "\\.svelte$" (buffer-name)) (string-match "\\.js$" (buffer-name)))
(setq tab-width 2)
(setq web-mode-markup-indent-offset 2)
(setq web-mode-code-indent-offset 2)
(setq js2-basic-offset 2)
(setq web-mode-script-padding 2)
(setq web-mode-script-padding 2)
(setq web-mode-block-padding 2)))
(add-hook 'web-mode-hook 'hugot-javascript-web-mode-hook)
;; END JAVASCRIPT
;;;;;;;;;;;;;;;
;;;;; PHP ;;;;;
;;;;;;;;;;;;;;;
(defvar hugot-php-mode-expand-list nil "PHP mode expansions.")
(setq hugot-php-mode-expand-list
'(("pun" "public function (): \n{\n\n}\n" (17 18 21 24))
("prn" "private function (): \n{\n\n}\n" (18 19 22 25))
("fn" "function ():\n{\n\n}" (10 11 15))
("pr" "private " ())
("pu" "public " ())))
(add-to-list 'auto-mode-alist `("\\.php$" . php-mode))
(defun hugot-php-personal-hook ()
(require 'expand)
(expand-add-abbrevs php-mode-abbrev-table hugot-php-mode-expand-list)
(abbrev-mode 1)
(set (make-local-variable 'company-minimum-prefix-length) 0)
(set (make-local-variable 'company-tooltip-align-annotations) t)
(set (make-local-variable 'company-idle-delay) 0.1)
(set (make-local-variable 'company-backends) '(phpinspect-company-backend))
;; Handy namespace stuff
(define-key php-mode-map (kbd "C-c u") 'phpinspect-fix-uses-interactive)
(define-key php-mode-map (kbd "C-c t t") 'phptest-run-test-for-current-buffer)
(define-key php-mode-map (kbd "C-c t p") 'phptest-run-tests-for-current-buffer-project)
(define-key php-mode-map (kbd "C-c t o") 'phptest-open-test-for-current-buffer)
(phpinspect-mode))
(when (require 'phpinspect nil t)
(add-hook 'php-mode-hook #'hugot-php-personal-hook))
;; END PHP
;;;;;;;;;;;;;;;
;;;;; CSS ;;;;;
;;;;;;;;;;;;;;;
(defun hugot-css-mode-hook ()
"Custom actions to execute when initializing css-mode"
(setq-local company-minimum-prefix-length 1)
(setq-local company-idle-delay 0))
(add-hook 'css-mode-hook 'hugot-css-mode-hook)
;; END CSS
;;;;;;;;;;;;;;;;;;;;;;;;
;;;;; COMPANY MODE ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;
(with-eval-after-load 'company
(dolist (map (list company-active-map company-search-map))
(define-key map (kbd "C-n") nil)
(define-key map (kbd "C-p") nil)
(define-key map (kbd "M-n") #'company-select-next)
(define-key map (kbd "M-p") #'company-select-previous))
(setq company-auto-complete t)
(setq company-idle-delay 1)
(setq company-auto-complete 'company-explicit-action-p)
(global-set-key (kbd "M-p") 'company-select-previous)
(global-set-key (kbd "M-n") 'company-select-next)
(add-to-list 'company-backends 'company-shell t)
(add-to-list 'company-backends 'company-dabbrev-code t)
(add-to-list 'company-backends 'company-capf))
(defun hugot-make-capf-dominant-company-backend ()
(interactive)
(setq company-backends
`(company-capf
,@(seq-filter (lambda (elt)
(not (eq 'company-capf elt)))
company-backends))))
;; END COMPANY MODE
;;;;;;;;;;;;;;
;;;;; GO ;;;;;
;;;;;;;;;;;;;;
(require 'go-mode)
(require 'company-go)
(require 'go-eldoc)
(require 'flycheck)
(defvar hugot-go-mode-expand-list
'(("ern" "if err != nil {\n\n}\n" (17))
("die" "log.Fatal()" (11))
("ernd" "if err!= nil {\nlog.Fatal(err)\n}\n" ())
("fn" "func () {\n}\n" (6))
("prnl" "fmt.Prinln()" (12))
("prnf" "fmt.Printf()" (12))
("sprn" "fmt.Sprintf()" (13)))
"Alist with golang expand snippets for use with ABBREV-MODE.")
;;;###autoload
(defun hugot-go-mode-hook ()
"Personal go-mode hook."
(require 'lsp-mode)
(require 'lsp-ui)
(require 'expand)
(expand-add-abbrevs go-mode-abbrev-table hugot-go-mode-expand-list)
(abbrev-mode 1)
(lsp)
(lsp-deferred)
(lsp-ui-mode)
(lsp-ui-sideline-mode)
(add-hook 'before-save-hook 'gofmt-before-save) ; gofmt before every save
(flymake-mode 1)
(local-set-key (kbd "M-.") 'godef-jump) ; Godef jump key binding
(local-set-key (kbd "M-*") 'pop-tag-mark)
(local-set-key (kbd "M-p") 'compile) ; Invoke compiler
(local-set-key (kbd "M-P") 'recompile) ; Redo most recent compile cmd
(local-set-key (kbd "M-]") 'next-error) ; Go to next error (or msg)
(local-set-key (kbd "M-[") 'previous-error) ; Go to previous error or msg
(local-set-key (kbd "C-c g") 'hugot-go-run)
(setq gofmt-command "goimports")
(hugot-make-capf-dominant-company-backend))
(add-hook 'go-mode-hook 'hugot-go-mode-hook)
(defun hugot-go-run ()
(interactive)
(let ((project-dir (lsp--suggest-project-root))
(start-buffer (current-buffer)))
(with-current-buffer (get-buffer-create "GO-RUN")
(display-buffer (current-buffer))
(let ((default-directory project-dir))
(make-process
:name "GO-RUN OUTPUT"
:command `("go" "run" "main.go")
:buffer (current-buffer)
:stderr (current-buffer))))))
;; END GO
;;;;;;;;;;;;;;;;;;;
;;;;; SH MODE ;;;;;
;;;;;;;;;;;;;;;;;;;
(declare-function 'sh-electric-here-document-mode "sh-script")
;; Disable automatic expansion of << to <<EOF
(add-hook 'sh-mode-hook
(lambda ()
(sh-electric-here-document-mode -1)))
;; END SH MODE
;;;;;;;;;;;;;;;
;;;;; SQL ;;;;;
;;;;;;;;;;;;;;;
(add-hook 'sql-mode-hook 'sqlind-minor-mode)
;; END SQL
;;;;;;;;;;;;;;;;;;
;;;;; SVELTE ;;;;;
;;;;;;;;;;;;;;;;;;
(defun svelte-mode-sgml-empty-tag-p-advice (old-function tag-name)
"Advice function intended to wrap around `sgml-empty-tag-p
Makes case significant when checking whether tags need to be
closed or not, to not confuse elements with Svelte components."
(if (eq major-mode 'svelte-mode)
(assoc-string tag-name sgml-empty-tags)
(funcall old-function tag-name)))
(defun svelte-mode-sgml-unclosed-tag-p-advice (old-function tag-name)
"Advice function intended to wrap around `sgml-unclosed-tag-p
Makes case significant when checking whether tags need to be
closed or not, to not confuse elements with Svelte components."
(if (eq major-mode 'svelte-mode)
(assoc-string tag-name sgml-unclosed-tags)
(funcall old-function tag-name)))
(advice-add 'sgml-empty-tag-p :around 'svelte-mode-sgml-empty-tag-p-advice)
(advice-add 'sgml-unclosed-tag-p :around 'svelte-mode-sgml-unclosed-tag-p-advice)
;; END SVELTE
;;;;;;;;;;;;;;;;;;;;
;;;;; KEYBINDS ;;;;;
;;;;;;;;;;;;;;;;;;;;
(global-unset-key (kbd "C-x C-c"))
(global-set-key (kbd "C-x C-c C-x C-c") 'save-buffers-kill-terminal)
;; Unbind `dired'. Not necessary anyways since there is {C-x C-d} to run
;; `ido-list-directory' if I ever really want to use dired. Also there is {C-c
;; C-x C-d} to open `dired-sidebar'.
(global-unset-key (kbd "C-x d"))
(global-set-key (kbd "C-c e") 'emojify-insert-emoji)
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-x O") (lambda () (interactive) (other-window -1)))
;; TOOD: This keymap is only usefull for PHP projects, Maybe think of
;; a way to only enable it for files that are in PHP projects?
(global-set-key (kbd "C-c a") 'phpinspect-find-class-file)
(global-set-key (kbd "C-c c") 'phpinspect-find-own-class-file)
;; EVIL EVIL
(global-set-key (kbd "C-x 5 0")
(lambda ()
(interactive)
(message "That is probably not what you meant!")))
(global-set-key (kbd "C-c f") 'project-find-file)
(global-set-key (kbd "C-c b") 'hugot-project-switch-to-buffer)
;; Switch between tabs with C-number
(setq tab-bar-select-tab-modifiers '(control))
;; END KEYBINDS
;;;;;;;;;;;;;;;;;;;;;;
;;;;; NOTES LIST ;;;;;
;;;;;;;;;;;;;;;;;;;;;;
(when (and (require 'emcn-notes-list nil t)
(require 'notes-list nil t))
(setq notes-list-collect-notes-function #'emcn-notes-list-collect-notes)
(setq notes-list-open-function #'emcn-notes-list-open)
(setq notes-list-highlight-face 'font-lock-string-face)
(setq notes-list-stripe-face 'fringe)
(setq notes-list-display-tags nil))
;; END NOTES LIST
;;;;;;;;;;;;;;;;;;;;
;;;;; EWW MODE ;;;;;
;;;;;;;;;;;;;;;;;;;;
(defun hugot-eww-title (old-function)
"Intended to be added as advice around `eww-update-header-line-format'.
OLD-FUNCTION must be the function that is being adviced."
(rename-buffer (concat
"[eww] "
(or (plist-get eww-data :title)
"<untitled>"))
t)
(funcall old-function))
(advice-add #'eww-update-header-line-format :around #'hugot-eww-title)
;; END EWW MODE
;;;;;;;;;;;;;;;;;
;;;;; EMENT ;;;;;
;;;;;;;;;;;;;;;;;
(when (require 'ement nil t)
(setq ement-save-sessions t)
(setq ement-room-left-margin-width 0)
(setq ement-room-message-format-spec "[%S]\n%B%r\n%R%t")
(defun hugot-ement-hook ()
(emojify-mode))
(add-hook 'ement-room-list-mode-hook #'hugot-ement-hook)
(add-hook 'ement-room-mode-hook #'hugot-ement-hook))
;; END EMENT
;;;;;;;;;;;;;;;
;;;;; IDO ;;;;;
;;;;;;;;;;;;;;;
(require 'ido)
(setq ido-enable-flex-matching t)
(ido-everywhere 1)
(ido-vertical-mode 1)
;;; This is from ido-completing-read+ which made function/command completion garbage slow.
;;(ido-ubiquitous-mode 1)
(ido-mode 1)
(defmacro hugot-get-function-object (sym-or-var)
`(or (when (symbolp ,sym-or-var)
(or (indirect-function ,sym-or-var)
(indirect-function (symbol-value ,sym-or-var))))
,sym-or-var))
(defun hugot-function= (f1 f2)
(eq
(hugot-get-function-object f1)
(hugot-get-function-object f2)))
(defun hugot-completing-read (prompt coll pred &rest args)
"`completing-read-default' wrapper to use as `completing-read-function'.
Enables ido for M-x and describe-function/describe-variable."
(let ((cr-args `(,prompt ,coll ,pred ,@args))
(cr-function #'completing-read-default))
;; When the collection is a list, ido knows what to do with it
(cond ((and (listp coll) (stringp (car coll)))
(setq cr-function #'ido-completing-read))
((and (listp coll) (consp (car coll)))
(setq cr-function #'ido-completing-read)
(setq coll (mapcar 'car coll))
(setq cr-args `(,prompt ,coll ,pred ,@args)))
;; Collection is a function, ido can't deal with those, so for some cases we
;; force the function to return all matches that contain "empty string", which
;; (usually) results in them returning every possible value.
((functionp coll)
;; Used for `describe-function'
(if (or (eq #'help--symbol-completion-table coll)
;; Should match the prompt of `project-find-file'
(string-match "^Find file in" prompt))
(setq cr-function #'ido-completing-read
cr-args `(,prompt ,(funcall coll "" pred t) ,pred ,@args))
(cond
;; Used for M-x (`read-extended-command')
((or (hugot-function= 'commandp pred)
(hugot-function= 'read-extended-command-predicate pred)
(string-match "M-x" prompt))
(setq cr-function #'ido-completing-read
cr-args `(,prompt ,(funcall coll "" pred t) ,pred ,@args)))))))
(apply cr-function cr-args)))
(setq completing-read-function #'hugot-completing-read)
;; Use IDO for M-x
;;(smex-initialize)
;; (global-set-key (kbd "M-x") 'smex)
;; (global-set-key (kbd "M-X") 'smex-major-mode-commands)
;; This is your old M-x.
(global-set-key (kbd "C-c C-c M-x") 'execute-extended-command)
(defvar hugot-kr-cr-corpse-length 20)
(defun hugot-kr-cr ()
"Completing read for the `kill-ring'.
Returns the kill-ring index of the selected item, for use as
argument to `yank' and the like."
(interactive)
(let* ((body-count 0)
(alist (mapcar (lambda (corpse)
(cons
(replace-regexp-in-string
"[[:blank:]]+"
" "
(truncate-string-to-width corpse
hugot-kr-cr-corpse-length))
(setq body-count (+ body-count 1))))
kill-ring-yank-pointer))
(corpse (completing-read "Kill ring: " alist)))
(alist-get corpse alist 0 nil #'string=)))
(defun hugot-kr-cr-yank (&optional arg)
"Yank from the kill-ring, seleting which string to yank using `completing-read'.
See `yank' for documentation of ARG."
(interactive (list (hugot-kr-cr)))
(let ((yank-function #'yank)
;; The yank pointer should stay the same, but there's no way to pass DO-NOT-MOVE
;; to `current-kill' when calling the yank function, so it's stored here to
;; recover it's state after yanking. The yank function appropriate for the current
;; mode needs to be called in stead of just using `insert', because using `insert'
;; in kotl-mode (for example) breaks it.
(stored-yank-pointer (cl-copy-list kill-ring-yank-pointer)))
(cond ((eq major-mode 'kotl-mode)
(setq yank-function #'kotl-mode:yank)))
(funcall yank-function arg)
;; Restore yank-pointer
(setq kill-ring-yank-pointer stored-yank-pointer)))
;; END IDO
(require 'hyperbole)
;(eval-after-load 'kotl-mode '(require 'hugot-kotl-mode))
;; Emoji support
(set-fontset-font t 'symbol "Apple Color Emoji")
(set-fontset-font t 'symbol "Noto Color Emoji" nil 'append)
(set-fontset-font t 'symbol "Segoe UI Emoji" nil 'append)
(set-fontset-font t 'symbol "Symbola" nil 'append)
(setq server-socket-dir (concat (getenv "HOME") "/.cache/emacs"))
(defun hugot-set-appearance ()
"Set appearance settings."
(interactive)
(load-theme 'epaper)
(enable-theme 'epaper)
(fringe-mode (alist-get "right-only" fringe-styles nil nil 'string=))
(window-divider-mode)
(scroll-bar-mode -1)
(menu-bar-mode -1)
;; (set-frame-font "Hack 11" nil t)
;; (set-face-attribute 'default nil :height 110)
(setq linum-format "%d "))
(hugot-set-appearance)
(put 'downcase-region 'disabled nil)
;;;;;;;;;;;;;;;;;;;;
;;;;; COMMANDS ;;;;;
;;;;;;;;;;;;;;;;;;;;
(defun insert-date ()
(interactive)
(insert (format-time-string "%Y-%m-%d %H:%M")))
(defun hugot-list-project-buffers ()
(let ((project-dir (cdr (project-current)))
(buffers))
(dolist (buffer (buffer-list))
(when (and (buffer-file-name buffer)
(file-in-directory-p (buffer-file-name buffer)
project-dir)
(push buffer buffers))))
buffers))
(defun hugot-project-switch-to-buffer (buffer)
(interactive (list (completing-read
"Buffer: "
(mapcar #'buffer-name
(hugot-list-project-buffers)))))
(switch-to-buffer buffer))
(defun hugot-cp-rsa ()
(interactive)
(with-temp-buffer
(insert-file-contents-literally "~/.ssh/id_rsa.pub")
(copy-region-as-kill (point-min) (point-max))
(message "~/.ssh/id_rsa.pub contents added to kill-ring")))
;; END COMMANDS