3771 lines
97 KiB
Org Mode
3771 lines
97 KiB
Org Mode
* Add some directories to ~load-path~
|
||
|
||
** My own (version controlled) ~lisp~ directory
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-to-list 'load-path (expand-file-name
|
||
(convert-standard-filename "lisp/")
|
||
user-emacs-directory))
|
||
(add-to-list 'load-path (expand-file-name
|
||
(convert-standard-filename "lisp/nyan-prompt")
|
||
user-emacs-directory))
|
||
#+END_SRC
|
||
|
||
** The local site-lisp
|
||
|
||
…if it exists.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(let ((site-lisp-dir "/usr/local/share/emacs/site-lisp"))
|
||
(when (file-directory-p site-lisp-dir)
|
||
(dolist (elt (directory-files site-lisp-dir))
|
||
(unless (or (string= elt ".") (string= elt ".."))
|
||
(add-to-list 'load-path (expand-file-name elt site-lisp-dir))))))
|
||
#+END_SRC
|
||
|
||
* Load some prerequisites
|
||
|
||
** Load ~xdg-paths~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(load "xdg-paths")
|
||
#+END_SRC
|
||
|
||
** Load the tango dark theme
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(load-theme 'tango-dark t)
|
||
#+END_SRC
|
||
|
||
* Emacs configuration
|
||
|
||
** Set up the package archives
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(require 'package)
|
||
(add-to-list 'package-archives
|
||
'("gnu" . "https://elpa.gnu.org/packages/"))
|
||
(add-to-list 'package-archives
|
||
'("melpa-stable" . "https://stable.melpa.org/packages/") t)
|
||
(add-to-list 'package-archives
|
||
'("melpa" . "https://melpa.org/packages/") t)
|
||
(add-to-list 'package-archives
|
||
'("org" . "https://orgmode.org/elpa/") t)
|
||
(package-initialize)
|
||
#+END_SRC
|
||
|
||
** Configure ~use-package~ and preload ~bind-key~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(unless (package-installed-p 'use-package)
|
||
(package-refresh-contents)
|
||
(package-install 'use-package))
|
||
|
||
(require 'use-package)
|
||
|
||
(customize-set-variable 'use-package-always-ensure t)
|
||
(customize-set-variable 'use-package-verbose nil)
|
||
|
||
(use-package bind-key)
|
||
#+END_SRC
|
||
|
||
** Install and configure Quelpa
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(unless (package-installed-p 'quelpa)
|
||
(with-temp-buffer
|
||
(url-insert-file-contents "https://raw.githubusercontent.com/quelpa/quelpa/master/quelpa.el")
|
||
(eval-buffer)
|
||
(quelpa-self-upgrade)))
|
||
#+END_SRC
|
||
|
||
*** And quelpa-use-package, too!
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(quelpa
|
||
'(quelpa-use-package
|
||
:fetcher git
|
||
:url "https://github.com/quelpa/quelpa-use-package.git"))
|
||
(require 'quelpa-use-package)
|
||
#+END_SRC
|
||
|
||
** Set up the really basic things
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package emacs
|
||
:ensure nil
|
||
:custom
|
||
(user-full-name "Gergely Polonkai")
|
||
(user-mail-address "gergely@polonkai.eu")
|
||
(kill-read-only-ok t)
|
||
(use-dialog-box nil))
|
||
#+END_SRC
|
||
|
||
** Set up my personal keymap
|
||
|
||
I set it up early so i can use it in ~use-package~ calls immediately.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defvar gpolonkai/pers-map (make-sparse-keymap)
|
||
"My own, personal, keymap!")
|
||
(define-prefix-command 'gpolonkai/pers-map)
|
||
(define-key ctl-x-map "t" 'gpolonkai/pers-map)
|
||
(define-key global-map (kbd "C-t") 'gpolonkai/pers-map)
|
||
#+END_SRC
|
||
|
||
** I really don’t want to type more than i really must…
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defalias 'yes-or-no-p 'y-or-n-p)
|
||
#+END_SRC
|
||
|
||
** Set UTF-8 as the default encoding
|
||
|
||
Just to make sure, although most Linux DEs do this for me.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(set-language-environment "UTF-8")
|
||
(set-default-coding-systems 'utf-8)
|
||
#+END_SRC
|
||
|
||
** Set Org’s main directory
|
||
|
||
Since a lot of packages use it as their base (org-projectile, org-caldav, etc.), i need
|
||
it as early as possible.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-directory (expand-file-name "NextCloud/orgmode" user-documents-directory))
|
||
#+END_SRC
|
||
|
||
* Custom commands and functions
|
||
|
||
** Utility functions
|
||
|
||
*** Check if something is ~nil~ or a list of strings
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun nil-or-list-of-strings-p (var)
|
||
"Return t if VAR is either nil or a list holding only strings."
|
||
(or (null var)
|
||
(not (null (delq nil
|
||
(mapcar (lambda (x) (and (stringp x) x)) var))))))
|
||
#+END_SRC
|
||
|
||
*** Get the number at point
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun get-number-at-point ()
|
||
(interactive)
|
||
(skip-chars-backward "0123456789.-")
|
||
(or (looking-at "[0123456789.-]+")
|
||
(error "No number at point"))
|
||
(string-to-number (match-string 0)))
|
||
#+END_SRC
|
||
|
||
*** Round number at point to the given decimals
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun round-number-at-point-to-decimals (decimal-count)
|
||
(interactive "NDecimal count: ")
|
||
(let ((mult (expt 10 decimal-count)))
|
||
(replace-match (number-to-string
|
||
(/
|
||
(fround
|
||
(*
|
||
mult
|
||
(get-number-at-point)))
|
||
mult)))))
|
||
#+END_SRC
|
||
|
||
*** Make a backup filename under ~user-emacs-cache-directory~
|
||
|
||
Taken from [[http://ergoemacs.org/emacs/emacs_set_backup_into_a_directory.html][Xah’s site]].
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun xah/backup-file-name (fpath)
|
||
"Return a new file path for FPATH under `user-emacs-cache-directory'"
|
||
(let* ((backup-root-dir (expand-file-name "backup" user-emacs-cache-directory))
|
||
(file-path (replace-regexp-in-string "[A-Za-z]:" "" fpath))
|
||
(backup-file-path (replace-regexp-in-string "//" "/" (concat backup-root-dir file-path "~"))))
|
||
(make-directory (file-name-directory backup-file-path) (file-name-directory backup-file-path))
|
||
backup-file-path))
|
||
#+END_SRC
|
||
|
||
*** Run a function on a region
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun func-region (start end func)
|
||
"Run a function over the region between START and END in current buffer."
|
||
(save-excursion
|
||
(let ((text (delete-and-extract-region start end)))
|
||
(insert (funcall func text)))))
|
||
#+END_SRC
|
||
|
||
** Check if we are running under Termux
|
||
|
||
We need to do things differently, if so.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun termux-p ()
|
||
"Check if Emacs is running under Termux."
|
||
(string-match-p
|
||
(regexp-quote "/com.termux/")
|
||
(expand-file-name "~")))
|
||
#+END_SRC
|
||
|
||
** Misc text manipulation functions
|
||
|
||
*** Delete the current line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/delete-current-line ()
|
||
"Kill the whole line on which point is."
|
||
(interactive)
|
||
|
||
(beginning-of-line)
|
||
(kill-line 1))
|
||
#+END_SRC
|
||
|
||
*** Duplicate current line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/duplicate-line()
|
||
"Duplicate line at point."
|
||
|
||
(interactive)
|
||
|
||
(save-excursion
|
||
(move-beginning-of-line 1)
|
||
(kill-line)
|
||
(yank)
|
||
(open-line 1)
|
||
(forward-line 1)
|
||
(yank)))
|
||
#+END_SRC
|
||
|
||
*** Toggle case of character at point
|
||
|
||
Based on [[http://ergoemacs.org/emacs/modernization_upcase-word.html][Xah’s toggle letter case defun version 2015-12-22]]
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun toggle-char-case (arg-move-point)
|
||
"Toggle the case of the char after point.
|
||
|
||
If prefix argument ARG-MOVE-POINT is non-nil, move point after the char."
|
||
(interactive "P")
|
||
(let ((case-fold-search nil))
|
||
(cond
|
||
((looking-at "[[:lower:]]") (upcase-region (point) (1+ (point))))
|
||
((looking-at "[[:upper:]]") (downcase-region (point) (1+ (point)))))
|
||
(cond
|
||
(arg-move-point (right-char)))))
|
||
#+END_SRC
|
||
|
||
*** Open a new line below
|
||
|
||
Copied from http://whattheemacsd.com/editing-defuns.el-01.html
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun open-line-below ()
|
||
"Open a new line below point."
|
||
|
||
(interactive)
|
||
|
||
(end-of-line)
|
||
(newline)
|
||
(indent-for-tab-command))
|
||
#+END_SRC
|
||
|
||
*** Open a new line above
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun open-line-above ()
|
||
"Open a new line above point."
|
||
|
||
(interactive)
|
||
|
||
(beginning-of-line)
|
||
(newline)
|
||
(forward-line -1)
|
||
(indent-for-tab-command))
|
||
#+END_SRC
|
||
|
||
*** TODO Kill or copy the whole line
|
||
|
||
Got from Xah’s site (TODO is for adding a link here.)
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun æ-kill-or-copy-whole-line (kill)
|
||
"Kill or copy the whole line point is on.
|
||
|
||
If KILL is non-nil, the line gets killed. Otherwise, it gets just
|
||
copied to the kill ring."
|
||
(interactive "P")
|
||
|
||
(if kill
|
||
(kill-whole-line)
|
||
(let ((beginning (progn (beginning-of-line) (point)))
|
||
(end (progn (end-of-line) (point))))
|
||
(copy-region-as-kill beginning end))))
|
||
#+END_SRC
|
||
|
||
*** Enclose region in a specific character
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/enclose-region (character &optional start end)
|
||
"Enclose region between CHARACTER.
|
||
|
||
If region is empty and neither START nor END is set, simply inserts CHARACTER
|
||
two times and moves point between them.
|
||
|
||
If character is present in `insert-pair-alist', this function will enclose
|
||
region in the corresponding pair. In this case, CHARACTER must be the opening
|
||
member of the pair."
|
||
|
||
(interactive "cWhat character? \nr")
|
||
|
||
(let ((open character)
|
||
(close character)
|
||
(pair (assq character insert-pair-alist)))
|
||
(if pair
|
||
(if (nth 2 pair)
|
||
(setq open (nth 1 pair) close (nth 2 pair))
|
||
(setq open (nth 0 pair) close (nth 1 pair))))
|
||
(unless (and open close)
|
||
(setq open character
|
||
close character))
|
||
(unless (use-region-p)
|
||
(setq start (point)
|
||
end (point)))
|
||
(save-excursion
|
||
(goto-char end)
|
||
(insert-char close)
|
||
|
||
(goto-char start)
|
||
(insert-char open))
|
||
(unless (use-region-p)
|
||
(forward-char))))
|
||
#+END_SRC
|
||
|
||
*** Convert ~camelCase~ to ~snake_case~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun camel-to-snake-case (arg)
|
||
"Convert a camelCase word to snake_case.
|
||
|
||
If the prefix argument ARG is non-nil, convert the text to uppercase."
|
||
(interactive "p")
|
||
(progn
|
||
(let ((start (region-beginning))
|
||
(end (region-end))
|
||
(case-fold-search nil)
|
||
(had-initial-underscore nil))
|
||
(goto-char start)
|
||
(when (looking-at "_") (setq had-initial-underscore t))
|
||
(while (re-search-forward "\\([A-Z]\\)" end t)
|
||
(replace-match "_\\1")
|
||
(setq end (1+ end)))
|
||
(if arg
|
||
(upcase-region start end)
|
||
(downcase-region start end))
|
||
(goto-char start)
|
||
(unless had-initial-underscore (delete-char 1)))))
|
||
#+END_SRC
|
||
|
||
*** Insert two spaces after specific characters
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun org-space-key (&optional arg)
|
||
"Insert two spaces after a period.
|
||
|
||
ARG will be passed down verbatim to `self-insert-command'"
|
||
(interactive "p")
|
||
|
||
(when (looking-back "[.!?…]" nil)
|
||
(call-interactively 'self-insert-command arg))
|
||
(call-interactively 'self-insert-command arg))
|
||
#+END_SRC
|
||
|
||
*** Fill or unfill a paragraph
|
||
:PROPERTIES:
|
||
:SOURCE: http://pages.sachachua.com/.emacs.d/Sacha.html
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun sachachua/fill-or-unfill-paragraph (&optional unfill region)
|
||
"Fill (or unfill, if UNFILL is non-nil) paragraph (or REGION)."
|
||
(interactive (progn
|
||
(barf-if-buffer-read-only)
|
||
(list (if current-prefix-arg 'unfill) t)))
|
||
(let ((fill-column (if unfill (point-max) fill-column)))
|
||
(fill-paragraph nil region)))
|
||
#+END_SRC
|
||
|
||
*** Swap occurences of strings
|
||
:PROPERTIES:
|
||
:SOURCE: http://emacs.stackexchange.com/a/27170/507
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun so/query-swap-strings (from-string
|
||
to-string
|
||
&optional delimited start end)
|
||
"Swap occurrences of FROM-STRING and TO-STRING.
|
||
|
||
DELIMITED, START, and END are passed down verbatim to `perform-replace'."
|
||
(interactive
|
||
(let ((common
|
||
(query-replace-read-args
|
||
(concat "Query swap"
|
||
(if current-prefix-arg
|
||
(if (eq current-prefix-arg '-) " backward" " word")
|
||
"")
|
||
(if (use-region-p) " in region" ""))
|
||
nil)))
|
||
(list (nth 0 common) (nth 1 common) (nth 2 common)
|
||
(if (use-region-p) (region-beginning))
|
||
(if (use-region-p) (region-end)))))
|
||
(perform-replace
|
||
(concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string))
|
||
`(replace-eval-replacement replace-quote
|
||
(if (match-string 1)
|
||
,to-string
|
||
,from-string))
|
||
t t delimited nil nil start end))
|
||
#+END_SRC
|
||
|
||
*** Insert the current file’s name at point
|
||
:PROPERTIES:
|
||
:SOURCE: http://mbork.pl/2019-02-17_Inserting_the_current_file_name_at_point
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun insert-current-file-name-at-point (&optional full-path)
|
||
"Insert the current filename at point.
|
||
With prefix argument, use full path."
|
||
(interactive "P")
|
||
(let* ((buffer
|
||
(if (minibufferp)
|
||
(window-buffer
|
||
(minibuffer-selected-window))
|
||
(current-buffer)))
|
||
(filename (buffer-file-name buffer)))
|
||
(if filename
|
||
(insert (if full-path filename (file-name-nondirectory filename)))
|
||
(error (format "Buffer %s is not visiting a file" (buffer-name buffer))))))
|
||
#+END_SRC
|
||
|
||
** Navigation
|
||
|
||
*** Move to different beginnings of the current line
|
||
|
||
Inspired by Bozhidar Batsov's [[http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/][solution]].
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/move-to-beginning-of-line ()
|
||
"Move to different beginnings of the line.
|
||
|
||
These are, in order:
|
||
|
||
- beginning of the visual line if `visual-line-mode' is active,
|
||
- the first non-whitespace (indentation),
|
||
- the actual beginning of the line.
|
||
|
||
This function will jump between the first character and the
|
||
indentation if used multiple times."
|
||
(interactive)
|
||
(let ((last-pos (point)))
|
||
(when visual-line-mode
|
||
(beginning-of-visual-line))
|
||
(when (= (point) last-pos)
|
||
(back-to-indentation))
|
||
(when (= (point) last-pos)
|
||
(beginning-of-line))
|
||
(when (and (eq major-mode 'org-mode)
|
||
(= (point) last-pos))
|
||
(org-beginning-of-line))
|
||
(when (= (point) last-pos)
|
||
(back-to-indentation))))
|
||
#+END_SRC
|
||
|
||
*** Move to the different ends of the current line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/move-to-end-of-line ()
|
||
"Move to the end of the line.
|
||
|
||
If `visual-line-mode' is active, jump to the end of the visual
|
||
line first. Then jump to the actual end of the line."
|
||
(interactive)
|
||
(let ((last-pos (point)))
|
||
(when visual-line-mode
|
||
(end-of-visual-line))
|
||
(when (= (point) last-pos)
|
||
(end-of-line))
|
||
(when (and (eq major-mode 'org-mode)
|
||
(= (point) last-pos))
|
||
(org-end-of-line))))
|
||
#+END_SRC
|
||
|
||
*** Move to the next occurence of a character within the same line
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun goto-next-char (chr)
|
||
(interactive "c")
|
||
(let ((substr (char-to-string chr))
|
||
(end (save-excursion (end-of-line) (point))))
|
||
(when (search-forward substr end t)
|
||
(backward-char))))
|
||
#+end_src
|
||
|
||
** File manipulation
|
||
|
||
*** Rename the current file
|
||
:PROPERTIES:
|
||
:SOURCE: http://whattheemacsd.com/file-defuns.el-01.html
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun rename-current-buffer-file ()
|
||
"Renames current buffer and file it is visiting."
|
||
(interactive)
|
||
|
||
(let ((name (buffer-name))
|
||
(filename (buffer-file-name)))
|
||
(if (not (and filename (file-exists-p filename)))
|
||
(error "Buffer '%s' is not visiting a file!" name)
|
||
(let ((new-name (read-file-name "New name: " filename)))
|
||
(if (get-buffer new-name)
|
||
(error "A buffer named '%s' already exists!" new-name)
|
||
(rename-file filename new-name 1)
|
||
(rename-buffer new-name)
|
||
(set-visited-file-name new-name)
|
||
; TODO: this is suspicious for me…
|
||
(set-buffer-modified-p nil)
|
||
(message "File '%s' successfully renamed to '%s'"
|
||
name (file-name-nondirectory new-name)))))))
|
||
#+END_SRC
|
||
|
||
*** Delete the current file
|
||
:PROPERTIES:
|
||
:SOURCE: http://whattheemacsd.com/file-defuns.el-02.html
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun delete-current-buffer-file ()
|
||
"Remove file connected to current buffer and kill the buffer."
|
||
(interactive)
|
||
|
||
(let ((filename (buffer-file-name))
|
||
(name (buffer-name))
|
||
(buffer (current-buffer)))
|
||
(if (not (and filename (file-exists-p filename)))
|
||
(kill-buffer buffer)
|
||
(when (yes-or-no-p "Are you sure you want to remove this file? ")
|
||
(delete-file filename)
|
||
(kill-buffer buffer)
|
||
(message "File '%s' successfully removed" filename)))))
|
||
#+END_SRC
|
||
|
||
*** Allow reopening the previously closed file
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defvar gpolonkai/last-killed-buffer-file-name
|
||
nil
|
||
"The last killed buffer.
|
||
|
||
Used by `gpolonkai/save-killed-buffer-filename' and `gpolonkai/undo-buffer-kill'.")
|
||
|
||
(defun gpolonkai/save-killed-buffer-filename ()
|
||
"Save the filename of the killed buffer in `gpolonkai/last-killed-buffer-file-name'."
|
||
(let ((filename (buffer-file-name)))
|
||
(unless filename
|
||
(setq gpolonkai/last-killed-buffer-file-name (buffer-file-name)))))
|
||
|
||
(add-hook 'kill-buffer-hook 'gpolonkai/save-killed-buffer-filename)
|
||
|
||
(defun gpolonkai/undo-buffer-kill ()
|
||
"Undo killing the last buffer.
|
||
|
||
Esentially it visits the file again."
|
||
(interactive)
|
||
(if gpolonkai/last-killed-buffer-file-name
|
||
(progn
|
||
(find-file gpolonkai/last-killed-buffer-file-name)
|
||
(setq gpolonkai/last-killed-buffer-file-name nil))
|
||
(message "The buffer last killed didn’t visit a file.")))
|
||
#+END_SRC
|
||
|
||
*** Open this file as another user
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun open-this-file-as-other-user (user)
|
||
"Edit current file as USER, using `tramp' and `sudo'.
|
||
|
||
If the current buffer is not visiting a file, prompt for a file
|
||
name."
|
||
(interactive "sEdit as user (default: root): ")
|
||
(when (string= "" user)
|
||
(setq user "root"))
|
||
(let* ((filename (or buffer-file-name
|
||
(read-file-name (format "Find file (as %s): "
|
||
user))))
|
||
(tramp-path (concat (format "/sudo:%s@localhost:" user) filename)))
|
||
(if buffer-file-name
|
||
(find-alternate-file tramp-path)
|
||
(find-file tramp-path))))
|
||
#+END_SRC
|
||
|
||
*** Open my own ~init.el~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/visit-init-file ()
|
||
"Open the init file."
|
||
(interactive)
|
||
(find-file-other-window (expand-file-name "configuration.org" user-emacs-directory)))
|
||
#+END_SRC
|
||
|
||
*** Open my Org-mode index file
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/visit-org-index ()
|
||
"Visit the root of Org-mode notes."
|
||
(interactive)
|
||
(find-file-other-window (expand-file-name "index.org" org-directory)))
|
||
#+END_SRC
|
||
|
||
** Frame manipulation
|
||
|
||
*** Hidden modeline mode
|
||
:PROPERTIES:
|
||
:SOURCE: http://emacs-doctor.com/emacs-strip-tease.html
|
||
:END:
|
||
|
||
To temporarily hide the mode line.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defvar hidden-mode-line-mode nil)
|
||
(defvar hide-mode-line nil)
|
||
|
||
(define-minor-mode hidden-mode-line-mode
|
||
"Minor mode to hide the mode-line in the current buffer."
|
||
:init-value nil
|
||
:global nil
|
||
:variable hidden-mode-line-mode
|
||
:group 'editing-basics
|
||
(if hidden-mode-line-mode
|
||
(setq hide-mode-line mode-line-format
|
||
mode-line-format nil)
|
||
(setq mode-line-format hide-mode-line
|
||
hide-mode-line nil))
|
||
(force-mode-line-update)
|
||
(redraw-display)
|
||
(when (and (called-interactively-p 'interactive)
|
||
hidden-mode-line-mode)
|
||
(run-with-idle-timer
|
||
0 nil 'message
|
||
(concat "Hidden Mode Line Mode enabled. "
|
||
"Use M-x hidden-mode-line-mode to make mode-line appear."))))
|
||
#+END_SRC
|
||
|
||
** Window manipulation
|
||
|
||
*** Transpose windows
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun transpose-windows (arg)
|
||
"Transpose the buffers shown in two windows."
|
||
(interactive "p")
|
||
(let ((selector (if (>= arg 0) 'next-window 'previous-window)))
|
||
(while (/= arg 0)
|
||
(let ((this-win (window-buffer))
|
||
(next-win (window-buffer (funcall selector))))
|
||
(set-window-buffer (selected-window) next-win)
|
||
(set-window-buffer (funcall selector) this-win)
|
||
(select-window (funcall selector)))
|
||
(setq arg (if (plusp arg) (1- arg) (1+ arg))))))
|
||
#+END_SRC
|
||
|
||
*** Toggle window split between horizontal and vertical
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun toggle-window-split ()
|
||
(interactive)
|
||
(if (= (count-windows) 2)
|
||
(let* ((this-win-buffer (window-buffer))
|
||
(next-win-buffer (window-buffer (next-window)))
|
||
(this-win-edges (window-edges (selected-window)))
|
||
(next-win-edges (window-edges (next-window)))
|
||
(this-win-2nd (not (and (<= (car this-win-edges)
|
||
(car next-win-edges))
|
||
(<= (cadr this-win-edges)
|
||
(cadr next-win-edges)))))
|
||
(splitter
|
||
(if (= (car this-win-edges)
|
||
(car (window-edges (next-window))))
|
||
'split-window-horizontally
|
||
'split-window-vertically)))
|
||
(delete-other-windows)
|
||
(let ((first-win (selected-window)))
|
||
(funcall splitter)
|
||
(if this-win-2nd (other-window 1))
|
||
(set-window-buffer (selected-window) this-win-buffer)
|
||
(set-window-buffer (next-window) next-win-buffer)
|
||
(select-window first-win)
|
||
(if this-win-2nd (other-window 1))))
|
||
(error "This works only for two windows!")))
|
||
#+END_SRC
|
||
|
||
*** Scroll up or down in a specific window
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/scroll-window-up (window)
|
||
"Scroll WINDOW up as `scroll-up-command' would."
|
||
(interactive)
|
||
(save-selected-window
|
||
(select-window window)
|
||
(scroll-up)))
|
||
|
||
(defun gpolonkai/scroll-window-down (window)
|
||
"Scroll WINDOW down as `scroll-down-command' would."
|
||
(interactive)
|
||
(save-selected-window
|
||
(select-window window)
|
||
(scroll-down)))
|
||
#+END_SRC
|
||
|
||
*** Bury a window
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/bury-window (window)
|
||
"Quit WINDOW without killing it."
|
||
(interactive)
|
||
(quit-window nil window))
|
||
#+END_SRC
|
||
|
||
** ~c-mode~ related
|
||
|
||
*** Copy the prototype of the current function
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/copy-func-prototype ()
|
||
"Copy the current function's prototype to the kill ring."
|
||
|
||
(interactive)
|
||
|
||
(save-excursion
|
||
(beginning-of-defun)
|
||
(let ((protocopy-begin (point)))
|
||
(forward-list)
|
||
(let ((protocopy-end (point)))
|
||
(kill-ring-save protocopy-begin protocopy-end)))))
|
||
#+END_SRC
|
||
|
||
** Programming related
|
||
|
||
*** Check if we are inside a string
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/prog-in-string-p ()
|
||
"Return t if point is inside a string."
|
||
(nth 3 (syntax-ppss)))
|
||
#+END_SRC
|
||
|
||
*** Check if we are inside a comment
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/prog-in-comment-p ()
|
||
"Return t if point is inside a comment."
|
||
(nth 4 (syntax-ppss)))
|
||
#+END_SRC
|
||
|
||
*** Add code references to Org documents
|
||
:PROPERTIES:
|
||
:SOURCE: http://www.howardism.org/Technical/Emacs/capturing-content.html
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun ha/org-capture-fileref-snippet (f type headers func-name)
|
||
(let* ((code-snippet
|
||
(buffer-substring-no-properties (mark) (- (point) 1)))
|
||
(file-name (buffer-file-name))
|
||
(file-base (file-name-nondirectory file-name))
|
||
(line-number (line-number-at-pos (region-beginning)))
|
||
(initial-txt (if (null func-name)
|
||
(format "From [[file:%s::%s][%s]]:"
|
||
file-name line-number file-base)
|
||
(format "From ~%s~ (in [[file:%s::%s][%s]]):"
|
||
func-name file-name line-number
|
||
file-base))))
|
||
(format "
|
||
%s
|
||
|
||
,#+BEGIN_%s %s
|
||
%s
|
||
,#+END_%s" initial-txt type headers code-snippet type)))
|
||
|
||
(defun ha/org-capture-clip-snippet (f)
|
||
"Given a file, F, this captures the currently selected text
|
||
within an Org EXAMPLE block and a backlink to the file."
|
||
(with-current-buffer (find-buffer-visiting f)
|
||
(ha/org-capture-fileref-snippet f "EXAMPLE" "" nil)))
|
||
|
||
(defun ha/org-capture-code-snippet (f)
|
||
"Given a file, F, this captures the currently selected text
|
||
within an Org SRC block with a language based on the current mode
|
||
and a backlink to the function and the file."
|
||
(with-current-buffer (find-buffer-visiting f)
|
||
(let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode)))
|
||
(func-name (which-function)))
|
||
(ha/org-capture-fileref-snippet f "SRC" org-src-mode func-name))))
|
||
#+END_SRC
|
||
|
||
** ~python-mode~ related
|
||
|
||
*** Add a docstring to the current thing
|
||
|
||
…be it a function, class, or a module
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/python-add-docstring ()
|
||
"Add a Python docstring to the current thing.
|
||
|
||
If point is inside a function, add docstring to that. If point
|
||
is in a class, add docstring to that. If neither, add docstring
|
||
to the beginning of the file."
|
||
(interactive)
|
||
(save-restriction
|
||
(widen)
|
||
(beginning-of-defun)
|
||
(if (not (looking-at-p "\\(def\\|class\\) "))
|
||
(progn
|
||
(goto-char (point-min))
|
||
(back-to-indentation)
|
||
(forward-char)
|
||
(while (gpolonkai/prog-in-comment-p)
|
||
(forward-line)
|
||
(back-to-indentation)
|
||
(forward-char)))
|
||
(search-forward ":")
|
||
(while (or (gpolonkai/prog-in-string-p)
|
||
(gpolonkai/prog-in-comment-p))
|
||
(search-forward ":")))
|
||
(if (eq 1 (count-lines 1 (point)))
|
||
(open-line-above)
|
||
(open-line-below))
|
||
(insert "\"\"\"")
|
||
(let ((point-pos (point)))
|
||
(open-line-below)
|
||
(insert "\"\"\"\n")
|
||
(goto-char point-pos))))
|
||
#+END_SRC
|
||
|
||
*** Font-lock variables in f-strings
|
||
:PROPERTIES:
|
||
:SOURCE: https://emacs.stackexchange.com/a/55186/507
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp :tangle no
|
||
(with-eval-after-load "python"
|
||
(setq python-font-lock-keywords
|
||
(append python-font-lock-keywords
|
||
'(;; this is the full string.
|
||
;; group 1 is the quote type and a closing quote is matched
|
||
;; group 2 is the string part
|
||
("f\\(['\"]\\{1,3\\}\\)\\([^\\1]+?\\)\\1"
|
||
;; these are the {keywords}
|
||
("{[^}]*?}"
|
||
;; Pre-match form
|
||
(progn (goto-char (match-beginning 0)) (match-end 0))
|
||
;; Post-match form
|
||
(goto-char (match-end 0))
|
||
;; face for this match
|
||
(0 font-lock-variable-name-face t)))))))
|
||
#+END_SRC
|
||
|
||
** Jinja related
|
||
|
||
*** Mark a string as translatable
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun jinja-mark-translatable (begin end)
|
||
(interactive (if (use-region-p)
|
||
(list (region-beginning) (region-end))
|
||
(list (point-min) (point-max))))
|
||
(save-excursion
|
||
(goto-char end)
|
||
(insert "{% endtrans %}")
|
||
(goto-char begin)
|
||
(insert "{% trans %}")))
|
||
#+END_SRC
|
||
|
||
*** URL-ify and de-URL-ify region
|
||
|
||
These functions URL-encode/decode a text. Might be helpful when embedding/extracting data to/from
|
||
HTML.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun hex-region (start end)
|
||
"urlencode the region between START and END in current buffer."
|
||
(interactive "r")
|
||
(func-region start end #'url-hexify-string))
|
||
|
||
(defun unhex-region (start end)
|
||
"de-urlencode the region between START and END in current buffer."
|
||
(interactive "r")
|
||
(func-region start end #'url-unhex-string))
|
||
#+END_SRC
|
||
|
||
** Automatically zone out after 60 seconds
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/zone-enable ()
|
||
"Enable zoning out."
|
||
(interactive)
|
||
(zone-when-idle 60)
|
||
(message "I will zone out after idling for 60 seconds."))
|
||
#+END_SRC
|
||
|
||
** Utility functions for editing Zim wiki files
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun zim-timestamp ()
|
||
(with-temp-buffer
|
||
(insert (format-time-string "%Y-%m-%dT%H:%M:%S%z"))
|
||
(forward-char -2)
|
||
(insert ":")
|
||
(buffer-string)))
|
||
|
||
(defun insert-zim-timestamp ()
|
||
(interactive)
|
||
(insert (zim-timestamp)))
|
||
|
||
(defun insert-zim-header ()
|
||
(interactive)
|
||
(save-excursion
|
||
(goto-char (point-min))
|
||
(insert
|
||
(concat "Content-Type: text/x-zim-wiki\n"
|
||
"Wiki-Format: zim 0.4\n"
|
||
"Creation-Date: " (zim-timestamp) "\n\n"))))
|
||
#+END_SRC
|
||
|
||
** Utility functions for EDiff
|
||
:PROPERTIES:
|
||
:SOURCE: http://article.gmane.org/gmane.emacs.orgmode/75222
|
||
:END:
|
||
|
||
EDiff and Org-mode files don’t play nice together…
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun f-ediff-org-showhide (buf command &rest cmdargs)
|
||
"If buffer BUF exists and in `org-mode', execute COMMAND with CMDARGS."
|
||
(when buf
|
||
(when (eq (buffer-local-value 'major-mode (get-buffer buf)) 'org-mode)
|
||
(save-excursion
|
||
(set-buffer buf)
|
||
(apply command cmdargs)))))
|
||
|
||
(defun f-ediff-org-unfold-tree-element ()
|
||
"Unfold tree at diff location."
|
||
(f-ediff-org-showhide ediff-buffer-A 'org-reveal)
|
||
(f-ediff-org-showhide ediff-buffer-B 'org-reveal)
|
||
(f-ediff-org-showhide ediff-buffer-C 'org-reveal))
|
||
|
||
(defun f-ediff-org-fold-tree ()
|
||
"Fold tree back to top level."
|
||
(f-ediff-org-showhide ediff-buffer-A 'hide-sublevels 1)
|
||
(f-ediff-org-showhide ediff-buffer-B 'hide-sublevels 1)
|
||
(f-ediff-org-showhide ediff-buffer-C 'hide-sublevels 1))
|
||
#+END_SRC
|
||
|
||
** Leave ~isearch~ at the other end of the matched string
|
||
:PROPERTIES:
|
||
:SOURCE: http://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.html
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun isearch-exit-other-end ()
|
||
"Exit isearch, at the opposite end of the string."
|
||
(interactive)
|
||
|
||
(isearch-exit)
|
||
(goto-char isearch-other-end))
|
||
#+END_SRC
|
||
|
||
** Mark the current match after leaving ~isearch~
|
||
:PROPERTIES:
|
||
:SOURCE: http://emacs.stackexchange.com/a/31321/507
|
||
:END:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun isearch-exit-mark-match ()
|
||
"Exit isearch and mark the current match."
|
||
(interactive)
|
||
(isearch-exit)
|
||
(push-mark isearch-other-end)
|
||
(activate-mark))
|
||
#+END_SRC
|
||
|
||
** Turn the cursor to purple if Yasnippet’s TAB function would fire
|
||
|
||
Taken from [[http://pages.sachachua.com/.emacs.d/Sacha.html][Sacha Chua’s config]].
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
;; TODO: 'cursor-color is sometimes nil, but why?
|
||
(setq default-cursor-color (or (frame-parameter nil 'cursor-color) "#ffd85c"))
|
||
(setq yasnippet-can-fire-cursor-color "purple")
|
||
|
||
;; It will test whether it can expand, if yes, cursor color -> purple.
|
||
(defun yasnippet-can-fire-p (&optional field)
|
||
"Check if the word before point can be expanded with yasnippet.
|
||
|
||
TODO: What is FIELD for?"
|
||
(interactive)
|
||
(setq yas--condition-cache-timestamp (current-time))
|
||
(let (templates-and-pos)
|
||
(unless (and yas-expand-only-for-last-commands
|
||
(not (member last-command yas-expand-only-for-last-commands)))
|
||
(setq templates-and-pos (if field
|
||
(save-restriction
|
||
(narrow-to-region (yas--field-start field)
|
||
(yas--field-end field))
|
||
(yas--templates-for-key-at-point))
|
||
(yas--templates-for-key-at-point))))
|
||
(and templates-and-pos (first templates-and-pos))))
|
||
|
||
(defun sachachua/change-cursor-color-when-can-expand (&optional field)
|
||
"Change cursor color if the text before point can be expanded with yasnippet.
|
||
|
||
TODO: What is FIELD for?"
|
||
(interactive)
|
||
(when (eq last-command 'self-insert-command)
|
||
(set-cursor-color (if (sachachua/can-expand)
|
||
yasnippet-can-fire-cursor-color
|
||
default-cursor-color))))
|
||
|
||
(defun sachachua/can-expand ()
|
||
"Return t if right after an expandable thing."
|
||
(or (abbrev--before-point) (yasnippet-can-fire-p)))
|
||
#+END_SRC
|
||
|
||
** Org mode stuff
|
||
|
||
*** Filter out tasks from the Org agenda if they have a specific priority
|
||
|
||
The whole idea comes from [[https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html][here]], which i use almost verbatim. This is also the reason it has the
|
||
~air-~ prefix.
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun air-org-skip-subtree-if-priority (priority)
|
||
"Skip an agenda subtree if it has a priority of PRIORITY.
|
||
|
||
PRIORITY may be one of the characters ?A, ?B, or ?C."
|
||
(let ((subtree-end (save-excursion (org-end-of-subtree t)))
|
||
(pri-value (* 1000 (- org-lowest-priority priority)))
|
||
(pri-current (org-get-priority (thing-at-point 'line t))))
|
||
(if (= pri-value pri-current)
|
||
subtree-end
|
||
nil)))
|
||
#+end_src
|
||
|
||
*** Filter out habits from the Org agenda
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun air-org-skip-subtree-if-habit ()
|
||
"Skip an agenda entry if it has a STYLE property equal to \"habit\"."
|
||
(let ((subtree-end (save-excursion (org-end-of-subtree t))))
|
||
(if (string= (org-entry-get nil "STYLE") "habit")
|
||
subtree-end
|
||
nil)))
|
||
#+end_src
|
||
|
||
*** Filter out entries from the Org agenda with a specific state
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun gpolonkai/org-skip-subtree-if-state (state)
|
||
"Skip an agenda entry if its state is STATE."
|
||
(let ((subtree-end (save-excursion (org-end-of-subtree t))))
|
||
(if (string= (org-get-todo-state) state)
|
||
subtree-end
|
||
nil)))
|
||
#+end_src
|
||
|
||
*** Wrapper around ~org-agenda~ to open my own custom list
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun gpolonkai/org-agenda-list (&optional arg)
|
||
(interactive "P")
|
||
(org-agenda arg "c"))
|
||
#+end_src
|
||
|
||
*** Insert the current timestamp
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun gpolonkai/org-insert-current-timestamp (&optional arg)
|
||
"Insert the current timestamp"
|
||
(interactive "P")
|
||
(org-time-stamp '(16) arg))
|
||
#+end_src
|
||
|
||
*** Insert a heading with CREATED set to the current time
|
||
|
||
This emulates how Orgzly work with my current settings.
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun gpolonkai/org-insert-heading-created (&optional arg)
|
||
(interactive "p")
|
||
(let* ((org-insert-heading-respect-content t)
|
||
(format-string (concat "[" (substring (cdr org-time-stamp-formats) 1 -1) "]"))
|
||
(timestamp (format-time-string format-string (current-time))))
|
||
(if (> arg 1)
|
||
(org-insert-subheading '(4))
|
||
(org-insert-heading))
|
||
(org-set-property "CREATED" timestamp)))
|
||
#+end_src
|
||
|
||
* UI preferences
|
||
|
||
** Tweak window chrome
|
||
|
||
Turn off the scroll bar (that’s why Nyan-cat is here), the toolbar (I don’t really use it), and
|
||
the menu bar (I rarely use it, and in those rare occasions I can simply turn it on.)
|
||
|
||
Also, maximise the frame.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(tool-bar-mode 0)
|
||
(menu-bar-mode 0)
|
||
(when window-system
|
||
(scroll-bar-mode -1))
|
||
|
||
(set-frame-parameter nil 'fullscreen 'maximized)
|
||
#+END_SRC
|
||
|
||
** Set the default font and configure font resizing
|
||
|
||
Before this can be used, make sure the [[https://zhm.github.io/symbola/][Symbola]] font is installed.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/set-font-size (frame)
|
||
(when (display-graphic-p frame)
|
||
(set-face-attribute 'default frame :font "Hack-12")
|
||
(set-frame-font "Hack-12" t (list frame))))
|
||
|
||
(defun --set-emoji-font (frame)
|
||
"Adjust the font setting of FRAME so Emacs can display Emoji properly."
|
||
(when (display-graphic-p frame)
|
||
(set-fontset-font t 'symbol
|
||
(font-spec :family "Symbola")
|
||
frame 'prepend)
|
||
(set-fontset-font t 'unicode
|
||
"Noto Emoji"
|
||
nil 'append)))
|
||
|
||
(add-hook 'after-make-frame-functions 'gpolonkai/set-font-size)
|
||
(add-hook 'after-make-frame-functions '--set-emoji-font)
|
||
|
||
(gpolonkai/set-font-size nil)
|
||
(--set-emoji-font nil)
|
||
#+END_SRC
|
||
|
||
* Set up global minor modes provided by Emacs
|
||
|
||
** Pretty lambdas
|
||
|
||
Because we can.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(global-prettify-symbols-mode t)
|
||
#+END_SRC
|
||
|
||
And set up all the pretty symbols.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq prettify-symbols-alist
|
||
'(("lambda" . 955) ; λ
|
||
("function" . 402) ; ƒ
|
||
("->" . 8594) ; →
|
||
("=>" . 8658) ; ⇒
|
||
("map" . 8614) ; ↦
|
||
("not" . 172))) ; ¬
|
||
#+END_SRC
|
||
|
||
…and some pairs to complete
|
||
|
||
*************** TODO Maybe add-to-list is a better way to do it
|
||
*************** END
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq insert-pair-alist '(
|
||
(40 41) ; ()
|
||
(91 93) ; []
|
||
(123 125) ; {}
|
||
(60 62) ; <>
|
||
(34 34) ; ""
|
||
(39 39) ; ''
|
||
(96 39) ; `'
|
||
(8220 8221) ; “”
|
||
(8222 8221) ; „”
|
||
(8216 8217) ; ‘’
|
||
(8249 8250) ; ‹›
|
||
(8250 8249) ; ›‹
|
||
(171 187) ; «»
|
||
(187 171))) ; »«
|
||
#+END_SRC
|
||
|
||
Finally, set the frame title to the current file name
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq frame-title-format '((:eval (concat system-name
|
||
": "
|
||
(if (buffer-file-name)
|
||
(abbreviate-file-name (buffer-file-name))
|
||
"%b")))))
|
||
#+END_SRC
|
||
|
||
** Treat soft line breaks as hard ones in textual modes
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-hook 'text-mode-hook (lambda () (visual-line-mode t)))
|
||
#+END_SRC
|
||
|
||
* Enable disabled commands
|
||
|
||
Because i’m a rock star like that.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(put 'downcase-region 'disabled nil)
|
||
(put 'upcase-region 'disabled nil)
|
||
(put 'erase-buffer 'disabled nil)
|
||
(put 'narrow-to-region 'disabled nil)
|
||
(put 'narrow-to-page 'disabled nil)
|
||
(put 'set-goal-column 'disabled nil)
|
||
(put 'scroll-left 'disabled nil)
|
||
(put 'dired-find-alternate-file 'disabled nil)
|
||
(put 'Info-edit 'disabled nil)
|
||
(put 'list-timers 'disabled nil)
|
||
#+END_SRC
|
||
|
||
* Packages installed from Quelpa
|
||
|
||
For some strange reason having this at the end of my configuration can cause unexpected results.
|
||
|
||
** Matrix client
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package matrix-client
|
||
:after quelpa-use-package
|
||
:ensure nil
|
||
:quelpa (matrix-client :fetcher github :repo "alphapapa/matrix-client.el"
|
||
:files (:defaults "logo.png" "matrix-client-standalone.el.sh")))
|
||
#+END_SRC
|
||
|
||
** Ement
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package plz
|
||
:ensure nil
|
||
:quelpa (plz :fetcher github :repo "alphapapa/plz.el"))
|
||
|
||
(use-package ement
|
||
:ensure nil
|
||
:quelpa (ement :fetcher github :repo "alphapapa/ement.el")
|
||
:custom
|
||
(ement-save-token t))
|
||
#+end_src
|
||
|
||
* Load some built-in libraries
|
||
|
||
** ~thingatpt~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package thingatpt
|
||
:ensure nil)
|
||
#+END_SRC
|
||
|
||
** Calendar
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package calendar
|
||
:ensure nil
|
||
:init
|
||
(setq calendar-week-start-day 1
|
||
calendar-latitude 47.4
|
||
calendar-longitude 19.0
|
||
calendar-location-name "Budapest, Hungary"
|
||
calendar-time-zone 60
|
||
calendar-standard-time-zone-name "CET"
|
||
calendar-daylight-time-zone-name "CEST"))
|
||
#+END_SRC
|
||
|
||
*** Add the SysAdmin day to the calendar
|
||
|
||
Because I’m a sysadmin, too.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-to-list 'holiday-other-holidays '(holiday-float 7 5 -1 "SysAdmin Day") t)
|
||
(add-to-list 'holiday-other-holidays '(holiday-fixed 10 21 "Reptile Awareness Day") t)
|
||
#+END_SRC
|
||
|
||
** nXML
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package nxml-mode
|
||
:ensure nil
|
||
:custom
|
||
(nxml-attribute-indent 4)
|
||
(nxml-child-indent 4)
|
||
(nxml-outline-child-indent 4))
|
||
#+END_SRC
|
||
|
||
** ~recentf~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package recentf
|
||
:ensure nil
|
||
:config
|
||
(run-at-time nil (* 5 60) 'recentf-save-list)
|
||
(add-to-list 'recentf-exclude (expand-file-name "elpa" user-emacs-directory)))
|
||
#+END_SRC
|
||
|
||
** ~files~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package files
|
||
:ensure nil
|
||
:custom
|
||
(make-backup-file-name-function 'xah/backup-file-name))
|
||
#+END_SRC
|
||
|
||
** ~whitespace~
|
||
~whitespace-mode~ is turned on by default, and can be toggled with ~F10~.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun prevent-whitespace-mode-for-some ()
|
||
"Prevent whitespace-mode from running in some modes."
|
||
(and
|
||
(not (derived-mode-p 'magit-mode))
|
||
(not (derived-mode-p 'org-mode))))
|
||
|
||
(use-package whitespace
|
||
:demand
|
||
:config
|
||
(add-function :before-while whitespace-enable-predicate 'prevent-whitespace-mode-for-some)
|
||
(global-whitespace-mode 1)
|
||
:custom
|
||
(whitespace-line-column 100)
|
||
:bind
|
||
(([f10] . whitespace-mode)
|
||
([(shift f10)] . global-whitespace-mode)
|
||
:map gpolonkai/pers-map
|
||
("w" . whitespace-cleanup)))
|
||
#+END_SRC
|
||
|
||
** ~eshell~
|
||
|
||
This is a function to delete a character, or close ~eshell~ if there’s nothing to delete. Taken
|
||
from [[https://ryuslash.org/posts/C-d-to-close-eshell.html][here]].
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun eshell-C-d ()
|
||
"Either call `delete-char' interactively or quit."
|
||
(interactive)
|
||
|
||
(condition-case err
|
||
(call-interactively #'delete-char)
|
||
(error (if (and (eq (car err) 'end-of-buffer)
|
||
(looking-back eshell-prompt-regexp nil))
|
||
(kill-buffer)
|
||
(signal (car err) (cdr err))))))
|
||
#+END_SRC
|
||
|
||
Function to bind it locally to =C-d=.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/eshell-set-c-d-locally ()
|
||
(local-set-key (kbd "C-d") #'eshell-C-d))
|
||
#+END_SRC
|
||
|
||
Now set up eshell.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package eshell
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("e" . eshell))
|
||
:hook
|
||
(eshell-mode . gpolonkai/eshell-set-c-d-locally))
|
||
#+END_SRC
|
||
|
||
** ~saveplace~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
;; Save place
|
||
(use-package saveplace
|
||
:config'
|
||
(save-place-mode 1)
|
||
:custom
|
||
(save-place-file (expand-file-name ".places" user-emacs-directory)))
|
||
#+END_SRC
|
||
|
||
** EDiff
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ediff
|
||
:custom
|
||
(ediff-merge-split-window-function 'split-window-horizontally)
|
||
(ediff-split-window-function 'split-window-vertically)
|
||
(ediff-window-setup-function 'ediff-setup-windows-plain))
|
||
#+END_SRC
|
||
|
||
** Automatically revert changed files
|
||
|
||
…unless they are modified, of course.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package autorevert
|
||
:config
|
||
(global-auto-revert-mode 1))
|
||
#+END_SRC
|
||
|
||
** Eww
|
||
|
||
For in-Emacs browsing needs.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package eww
|
||
:custom
|
||
(eww-search-prefix "https://duckduckgo.com/html/?q="))
|
||
#+END_SRC
|
||
|
||
** Electric indent mode
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package electric
|
||
:config
|
||
;; This seems to be the default, but let’s make sure…
|
||
(electric-indent-mode 1))
|
||
#+END_SRC
|
||
|
||
** Save history
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package savehist
|
||
:config
|
||
(savehist-mode 1))
|
||
#+END_SRC
|
||
|
||
** Web jump
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package webjump
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("j" . webjump)))
|
||
#+END_SRC
|
||
|
||
** Which function am i in?
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/activate-which-func-mode ()
|
||
(if (fboundp 'which-function-mode)
|
||
(which-function-mode)
|
||
(which-func-mode)))
|
||
#+END_SRC
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package which-func
|
||
:config
|
||
(setq which-func-unknown "∅")
|
||
:hook
|
||
(prog-mode . gpolonkai/activate-which-func-mode))
|
||
#+END_SRC
|
||
|
||
** Fortune cookies
|
||
|
||
The cookies are from the Hungarian version an ancient MS-DOS based program called ~TAGLINE~.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package cookie1
|
||
:demand t
|
||
:custom
|
||
(cookie-file (expand-file-name "fortune-cookies.txt" user-emacs-directory))
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("k" . cookie)))
|
||
#+END_SRC
|
||
|
||
** Browse URL functionality in Termux
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(when (termux-p)
|
||
(use-package browse-url
|
||
:ensure nil
|
||
:config
|
||
(advice-add 'browse-url-default-browser :override
|
||
(lambda (url &rest args)
|
||
(start-process-shell-command
|
||
"open-url"
|
||
nil
|
||
(concat "am start -a android.intent.action.VIEW --user 0 -d "
|
||
url))))))
|
||
#+END_SRC
|
||
|
||
** Dired customisation
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired
|
||
:ensure nil
|
||
:custom
|
||
(dired-dwim-target t)
|
||
(wdired-create-parent-directories t)
|
||
(wdired-allow-to-change-permissions t)
|
||
:bind
|
||
(:map dired-mode-map
|
||
("RET" . dired-find-alternate-file)
|
||
("^" . (lambda () (interactive) (find-alternate-file "..")))
|
||
("W" . wdired-change-to-wdired-mode)))
|
||
#+END_SRC
|
||
|
||
** Actionable URLs
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package goto-addr
|
||
:hook ((compilation-mode . goto-address-mode)
|
||
(prog-mode . goto-address-prog-mode)
|
||
(eshell-mode . goto-address-mode)
|
||
(shell-mode . goto-address-mode))
|
||
:bind
|
||
(:map goto-address-highlight-keymap
|
||
("<RET>" . goto-address-at-point)
|
||
("M-<RET>" . newline))
|
||
:commands (goto-address-prog-mode goto-address-mode))
|
||
#+END_SRC
|
||
|
||
** Do things at midnight
|
||
|
||
By default, it closes a bunch of unused buffers. I might add some more things there later.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package midnight
|
||
:ensure nil
|
||
:config
|
||
(setq clean-buffer-list-kill-never-buffer-names '("*scratch*"
|
||
"*Messages*"
|
||
"*dashboard*"))
|
||
(midnight-mode t))
|
||
#+END_SRC
|
||
|
||
** Show line numbers
|
||
|
||
I don’t usually like to see them, but there are occasions when they can be useful.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package display-line-numbers
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("C-n" . display-line-numbers-mode)))
|
||
#+END_SRC
|
||
|
||
** Check for spelling errors
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ispell
|
||
:custom
|
||
(ispell-dictionary "en_GB")
|
||
(ispell-program-name "/usr/bin/aspell")
|
||
:hook
|
||
(mail-send . ispell-message)
|
||
(message-send . ispell-message))
|
||
#+END_SRC
|
||
|
||
** Speed bar
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package speedbar)
|
||
#+END_SRC
|
||
|
||
* ~use-package~ packages
|
||
|
||
** Make sure we have the latest ELPA GPG keys
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package gnu-elpa-keyring-update)
|
||
#+END_SRC
|
||
|
||
** Automatically upgrade packages every week
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package auto-package-update
|
||
:custom
|
||
(auto-package-update-interval 7)
|
||
(auto-package-update-delete-old-versions t)
|
||
;; Let’s do this in after-init-hook, as use-package invocations may modify
|
||
;; the list of installed packages
|
||
:hook
|
||
(after-init . auto-package-update-maybe))
|
||
#+END_SRC
|
||
|
||
** Nyanyanyanyanya
|
||
|
||
*** Nyan-cat style position marker
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package nyan-mode
|
||
:config
|
||
(nyan-mode t)
|
||
:custom
|
||
(nyan-bar-length 20)
|
||
(nyan-animate-nyancat t)
|
||
(nyan-wavy-trail t))
|
||
#+END_SRC
|
||
|
||
*** Nyan prompt in EShell
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package nyan-prompt
|
||
:disabled
|
||
:hook
|
||
(eshell-load . nyan-prompt-enable))
|
||
#+END_SRC
|
||
|
||
*** Zone out with Nyancat
|
||
|
||
Unfortunately, this works only in a graphical mode.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package zone-nyan
|
||
:after
|
||
zone
|
||
:config
|
||
(setq zone-programs (vconcat zone-programs [zone-nyan]))
|
||
:custom
|
||
(zone-nyan-hide-progress t))
|
||
#+END_SRC
|
||
|
||
** De-light some minor modes
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package delight)
|
||
#+END_SRC
|
||
|
||
** Eye candy
|
||
|
||
*** Moody mode-line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package moody
|
||
:config
|
||
(moody-replace-mode-line-buffer-identification)
|
||
(moody-replace-vc-mode)
|
||
(set-face-attribute 'mode-line nil :box nil :foreground "#7e7486")
|
||
(set-face-attribute 'mode-line-inactive nil :box nil)
|
||
:custom
|
||
(moody-mode-line-height 18))
|
||
#+END_SRC
|
||
|
||
*** Minions
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package minions
|
||
:config
|
||
(minions-mode 1))
|
||
#+END_SRC
|
||
|
||
*** Spinner, e.g. to display running background tasks
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package spinner)
|
||
#+END_SRC
|
||
|
||
*** Beacon
|
||
|
||
Highlight point. Sometimes it’s not easy to see.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package beacon
|
||
:demand
|
||
:config
|
||
(beacon-mode 1)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("b" . beacon-blink)))
|
||
#+END_SRC
|
||
|
||
*** Display the status of the last command in the fringe of EShell
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package eshell-fringe-status
|
||
:hook
|
||
(eshell-mode . eshell-fringe-status-mode))
|
||
#+END_SRC
|
||
|
||
*** Extras for the EShell prompt
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package eshell-prompt-extras
|
||
:config
|
||
(with-eval-after-load "esh-opt"
|
||
(autoload 'epe-theme-lambda "eshell-prompt-extras"))
|
||
:custom
|
||
(eshell-highlight-prompt nil)
|
||
(eshell-prompt-function 'epe-theme-lambda))
|
||
#+END_SRC
|
||
|
||
*** Show form feeds as a horizontal line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package form-feed
|
||
:hook
|
||
(emacs-lisp-mode . form-feed-mode)
|
||
(compilation-mode . form-feed-mode)
|
||
(help-mode . form-feed-mode))
|
||
#+END_SRC
|
||
|
||
** Highlight the current line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package hl-line
|
||
:config
|
||
(when window-system
|
||
(global-hl-line-mode)))
|
||
#+END_SRC
|
||
|
||
** GNU Globals
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/cond-enable-ggtags-mode ()
|
||
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
|
||
(ggtags-mode t)))
|
||
|
||
(use-package ggtags
|
||
:hook
|
||
(c-mode-common . gpolonkai/cond-enable-ggtags-mode))
|
||
#+END_SRC
|
||
|
||
** Multiple cursors
|
||
|
||
Because one is never enough.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/no-blink-matching-paren ()
|
||
(customize-set-variable 'blink-matching-paren nil))
|
||
|
||
(defun gpolonkai/blink-matching-paren ()
|
||
(customize-set-variable 'blink-matching-paren t))
|
||
|
||
(use-package multiple-cursors
|
||
:init
|
||
(defvar gpolonkai/mc-prefix-map (make-sparse-keymap)
|
||
"Prefix keymap for multiple-cursors")
|
||
(define-prefix-command 'gpolonkai/mc-prefix-map)
|
||
(define-key global-map (kbd "C-c m") 'gpolonkai/mc-prefix-map)
|
||
:hook
|
||
(multiple-cursors-mode-enabled . gpolonkai/no-blink-matching-paren)
|
||
(multiple-cursors-mode-disabled . gpolonkai/blink-matching-paren)
|
||
:bind
|
||
(:map gpolonkai/mc-prefix-map
|
||
("t" . mc/mark-all-like-this)
|
||
("m" . mc/mark-all-like-this-dwim)
|
||
("l" . mc/edit-lines)
|
||
("e" . mc/edit-ends-of-lines)
|
||
("a" . mc/edit-beginnings-of-lines)
|
||
("n" . mc/mark-next-like-this)
|
||
("p" . mc/mark-previous-like-this)
|
||
("s" . mc/mark-sgml-tag-pair)
|
||
("d" . mc/mark-all-like-this-in-defun)
|
||
("M-<mouse-1>" . mc/add-cursor-on-click)))
|
||
#+END_SRC
|
||
|
||
*** Incremental search for multiple cursors
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package phi-search)
|
||
|
||
(use-package phi-search-mc
|
||
:config
|
||
(phi-search-mc/setup-keys))
|
||
#+END_SRC
|
||
|
||
*** Some extras
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package mc-extras
|
||
:demand
|
||
:bind
|
||
(:map mc/keymap
|
||
("C-c m =" . mc/compare-chars)))
|
||
#+END_SRC
|
||
|
||
*** Add extra cursors via ~ace-jump~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ace-mc
|
||
:bind
|
||
(:map gpolonkai/mc-prefix-map
|
||
("SPC" . ace-mc-add-multiple-cursors)
|
||
("C-SPC" . ace-mc-add-single-cursor)))
|
||
#+END_SRC
|
||
|
||
** Magit
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package magit
|
||
:custom
|
||
(magit-auto-revert-mode nil)
|
||
(magit-last-seen-setup-instructions "1.4.0")
|
||
:bind
|
||
(:map ctl-x-map
|
||
("g" . magit-status))
|
||
:hook
|
||
(git-commit-mode . turn-on-flyspell))
|
||
|
||
#+END_SRC
|
||
|
||
*** Make Magit work with Git forges
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package forge)
|
||
#+END_SRC
|
||
|
||
** Zone
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package zone
|
||
:demand
|
||
:config
|
||
(zone-when-idle 60)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("zi" . gpolonkai/zone-enable)
|
||
("zq" . zone-leave-me-alone)))
|
||
#+END_SRC
|
||
|
||
** Origami
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package origami
|
||
:demand
|
||
:config
|
||
(define-prefix-command 'origami-mode-map)
|
||
(define-key ctl-x-map (kbd "z") 'origami-mode-map)
|
||
(global-origami-mode)
|
||
:bind
|
||
(:map origami-mode-map
|
||
("o" . origami-open-node)
|
||
("O" . origami-open-node-recursively)
|
||
("c" . origami-close-node)
|
||
("C" . origami-close-node-recursively)
|
||
("a" . origami-toggle-node)
|
||
("A" . origami-recursively-toggle-node)
|
||
("R" . origami-open-all-nodes)
|
||
("M" . origami-close-all-nodes)
|
||
("v" . origami-show-only-node)
|
||
("k" . origami-previous-fold)
|
||
("j" . origami-forward-fold)
|
||
("x" . origami-reset)))
|
||
#+END_SRC
|
||
|
||
** Smart parens
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package smartparens
|
||
:demand
|
||
:config
|
||
(show-smartparens-global-mode t)
|
||
:hook
|
||
(prog-mode . turn-on-smartparens-strict-mode)
|
||
(markdown-mode . turn-on-smartparens-strict-mode)
|
||
:bind
|
||
(([f9] . smartparens-strict-mode)
|
||
("C-c s u" . sp-unwrap-sexp)
|
||
("C-c s k" . sp-kill-sexp)))
|
||
#+END_SRC
|
||
|
||
** Projectile
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package projectile
|
||
:delight '(:eval (concat " [" projectile-project-name "]"))
|
||
:pin melpa-stable
|
||
:config
|
||
(projectile-mode t)
|
||
:bind
|
||
(:map projectile-mode-map
|
||
("C-c p" . projectile-command-map)))
|
||
#+END_SRC
|
||
|
||
*** Repository-based ToDo management with Org mode
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-projectile
|
||
:after (:all projectile org)
|
||
:defer t
|
||
:bind
|
||
(:map projectile-command-map
|
||
("n" . org-projectile-project-todo-completing-read))
|
||
:custom
|
||
(org-projectile-projects-file (expand-file-name "projects.org" org-directory))
|
||
:config
|
||
(push (org-projectile-project-todo-entry) org-capture-templates))
|
||
#+END_SRC
|
||
|
||
** Text object manipulation
|
||
|
||
From the package description:
|
||
|
||
#+BEGIN_QUOTE
|
||
Text objects are textual patterns like a line, a top level definition, a word, a sentence or any
|
||
other unit of text. When objed-mode is enabled, certain editing commands (configurable) will
|
||
activate objed and enable its modal editing features.
|
||
#+END_QUOTE
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package objed
|
||
:demand t
|
||
:bind
|
||
(:map global-map
|
||
("M-SPC" . objed-activate)))
|
||
#+END_SRC
|
||
|
||
** Ace window
|
||
|
||
Besides its standard functionality, I also make add key bindings for burying or scrolling another
|
||
window.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ace-window
|
||
:custom
|
||
(aw-background nil)
|
||
(aw-dispatch-always t)
|
||
:config
|
||
(add-to-list 'aw-dispatch-alist
|
||
'(?s gpolonkai/scroll-window-up " Scroll window up")
|
||
t)
|
||
(add-to-list 'aw-dispatch-alist
|
||
'(?S gpolonkai/scroll-window-down " Scroll window down")
|
||
t)
|
||
(add-to-list 'aw-dispatch-alist
|
||
'(?q gpolonkai/bury-window " Bury (quit) window")
|
||
t)
|
||
:bind
|
||
(:map ctl-x-map
|
||
("o" . ace-window)))
|
||
#+END_SRC
|
||
|
||
** Golden ratio
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package golden-ratio
|
||
:config
|
||
(add-to-list 'golden-ratio-extra-commands 'ace-window)
|
||
(golden-ratio-mode t))
|
||
#+END_SRC
|
||
|
||
** Avy
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package avy
|
||
:demand
|
||
:config
|
||
(avy-setup-default)
|
||
:bind
|
||
(("M-g c" . avy-goto-char)
|
||
("M-g C" . avy-goto-char-2)
|
||
("M-g f" . avy-goto-line)
|
||
("M-g w" . avy-goto-word-1)
|
||
("M-g e" . avy-goto-word-0)))
|
||
#+END_SRC
|
||
|
||
** Focus mode
|
||
|
||
It is similar to narrow mode, except the narrowing part; it dims everything outside of the current
|
||
context.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package focus
|
||
:bind
|
||
(([f8] . focus-mode)))
|
||
#+END_SRC
|
||
|
||
** Command logging mode
|
||
|
||
For occasional screen casting recordings.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package command-log-mode)
|
||
#+END_SRC
|
||
|
||
** Emamux
|
||
|
||
For controlling tmux from within Emacs.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package emamux)
|
||
#+END_SRC
|
||
|
||
** Use StackExchange sites in an Emacs window
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package sx
|
||
:demand
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("qi" . sx-inbox)
|
||
("qs" . sx-search)))
|
||
#+END_SRC
|
||
|
||
** Goto last change
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package goto-last-change
|
||
:bind
|
||
(("M-g /" . goto-last-change)))
|
||
#+END_SRC
|
||
|
||
** Rainbow mode
|
||
|
||
To highlight colours based on their name or hex code.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package rainbow-mode
|
||
:hook
|
||
(css-mode . rainbow-mode)
|
||
(scss-mode . rainbow-mode)
|
||
(sass-mode . rainbow-mode))
|
||
#+END_SRC
|
||
|
||
** Zygospore
|
||
|
||
Toggle other windows for maximum focus. When focus is no longer needed, they can be toggled back.
|
||
~C-x 1~ is conveniently bound to it.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package zygospore
|
||
:bind
|
||
(:map ctl-x-map
|
||
("1" . zygospore-toggle-delete-other-windows)))
|
||
#+END_SRC
|
||
|
||
** Kanban board
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package kanban)
|
||
#+END_SRC
|
||
|
||
** Highlight dired buffer by file size, modified time, git status
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired-k
|
||
:bind
|
||
(:map dired-mode-map
|
||
("K" . dired-k)))
|
||
#+END_SRC
|
||
|
||
** Show number of matches in the mode line while searching
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package anzu
|
||
:delight
|
||
:config
|
||
(global-anzu-mode 1))
|
||
#+END_SRC
|
||
|
||
** Gradually expand region
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package expand-region
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("x" . er/expand-region)))
|
||
#+END_SRC
|
||
|
||
** Read and Edit MediaWiki pages in an Emacs window
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package mediawiki
|
||
:after
|
||
id-manager
|
||
:config
|
||
(add-to-list 'mediawiki-site-alist
|
||
'("WikEmacs"
|
||
"http://wikemacs.org/wiki/"
|
||
(password-store-get-field "wikemacs.org" "username")
|
||
(password-store-get "wikemacs.org" "password"))))
|
||
#+END_SRC
|
||
|
||
** An Emacs Dashboard
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dashboard
|
||
:after
|
||
projectile
|
||
:config
|
||
(add-to-list 'dashboard-items '(projects . 5) t)
|
||
(dashboard-setup-startup-hook))
|
||
#+END_SRC
|
||
|
||
** Hungarian holidays in the Calendar
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package hungarian-holidays
|
||
:config
|
||
(hungarian-holidays-add))
|
||
#+END_SRC
|
||
|
||
** FlySpell
|
||
|
||
For all your spell-checking needs.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package flyspell
|
||
:hook
|
||
(prog-mode . flyspell-prog-mode)
|
||
(text-mode . flyspell-mode))
|
||
#+END_SRC
|
||
|
||
** Delete all the whitespace
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package hungry-delete
|
||
:config
|
||
(global-hungry-delete-mode))
|
||
#+END_SRC
|
||
|
||
** Send alerts to a notification system
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package alert
|
||
:config
|
||
(setq alert-default-style
|
||
(if (termux-p)
|
||
(progn
|
||
;; TODO Remove this as soon as my PR gets merged
|
||
;; https://github.com/jwiegley/alert/pull/41
|
||
(unless (fboundp 'alert-termux-notify)
|
||
(defcustom alert-termux-command (executable-find "termux-notification")
|
||
"Path to the termux-notification command.
|
||
This is found in the termux-api package, and it requires the Termux
|
||
API addon app to be installed."
|
||
:type 'file
|
||
:group 'alert)
|
||
|
||
(defun alert-termux-notify (info)
|
||
"Send INFO using termux-notification.
|
||
Handles :TITLE and :MESSAGE keywords from the
|
||
INFO plist."
|
||
(if alert-termux-command
|
||
(let ((args (nconc
|
||
(when (plist-get info :title)
|
||
(list "-t" (alert-encode-string (plist-get info :title))))
|
||
(list "-c" (alert-encode-string (plist-get info :message))))))
|
||
(apply #'call-process alert-termux-command nil
|
||
(list (get-buffer-create " *termux-notification output*") t)
|
||
nil args))
|
||
(alert-message-notify info)))
|
||
|
||
(alert-define-style 'termux :title "Notify using termux"
|
||
:notifier #'alert-termux-notify))
|
||
'termux)
|
||
'libnotify)))
|
||
#+END_SRC
|
||
|
||
** Replace the GUI popup menu with something more efficient
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ace-popup-menu
|
||
;; Unfortunately, avy-menu (used by this package) is not compatible with minions. I just
|
||
;; disable it for now.
|
||
:disabled
|
||
:config
|
||
(ace-popup-menu-mode 1))
|
||
#+END_SRC
|
||
|
||
** I’m an achiever!
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package achievements
|
||
:demand
|
||
:config
|
||
(achievements-mode 1)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("C-a" . achievements-list-achievements)))
|
||
#+END_SRC
|
||
|
||
** Secretaria
|
||
|
||
Because even secretaries need a secretary today.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package secretaria
|
||
:after
|
||
alert
|
||
:hook
|
||
;; use this for getting a reminder every 30 minutes of those tasks
|
||
;; scheduled for today and which have no time of day defined.
|
||
(after-init . secretaria-unknown-time-always-remind-me))
|
||
#+END_SRC
|
||
|
||
** The Silver Searcher
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ag
|
||
:after projectile
|
||
:bind
|
||
(:map projectile-mode-map
|
||
("C-c p C-a" . ag-project)))
|
||
#+END_SRC
|
||
|
||
** A fancier ~narrow-mode~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package fancy-narrow
|
||
:config
|
||
(fancy-narrow-mode))
|
||
#+END_SRC
|
||
|
||
** Undo tree
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package undo-tree)
|
||
#+END_SRC
|
||
|
||
** All the icons!
|
||
|
||
Should the fonts be missing, run ~(all-the-icons-install-fonts)~. It’s not run automatically, as it
|
||
requires connecting to a website and download a pretty large font file.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package all-the-icons)
|
||
#+END_SRC
|
||
|
||
** NeoTree, if Dired is not an option
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/neo-set-theme ()
|
||
(customize-set-variable 'neo-theme (if (display-graphic-p) 'icons 'arrow)))
|
||
|
||
(use-package neotree
|
||
:after
|
||
all-the-icons
|
||
:bind
|
||
(([f5] . neotree-toggle))
|
||
:hook
|
||
(neo-enter . gpolonkai/neo-set-theme))
|
||
#+END_SRC
|
||
|
||
** Waka-waka (AKA ActivityWatch)
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package activity-watch-mode
|
||
:config
|
||
(global-activity-watch-mode))
|
||
#+end_src
|
||
|
||
** Jump to character, word, line
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ace-jump-mode
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("SPC" . ace-jump-mode)))
|
||
#+END_SRC
|
||
|
||
** Command frequency meter
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package keyfreq
|
||
:demand
|
||
:custom
|
||
(keyfreq-file (expand-file-name "keyfreq" user-emacs-directory))
|
||
(keyfreq-file-lock (expand-file-name "keyfreq.lock" user-emacs-directory))
|
||
:config
|
||
(keyfreq-mode 1)
|
||
(keyfreq-autosave-mode 1)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("C-f" . keyfreq-show)))
|
||
#+END_SRC
|
||
|
||
** EditorConfig
|
||
|
||
[[http://editorconfig.org/][EditorConfig]] is a nice tool to unify, well, configuration of different editors.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package editorconfig
|
||
:config
|
||
(editorconfig-mode t))
|
||
#+END_SRC
|
||
|
||
** occur-like folding in the current buffer
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun gpolonkai/toggle-loccur ()
|
||
"Toggle `loccur-mode'.
|
||
|
||
If `loccur-mode' is not active, starts it (which, in turn, will ask for the
|
||
pattern to look for). If it is active, it will disable it."
|
||
(interactive)
|
||
(if loccur-mode
|
||
(loccur-mode nil)
|
||
(call-interactively 'loccur)))
|
||
|
||
(use-package loccur
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("C-o" . gpolonkai/toggle-loccur)))
|
||
#+END_SRC
|
||
|
||
** Help merging ~pacsave~ and ~pacnew~ files
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package pacfiles-mode
|
||
:commands pacfiles)
|
||
#+END_SRC
|
||
|
||
** Mailing with mu4e
|
||
|
||
Due to my programming (and maybe a bit of OCD) needs, i set trailing whitespace to have a red
|
||
background so it stands out *a lot*. However, many emails contain a lot of trailing whitespace
|
||
which makes them really hard to read in Emacs.
|
||
|
||
The below snippet creates a trailing whitespace face specific to mu4e view buffers. The
|
||
accompanying function will be added to ~mu4e-view-mode-hook~.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(copy-face 'trailing-whitespace 'trailing-whitespace-mu4e)
|
||
(set-face-attribute 'trailing-whitespace-mu4e nil :background 'unspecified)
|
||
|
||
(defun gpolonkai/mu4e-trailing-whitespace-fix ()
|
||
(set (make-local-variable 'face-remapping-alist)
|
||
'((trailing-whitespace trailing-whitespace-mu4e))))
|
||
#+END_SRC
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package mu4e
|
||
:after ivy
|
||
:ensure nil
|
||
:config
|
||
(require 'org-mu4e)
|
||
(setq mu4e-contexts
|
||
`( ,(make-mu4e-context
|
||
:name "polonkai.eu"
|
||
:enter-func (lambda () (mu4e-message "Entering polonkai.eu Context"))
|
||
:leave-func (lambda () (mu4e-message "Leaving polonkai.eu Context"))
|
||
:match-func (lambda (msg)
|
||
(when msg
|
||
(mu4e-message-contact-field-matches
|
||
msg
|
||
:to "gergely@polonkai.eu")))
|
||
:vars '((user-mail-address . "gergely@polonkai.eu")
|
||
(mu4e-sent-folder . "/Polonkai/[Gmail].Sendur p&APM-stur")
|
||
(mu4e-drafts-folder . "/Polonkai/[Gmail].Dr&APY-g")
|
||
(mu4e-trash-folder . "/Polonkai/[Gmail].Rusl")
|
||
(mu4e-refile-folder . "/Polonkai/[Gmail].Dr&APY-g")
|
||
(message-sendmail-extra-arguments . ("--account=polonkai"))))
|
||
,(make-mu4e-context
|
||
:name "Benchmark.games"
|
||
:enter-func (lambda () (mu4e-message "Entering Benchmark.games Context"))
|
||
:leave-func (lambda () (mu4e-message "Leaving Benchmark.games Context"))
|
||
:match-func (lambda (msg)
|
||
(when msg
|
||
(or
|
||
(mu4e-message-contact-field-matches
|
||
msg
|
||
:to "gergo@gt2.io")
|
||
(mu4e-message-contact-field-matches
|
||
msg
|
||
:to "gergo@benchmarked.games")
|
||
(mu4e-message-contact-field-matches
|
||
msg
|
||
:to "gergo@benchmark.games"))))
|
||
:vars '((user-mail-address . "gergo@benchmark.games")
|
||
(mu4e-sent-folder . "/GT2/[Gmail].Sent Mail")
|
||
(mu4e-drafts-folder . "/GT2/[Gmail].Drafts")
|
||
(mu4e-trash-folder . "/GT2/[Gmail].Trash")
|
||
(mu4e-refile-folder . "/GT2/[Gmail].Drafts")
|
||
(message-sendmail-extra-arguments . ("--account=gt2"))))
|
||
,(make-mu4e-context
|
||
:name "Private"
|
||
:enter-func (lambda () (mu4e-message "Entering Private Context"))
|
||
:leave-func (lambda () (mu4e-message "Leaving Private Context"))
|
||
:match-func (lambda (msg)
|
||
(when msg
|
||
(string-match-p "^/Private" (mu4e-message-field msg :maildir))))
|
||
:vars '((user-mail-address . "me@gergely.polonkai.eu")
|
||
(mu4e-sent-folder . "/Private/Sent")
|
||
(mu4e-drafts-folder . "/Private/Drafts")
|
||
(mu4e-trash-folder . "/Private/Trash")
|
||
(mu4e-refile-folder . "/Private/Drafts")
|
||
(message-sendmail-extra-arguments . ("--account=private" "--read-envelope-from")))))
|
||
org-mu4e-link-query-in-headers-mode nil)
|
||
:custom
|
||
(mu4e-completing-read-function 'ivy-completing-read)
|
||
(mu4e-context-policy 'pick-first)
|
||
(mu4e-confirm-quit nil)
|
||
(mail-user-agent 'sendmail-user-agent)
|
||
:hook
|
||
(mu4e-view-mode . gpolonkai/mu4e-trailing-whitespace-fix)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("m m" . mu4e)
|
||
("m i" . mu4e~headers-jump-to-maildir)
|
||
("m c" . mu4e-compose-new)
|
||
("m s" . mu4e-headers-search)))
|
||
#+END_SRC
|
||
|
||
*** Maildir extension so i see a summary of mailboxes
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package mu4e-maildirs-extension
|
||
:custom
|
||
(mu4e-maildirs-extension-custom-list '("INBOX")))
|
||
#+END_SRC
|
||
|
||
*** Also, some sendmail hacking
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package sendmail
|
||
:custom
|
||
(sendmail-program "/usr/bin/msmtp")
|
||
(message-sendmail-f-is-evil t)
|
||
(message-sendmail-extra-arguments '("--read-envelope-from"))
|
||
(send-mail-function 'sendmail-send-it)
|
||
(message-send-mail-function 'message-send-mail-with-sendmail))
|
||
#+end_src
|
||
|
||
** ViM’s ~ci~ functionality
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ciel
|
||
:bind
|
||
(:map global-map
|
||
("C-c i" . ciel-ci)
|
||
("C-c o" . ciel-co)))
|
||
#+END_SRC
|
||
|
||
** Access files in Docker containers using TRAMP
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package docker-tramp)
|
||
#+END_SRC
|
||
|
||
** Transient for creating beautiful command menus
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package transient)
|
||
#+END_SRC
|
||
|
||
** Speed bar in the same frame
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package sr-speedbar
|
||
:after speedbar)
|
||
#+END_SRC
|
||
|
||
** Speedbar for projectile
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package projectile-speedbar
|
||
:after (:all projectile sr-speedbar)
|
||
:bind
|
||
(:map projectile-mode-map
|
||
("C-c p B" . projectile-speedbar-toggle)))
|
||
#+END_SRC
|
||
|
||
** Kubernetes dashboard
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package kubernetes
|
||
:commands (kubernetes-overview))
|
||
#+END_SRC
|
||
|
||
** A Gopher client
|
||
|
||
Gopher is the next generation text protocol. Despite its age (40-ish, as of writing), it still
|
||
beats the Web in a lot of aspects.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package elpher)
|
||
#+END_SRC
|
||
|
||
** Tidal, for improvising music
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package tidal)
|
||
#+END_SRC
|
||
|
||
** Paradox, for better package management
|
||
|
||
I don’t always use the package menu, but when i do, i want to do it in style…
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package paradox
|
||
:custom
|
||
(paradox-lines-per-entry 2)
|
||
(paradox-automatically-star t)
|
||
(paradox-github-token (nth 1 (auth-source-user-and-password "api.github.com" "gergelypolonkai^paradox")))
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("C-p" . paradox-list-packages)))
|
||
#+end_src
|
||
|
||
** Help editing Ansible files
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ansible)
|
||
#+end_src
|
||
|
||
** Edit browser textareas in Emacs
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package edit-server
|
||
:ensure t
|
||
:commands edit-server-start
|
||
:init (if after-init-time
|
||
(edit-server-start)
|
||
(add-hook 'after-init-hook
|
||
#'(lambda() (edit-server-start))))
|
||
:config (setq edit-server-new-frame-alist
|
||
'((name . "Edit with Emacs FRAME")
|
||
(top . 200)
|
||
(left . 200)
|
||
(width . 80)
|
||
(height . 25)
|
||
(minibuffer . t)
|
||
(menu-bar-lines . t)
|
||
(window-system . x))))
|
||
#+end_src
|
||
|
||
* Dired related packages
|
||
|
||
** Collapse directories that only contain one file somewhere deep
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired-collapse)
|
||
#+END_SRC
|
||
|
||
** Show directory sizes
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired-du)
|
||
#+END_SRC
|
||
|
||
** Show Git version information
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired-git-info
|
||
:bind
|
||
(:map dired-mode-map
|
||
(")" . dired-git-info-mode)))
|
||
#+END_SRC
|
||
|
||
** Show/hide dot (hidden) files
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired-hide-dotfiles
|
||
:bind
|
||
(:map dired-mode-map
|
||
("." . dired-hide-dotfiles-mode)))
|
||
#+END_SRC
|
||
|
||
** Rainbow to the stars…
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dired-rainbow
|
||
:config
|
||
(dired-rainbow-define-chmod executable-unix "Green" "-.*x.*"))
|
||
#+END_SRC
|
||
|
||
* Make programming a bit easier
|
||
|
||
** Electric case
|
||
|
||
Insert ~snake_case~ and ~camelCase~ without using the Shift key. It is automatically enabled in C
|
||
mode.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package electric-case
|
||
:hook
|
||
(c-mode . electric-case-c-init))
|
||
#+END_SRC
|
||
|
||
** Electric operator
|
||
|
||
Automatically add spaces around operators.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package electric-operator
|
||
:config
|
||
;; Apply electric-operator-mode to vala-mode, too
|
||
(apply #'electric-operator-add-rules-for-mode 'vala-mode
|
||
(electric-operator-get-rules-for-mode 'prog-mode))
|
||
:hook
|
||
(c-mode-common . electric-operator-mode)
|
||
(python-mode . electric-operator-mode))
|
||
#+END_SRC
|
||
|
||
** Yasnippets
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package yasnippet
|
||
:demand
|
||
:config
|
||
(yas-global-mode 1)
|
||
:hook
|
||
(post-command . sachachua/change-cursor-color-when-can-expand))
|
||
#+END_SRC
|
||
|
||
*** Extra snippets for Vala
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package vala-snippets
|
||
:after
|
||
yasnippet)
|
||
#+END_SRC
|
||
|
||
*** Miscellanous extra snippets
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package yasnippet-snippets
|
||
:after
|
||
yasnippet)
|
||
#+END_SRC
|
||
|
||
** Colourful delimiters
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package rainbow-delimiters
|
||
:hook
|
||
(prog-mode . rainbow-delimiters-mode))
|
||
#+END_SRC
|
||
|
||
** Colourful identifiers
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package rainbow-identifiers)
|
||
#+end_src
|
||
|
||
** REST Client
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package restclient)
|
||
#+END_SRC
|
||
|
||
** REST Client power for Org-mode!
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ob-restclient
|
||
:after org
|
||
:init
|
||
(org-babel-do-load-languages 'org-babel-load-languages
|
||
'((restclient . t))))
|
||
#+END_SRC
|
||
|
||
** Highlight current symbol
|
||
|
||
A big help during refactoring.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package auto-highlight-symbol
|
||
:config
|
||
(global-auto-highlight-symbol-mode t))
|
||
#+END_SRC
|
||
|
||
** Make ReallyLongCamelCaseWords more readable
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package glasses
|
||
:delight " 👓"
|
||
:hook
|
||
(prog-mode . glasses-mode))
|
||
#+END_SRC
|
||
|
||
** GObject boilerplate generator
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package gobgen)
|
||
#+END_SRC
|
||
|
||
** Highlight TODO, FIXME, and XXX
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package hl-todo)
|
||
#+END_SRC
|
||
|
||
** Bug and patch links
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defvar gpolonkai/bug-reference-url-bug-string "issues"
|
||
"String to insert in a `bug-reference-url-format' for bug references.")
|
||
|
||
(put 'gpolonkai/bug-reference-url-bug-string 'safe-local-variable 'stringp)
|
||
|
||
(defvar gpolonkai/bug-reference-url-patch-string "merge_requests"
|
||
"String to insert in a `bug-reference-url-format' for patch references.")
|
||
|
||
(defvar-local bug-reference-host "gitlab.com"
|
||
"The hostname to use in `bug-reference-url-format'.")
|
||
|
||
(defvar-local bug-reference-group "gamesystems"
|
||
"The group name or username to use in `bug-reference-url-format'.")
|
||
|
||
(defvar-local bug-reference-repository "game-app"
|
||
"The repository name to use in `bug-reference-url-format'.")
|
||
|
||
(put 'gpolonkai/bug-reference-url-patch-string 'safe-local-variable 'stringp)
|
||
|
||
(defun gpolonkai/bug-reference-url ()
|
||
"Return a GitLab issue or Merge Request URL.
|
||
Intended as a value for `bug-referecne-url-format'."
|
||
(format "https://%s/%s/%s/%s/%s"
|
||
bug-reference-host
|
||
bug-reference-group
|
||
bug-reference-repository
|
||
(if (string-suffix-p "!" (match-string-no-properties 1))
|
||
gpolonkai/bug-reference-url-patch-string
|
||
gpolonkai/bug-reference-url-bug-string)
|
||
(match-string-no-properties 2))
|
||
)
|
||
|
||
(use-package bug-reference
|
||
:custom
|
||
(bug-reference-bug-regexp (rx (group (in ?! ?#))
|
||
(group (+ digit))))
|
||
(bug-reference-url-format #'my-gitlab-url)
|
||
:hook
|
||
(text-mode . bug-reference-mode)
|
||
(prog-mode . bug-reference-prog-mode))
|
||
#+END_SRC
|
||
|
||
** Highlight indentation
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package highlight-indentation
|
||
:hook
|
||
(python-mode . highlight-indentation-mode))
|
||
#+end_src
|
||
|
||
* Python related setup and ~use-package~ calls
|
||
|
||
Because, well, that’s my job now. Of course it gets a dedicated section.
|
||
|
||
** Set up pretty symbols for Python
|
||
|
||
Because they are fancy.
|
||
|
||
- not: ¬
|
||
- in: ∈
|
||
- def: ƒ
|
||
|
||
Maybe add ∉ for ~not in~ later, if possible.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-hook 'python-mode-hook
|
||
(lambda ()
|
||
(add-to-list 'prettify-symbols-alist
|
||
'("not" . 172))
|
||
(add-to-list 'prettify-symbols-alist
|
||
'("in" . 8712))
|
||
(add-to-list 'prettify-symbols-alist
|
||
'("def" . 402))))
|
||
#+END_SRC
|
||
|
||
** Pyre-based LSP
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-pyre
|
||
:hook
|
||
(python-mode . lsp))
|
||
#+end_src
|
||
|
||
** Poetry
|
||
|
||
Because it’s also great.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package poetry
|
||
:config
|
||
(poetry-tracking-mode)
|
||
(remove-hook 'post-command-hook 'poetry-track-virtualenv)
|
||
:hook
|
||
(poetry-tracking-mode . (lambda () (remove-hook 'post-command-hook 'poetry-track-virtualenv)))
|
||
(python-mode . poetry-track-virtualenv)
|
||
(projectile-after-switch-project-hook . poetry-track-virtualenv))
|
||
#+END_SRC
|
||
|
||
** Automatically insert Sphinx-style docstrings
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package sphinx-doc
|
||
:hook
|
||
(python-mode . sphinx-doc-mode))
|
||
#+END_SRC
|
||
|
||
* C mode
|
||
|
||
Because that’s still my favourite language.
|
||
|
||
** Set up my own C style
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defconst my-c-style
|
||
'((c-tab-always-indent . t)
|
||
(c-comment-only-line-offset . 4)
|
||
(c-hanging-braces-alist . ((substatement-open after)
|
||
(brace-list-open)))
|
||
(c-hanging-colons-alist . ((member-init-intro before)
|
||
(inher-intro)
|
||
(case-label after)
|
||
(label after)
|
||
(access-label after)))
|
||
(c-cleanup-list . (scope-operator
|
||
empty-defun-braces
|
||
defun-close-semi))
|
||
(c-offsets-alist . ((arglist-close . +)
|
||
(arglist-intro . +)
|
||
(substatement-open . 0)
|
||
(case-label . 4)
|
||
(block-open . 0)
|
||
(knr-argdecl-intro . -)
|
||
(comment-intro . 0)
|
||
(member-init-intro . ++)))
|
||
(c-echo-syntactic-information-p . t))
|
||
"My C Programming Style.")
|
||
(c-add-style "PERSONAL" my-c-style)
|
||
#+END_SRC
|
||
|
||
** Some common initialisation for C mode
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-hook 'c-mode-common-hook
|
||
(lambda ()
|
||
(local-set-key (kbd "C-c o") 'ff-find-other-file)
|
||
(c-set-style "PERSONAL")
|
||
(customize-set-variable 'c-basic-offset 4)
|
||
(customize-set-variable 'tab-width 4)
|
||
(customize-set-variable 'indent-tabs-mode nil)
|
||
(c-toggle-auto-newline 1)))
|
||
(add-hook 'c-initialization-hook
|
||
(lambda ()
|
||
(define-key c-mode-base-map (kbd "C-m") 'c-context-line-break)))
|
||
#+END_SRC
|
||
|
||
** Set indentation levels to the same as the tab width
|
||
|
||
#+BEGIN_SRC emacs-lisp :tangle no
|
||
(defvaralias 'c-basic-offset 'tab-width)
|
||
(defvaralias 'cperl-indent-level 'tab-width)
|
||
#+END_SRC
|
||
|
||
* Web development
|
||
|
||
** Web mode
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package web-mode
|
||
:mode "\\.html?\\'"
|
||
:custom
|
||
(web-mode-enable-auto-indentation nil)
|
||
(web-mode-enable-engine-detection t))
|
||
#+END_SRC
|
||
|
||
** Emmet mode
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package emmet-mode
|
||
:custom
|
||
(emmet-self-closing-tag-style "")
|
||
:hook
|
||
(web-mode . emmet-mode)
|
||
(css-mode . emmet-mode))
|
||
#+END_SRC
|
||
|
||
** Query HTML tags by CSS selectors
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package enlive)
|
||
#+END_SRC
|
||
|
||
* FlyCheck
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package flycheck
|
||
:config
|
||
(global-flycheck-mode)
|
||
:custom
|
||
(flycheck-python-pylint-executable "python3"))
|
||
#+END_SRC
|
||
|
||
** FlyCheck for pkg-config files
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package flycheck-pkg-config)
|
||
#+END_SRC
|
||
|
||
* Org mode
|
||
|
||
This is a big one; I use a lot of customisation here.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org
|
||
:demand
|
||
:init
|
||
(require 'xdg-paths)
|
||
(defface org-checkbox-todo-text
|
||
'((t (:inherit org-todo)))
|
||
"Face for the text part of an unchecked org-mode checkbox.")
|
||
(defface org-checkbox-done-text
|
||
'((t (:inherit org-done)))
|
||
"Face for the text part of a checked org-mode checkbox.")
|
||
(font-lock-add-keywords
|
||
'org-mode
|
||
`(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?: \\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 1 'org-checkbox-todo-text prepend))
|
||
'append)
|
||
(font-lock-add-keywords
|
||
'org-mode
|
||
`(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 12 'org-checkbox-done-text prepend))
|
||
'append)
|
||
(setq-default org-default-notes-file (expand-file-name "notes.org" org-directory)
|
||
org-agenda-files `(,org-directory)
|
||
org-time-stamp-formats '("<%Y-%m-%d>" . "<%Y-%m-%d %H:%M>")
|
||
org-todo-keywords '((sequence "TODO(t)"
|
||
"DOING(w@/!)"
|
||
"BLOCKED(b@/!)"
|
||
"SOMEDAY(s!)"
|
||
"|"
|
||
"CANCELED(c@/!)"
|
||
"REVIEW(r@/!)"
|
||
"DONE(d@/!)"))
|
||
org-todo-keyword-faces '(("SOMEDAY" . (:foreground "goldenrod"))
|
||
("CANCELED" . (:foreground "#228b22" :strike-through t)))
|
||
org-html-checkbox-types
|
||
'((unicode (on . "<span class=\"task-done\">☑</span>")
|
||
(off . "<span class=\"task-todo\">☐</span>")
|
||
(trans . "<span class=\"task-in-progress\">▣</span>"))))
|
||
:config
|
||
;; Load the markdown exporter
|
||
(require 'ox-md)
|
||
;; Handle org-protocol:// links
|
||
(require 'org-protocol)
|
||
;; Make it possible to encrypt headings
|
||
(require 'org-crypt)
|
||
;; Make it possible to use inline tasks
|
||
(require 'org-inlinetask)
|
||
;; Make it possible to use structure templates with < X TAB
|
||
(require 'org-tempo)
|
||
|
||
:custom
|
||
(org-log-into-drawer t)
|
||
(org-ellipsis "…#")
|
||
(org-startup-folded 'content)
|
||
(org-log-done 'time)
|
||
(org-src-preserve-indentation t)
|
||
(org-tags-column 0)
|
||
(org-startup-indented t)
|
||
(org-special-ctrl-a/e t)
|
||
(org-return-follows-link t)
|
||
(org-src-fontify-natively t)
|
||
(org-goto-interface 'outline-path-completion)
|
||
(org-goto-max-level 10)
|
||
(org-html-checkbox-type 'unicode)
|
||
(org-src-window-setup 'current-window)
|
||
(org-pretty-entities t)
|
||
(org-pretty-entities-include-sub-superscripts t)
|
||
(org-use-speed-commands t)
|
||
(org-hide-leading-stars t)
|
||
(org-enforce-todo-dependencies t)
|
||
(org-enforce-todo-checkbox-dependencies t)
|
||
(org-catch-invisible-edits 'show)
|
||
(org-log-reschedule 'time)
|
||
(org-log-redeadline 'note)
|
||
(org-refile-use-outline-path 'file)
|
||
(org-outline-path-complete-in-steps nil)
|
||
(org-refile-allow-creating-parent-nodes 'confirm)
|
||
(org-crypt-key "B0740C4C")
|
||
(org-speed-commands-user '(("m" . org-mark-subtree)))
|
||
(org-refile-targets '((org-agenda-files :maxlevel . 3)))
|
||
(org-agenda-custom-commands '(("c" "Simple agenda view"
|
||
((tags "PRIORITY=\"A\""
|
||
((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
|
||
(org-agenda-overriding-header "High priority unfinished tasks")))
|
||
(agenda "")
|
||
(alltodo ""
|
||
((org-agenda-skip-function
|
||
'(or (air-org-skip-subtree-if-habit)
|
||
(air-org-skip-subtree-if-priority ?A)
|
||
(gpolonkai/org-skip-subtree-if-state "SOMEDAY")
|
||
(org-agenda-skip-if nil '(scheduled deadline))))
|
||
(org-agenda-overriding-header "ALL normal priority tasks"))))
|
||
((org-agenda-compact-blocks t)))))
|
||
(org-log-note-clock-out t)
|
||
(org-capture-templates '(("L" "Org-protocol capture" entry
|
||
(file+headline
|
||
(lambda ()
|
||
(expand-file-name "index.org" org-directory))
|
||
"Captures")
|
||
"** %:description\n:PROPERTIES:\n:SOURCE: %:link\n:END:\n\n%:initial"
|
||
:empty-lines 1)
|
||
("R" "Region to Current Clocked Task" plain
|
||
(clock)
|
||
"%i"
|
||
:immediate-finish t
|
||
:empty-lines 1)
|
||
("K" "Kill-ring to Current Clocked Task" plain
|
||
(clock)
|
||
"%c"
|
||
:immediate-finish t
|
||
:empty-lines 1)
|
||
("c" "Item to current Clocked Task" item
|
||
(clock)
|
||
"%i%?"
|
||
:empty-lines 1)
|
||
("g" "GT2 note" entry
|
||
(file+headline
|
||
(lambda ()
|
||
(expand-file-name "gt2-notes.org" org-directory))
|
||
"Captures")
|
||
"** %^{Title}\n:PROPERTIES:\n:CREATED: %T\n:END:\n\n%a\n\n%i%?")
|
||
("p" "Blog post" entry
|
||
(file+olp+datetree
|
||
(lambda ()
|
||
(expand-file-name "blog.org" org-directory)))
|
||
"* %^{Title} :blog:\n:PROPERTIES:\n:CREATED: %T\n:END:\n\n%i%?")))
|
||
(org-read-date-force-compatible-dates nil)
|
||
(org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t% s")
|
||
(todo . " %i %-12:c %(concat \"[ \"(org-format-outline-path (org-get-outline-path)) \" ]\") ")
|
||
(tags . " %i %-12:c %(concat \"[ \"(org-format-outline-path (org-get-outline-path)) \" ]\") ")
|
||
(timeline . " % s")
|
||
(search . " %i %-12:c")))
|
||
(org-agenda-dim-blocked-tasks t)
|
||
:hook
|
||
(ediff-select . f-ediff-org-unfold-tree-element)
|
||
(ediff-unselect . f-ediff-org-fold-tree)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("a" . gpolonkai/org-agenda-list)
|
||
("C" . org-capture)
|
||
("l" . org-store-link)
|
||
:map org-mode-map
|
||
("SPC" . org-space-key)
|
||
("C-c l" . org-toggle-link-display)
|
||
("C-a" . gpolonkai/move-to-beginning-of-line)
|
||
("C-e" . gpolonkai/move-to-end-of-line)
|
||
("C-c h" . outline-previous-heading)
|
||
("C-c ;" . org-toggle-timestamp-type)))
|
||
#+END_SRC
|
||
|
||
** Show a random ToDo every hour
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-random-todo
|
||
:demand
|
||
:config
|
||
;; Don’t bug me too often…
|
||
(setq org-random-todo-how-often 3600)
|
||
:custom
|
||
(org-random-todo-skip-keywords '("SOMEDAY"))
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("r" . org-random-todo)))
|
||
#+END_SRC
|
||
|
||
** Load CalDAV entries from NextCloud
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-caldav
|
||
:after org
|
||
:config
|
||
(setq
|
||
org-caldav-url "https://cloud.polonkai.eu/remote.php/dav/calendars/gergely"
|
||
org-caldav-calendar-id "org"
|
||
org-caldav-inbox (expand-file-name "cloud-calendar.org" org-directory)
|
||
org-caldav-files nil))
|
||
#+END_SRC
|
||
|
||
** Improved list management
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-autolist
|
||
:hook
|
||
(org-mode . org-autolist-mode))
|
||
#+END_SRC
|
||
|
||
** Write messages with Org-mode
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-msg
|
||
:after mu4e
|
||
:defer t
|
||
:config
|
||
(org-msg-mode)
|
||
:custom
|
||
(org-msg-supported-mua '((sendmail-user-agent . "mu4e")))
|
||
(org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil")
|
||
(org-msg-startup "hidestars indent inlineimages")
|
||
(org-msg-greeting-fmt "\nHello,\n\n")
|
||
(org-msg-greeting-fmt-mailto nil)
|
||
(org-msg-signature "\n\nBest,\n\n,#+begin_signature\n-- *Gergely Polonkai* \\\\\n,#+end_signature"))
|
||
#+END_SRC
|
||
|
||
** Sticky headers so i always know where i am
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-sticky-header
|
||
:custom
|
||
(org-sticky-header-full-path 'full)
|
||
:hook
|
||
(org-mode . org-sticky-header-mode))
|
||
#+END_SRC
|
||
|
||
** Custom bullets
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-bullets
|
||
:custom
|
||
(org-bullets-face-name 'org-bullet-face)
|
||
(org-bullets-bullet-list '("✙" "♱" "♰" "☥" "✞" "✟" "✝" "†" "✠" "✚" "✜" "✛" "✢" "✣" "✤" "✥"))
|
||
:hook
|
||
(org-mode . org-bullets-mode))
|
||
#+END_SRC
|
||
|
||
** Edit diagrams with mermaid
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ob-mermaid
|
||
:custom
|
||
(ob-mermaid-cli-path "/home/polesz/.local/node/bin/mmdc"))
|
||
#+END_SRC
|
||
|
||
** Allow exporting to ReSTructured text
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ox-rst
|
||
:after org)
|
||
#+END_SRC
|
||
|
||
** Export currently clocked in task for Waybar
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package org-clock-waybar
|
||
:ensure nil
|
||
:quelpa (org-clock-waybar
|
||
:fetcher git
|
||
:url "https://gitea.polonkai.eu/gergely/org-clock-waybar.git")
|
||
:config
|
||
(org-clock-waybar-setup))
|
||
#+end_src
|
||
|
||
* Git & Co.
|
||
|
||
** Git status on the fringe
|
||
|
||
In graphical modes we use ~git-gutter-fringe~, and ~git-gutter~ otherwise.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
;; Git gutter
|
||
;; If we are in text-only mode, there is no fringe.
|
||
(let ((gitgutter-package
|
||
(if (display-graphic-p)
|
||
"git-gutter-fringe"
|
||
"git-gutter")))
|
||
(eval `(use-package ,gitgutter-package
|
||
:demand
|
||
:config
|
||
(global-git-gutter-mode t)
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("gg" . git-gutter:update-all-windows)
|
||
("gn" . git-gutter:next-hunk)
|
||
("gp" . git-gutter:previous-hunk)))))
|
||
#+END_SRC
|
||
|
||
** Git messenger
|
||
|
||
AKA blame current line.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package git-messenger
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("gm" . git-messenger:popup-message)))
|
||
#+END_SRC
|
||
|
||
** Git time machine
|
||
|
||
See previous versions of the current file.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package git-timemachine
|
||
:bind
|
||
(([f6] . git-timemachine-toggle)))
|
||
#+END_SRC
|
||
|
||
* Company & Co.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company
|
||
:delight " 🏢"
|
||
:custom
|
||
(company-idle-delay nil)
|
||
(company-dabbrev-downcase nil)
|
||
:config
|
||
(setq company-frontends '(company-pseudo-tooltip-frontend
|
||
company-echo-metadata-frontend))
|
||
(put 'company-clang-arguments 'safe-local-variable #'nil-or-list-of-strings-p)
|
||
(global-company-mode))
|
||
#+END_SRC
|
||
|
||
** Company completion based on local C headers
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company-c-headers)
|
||
#+END_SRC
|
||
|
||
** Company mode in the shell
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company-shell)
|
||
#+END_SRC
|
||
|
||
** REST Client completion via Company
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company-restclient)
|
||
#+END_SRC
|
||
|
||
** Insert Emoji with Company
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company-emoji
|
||
:after
|
||
company
|
||
:init
|
||
(--set-emoji-font nil)
|
||
:config
|
||
(add-to-list 'company-backends 'company-emoji))
|
||
#+END_SRC
|
||
|
||
** Web mode (~web-mode~ and ~emmet-mode~, too) backend for Company
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company-web
|
||
:config
|
||
(require 'company-web-html))
|
||
#+END_SRC
|
||
|
||
* Ivy & Co.
|
||
|
||
** Ivy & Counsel
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy
|
||
:config
|
||
(ivy-mode 1)
|
||
:custom
|
||
(ivy-use-virtual-buffers t)
|
||
(ivy-count-format "(%d/%d) ")
|
||
(ivy-use-selectable-prompt t))
|
||
(use-package counsel
|
||
:config
|
||
(counsel-mode)
|
||
:bind
|
||
(:map company-mode-map
|
||
("C-c j" . counsel-company)
|
||
:map company-active-map
|
||
("C-c j" . counsel-company)))
|
||
#+end_src
|
||
|
||
** GNU Globals with Counsel
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun gpolonkai/enable-counsel-gtags-mode ()
|
||
(counsel-gtags-mode t))
|
||
|
||
(use-package counsel-gtags
|
||
:custom
|
||
(counsel-gtags-auto-update t)
|
||
(counsel-gtags-path-style 'relative)
|
||
:hook
|
||
(c-mode . gpolonkai/enable-counsel-gtags-mode)
|
||
:bind
|
||
(:map counsel-gtags-mode-map
|
||
("M-t" . counsel-gtags-find-definition)
|
||
("M-r" . counsel-gtags-find-reference)
|
||
("M-s" . counsel-gtags-find-symbol)
|
||
("C-c <" . counsel-gtags-go-backward)
|
||
("C-c >" . counsel-gtags-go-forward)))
|
||
#+end_src
|
||
|
||
** Ag with Counsel
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package counsel-ag-popup
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("s" . counsel-ag-popup)))
|
||
#+end_src
|
||
|
||
** Projectile with Counsel
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package counsel-projectile
|
||
:custom
|
||
(projectile-completion-system 'ivy)
|
||
:config
|
||
(counsel-projectile-mode))
|
||
#+end_src
|
||
|
||
** FlySpell with Ace
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ace-flyspell
|
||
:bind
|
||
(:map flyspell-mode-map
|
||
("C-M-i" . ace-flyspell-correct-word)))
|
||
#+end_src
|
||
|
||
** C Yasnippets with Ivy
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-yasnippet
|
||
:after
|
||
yasnippet
|
||
:bind
|
||
(("C-c y" . ivy-yasnippet)))
|
||
#+end_src
|
||
|
||
** PyDoc with Counsel
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package counsel-pydoc)
|
||
#+end_src
|
||
|
||
** BibTex with Ivy
|
||
|
||
First, set up ~bibtex-completion~:
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package bibtex-completion
|
||
:after
|
||
org
|
||
:custom
|
||
(bibtex-completion-bibliography (expand-file-name "references.bib" org-directory))
|
||
(bibtex-completion-library-path (expand-file-name "bibtex-pdfs" org-directory))
|
||
(bibtex-completion-pdf-open-function 'org-open-file)
|
||
(bibtex-completion-notes-path (expand-file-name
|
||
(convert-standard-filename "bibliography/ivy-bibtex-notes")
|
||
org-directory)))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-bibtex
|
||
:after bibtex-completion)
|
||
#+end_src
|
||
|
||
** Access passwords in pass using Ivy
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-pass)
|
||
#+end_src
|
||
|
||
* Mode specific ~use-package~ calls
|
||
|
||
** JavaScript
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package js2-mode
|
||
:pin melpa-stable
|
||
:mode "\\.js\\'")
|
||
#+END_SRC
|
||
|
||
** Jinja templates
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package jinja2-mode
|
||
:mode "\\.j2\\'")
|
||
#+end_src
|
||
|
||
** TypeScript
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package typescript-mode
|
||
:mode "\\.ts\\'")
|
||
#+END_SRC
|
||
|
||
** CoffeeScript
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package coffee-mode
|
||
:mode "\\.coffee\\'")
|
||
#+END_SRC
|
||
|
||
** JSON
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package json-mode
|
||
:mode "\\.json\\'")
|
||
#+END_SRC
|
||
|
||
** YAML
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package yaml-mode
|
||
:mode (("\\.yml\\'" . yaml-mode)
|
||
("\\.yaml\\'" . yaml-mode))
|
||
:init
|
||
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)))
|
||
#+END_SRC
|
||
|
||
** Markdown
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package markdown-mode
|
||
:mode (("\\.md\\'" . markdown-mode)
|
||
("\\.markdown\\'" . markdown-mode)))
|
||
#+END_SRC
|
||
|
||
** Less
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package less-css-mode
|
||
:mode "\\.less\\'")
|
||
#+END_SRC
|
||
|
||
** Sass
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package sass-mode
|
||
:mode "\\.sass\\'")
|
||
#+END_SRC
|
||
|
||
** Vala
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package vala-mode
|
||
:mode "\\.vala\\'")
|
||
#+END_SRC
|
||
|
||
** Dockerfile
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package dockerfile-mode)
|
||
#+END_SRC
|
||
|
||
** ~po-mode~
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package po-mode
|
||
:ensure nil
|
||
:mode "\\.po\\'")
|
||
#+END_SRC
|
||
|
||
** C#
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package csharp-mode
|
||
:mode "\\.cs\\'")
|
||
#+END_SRC
|
||
|
||
** Gherkin (BDD) feature files
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package feature-mode
|
||
:mode "\\.feature\\'")
|
||
#+END_SRC
|
||
|
||
** PlantUML
|
||
|
||
Before using this, make sure the latest PlantUML JAR file is downloaded into the downloads
|
||
directory. It is available from [[http://plantuml.com/download][here]].
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package plantuml-mode
|
||
:init
|
||
(setq plantuml-jar-path
|
||
(expand-file-name
|
||
;; Make sure we have a download location even if XDG is not working
|
||
(cond
|
||
((xdg-user-dir "DOWNLOAD")
|
||
(expand-file-name "plantuml.jar" (xdg-user-dir "DOWNLOAD")))
|
||
(t
|
||
"~/Downloads/plantuml.jar"))))
|
||
(defvaralias 'org-plantuml-jar-path 'plantuml-jar-path)
|
||
:config
|
||
(org-babel-do-load-languages
|
||
'org-babel-load-languages
|
||
'((plantuml . t))))
|
||
#+END_SRC
|
||
|
||
** For editing CSV files
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package csv-mode
|
||
:mode "\\.csv\\'")
|
||
#+END_SRC
|
||
|
||
** The Go programming language
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package go-mode
|
||
:mode "\\.go\\'")
|
||
#+END_SRC
|
||
|
||
** Meson build system
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package meson-mode
|
||
:mode "\\.meson\\'")
|
||
#+END_SRC
|
||
|
||
** GraphQL
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package graphql
|
||
:mode "\\.graphql\\'")
|
||
#+END_SRC
|
||
|
||
** Gitlab-CI
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package gitlab-ci-mode
|
||
:mode "\\.gitlab-ci.yml\\'")
|
||
(use-package gitlab-ci-mode-flycheck
|
||
:after flycheck gitlab-ci-mode
|
||
:init
|
||
(gitlab-ci-mode-flycheck-enable))
|
||
#+END_SRC
|
||
|
||
** Arduino
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package arduino-mode
|
||
:mode "\\.ino\\'")
|
||
#+END_SRC
|
||
|
||
** Vue templates
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package vue-html-mode
|
||
:mode "\\.vue\\'")
|
||
#+END_SRC
|
||
|
||
** Pony is awesome!
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ponylang-mode
|
||
:mode "\\.pony\\'")
|
||
#+END_SRC
|
||
|
||
** Rust
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package rust-mode
|
||
:mode "\\.rs\\'")
|
||
(use-package cargo)
|
||
(use-package flycheck-rust)
|
||
#+END_SRC
|
||
|
||
** Fish shell
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package fish-mode
|
||
:hook
|
||
(fish-mode . (lambda () (add-hook 'before-save-hook 'fish_indent-before-save))))
|
||
#+END_SRC
|
||
|
||
** Clojure
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package clojure-mode)
|
||
#+end_src
|
||
|
||
** Flutter specific things
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-mode)
|
||
|
||
(use-package lsp-dart
|
||
:hook
|
||
(dart-mode . lsp))
|
||
|
||
(use-package lsp-ui)
|
||
|
||
(use-package hover)
|
||
#+end_src
|
||
|
||
** Bats, for testing shell scripts
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package bats-mode
|
||
:mode "\\.bats\\'")
|
||
#+end_src
|
||
|
||
** Terraform
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package terraform-mode
|
||
:mode "\\.tf\\'")
|
||
#+end_src
|
||
|
||
* Games
|
||
|
||
** Gnu Go
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package gnugo)
|
||
#+END_SRC
|
||
|
||
* Last, but not least, key bindings!
|
||
|
||
** TODO My own, personal, Magit-popup! :experimental:
|
||
|
||
With the new Transient package it will be easier. I just don’t know how to use it yet.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(define-transient-command gpolonkai/clock-menu ()
|
||
[("I" "Clock in to last clocked task" org-clock-in-last)
|
||
("g" "Go to the currently clocked task" org-clock-goto)
|
||
("i" "Clock in here" org-clock-in)
|
||
("o" "Clock out" org-clock-out)])
|
||
|
||
(define-transient-command gpolonkai/special-files-menu ()
|
||
[("i" "My Emacs init file" gpolonkai/visit-init-file)
|
||
("o" "My main Org file" gpolonkai/visit-org-index)])
|
||
|
||
(define-transient-command gpolonkai/git-menu ()
|
||
[("g" "Update Git gutter everywhere" git-gutter:update-all-windows)
|
||
("m" "Show the origin of this line" git-messenger:popup-message)
|
||
("n" "Next hunk" git-gutter:next-hunk)
|
||
("p" "Previous hunk" git-gutter:previous-hunk)])
|
||
|
||
(define-transient-command gpolonkai/mail-menu ()
|
||
[("c" "Compose mail" mu4e-compose-new)
|
||
("i" "Jump to folder" mu4e~headers-jump-to-maildir)
|
||
("m" "Mu4e main screen" mu4e)
|
||
("s" "Mu4e search" mu4e-headers-search)])
|
||
|
||
(define-transient-command gpolonkai/sx-menu ()
|
||
[("i" "Inbox" sx-inbox)
|
||
("s" "Search" sx-search)])
|
||
|
||
(define-transient-command gpolonkai/zone-menu ()
|
||
[("i" "Enable zone on idle" gpolonkai/zone-enable)
|
||
("q" "Disable zone on idle" zone-leave-me-alone)])
|
||
|
||
(define-transient-command gpolonkai/python-menu ()
|
||
[("p" "Poetry" poetry)])
|
||
|
||
(define-transient-command gpolonkai/menu ()
|
||
[("a" "My agenda" gpolonkai/org-agenda-list)
|
||
("b" "Where has my cursor gone?" beacon-blink)
|
||
("C" "Capture" org-capture)
|
||
("c" "Clocking…" gpolonkai/clock-menu)
|
||
("M-C" "Clean up old buffers" clean-buffer-list)
|
||
("e" "EShell" eshell)
|
||
("g" "Git…" gpolonkai/git-menu)
|
||
("h" "Hide mode-line" hidden-mode-line-mode)
|
||
("l" "Store Org link" org-store-link)
|
||
("m" "Mail…" gpolonkai/mail-menu)
|
||
("o" "Special files…" gpolonkai/special-files-menu)
|
||
("p" "Python…" gpolonkai/python-menu)
|
||
("q" "Stack Exchange…" gpolonkai/sx-menu)
|
||
("r" "Show a random TODO" org-random-todo)
|
||
("u" "Open URL" browse-url-at-point)
|
||
("w" "Clean up whitespace problems" whitespace-cleanup)
|
||
("x" "Expand region" er/expand-region)
|
||
("z" "Zone…" gpolonkai/zone-menu)])
|
||
#+END_SRC
|
||
|
||
** The actual key bindings
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun gpolonkai/isearch-regexp (prefix)
|
||
"Call `isearch-forward-regex'. If PREFIX is non-nil, call `isearch-backward-regex' instead."
|
||
(interactive "P")
|
||
(call-interactively
|
||
(if prefix
|
||
'isearch-backward-regexp
|
||
'isearch-forward-regexp)))
|
||
#+end_src
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(bind-keys
|
||
:map global-map
|
||
("M-(" . gpolonkai/enclose-region)
|
||
("<C-return>" . open-line-below)
|
||
("<C-S-return>" . open-line-above)
|
||
("M-t" . nil) ;; Remove the old keybinding
|
||
("M-t c" . transpose-chars)
|
||
("M-t w" . transpose-words)
|
||
("M-t l" . transpose-lines)
|
||
("M-t e" . transpose-sexps)
|
||
("M-t s" . transpose-sentences)
|
||
("M-t p" . transpose-paragraphs)
|
||
("M-t W" . transpose-windows)
|
||
("C-a" . gpolonkai/move-to-beginning-of-line)
|
||
("C-e" . gpolonkai/move-to-end-of-line)
|
||
("M-q" . sachachua/fill-or-unfill-paragraph)
|
||
("C-c r" . round-number-at-point-to-decimals)
|
||
("C-s" . swiper)
|
||
("C-r" . gpolonkai/isearch-regexp)
|
||
("C-M-s" . isearch-forward)
|
||
("C-M-r" . isearch-backward)
|
||
("C-~" . toggle-char-case)
|
||
("C-z" . nil)
|
||
("M-g SPC" . goto-next-char)
|
||
:map ctl-x-map
|
||
("C-y" . gpolonkai/duplicate-line)
|
||
("_" . maximize-window)
|
||
("C-r" . rename-current-buffer-file)
|
||
("C-d" . delete-current-buffer-file)
|
||
("|" . toggle-window-split)
|
||
("k" . kill-this-buffer)
|
||
("M-k" . gpolonkai/undo-buffer-kill)
|
||
("C-b" . bury-buffer)
|
||
("/" . repeat)
|
||
("C-f" . counsel-find-file)
|
||
("b" . counsel-switch-buffer)
|
||
:map isearch-mode-map
|
||
("<C-return>" . isearch-exit-other-end)
|
||
("<S-return>" . isearch-exit-mark-match)
|
||
:map gpolonkai/pers-map
|
||
("C-t" . gpolonkai/menu)
|
||
("h" . hidden-mode-line-mode)
|
||
("C-i e" . "gergely@polonkai.eu")
|
||
("C-i w" . "http://gergely.polonkai.eu/")
|
||
("o i" . gpolonkai/visit-init-file)
|
||
("o o" . gpolonkai/visit-org-index)
|
||
("u" . browse-url-at-point)
|
||
("M-C" . clean-buffer-list)
|
||
("C-c" . calc)
|
||
("c i" . org-clock-in)
|
||
("c I" . org-clock-in-last)
|
||
("c o" . org-clock-out)
|
||
("c g" . org-clock-goto)
|
||
("M-o" . insert-current-file-name-at-point))
|
||
#+END_SRC
|
||
|
||
** TODO These fail to work using ~bind-keys~, but why?
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(define-key 'help-command (kbd "C-l") 'find-library)
|
||
(define-key 'help-command (kbd "C-f") 'find-function)
|
||
(define-key 'help-command (kbd "C-k") 'find-function-on-key)
|
||
(define-key 'help-command (kbd "C-v") 'find-variable)
|
||
#+END_SRC
|
||
|
||
* And finally, server mode
|
||
|
||
Sometimes i start an ~emacsclient~ process, like for editing a commit message or something
|
||
similar. As my startup time is pretty long, waiting for everything to complete is undesirable.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(require 'server)
|
||
(unless (server-running-p)
|
||
(server-start))
|
||
#+END_SRC
|