3071 lines
		
	
	
		
			86 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
			
		
		
	
	
			3071 lines
		
	
	
		
			86 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
* Custom functions and commands
 | 
						||
 | 
						||
This is a collection of functions and commands i wrote or stole from all around the internet.
 | 
						||
 | 
						||
** Org-mode related
 | 
						||
 | 
						||
*** 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 two spaces after certain marks
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defcustom gpolonkai/org-dbl-space-punct-marks (list ?. ?! ?? ?…)
 | 
						||
  "Punctuation marks after which the space key should insert two space characters."
 | 
						||
  :type '(set character))
 | 
						||
 | 
						||
(defun gpolonkai/org-space-key (&optional arg)
 | 
						||
  "Insert two spaces after certain markers.
 | 
						||
 | 
						||
ARG will be passed down verbatim to `self-insert-command'."
 | 
						||
  (interactive "p")
 | 
						||
 | 
						||
  (when (and
 | 
						||
         (not (org-in-block-p '("src")))
 | 
						||
         (looking-back (rx-to-string `(any,@ gpolonkai/org-dbl-space-punct-marks)) nil))
 | 
						||
    (call-interactively 'self-insert-command arg))
 | 
						||
  (call-interactively 'self-insert-command arg))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** 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, hence 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
 | 
						||
 | 
						||
*** 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
 | 
						||
 | 
						||
*** Unfold everything during ~ediff~ sessions
 | 
						||
 | 
						||
EDiff and Org-mode files don’t play nice together…
 | 
						||
 | 
						||
From [[https://list.orgmode.org/loom.20130801T011342-572@post.gmane.org/][the org-mode mailing list]].
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
*** Add code references to Org documents
 | 
						||
 | 
						||
From the [[http://www.howardism.org/Technical/Emacs/capturing-content.html][Howardism blog]].
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** Text manipulation
 | 
						||
 | 
						||
*** Fill or unfill a paragraph
 | 
						||
 | 
						||
From Sacha Chua’s [[http://pages.sachachua.com/.emacs.d/Sacha.html][blog]].
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
*** 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 gpolonkai/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
 | 
						||
 | 
						||
*** Sort lines by the first number on it
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun gpolonkai/numeric-sort-lines (reverse beg end)
 | 
						||
  "Sort lines in region by version.
 | 
						||
Interactively, REVERSE is the prefix argument, and BEG and END are the region.
 | 
						||
Non-nil REVERSE means to sort in reverse order."
 | 
						||
  (interactive "P\nr")
 | 
						||
  (save-excursion
 | 
						||
    (save-restriction
 | 
						||
      (narrow-to-region beg end)
 | 
						||
      (goto-char (point-min))
 | 
						||
      (let ((indibit-field-text-motion t))
 | 
						||
        (sort-subr reverse 'forward-line 'end-of-line #'gpolonkai/find-number-on-line)))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Open a new line above
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun wted/open-line-above ()
 | 
						||
  "Open a new line above point."
 | 
						||
 | 
						||
  (interactive)
 | 
						||
 | 
						||
  (beginning-of-line)
 | 
						||
  (newline)
 | 
						||
  (forward-line -1)
 | 
						||
  (let ((tab-always-indent t)
 | 
						||
	      (c-tab-always-indent t))
 | 
						||
    (indent-for-tab-command)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Open a new line below
 | 
						||
 | 
						||
Copied from [[http://whattheemacsd.com/editing-defuns.el-01.html][whattheemacsd.com]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun wted/open-line-below ()
 | 
						||
  "Open a new line below point."
 | 
						||
 | 
						||
  (interactive)
 | 
						||
 | 
						||
  (end-of-line)
 | 
						||
  (newline)
 | 
						||
  (let ((tab-always-indent t)
 | 
						||
        (c-tab-always-indent t))
 | 
						||
    (indent-for-tab-command)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Insert the current file’s name at point
 | 
						||
 | 
						||
From [[http://mbork.pl/2019-02-17_Inserting_the_current_file_name_at_point][Marcin Borkowski]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun mbork/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
 | 
						||
 | 
						||
*** Swap occurences of strings
 | 
						||
 | 
						||
From [[http://emacs.stackexchange.com/a/27170/507][Emacs SE]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun e-se/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
 | 
						||
 | 
						||
** Navigation
 | 
						||
 | 
						||
*** Move to different beginnings/ends 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))))
 | 
						||
 | 
						||
(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 gpolonkai/goto-next-char (chr)
 | 
						||
  (interactive "c")
 | 
						||
  (when (search-forward (char-to-string chr) (pos-eol) t)
 | 
						||
    (backward-char)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Move to the beginning of the next word
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun gpolonkai/beginning-of-next-word ()
 | 
						||
  (interactive)
 | 
						||
  (let ((current-point (point)))
 | 
						||
    (forward-word 1)
 | 
						||
    (backward-word 1)
 | 
						||
 | 
						||
    (when (<= (point) current-point)
 | 
						||
      (forward-word 2)
 | 
						||
      (backward-word 1))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** File manipulation
 | 
						||
 | 
						||
*** Rename the current file
 | 
						||
 | 
						||
From [[http://whattheemacsd.com/file-defuns.el-01.html][whattheemacsd.org]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun wted/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
 | 
						||
 | 
						||
From [[http://whattheemacsd.com/file-defuns.el-02.html][whattheemacsd.org]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun wted/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
 | 
						||
 | 
						||
** Magit
 | 
						||
 | 
						||
*** Go to the beginning of the current section
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun gpolonkai/magit-goto-beginning-of-section ()
 | 
						||
  (interactive)
 | 
						||
  (let ((section (magit-current-section)))
 | 
						||
    (magit-section-goto section)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Go to the end of the current section
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
 | 
						||
(defun gpolonkai/magit-goto-end-of-section ()
 | 
						||
  "Move to the beginning of the next visible section."
 | 
						||
  (interactive)
 | 
						||
  (unless (eobp)
 | 
						||
    (let ((section (magit-current-section)))
 | 
						||
      (if (oref section parent)
 | 
						||
          (let ((next (and (not (oref section hidden))
 | 
						||
                           (not (= (oref section end)
 | 
						||
                                   (1+ (point))))
 | 
						||
                           (car (oref section children)))))
 | 
						||
            (while (and section (not next))
 | 
						||
              (unless (setq next (car (magit-section-siblings section 'next)))
 | 
						||
                (setq section (oref section parent))))
 | 
						||
            (if next
 | 
						||
                (magit-section-goto next)
 | 
						||
              (end-of-buffer)))
 | 
						||
        (magit-section-goto 1)))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Find the first URL in the current section
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun gpolonkai/magit-find-first-link ()
 | 
						||
  (interactive)
 | 
						||
  (let ((bos (save-excursion
 | 
						||
               (gpolonkai/magit-goto-beginning-of-section)
 | 
						||
               (point)))
 | 
						||
        (eos (save-excursion
 | 
						||
               (gpolonkai/magit-goto-end-of-section)
 | 
						||
               (point))))
 | 
						||
    (goto-char bos)
 | 
						||
    (when (re-search-forward "https?://" eos t)
 | 
						||
      (goto-char (match-beginning 0)))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Set up the very basics
 | 
						||
 | 
						||
Now that we have package management configured we can set up defaults more easily.  This includes every builtin packages, font faces, and the like.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package emacs
 | 
						||
  :ensure nil
 | 
						||
  :init
 | 
						||
  ;; Required for Consult/Vertico
 | 
						||
  (defun crm-indicator (args)
 | 
						||
    (cons (format "[CRM%s] %s"
 | 
						||
                  (replace-regexp-in-string
 | 
						||
                   "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
 | 
						||
                   crm-separator)
 | 
						||
                  (car args))
 | 
						||
          (cdr args)))
 | 
						||
  (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
 | 
						||
  (setq frame-title-format '((:eval (concat system-name
 | 
						||
                                            ": "
 | 
						||
                                            (if (buffer-file-name)
 | 
						||
                                                (abbreviate-file-name (buffer-file-name))
 | 
						||
                                              "%b")))))
 | 
						||
  :custom
 | 
						||
  (user-full-name "Gergely Polonkai")
 | 
						||
  (user-mail-address "gergely@polonkai.eu")
 | 
						||
  (kill-read-only-ok t)
 | 
						||
  (use-dialog-box nil)
 | 
						||
  (cursor-type 'bar)
 | 
						||
  (echo-keystrokes .01)
 | 
						||
  (fill-column 120)
 | 
						||
  (initial-scratch-message "")
 | 
						||
  (minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt))
 | 
						||
  (enable-recursive-minibuffers t)
 | 
						||
  (completion-cycle-threshold 3)
 | 
						||
  (tab-always-indent 'complete)
 | 
						||
  :hook
 | 
						||
  (minibuffer-setup .  cursor-intangible-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Set Org’s main directory
 | 
						||
 | 
						||
Since a lot of packages (org-projectile, org-caldav, etc.) rely on it, it needs to be set as early as possible.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(setq org-directory (expand-file-name "org-mode" user-documents-directory))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Set up my personal keymap
 | 
						||
 | 
						||
I set it up at the beginning so i can use it with ~use-package~ invocations from early on
 | 
						||
 | 
						||
This might (should?) become a [[*general][general]] map later.
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** Set up some faces
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package faces
 | 
						||
  :ensure nil
 | 
						||
  :custom-face
 | 
						||
  (default ((t (:family "Fira Code Retina" :foundry "simp" :slant normal :weight normal :height 100 :width normal))))
 | 
						||
  (trailing-whitespace ((t (:inherit nil :background "red3")))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Fira Code comes with nice ligatures, let’s use them!
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ligature
 | 
						||
  :config
 | 
						||
  ;; Enable the "www" ligature in every possible major mode
 | 
						||
  (ligature-set-ligatures 't '("www"))
 | 
						||
  ;; Enable traditional ligature support in eww-mode, if the
 | 
						||
  ;; `variable-pitch' face supports it
 | 
						||
  (ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
 | 
						||
  ;; Enable all Cascadia and Fira Code ligatures in programming modes
 | 
						||
  (ligature-set-ligatures 'prog-mode
 | 
						||
                          '(;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~
 | 
						||
                            ;; =:= =!=
 | 
						||
                            ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "="))))
 | 
						||
                            ;; ;; ;;;
 | 
						||
                            (";" (rx (+ ";")))
 | 
						||
                            ;; && &&&
 | 
						||
                            ("&" (rx (+ "&")))
 | 
						||
                            ;; !! !!! !. !: !!. != !== !~
 | 
						||
                            ("!" (rx (+ (or "=" "!" "\." ":" "~"))))
 | 
						||
                            ;; ?? ??? ?:  ?=  ?.
 | 
						||
                            ("?" (rx (or ":" "=" "\." (+ "?"))))
 | 
						||
                            ;; %% %%%
 | 
						||
                            ("%" (rx (+ "%")))
 | 
						||
                            ;; |> ||> |||> ||||> |] |} || ||| |-> ||-||
 | 
						||
                            ;; |->>-||-<<-| |- |== ||=||
 | 
						||
                            ;; |==>>==<<==<=>==//==/=!==:===>
 | 
						||
                            ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]"
 | 
						||
                                            "-" "=" ))))
 | 
						||
                            ;; \\ \\\ \/
 | 
						||
                            ("\\" (rx (or "/" (+ "\\"))))
 | 
						||
                            ;; ++ +++ ++++ +>
 | 
						||
                            ("+" (rx (or ">" (+ "+"))))
 | 
						||
                            ;; :: ::: :::: :> :< := :// ::=
 | 
						||
                            (":" (rx (or ">" "<" "=" "//" ":=" (+ ":"))))
 | 
						||
                            ;; // /// //// /\ /* /> /===:===!=//===>>==>==/
 | 
						||
                            ("/" (rx (+ (or ">"  "<" "|" "/" "\\" "\*" ":" "!"
 | 
						||
                                            "="))))
 | 
						||
                            ;; .. ... .... .= .- .? ..= ..<
 | 
						||
                            ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\."))))
 | 
						||
                            ;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-|
 | 
						||
                            ("-" (rx (+ (or ">" "<" "|" "~" "-"))))
 | 
						||
                            ;; *> */ *)  ** *** ****
 | 
						||
                            ("*" (rx (or ">" "/" ")" (+ "*"))))
 | 
						||
                            ;; www wwww
 | 
						||
                            ("w" (rx (+ "w")))
 | 
						||
                            ;; <> <!-- <|> <: <~ <~> <~~ <+ <* <$ </  <+> <*>
 | 
						||
                            ;; <$> </> <|  <||  <||| <|||| <- <-| <-<<-|-> <->>
 | 
						||
                            ;; <<-> <= <=> <<==<<==>=|=>==/==//=!==:=>
 | 
						||
                            ;; << <<< <<<<
 | 
						||
                            ("<" (rx (+ (or "\+" "\*" "\$" "<" ">" ":" "~"  "!"
 | 
						||
                                            "-"  "/" "|" "="))))
 | 
						||
                            ;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>>
 | 
						||
                            ;; >> >>> >>>>
 | 
						||
                            (">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-"))))
 | 
						||
                            ;; #: #= #! #( #? #[ #{ #_ #_( ## ### #####
 | 
						||
                            ("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_"
 | 
						||
                                         (+ "#"))))
 | 
						||
                            ;; ~~ ~~~ ~=  ~-  ~@ ~> ~~>
 | 
						||
                            ("~" (rx (or ">" "=" "-" "@" "~>" (+ "~"))))
 | 
						||
                            ;; __ ___ ____ _|_ __|____|_
 | 
						||
                            ("_" (rx (+ (or "_" "|"))))
 | 
						||
                            ;; Fira code: 0xFF 0x12
 | 
						||
                            ("0" (rx (and "x" (+ (in "A-F" "a-f" "0-9")))))
 | 
						||
                            ;; Fira code:
 | 
						||
                            "Fl"  "Tl"  "fi"  "fj"  "fl"  "ft"
 | 
						||
                            ;; The few not covered by the regexps.
 | 
						||
                            "{|"  "[|"  "]#"  "(*"  "}#"  "$>"  "^="))
 | 
						||
  ;; Enables ligature checks globally in all buffers. You can also do it
 | 
						||
  ;; per mode with `ligature-mode'.
 | 
						||
  (global-ligature-mode t))
 | 
						||
#+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 "Fira Code Retina-10")
 | 
						||
    (set-frame-font "Fira Code Retina-10" 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 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
 | 
						||
 | 
						||
** Default frame settings
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package frame
 | 
						||
  :ensure nil
 | 
						||
  :custom
 | 
						||
  ;; Make that cursor blink!
 | 
						||
  (blink-cursor-mode t))
 | 
						||
#+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
 | 
						||
 | 
						||
** Tweak window chrome, AKA let’s set up the UI
 | 
						||
 | 
						||
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
 | 
						||
 | 
						||
** Enable all the commands!
 | 
						||
 | 
						||
These are disabled for a reason, but i’m a rockstar, so who cares‽
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
* Global built-in packages
 | 
						||
 | 
						||
** ~simple~, to always show the current column, and using visual lines in text modes
 | 
						||
 | 
						||
Column numbers help a lot in debugging, while visual line mode is easier on the eye when writing long text.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package simple
 | 
						||
  :ensure nil
 | 
						||
  :custom
 | 
						||
  (column-number-mode t)
 | 
						||
  :hook
 | 
						||
  (text-mode . (lambda () (visual-line-mode t))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~prog-mode~
 | 
						||
 | 
						||
Plus prettify all the symbols!
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package prog-mode
 | 
						||
  :ensure nil
 | 
						||
  :init
 | 
						||
  (setq prettify-symbols-alist
 | 
						||
        '(("lambda" . ?λ)
 | 
						||
          ("function" . ?ƒ)
 | 
						||
          ("map" . ?↦)
 | 
						||
          ("not" . ?¬)
 | 
						||
          ("and" . ?∧)
 | 
						||
          ("or" . ?∨)))
 | 
						||
  :config
 | 
						||
  (global-prettify-symbols-mode t))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~thingatpt~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package thingatpt
 | 
						||
  :ensure nil)
 | 
						||
#+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 120)
 | 
						||
  :bind
 | 
						||
  (([f10] . whitespace-mode)
 | 
						||
   ([(shift f10)] . global-whitespace-mode)
 | 
						||
   :map gpolonkai/pers-map
 | 
						||
   ("w" . whitespace-cleanup))
 | 
						||
  :custom-face
 | 
						||
  (whitespace-line ((t (:inherit nil :background "orange4")))))
 | 
						||
#+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
 | 
						||
 | 
						||
This sends an alert when an eshell command is finished.  Taken from
 | 
						||
[[https://blog.hoetzel.info/post/eshell-notifications/][here]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun eshell-command-alert (process status)
 | 
						||
  "Send `alert' with severity based on STATUS when PROCESS finished."
 | 
						||
  (let* ((cmd (process-command process))
 | 
						||
         (buffer (process-buffer process))
 | 
						||
         (msg (format "%s: %s" (mapconcat 'identity cmd " ")  status)))
 | 
						||
    (if (string-prefix-p "finished" status)
 | 
						||
        (alert msg :buffer buffer :severity  'normal)
 | 
						||
      (alert msg :buffer buffer :severity 'urgent))))
 | 
						||
#+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)
 | 
						||
  (eshell-kill . eshell-command-alert))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~calendar~ & Co.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package calendar
 | 
						||
  :ensure nil
 | 
						||
  :custom
 | 
						||
  (calendar-week-start-day 1))
 | 
						||
 | 
						||
(use-package cal-dst
 | 
						||
  :ensure nil
 | 
						||
  :custom
 | 
						||
  (calendar-time-zone 60)
 | 
						||
  (calendar-standard-time-zone-name "CET")
 | 
						||
  (calendar-daylight-time-zone-name "CEST"))
 | 
						||
 | 
						||
(use-package solar
 | 
						||
  :ensure nil
 | 
						||
  :custom
 | 
						||
  (calendar-latitude 47.4)
 | 
						||
  (calendar-longitude 19.0)
 | 
						||
  (calendar-location-name "Budapest, Hungary"))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Add Hungarian holidays to the calendar
 | 
						||
 | 
						||
I know this is the builtin packages section.  Sorry for cheating.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package hungarian-holidays
 | 
						||
  :config
 | 
						||
  (hungarian-holidays-add))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Add some other important dates to the calendar
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~saveplace~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package saveplace
 | 
						||
  :ensure nil
 | 
						||
  :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
 | 
						||
  :ensure nil
 | 
						||
  :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
 | 
						||
 | 
						||
** ~autorevert~
 | 
						||
 | 
						||
…unless they are modified, of course.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package autorevert
 | 
						||
  :ensure nil
 | 
						||
  :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~, for automatic indentation
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~savehist~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package savehist
 | 
						||
  :config
 | 
						||
  (savehist-mode 1))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~webjump~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package webjump
 | 
						||
  :bind
 | 
						||
  (:map gpolonkai/pers-map
 | 
						||
   ("j" . webjump)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~which-func~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun gpolonkai/activate-which-func-mode ()
 | 
						||
  (if (fboundp 'which-function-mode)
 | 
						||
      (which-function-mode)
 | 
						||
    (which-func-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
Enable ~which-func-mode~ in every ~prog-mode~ derived mode.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package which-func
 | 
						||
  :config
 | 
						||
  (setq which-func-unknown "∅")
 | 
						||
  :hook
 | 
						||
  (prog-mode . gpolonkai/activate-which-func-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~cookie1~, AKA fortune cookies
 | 
						||
 | 
						||
“Fortunes” 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
 | 
						||
 | 
						||
** ~dired~
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~goto-addr~, 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~
 | 
						||
 | 
						||
Since my machine (and thus, my Emacs) is turned on pretty much 24/7, it’s a pretty good idea.
 | 
						||
 | 
						||
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
 | 
						||
 | 
						||
** ~display-line-numbers~
 | 
						||
 | 
						||
I usually don’t want to see them, but there are occasions when they’re useful.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package display-line-numbers
 | 
						||
  :bind
 | 
						||
  (:map gpolonkai/pers-map
 | 
						||
   ("C-n" . display-line-numbers-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ispell~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ispell
 | 
						||
  :custom
 | 
						||
  (ispell-dictionary "en_GB")
 | 
						||
  (ispell-program-name "/usr/bin/hunspell")
 | 
						||
  :hook
 | 
						||
  (mail-send . ispell-message)
 | 
						||
  (message-send . ispell-message))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~speedbar~
 | 
						||
 | 
						||
This is basically just a dependency for [[*projectile-speedbar][projectile-speedbar]].
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package speedbar)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~browse-url~
 | 
						||
 | 
						||
This is a Termux-specific override.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(when (gpolonkai/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
 | 
						||
 | 
						||
** ~dabbrev~
 | 
						||
 | 
						||
I simply remap ~dabbrev-expand~ to a different key and replace the default binding with ~dabbrev-completion~.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dabbrev
 | 
						||
  :bind (("M-/" . dabbrev-completion)
 | 
						||
         ("C-M-/" . dabbrev-expand)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Project management
 | 
						||
 | 
						||
** ~projectile~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package projectile
 | 
						||
  :demand t
 | 
						||
  :delight '(:eval (concat " [" projectile-project-name "]"))
 | 
						||
  :config
 | 
						||
  (projectile-mode t)
 | 
						||
  :bind
 | 
						||
  (:map mode-specific-map
 | 
						||
   ("p" . projectile-command-map)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~projectile-speedbar~
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~org-projectile~ for per-repository ToDo files using Org
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-projectile
 | 
						||
  :after (:all projectile org)
 | 
						||
  :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
 | 
						||
 | 
						||
* External packages to boost usability
 | 
						||
 | 
						||
** ~gnu-elpa-keyring-update~, to make sure we always have the latest ELPA GPG keys
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package gnu-elpa-keyring-update)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~auto-package-update~, to 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
 | 
						||
 | 
						||
** ~ace-window~, for better window navigation
 | 
						||
 | 
						||
Besides its standard functionality i also add key bindings for burying or scrolling other windows.
 | 
						||
 | 
						||
#+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))
 | 
						||
  :custom-face
 | 
						||
  (aw-leading-char-face ((t (:inherit ace-jump-face-foreground :height 2.0)))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~doom-themes~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package doom-themes
 | 
						||
  :custom
 | 
						||
  (doom-themes-enable-bold t)
 | 
						||
  (doom-themes-enable-italic t)
 | 
						||
  :config
 | 
						||
  (load-theme 'doom-nord-aurora t)
 | 
						||
  (doom-themes-visual-bell-config)
 | 
						||
  (doom-themes-org-config))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Nyanyanyanyanya
 | 
						||
 | 
						||
*** ~nyan-mode~: Nyan-cat style position marker
 | 
						||
 | 
						||
The package that [[https://gergely.polonkai.eu/blog/2014/9/17/nyanmacs.html][made me]] switch to Emacs.
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~delight~ to de-light some minor modes
 | 
						||
 | 
						||
The list of active minor modes can easily fill my whole mode line (twice…).  This is one of the things to protect me from that.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package delight)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~minions~, to put all minor modes into a menu
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package minions
 | 
						||
  :config
 | 
						||
  (minions-mode 1))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~doom-modeline~, because it’s much, much more beautiful than the vanilla one
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package doom-modeline
 | 
						||
  :init
 | 
						||
  (doom-modeline-mode 1)
 | 
						||
  :custom
 | 
						||
  (doom-modeline-continuous-word-count-modes '(markdown-mode gfm-mode org-mode rst-mode))
 | 
						||
  (doom-modeline-hud t)
 | 
						||
  (doom-modeline-minor-modes t))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~beacon~ to find the cursor
 | 
						||
 | 
						||
Sometimes it disappears, or just too hard to see.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package beacon
 | 
						||
  :demand
 | 
						||
  :config
 | 
						||
  (beacon-mode 1)
 | 
						||
  :bind
 | 
						||
  (:map gpolonkai/pers-map
 | 
						||
   ("b" . beacon-blink)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~eshell~ extras
 | 
						||
 | 
						||
*** 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
 | 
						||
 | 
						||
** ~form-feed~, to show form feed characters as a horizontal line
 | 
						||
 | 
						||
Some (many?  most?) Emacs packages use this to do some logical separation of the code.  It is also used by some compilers, and Emacs’ help system.
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~hl-line~, to highlight the current line
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package hl-line
 | 
						||
  :config
 | 
						||
  (when window-system
 | 
						||
    (global-hl-line-mode))
 | 
						||
  :custom-face
 | 
						||
  (hl-line ((t (:inherit nil :background "gray25")))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ace-jump-mode~, to jump to a specific character
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ace-jump-mode
 | 
						||
  :bind
 | 
						||
  (:map gpolonkai/pers-map
 | 
						||
   ("SPC" . ace-jump-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Multiple cursors, because one is often not enough
 | 
						||
 | 
						||
*** ~multiple-cursors~
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
*** ~phi-search~, incremental search compatible with ~multiple-cursors~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package phi-search)
 | 
						||
 | 
						||
(use-package phi-search-mc
 | 
						||
  :config
 | 
						||
  (phi-search-mc/setup-keys))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** ~mc-extras~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package mc-extras
 | 
						||
  :demand
 | 
						||
  :bind
 | 
						||
  (:map mc/keymap
 | 
						||
   ("=" . mc/compare-chars)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** Add extra cursors with ~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
 | 
						||
 | 
						||
** ~smartparens~ for easier parentheses insertion
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package smartparens
 | 
						||
  :demand
 | 
						||
  :config
 | 
						||
  (require 'smartparens-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)
 | 
						||
   ("C-c s r" . sp-rewrap-sexp)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~which-key~ to display available key bindings
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package which-key
 | 
						||
  :config
 | 
						||
  (which-key-mode)
 | 
						||
  (which-key-setup-minibuffer)
 | 
						||
  :custom
 | 
						||
  (which-key-idle-delay 0.3))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~visual-fill-column~, width limited text view
 | 
						||
 | 
						||
It’s much easier on the eye when writing text, not code.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package visual-fill-column
 | 
						||
  :custom
 | 
						||
  (visual-fill-column-center-text t)
 | 
						||
  (visual-fill-column-width 120)
 | 
						||
  :hook
 | 
						||
  (org-mode . visual-fill-column-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~spinner~, to display a progress bar for e.g. background tasks
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package spinner)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~avy~ to jump to things
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~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/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~ to toggle other windows for maximum focus
 | 
						||
 | 
						||
When focus is no longer needed, they can be toggled back.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package zygospore
 | 
						||
  :bind
 | 
						||
  (:map ctl-x-map
 | 
						||
   ("1" . zygospore-toggle-delete-other-windows)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~dashboard~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dashboard
 | 
						||
  :after
 | 
						||
  projectile
 | 
						||
  :config
 | 
						||
  (add-to-list 'dashboard-items '(projects . 5) t)
 | 
						||
  (dashboard-setup-startup-hook)
 | 
						||
  :custom
 | 
						||
  (dashboard-set-heading-icons t)
 | 
						||
  (dashboard-set-file-icons t)
 | 
						||
  (dashboard-center-content t)
 | 
						||
  (dashboard-set-navigator t)
 | 
						||
  (dashboard-items '((agenda . 5)
 | 
						||
                     (projects . 5)
 | 
						||
                     (recents . 5)
 | 
						||
                     (bookmarks . 5))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~sr-speedbar~, speed bar in the same frame
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package sr-speedbar
 | 
						||
  :after speedbar)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~hungry-delete~ to delete all the whitespace
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package hungry-delete
 | 
						||
  :config
 | 
						||
  (global-hungry-delete-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~anzu~, to show number of matches while searching
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package anzu
 | 
						||
  :delight
 | 
						||
  :config
 | 
						||
  (global-anzu-mode 1))
 | 
						||
#+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
 | 
						||
 | 
						||
And apply it to dired, too.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package all-the-icons-dired
 | 
						||
  :hook
 | 
						||
  (dired-mode . all-the-icons-dired-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~flyspell~ for all my spell-checking needs
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package flyspell
 | 
						||
  :hook
 | 
						||
  (prog-mode . flyspell-prog-mode)
 | 
						||
  (text-mode . flyspell-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ace-flyspell~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ace-flyspell
 | 
						||
  :bind
 | 
						||
  (:map flyspell-mode-map
 | 
						||
   ("C-M-i" . ace-flyspell-correct-word)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~objed~, 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
 | 
						||
 | 
						||
** ~alert~ to send alerts to a notification system
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package alert
 | 
						||
  :config
 | 
						||
  (setq alert-default-style 'libnotify))
 | 
						||
#+end_src
 | 
						||
 | 
						||
Only send alerts from eshell when the buffer is not visible:
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(alert-add-rule
 | 
						||
 :status '(buried)
 | 
						||
 :mode   'eshell-mode
 | 
						||
 :style  'notifications)
 | 
						||
#+end_src
 | 
						||
 | 
						||
Send alerts to Termux if we are running there
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(when (gpolonkai/termux-p)
 | 
						||
  (use-package alert-termux
 | 
						||
    :after alert
 | 
						||
    :config
 | 
						||
    (setq alert-default-style 'termux)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~undo-tree~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package undo-tree
 | 
						||
  :config
 | 
						||
  (global-undo-tree-mode)
 | 
						||
  :custom
 | 
						||
  (undo-tree-auto-save-history nil))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ciel~ to mimic 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
 | 
						||
 | 
						||
** ~hide-mode-line~ to hide the modeline occasionally
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package hide-mode-line
 | 
						||
  :bind (:map gpolonkai/pers-map
 | 
						||
         ("h" . hide-mode-line-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~string-inflection~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package string-inflection
 | 
						||
  :bind (:map gpolonkai/pers-map
 | 
						||
         ("i" . string-inflection-all-cycle)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~spdx~ to insert SPDX compatible license text
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package spdx
 | 
						||
  :bind (:map gpolonkai/pers-map
 | 
						||
         ("L" . spdx-insert-spdx-copyright))
 | 
						||
  :custom
 | 
						||
  (spdx-copyright-holder 'user)
 | 
						||
  (spdx-copyright-sign 'unicode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ag~ to use the silver searcher
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ag
 | 
						||
  :commands (ag))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~rg~ to use ripgrep
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package rg
 | 
						||
  :commands (rg))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Dired extras
 | 
						||
 | 
						||
** ~dired-collapse~, to collapse directories that contain a single file somewhere deep
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dired-collapse)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~dired-du~ to show directory sizes
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dired-du)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~dired-git-info~ to show Git version information
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dired-git-info
 | 
						||
  :bind
 | 
						||
  (:map dired-mode-map
 | 
						||
   (")" . dired-git-info-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~dired-hide-dotfiles~ to show/hide hidden (dot) files
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dired-hide-dotfiles
 | 
						||
  :bind
 | 
						||
  (:map dired-mode-map
 | 
						||
   ("." . dired-hide-dotfiles-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~dired-rainbow~ to color code file types
 | 
						||
 | 
						||
Rainbow to the stars…
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dired-rainbow
 | 
						||
  :config
 | 
						||
  (dired-rainbow-define-chmod executable-unix "Green" "-.*x.*"))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~dired-k~ to highlight dired buffers by file size, mtime, git status, etc.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dired-k
 | 
						||
  :bind
 | 
						||
  (:map dired-mode-map
 | 
						||
   ("K" . dired-k)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Git related things
 | 
						||
 | 
						||
** ~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
 | 
						||
 | 
						||
** ~forge~ to make Magit work with Git forges
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package forge)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~git-gutter~ to see changed lines
 | 
						||
 | 
						||
In graphical mode we use ~git-gutter-finge~, ~git-gutter~ otherwise (as we have no fringe in that case).
 | 
						||
 | 
						||
It also provides some nice commands to navigate between change sets.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(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 annotate current line
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package git-messenger
 | 
						||
  :bind
 | 
						||
  (:map gpolonkai/pers-map
 | 
						||
   ("gm" . git-messenger:popup-message)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~git-timemachine~, to see previous versions of the current file
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package git-timemachine
 | 
						||
  :bind
 | 
						||
  (([f6] . git-timemachine-toggle)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Completion related external packages
 | 
						||
 | 
						||
** ~vertico~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package vertico
 | 
						||
  :init
 | 
						||
  (vertico-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~consult~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package consult
 | 
						||
  :bind (:map global-map
 | 
						||
         ([remap Info-search] . consult-info)
 | 
						||
         ("M-y" . consult-yank-pop)
 | 
						||
         :map ctl-x-map
 | 
						||
         ("M-:" . consult-complex-command)
 | 
						||
         ("4 b" . consult-buffer-other-window)
 | 
						||
         ("5 b" . consult-buffer-other-frame)
 | 
						||
         ("b" . consult-buffer)
 | 
						||
         ("r b" . consult-bookmark)
 | 
						||
         ("x b" . consult-project-buffer)
 | 
						||
         :map goto-map
 | 
						||
         ("e" . consult-compile-error)
 | 
						||
         ("F" . consult-flymake)
 | 
						||
         ("g" . consult-goto-line)
 | 
						||
         ("M-g" . consult-goto-line)
 | 
						||
         ("i" . consult-imenu)
 | 
						||
         ("I" . consult-imenu-multi)
 | 
						||
         ("k" . consult-global-mark)
 | 
						||
         ("m" . consult-mark)
 | 
						||
         ("o" . consult-org-heading)
 | 
						||
         :map search-map
 | 
						||
         ("d" . consult-find)
 | 
						||
         ("D" . consult-locate)
 | 
						||
         ("e" . consult-isearch-history)
 | 
						||
         ("k" . consult-keep-lines)
 | 
						||
         ("l" . consult-line)
 | 
						||
         ("L" . consult-line-multi)
 | 
						||
         :map isearch-mode-map
 | 
						||
         ("M-e" . consult-isearch-history)
 | 
						||
         :map minibuffer-local-map
 | 
						||
         ("M-s" . consult-history)
 | 
						||
         ("M-r" . consult-history))
 | 
						||
  :hook
 | 
						||
  (completion-list-mode . consult-preview-at-point-mode)
 | 
						||
  :custom
 | 
						||
  (consult-narrow-key "<")
 | 
						||
  (consult-project-function (lambda (_) (projectile-project-root)))
 | 
						||
  (register-preview-delay 0.5)
 | 
						||
  (xref-show-xrefs-function #'consult-xref)
 | 
						||
  (xref-show-definitions-function #'consult-xref)
 | 
						||
  :init
 | 
						||
  (setq register-preview-function #'consult-register-format)
 | 
						||
  (advice-add #'register-preview :override #'consult-register-window)
 | 
						||
  :config
 | 
						||
  (defalias 'consult-line-thing-at-point 'consult-line)
 | 
						||
  (consult-customize
 | 
						||
   consult-theme :preview-key '(:debounce 0.2 any)
 | 
						||
   consult-buffer :preview-key "M-."
 | 
						||
   consult-line-thing-at-point :initial (thing-at-point 'symbol)
 | 
						||
   consult-ripgrep
 | 
						||
   consult-git-grep
 | 
						||
   consult-grep
 | 
						||
   consult-bookmark
 | 
						||
   consult-recent-file
 | 
						||
   consult-xref
 | 
						||
   consult--source-bookmark
 | 
						||
   consult--source-file-register
 | 
						||
   consult--source-recent-file
 | 
						||
   consult--source-project-recent-file
 | 
						||
   :preview-key '(:debounce 0.4 any))
 | 
						||
  (autoload 'projectile-project-root "projectile"))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~orderless~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package orderless
 | 
						||
  :init
 | 
						||
  (setq completion-category-defaults nil)
 | 
						||
  :custom
 | 
						||
  (completion-styles '(orderless basic))
 | 
						||
  (completion-category-defaults nil)
 | 
						||
  (completion-category-overrides '((file (styles basic partial-completion)))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~marginalia~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package marginalia
 | 
						||
  :bind (:map minibuffer-local-map
 | 
						||
         ("M-A" . marginalia-cycle))
 | 
						||
  :init
 | 
						||
  (marginalia-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~embark~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package embark
 | 
						||
  :bind (:map global-map
 | 
						||
         ("C-." . embark-act))
 | 
						||
  :config
 | 
						||
  (add-to-list 'display-buffer-alist
 | 
						||
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
 | 
						||
                 nil
 | 
						||
                 (window-parameters (mode-line-format . none)))))
 | 
						||
 | 
						||
(use-package embark-consult
 | 
						||
  :hook
 | 
						||
  (embark-collect-mode . consult-preview-at-point-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~consult-projectile~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package consult-projectile
 | 
						||
  :demand t
 | 
						||
  :after (:all projectile consult embark)
 | 
						||
  :config
 | 
						||
  (defvar-keymap embark-consult-projectile-project-map
 | 
						||
    :doc "Keymap to use for the projectile menu"
 | 
						||
    :parent embark-general-map
 | 
						||
    "g" #'magit-status)
 | 
						||
  (add-to-list 'embark-keymap-alist '(consult-projectile-project embark-consult-projectile-project-map))
 | 
						||
  (autoload 'magit-status "magit")
 | 
						||
  :bind (:map projectile-command-map
 | 
						||
         ("p" . consult-projectile-switch-project)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~corfu~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package corfu
 | 
						||
  :init
 | 
						||
  (global-corfu-mode)
 | 
						||
  :custom
 | 
						||
  (corfu-cycle t)
 | 
						||
  (corfu-separator ?\s))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~cape~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defvar gpolonkai/completion-at-point-map (make-sparse-keymap)
 | 
						||
  "Map for traspose functions.")
 | 
						||
(define-prefix-command 'gpolonkai/completion-at-point-map)
 | 
						||
 | 
						||
(use-package cape
 | 
						||
  :bind (:map gpolonkai/completion-at-point-map
 | 
						||
             ("p" . completion-at-point)
 | 
						||
             :map gpolonkai/pers-map
 | 
						||
             ("p" . gpolonkai/completion-at-point-map))
 | 
						||
  :init
 | 
						||
  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
 | 
						||
  (add-to-list 'completion-at-point-functions #'cape-file)
 | 
						||
  (add-to-list 'completion-at-point-functions #'cape-elisp-block)
 | 
						||
  (add-to-list 'completion-at-point-functions #'cape-elisp-symbol))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Org mode
 | 
						||
 | 
						||
** ~outline~
 | 
						||
 | 
						||
This is the mode Org is based on.  It’s technically a built-in, but i configure it here so it remains together with other Org setup.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package outline
 | 
						||
  :ensure nil
 | 
						||
  :custom-face
 | 
						||
  (outline-1 ((t (:inherit font-lock-function-name-face :overline t :weight bold :height 1.2))))
 | 
						||
  (outline-2 ((t (:inherit font-lock-variable-name-face :overline t :weight bold :height 1.1))))
 | 
						||
  (outline-3 ((t (:inherit font-lock-keyword-face :overline t :weight bold)))))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Function to set up Org-mode buffers
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun gpolonkai/setup-org-mode ()
 | 
						||
  (org-indent-mode 1)
 | 
						||
  (variable-pitch-mode 1)
 | 
						||
  (auto-fill-mode 0)
 | 
						||
  (visual-line-mode 1))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Display horizontal rulers as a full-width line
 | 
						||
 | 
						||
From [[https://matrix.to/#/@suckless_shill:matrix.org][viz]] in the [[https://matrix.to/#/#org-mode:matrix.org][org-mode]] Matrix room.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defun vz/org-fontify-horizontal-break ()
 | 
						||
  "Display Org’s horizontal break (-----) as a full-width horizontal line"
 | 
						||
  (push '("^[[:space:]]*\\(------*\\)\n"
 | 
						||
          (0 (progn
 | 
						||
               (put-text-property (match-beginning 1) (match-end 1)
 | 
						||
                                  'display (make-string (- (match-end 1) (match-beginning 1)) ?\s))
 | 
						||
               (put-text-property (match-beginning 1) (match-end 0)
 | 
						||
                                  'face '(:strike-through t :extend t)))))
 | 
						||
        org-font-lock-extra-keywords)
 | 
						||
  (setq-local font-lock-extra-managed-props (cons 'display font-lock-extra-managed-props)))
 | 
						||
 | 
						||
(add-hook 'org-font-lock-set-keywords-hook #'vz/org-fontify-horizontal-break)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Main ~org~ configuration
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org
 | 
						||
  :demand
 | 
						||
  :custom-face
 | 
						||
  (org-block ((t (:inherit fixed-pitch))))
 | 
						||
  (org-code ((t (:inherit (shadow fixed-pitch)))))
 | 
						||
  (org-indent ((t (:inherit (org-hide fixed-pitch)))))
 | 
						||
  (org-verbatim ((t (:inherit (shadow fixed-pitch)))))
 | 
						||
  (org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 | 
						||
  (org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 | 
						||
  (org-checkbox ((t (:inherit fixed-pitch))))
 | 
						||
  (org-table ((t (:inherit (shadow fixed-pitch)))))
 | 
						||
  (org-_drawer ((t (:inherit (shadow fixed-pitch)))))
 | 
						||
  :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 sure we load Python babel stuff
 | 
						||
  (org-babel-do-load-languages
 | 
						||
   'org-babel-load-languages
 | 
						||
   '((python . t)))
 | 
						||
  ;; Track habits
 | 
						||
  (require 'org-habit)
 | 
						||
  :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 '((nil :maxlevel . 6)
 | 
						||
                        (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)
 | 
						||
  (org-link-descriptive t)
 | 
						||
  (org-hide-emphasis-markers t)
 | 
						||
  (org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled)
 | 
						||
  (org-deadline-warning-days 7)
 | 
						||
  :hook
 | 
						||
  (ediff-select . f-ediff-org-unfold-tree-element)
 | 
						||
  (ediff-unselect . f-ediff-org-fold-tree)
 | 
						||
  (org-mode .  gpolonkai/setup-org-mode)
 | 
						||
  :bind
 | 
						||
  (:map gpolonkai/pers-map
 | 
						||
        ("a" . gpolonkai/org-agenda-list)
 | 
						||
        ("C" . org-capture)
 | 
						||
        ("l" . org-store-link)
 | 
						||
        :map org-mode-map
 | 
						||
        ("SPC" . gpolonkai/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 ." . gpolonkai/org-insert-current-timestamp)
 | 
						||
        ("C-c ;" . org-toggle-timestamp-type)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~org-roam~
 | 
						||
 | 
						||
Let’s see if i can get my brain more organised this way…
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-roam
 | 
						||
  :after org
 | 
						||
  :ensure t
 | 
						||
  :config
 | 
						||
  (setq org-roam-node-display-template (concat "${title:*} "
 | 
						||
                                               (propertize "${tags:10}" 'face 'org-tag)))
 | 
						||
  (org-roam-db-autosync-mode)
 | 
						||
  (require 'org-roam-dailies)
 | 
						||
  (require 'org-roam-protocol)
 | 
						||
  :custom
 | 
						||
  (org-roam-directory (file-truename (expand-file-name "roam" org-directory)))
 | 
						||
  (org-roam-dailies-directory (file-truename (expand-file-name "roam/journal" org-directory)))
 | 
						||
  (org-roam-completion-everywhere t)
 | 
						||
  (org-roam-capture-templates '(("d" "default" plain "\n%?"
 | 
						||
                                 :target (file+head
 | 
						||
                                          "${slug}-%<%Y%m%d%H%M%S>.org"
 | 
						||
                                          "#+title: ${title}")
 | 
						||
                                 :unnarrowed t)))
 | 
						||
  (org-roam-dailies-capture-templates '(
 | 
						||
                                        ("d" "default" entry "* %<%H:%M>: %?"
 | 
						||
                                         :if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))
 | 
						||
  :bind
 | 
						||
  (("C-c n c" . org-roam-capture)
 | 
						||
   ("C-c n g" . org-roam-graph)
 | 
						||
   ("C-c n i" . org-roam-node-insert)
 | 
						||
   ("C-c n l" . org-roam-buffer-toggle)
 | 
						||
   :map org-mode-map
 | 
						||
   ("C-M-i" . completion-at-point)
 | 
						||
   :map org-roam-dailies-map
 | 
						||
   ("d" . org-roam-dailies-capture-date)
 | 
						||
   ("j" . org-roam-dailies-capture-today)
 | 
						||
   ("Y" . org-roam-dailies-capture-yesterday)
 | 
						||
   ("T" . org-roam-dailies-capture-tomorrow))
 | 
						||
  :bind-keymap
 | 
						||
  ("C-c n d" . org-roam-dailies-map))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~org-roam-timestamps~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-roam-timestamps
 | 
						||
  :after org-roam
 | 
						||
  :config
 | 
						||
  (org-roam-timestamps-mode)
 | 
						||
  :custom
 | 
						||
  (org-roam-timestamps-remember-timestamps t)
 | 
						||
  (org-roam-timestamps-timestamp-parent-file t))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~org-roam-ui~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-roam-ui
 | 
						||
  :after org-roam
 | 
						||
  :custom
 | 
						||
  (org-roam-ui-sync-theme t)
 | 
						||
  (org-roam-ui-follow t)
 | 
						||
  (org-roam-ui-update-on-save t)
 | 
						||
  (org-roam-ui-open-on-start nil))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~org-bullets~ for more beautiful bullet points
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~org-sticky-header~ 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
 | 
						||
 | 
						||
** ~org-random-todo~ to 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
 | 
						||
 | 
						||
** ~org-autolist~ for better list management
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-autolist
 | 
						||
  :hook
 | 
						||
  (org-mode . org-autolist-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~secretaria~ to remind me of my tasks
 | 
						||
 | 
						||
And 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
 | 
						||
 | 
						||
** ~org-clock-waybar~ to export currently clocked task for status bar display
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-clock-waybar
 | 
						||
  :ensure nil
 | 
						||
  :vc (:url "https://gitea.polonkai.eu/gergely/org-clock-waybar.git")
 | 
						||
  :config
 | 
						||
  (org-clock-waybar-setup))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~consult-org-roam~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package consult-org-roam
 | 
						||
  :config
 | 
						||
  (consult-org-roam-mode)
 | 
						||
  :bind (:map goto-map
 | 
						||
         ("r" . consult-org-roam-search)
 | 
						||
         :map global-map
 | 
						||
         ("C-c n f" . consult-org-roam-file-find)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~org-appear~, to display markup only when it’s actually needed
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package org-appear
 | 
						||
  :hook
 | 
						||
  (org-mode . org-appear-mode)
 | 
						||
  :custom
 | 
						||
  (org-appear-autosubmarkers t)
 | 
						||
  (org-appear-autolinks t)
 | 
						||
  (org-appear-autoemphasis t))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ob-mermaid~, to generate Mermaid diagrams
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ob-mermaid
 | 
						||
  :custom
 | 
						||
  (ob-mermaid-cli-path "/home/polesz/.local/node/bin/mmdc"))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~plantuml-mode~ to edit PlantUML files in and out of Org documents
 | 
						||
 | 
						||
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
 | 
						||
 | 
						||
** ~ox-rst~ to export to ReSTructured text
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ox-rst
 | 
						||
  :after org)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~orgit~ and ~orgit-forge~ to store link to Git stuff
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package orgit
 | 
						||
  :after magit org)
 | 
						||
 | 
						||
(use-package orgit-forge
 | 
						||
  :after magit org orgit)
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Mailing
 | 
						||
 | 
						||
** Set up whitespace handling in mu4e buffers
 | 
						||
 | 
						||
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
 | 
						||
 | 
						||
** ~mu4e~
 | 
						||
 | 
						||
Now that’s out of the way, let’s configure mu4e itself.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package mu4e
 | 
						||
  :after vertico
 | 
						||
  :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].Sent Mail")
 | 
						||
                     (mu4e-drafts-folder . "/Polonkai/[Gmail].Drafts")
 | 
						||
                     (mu4e-trash-folder . "/Polonkai/[Gmail].Bin")
 | 
						||
                     (mu4e-refile-folder . "/Polonkai/[Gmail].Drafts")
 | 
						||
                     (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 . "gergely@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-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
 | 
						||
 | 
						||
** ~sendmail~
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~org-msg~ to write messages using 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
 | 
						||
 | 
						||
* External packages to boost coding productivity
 | 
						||
 | 
						||
** ~electric-operator~ to 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
 | 
						||
 | 
						||
** ~rainbow-delimiters~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package rainbow-delimiters
 | 
						||
  :hook
 | 
						||
  (prog-mode . rainbow-delimiters-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~rainbow-identifiers~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package rainbow-identifiers)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~auto-highlight-symbol~ to hightlight current symbol
 | 
						||
 | 
						||
Great help during refactoring.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package auto-highlight-symbol
 | 
						||
  :config
 | 
						||
  (global-auto-highlight-symbol-mode t))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~glasses~, to make ReallyLongCamelCaseWords more readable
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package glasses
 | 
						||
  :delight " 👓"
 | 
						||
  :hook
 | 
						||
  (prog-mode . glasses-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~hl-todo~ to highlight TODO comments
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package hl-todo
 | 
						||
  :hook
 | 
						||
  (prog-mode . hl-todo-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~bug-reference~ to turn bug/patch references to 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 word-boundary
 | 
						||
                                       (: (| (: (in ?B ?b) "ug" (? " ") (? ?#))
 | 
						||
                                             (: (in ?P ?p) "atch" (? " ") ?#)
 | 
						||
                                             (: "RFE" (? " ") ?#)
 | 
						||
                                             (: "PR " (+ (any "a-z+-")) "/")
 | 
						||
                                             (: "MR" (? " ") (? "!"))))
 | 
						||
                                       (group (+ (any "0-9")) (opt (: ?# (+ (any "0-9"))))))))
 | 
						||
  (bug-reference-url-format #'my-gitlab-url)
 | 
						||
  :hook
 | 
						||
  (text-mode . bug-reference-mode)
 | 
						||
  (prog-mode . bug-reference-prog-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~highlight-indentation~ to highlight indentation levels
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package highlight-indentation
 | 
						||
  :hook
 | 
						||
  (python-mode . highlight-indentation-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~flycheck~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package flycheck
 | 
						||
  :config
 | 
						||
  (global-flycheck-mode)
 | 
						||
  :custom
 | 
						||
  (flycheck-python-pylint-executable "python3"))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~flycheck-pkg-config~ to aid FlyCheck using ~pkg-config~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package flycheck-pkg-config)
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Utilities
 | 
						||
 | 
						||
** ~kubernetes~, a kubernetes dashboard
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package kubernetes
 | 
						||
  :commands (kubernetes-overview))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~elpher~, a Gopher/Gemini 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
 | 
						||
  :commands (elpher))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~mastodon~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package mastodon
 | 
						||
  :custom
 | 
						||
  (mastodon-instance-url "https://social.polonkai.eu/")
 | 
						||
  (mastodon-active-user "gergely"))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~twtxt~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package twtxt
 | 
						||
  :custom
 | 
						||
  (twtxt-file (expand-file-name "~/Nextcloud/twtxt.txt"))
 | 
						||
  (twtxt-following '(("benaiah" "https://benaiah.me/twtxt.txt")
 | 
						||
                     ("jomo" "https://gist.githubusercontent.com/jomo/64d6bd1b95ec0a24612b/raw/twtxt.txt")
 | 
						||
                     ("quite" "https://lublin.se/twtxt.txt")
 | 
						||
                     ("xena" "https://xena.greedo.xeserv.us/files/xena.txt")
 | 
						||
                     ("hecanjog" "https://hecanjog.com/twtxt.txt"))))
 | 
						||
#+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
 | 
						||
 | 
						||
** ~tidal~ for improvising music
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package tidal
 | 
						||
  :mode "\\.tidal\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Programming-language specific packages
 | 
						||
 | 
						||
** Python
 | 
						||
 | 
						||
*** Set up pretty symbols
 | 
						||
 | 
						||
Because they are fancy.
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(add-hook 'python-mode-hook
 | 
						||
          (lambda ()
 | 
						||
            (add-to-list 'prettify-symbols-alist
 | 
						||
                         '("not in" . ?∉))
 | 
						||
            (add-to-list 'prettify-symbols-alist
 | 
						||
                         '("in" . ?∈))
 | 
						||
            (add-to-list 'prettify-symbols-alist
 | 
						||
                         '("def" . ?ƒ))
 | 
						||
            (add-to-list 'prettify-symbols-alist
 | 
						||
                         '("is not" . ?≭))
 | 
						||
            (add-to-list 'prettify-symbols-alist
 | 
						||
                         '("is" . ?≍))
 | 
						||
            ))
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** ~poetry~
 | 
						||
 | 
						||
#+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)
 | 
						||
  :bind (:map gpolonkai/pers-map
 | 
						||
         ("pp" . poetry)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** C
 | 
						||
 | 
						||
Because that’s still my favourite language.
 | 
						||
 | 
						||
*** Set up my indentation 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
 | 
						||
 | 
						||
*** 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
 | 
						||
 | 
						||
*** 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
 | 
						||
 | 
						||
** Web
 | 
						||
 | 
						||
*** ~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~ for easier HTML/CSS writing
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
*** ~enlive~, to query HTML tags by CSS selectors
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package enlive)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~json-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package json-mode
 | 
						||
  :mode "\\.json\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~yaml-mode~
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~dockerfile-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package dockerfile-mode)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~systemd~, for editing systemd unit files
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package systemd
 | 
						||
  :mode ("\\.\\(?:automount\\|mount\\|path\\|s\\(?:ervice\\|lice\\|ocket\\)\\|t\\(?:arget\\|imer\\)\\|wants\\)\\'" . systemd-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~terraform-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package terraform-mode
 | 
						||
  :mode "\\.tf\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~bats-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package bats-mode
 | 
						||
  :mode "\\.bats\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~fish-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package fish-mode
 | 
						||
  :hook
 | 
						||
  (fish-mode . (lambda () (add-hook 'before-save-hook 'fish_indent-before-save)))
 | 
						||
  :mode "\\.fish\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~gitlab-ci-mode~ and ~gitlab-ci-mode-flycheck~
 | 
						||
 | 
						||
#+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
 | 
						||
 | 
						||
** ~csv-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package csv-mode
 | 
						||
  :mode "\\.csv\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** Rust
 | 
						||
 | 
						||
*** ~rust-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package rust-mode
 | 
						||
  :mode "\\.rs\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
*** ~cargo~ and ~cargo-mode~ for Cargo usage
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package cargo)
 | 
						||
 | 
						||
(use-package cargo-mode
 | 
						||
  :mode "Cargo\\.toml\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~arduino-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package arduino-mode
 | 
						||
  :mode "\\.ino\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~nginx-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package nginx-mode)
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~js2-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package js2-mode
 | 
						||
  :pin melpa-stable
 | 
						||
  :mode "\\.js\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~typescript-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package typescript-mode
 | 
						||
  :mode "\\.ts\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~less-css-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package less-css-mode
 | 
						||
  :mode "\\.less\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~sass-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package sass-mode
 | 
						||
  :mode "\\.sass\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~vue-html-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package vue-html-mode
 | 
						||
  :mode "\\.vue\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~jinja2-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package jinja2-mode
 | 
						||
  :mode "\\.j2\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~markdown-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package markdown-mode
 | 
						||
  :mode (("\\.md\\'" . markdown-mode)
 | 
						||
         ("\\.markdown\\'" . markdown-mode)))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~vala-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package vala-mode
 | 
						||
  :mode "\\.vala\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~po-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package po-mode
 | 
						||
  :ensure nil
 | 
						||
  :mode "\\.po\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~meson-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package meson-mode
 | 
						||
  :mode "\\.meson\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ggtags~, an interfaco for 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
 | 
						||
 | 
						||
** ~yuck-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package yuck-mode
 | 
						||
  :mode "\\.yuck\\'")
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ebnf-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ebnf-mode
 | 
						||
  :commands (ebnf-mode))
 | 
						||
#+end_src
 | 
						||
 | 
						||
** ~ansible-vault-mode~
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(use-package ansible-vault)
 | 
						||
#+end_src
 | 
						||
 | 
						||
* Key bindings
 | 
						||
 | 
						||
#+begin_src emacs-lisp
 | 
						||
(defvar gpolonkai/transpose-map (make-sparse-keymap)
 | 
						||
  "Map for transpose commands.")
 | 
						||
(define-prefix-command 'gpolonkai/transpose-map)
 | 
						||
 | 
						||
(defvar gpolonkai/org-clock-map (make-sparse-keymap)
 | 
						||
  "Map for Org clocking commands.")
 | 
						||
(define-prefix-command 'gpolonkai/org-clock-map)
 | 
						||
 | 
						||
(bind-keys
 | 
						||
 :map global-map
 | 
						||
 ("<C-return>" . wted/open-line-below)
 | 
						||
 ("<C-S-return>" . wted/open-line-above)
 | 
						||
 ("C-~" . gpolonkai/toggle-char-case)
 | 
						||
 ("C-a" . gpolonkai/move-to-beginning-of-line)
 | 
						||
 ("C-e" . gpolonkai/move-to-end-of-line)
 | 
						||
 ("M-F" . gpolonkai/beginning-of-next-word)
 | 
						||
 ("C-h C-l" . find-library)
 | 
						||
 ("C-h C-f" . find-function)
 | 
						||
 ("C-h C-k" . find-function-on-key)
 | 
						||
 ("C-h C-v" . find-variable)
 | 
						||
 ("M-q" . sachachua/fill-or-unfill-paragraph)
 | 
						||
 ("C-r" . isearch-backward-regexp)
 | 
						||
 ("C-M-r" . isearch-backward)
 | 
						||
 ("C-s" . isearch-forward-regexp)
 | 
						||
 ("C-M-s" . isearch-forward)
 | 
						||
 ("M-t" . gpolonkai/transpose-map)
 | 
						||
 ("C-z" . nil)
 | 
						||
 :map mode-specific-map
 | 
						||
 ;; TODO this should be doable from consult-projectile’s config
 | 
						||
 ("p p" . consult-projectile-switch-project)
 | 
						||
 ("r" . gpolonkai/round-number-at-point-to-decimals)
 | 
						||
 :map gpolonkai/transpose-map
 | 
						||
 ("c" . transpose-chars)
 | 
						||
 ("e" . transpose-sexps)
 | 
						||
 ("l" . transpose-lines)
 | 
						||
 ("p" . transpose-paragraphs)
 | 
						||
 ("s" . transpose-sentences)
 | 
						||
 ("w" . transpose-words)
 | 
						||
 ("W" . gpolonkai/transpose-windows)
 | 
						||
 :map gpolonkai/org-clock-map
 | 
						||
 ("g" . org-clock-goto)
 | 
						||
 ("i" . org-clock-in)
 | 
						||
 ("I" . org-clock-in-last)
 | 
						||
 ("o" . org-clock-out)
 | 
						||
 :map gpolonkai/pers-map
 | 
						||
 ("c" . gpolonkai/org-clock-map)
 | 
						||
 ("C-c" . calc)
 | 
						||
 ("M-C" . clean-buffer-list)
 | 
						||
 ("M-o" . mbork/insert-current-file-name-at-point)
 | 
						||
 ("u" . browse-url-at-point)
 | 
						||
 :map ctl-x-map
 | 
						||
 ("|" . gpolonkai/toggle-window-split)
 | 
						||
 ("C-b" . bury-buffer)
 | 
						||
 ("C-d" . wted/delete-current-buffer-file)
 | 
						||
 ("k" . kill-current-buffer)
 | 
						||
 ("C-r" . wted/rename-current-buffer-file)
 | 
						||
 ("C-y" . duplicate-line)
 | 
						||
 :map isearch-mode-map
 | 
						||
 ("<C-return>" . ep/isearch-exit-other-end)
 | 
						||
 ("<S-return>" . e-se/isearch-exit-mark-match)
 | 
						||
 :map goto-map
 | 
						||
 ("SPC" . gpolonkai/goto-next-char))
 | 
						||
#+end_src
 | 
						||
 | 
						||
* And finally, start the Emacs server
 | 
						||
 | 
						||
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
 |