Skip to content

arttsu/dotemacs-bkp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

81 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My Emacs Configuration

Table of contents

README

Installation

  1. Clone the repo
    git clone [email protected]:arttsu/dotemacs.git ~/.emacs.d
        
  2. Create a local config
    cp ~/.emacs.d/local.el{.example,}
        
  3. Install dependencies

Dependencies

Notdeft

Fedora

sudo dnf -y install gcc-c++ xapian-core xapian-core-devel tclap

Dirvish

Fedora

sudo dnf -y install ImageMagick

Org Clock

macOS

When playing sounds, org clock tries to find aplay executable.

ln -s /usr/bin/afplay ~/bin/aplay

eradio

Depends on mpv.

Prepare to execute the config

Define utility functions

(defun my/mac-p ()
  "Return t if Emacs is running on a mac."
  (equal system-type 'darwin))

Load machine-local config

(load "~/.emacs.d/local.el")

macOS: Make sure that Emacs uses the right git

(when (my/mac-p)
  (setenv "PATH" (concat "/usr/local/bin:" (getenv "PATH")))
  (push "/usr/local/bin" exec-path))

straight.el

https://github.com/radian-software/straight.el

Install

 (defvar bootstrap-version)
 (let ((bootstrap-file
	 (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
	(bootstrap-version 5))
   (unless (file-exists-p bootstrap-file)
     (with-current-buffer
	  (url-retrieve-synchronously
	   "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
	   'silent 'inhibit-cookies)
	(goto-char (point-max))
	(eval-print-last-sexp)))
   (load bootstrap-file nil 'nomessage))

Configure

(setq straight-use-package-by-default t)

use-package

https://github.com/jwiegley/use-package

(straight-use-package 'use-package)

Hydra

https://github.com/abo-abo/hydra

(use-package hydra)

Auto minor mode

https://github.com/joewreschnig/auto-minor-mode

(use-package auto-minor-mode)

Org QL

https://github.com/alphapapa/org-ql

(use-package org-ql)

Operation

Use sh as shell

(setq shell-file-name "/bin/sh")

exec-path-from-shell

https://github.com/purcell/exec-path-from-shell

(use-package exec-path-from-shell
  :if (my/mac-p)
  :config
  (exec-path-from-shell-initialize))

Performance

https://emacs-lsp.github.io/lsp-mode/page/performance/

(setq gc-cons-threshold 100000000)
(setq read-process-output-max (* 1024 1024))

Don’t create unnecessary files

(setq create-lockfiles nil)
(setq make-backup-files nil)

Auto-revert buffers

(setq global-auto-revert-non-file-buffers t)

(global-auto-revert-mode)

Custom file

(setq custom-file (concat user-emacs-directory "custom.el"))

(when (file-exists-p custom-file)
  (load custom-file))

macOS: Option key behavior

(when (my/mac-p)
  (setq mac-right-option-modifier nil))

Super-save

https://github.com/bbatsov/super-save

(use-package super-save
  :init
  (setq super-save-auto-save-when-idle t)
  (setq auto-save-default nil)
  (setq super-save-exclude '(".sbt" "project/"))
  :config
  (add-to-list 'super-save-triggers 'find-file)
  (add-to-list 'super-save-triggers 'ace-window)
  (add-to-list 'super-save-triggers 'vterm)
  (add-to-list 'super-save-triggers 'vterm-other-window)
  (add-to-list 'super-save-triggers 'tab-next)
  (add-to-list 'super-save-triggers 'tab-previous)
  (add-to-list 'super-save-triggers 'tab-switch)
  (add-to-list 'super-save-triggers 'tab-bar-history-back)
  (add-to-list 'super-save-triggers 'tab-bar-history-forward)
  (add-to-list 'super-save-triggers 'delete-window)
  (add-to-list 'super-save-triggers 'magit-status)
  (super-save-mode +1))

Org

Org mode

https://orgmode.org/

(use-package org
  :init
  (setq org-agenda-files '("~/org/planner/personal.org"
                           "~/org/planner/work.org"
                           "~/org/planner/calendar.org"))
  (setq org-confirm-babel-evaluate nil)
  (setq org-startup-indented t)
  (setq org-export-copy-to-kill-ring 'if-interactive)
  (setq org-export-with-sub-superscripts '{})
  (setq org-use-sub-superscripts '{})
  (setq org-blank-before-new-entry '((heading . t) (plain-list-item . auto)))
  (setq org-clock-sound "~/.emacs.d/assets/mixkit-attention-bell-ding-586.wav"))

Capture templates

Helpers

(defvar my/capture-prompt-history nil)

(defun my/capture-prompt (prompt var)
  (make-local-variable var)
  (set var (read-string (concat prompt ": ") nil my/capture-prompt-history)))

(defun my/capture-template-path (template-name)
  (format "~/.emacs.d/capture-templates/%s.txt" template-name))

Configuration

(with-eval-after-load 'org-capture
  (setq org-capture-templates
        (list
         `("i" "Inbox" entry (file "~/org/planner/inbox.org") (file ,(my/capture-template-path "inbox-entry")))
         `("f" "Folder")
         `("fp" "Personal" entry (file "~/org/planner/personal.org") (file ,(my/capture-template-path "folder")))
         `("fw" "Work" entry (file "~/org/planner/work.org") (file ,(my/capture-template-path "folder")))
         `("fs" "Someday" entry (file "~/org/planner/someday.org") (file ,(my/capture-template-path "folder")))
         `("p" "Project")
         `("pp" "Personal" entry (file "~/org/planner/personal.org") (file ,(my/capture-template-path "project")))
         `("pw" "Work" entry (file "~/org/planner/work.org") (file ,(my/capture-template-path "project"))))))

Refiling

(with-eval-after-load 'org-refile
  (setq org-refile-use-outline-path 'file)
  (setq org-outline-path-complete-in-steps nil)

  (setq org-refile-targets
        '((("~/org/planner/personal.org" "~/org/planner/work.org" "~/org/planner/calendar.org" "~/org/planner/someday.org") :level . 1)
          (("~/org/planner/inbox.org" "~/org/planner/reading.org" "~/org/planner/music.org") :level . 0))))

Custom agendas

(defun my/day-agenda (keys title files)
  `(,keys
    ,title
    ((agenda "" ((org-agenda-span 1)
                 (org-agenda-skip-scheduled-if-done t)
                 (org-agenda-skip-deadline-if-done t)
                 (org-agenda-skip-timestamp-if-done t)))
     (todo "TODO" ((org-agenda-overriding-header "TODOs") (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled)))))
    ((org-agenda-compact-blocks)
     (org-agenda-files ',files))))

(with-eval-after-load 'org-agenda
  (setq org-agenda-custom-commands
        (list
         (my/day-agenda "p" "Personal agenda" '("~/org/planner/personal.org" "~/org/planner/calendar.org"))
         (my/day-agenda "w" "Work agenda" '("~/org/planner/work.org"))
         '("i" "Inbox" ((todo "TODO")) ((org-agenda-files '("~/org/planner/inbox.org")))))))

gnuplot

https://github.com/emacs-gnuplot/gnuplot

(use-package gnuplot)

ob-restclient

https://github.com/alf/ob-restclient.el

(use-package ob-restclient
  :after org-babel-load-languages
  :config
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((restclient . t))))

Auto tangle

https://github.com/yilkalargaw/org-auto-tangle

(use-package org-auto-tangle
  :hook (org-mode . org-auto-tangle-mode))

Org Roam

https://www.orgroam.com/

(use-package org-roam
  :init
  (setq org-roam-v2-ack t)
  (setq org-roam-directory "~/org/zettelkasten")
  :config
  (org-roam-setup)
  (org-roam-db-autosync-mode))

Org Roam UI

https://github.com/org-roam/org-roam-ui

(use-package org-roam-ui
  :after org-roam
  :init
  (setq org-roam-ui-sync-theme t)
  (setq org-roam-ui-follow t)
  (setq org-roam-ui-update-on-save t)
  (setq org-roam-ui-open-on-start t))

Export

Slack

https://github.com/titaniumbones/ox-slack

(use-package ox-slack)

Jira

https://github.com/stig/ox-jira.el

(use-package ox-jira)

htmlize

https://www.emacswiki.org/emacs/Htmlize

(use-package htmlize)

Org Reveal

(use-package ox-reveal)

Automatic table of contents

https://github.com/snosov1/toc-org

(use-package toc-org
  :hook ((org-mode markdown-mode) . toc-org-mode))

Anki

Anki Editor

https://github.com/louietan/anki-editor

(use-package anki-editor
  :init
  (setq anki-editor-create-decks t))

(add-to-list 'auto-mode-alist '("\\.anki\\'" . org-mode))
(add-to-list 'auto-minor-mode-alist '("\\.anki\\'" . anki-editor-mode))

Simple Anki notes

(defun my-anki-editor-note-at-point ()
  (let ((org-trust-scanner-tags t)
        (deck (or (org-entry-get-with-inheritance "ANKI_DECK") "Default"))
        (note-id (org-entry-get nil anki-editor-prop-note-id))
        (note-type "Basic_LaTeX")
        (tags (anki-editor--get-tags))
        (fields (my-anki-editor-build-fields)))
    `((deck . ,deck)
      (note-id . ,(string-to-number (or note-id "-1")))
      (note-type . ,note-type)
      (tags . ,(-filter (lambda (tag) (not (string= tag "ankiCard"))) tags))
      (fields . ,fields))))

(defun my-anki-editor-build-fields ()
  (let* ((element (org-element-at-point))
         (front (substring-no-properties
                 (org-element-property :raw-value element)))
         (contents-begin (org-element-property :contents-begin element))
         (contents-end (org-element-property :contents-end element))
         (back (org-export-string-as (buffer-substring contents-begin contents-end)
                                     anki-editor--ox-anki-html-backend
                                     t
                                     anki-editor--ox-export-ext-plist)))
    `(("Front" . ,front) ("Back" . ,back))))

(defun my-anki-editor-map-note-entries (func &optional match scope &rest skip)
  (let ((org-use-property-inheritance nil))
    (org-map-entries func (concat match "&ankiCard") scope skip)))

(defun my-anki-editor-push-notes ()
  (interactive)
  (anki-editor-mode 1)
  (advice-add 'anki-editor-map-note-entries :override
              #'my-anki-editor-map-note-entries
              '((name . my-anki-editor-map-note-entries-override)))
  (advice-add 'anki-editor-note-at-point :override
              #'my-anki-editor-note-at-point
              '((name . my-anki-editor-note-at-point-override)))
  (anki-editor-push-notes)
  (advice-remove 'anki-editor-map-note-entries 'my-anki-editor-map-note-entries-override)
  (advice-remove 'anki-editor-note-at-point 'my-anki-editor-note-at-point-override)
  (anki-editor-mode -1))

Notdeft

https://github.com/hasu/notdeft

(use-package notdeft
  :straight (notdeft :type git :host github :repo "hasu/notdeft"
                     :files ("*.el" "xapian"))
  :init
  (setq notdeft-directory "~/org/notes")
  (setq notdeft-directories '("~/org/notes" "~/org/zettelkasten"))
  (setq notdeft-notename-function #'my/notdeft-title-to-filename)
  (setq notdeft-new-file-data-function #'my-notdeft-new-file-data)
  (setq notdeft-xapian-program (expand-file-name "straight/build/notdeft/xapian/notdeft-xapian" user-emacs-directory))
  :config
  (notdeft-install))

(defun my-notdeft-new-file-data (dir notename ext data title)
  (let* ((notename (or notename
                       (when title
                         (notdeft-title-to-notename title))))
         (file (if notename
                   (notdeft-make-filename notename ext dir)
                 (notdeft-generate-filename ext dir))))
    (cons file (or data (format "#+TITLE: %s" title)))))

(defun my/notdeft-title-to-filename (title)
  (let ((timestamp (format-time-string "%Y%m%d%H%M%S"))
        (default-title (notdeft-default-title-to-notename title)))
    (format "%s-%s" timestamp default-title)))

Bookmark heading

https://github.com/alphapapa/org-bookmark-heading

(use-package org-bookmark-heading)

UI

Startup

(setq inhibit-startup-screen t)
(setq initial-scratch-message nil)
(setq initial-major-mode 'org-mode)

Hide unnecessary UI elements

(scroll-bar-mode -1)
(tool-bar-mode -1)
(menu-bar-mode -1)

Alert via flashing the screen instead of a sound

(setq visible-bell t)

Enable pixel scroll precision

(if (boundp 'pixel-scroll-precision-mode)
    (pixel-scroll-precision-mode +1)
  (pixel-scroll-mode +1))

Show line numbers

(add-hook 'prog-mode-hook 'display-line-numbers-mode)

Confirm with “y or n” instead of “yes or no”

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

Use tabs

(tab-bar-mode)
(tab-bar-history-mode)

Font

(set-face-attribute 'default nil :font "Iosevka Comfy" :height my/font-height)
(set-frame-font "Iosevka Comfy" nil t)

my/font-height is defined in local.el.

Iosevka Comfy: https://github.com/protesilaos/iosevka-comfy

Modus themes

https://protesilaos.com/emacs/modus-themes

(defun my/apply-theme (appearance)
  (mapc #'disable-theme custom-enabled-themes)
  (pcase appearance
    ('light (modus-themes-load-operandi))
    ('dark (modus-themes-load-vivendi))))

(use-package modus-themes
  :init
  (setq modus-themes-bold-constructs nil)
  (setq modus-themes-italic-constructs t)
  (setq modus-themes-links '(italic background))
  (setq modus-themes-mode-line '(accented))
  (setq modus-themes-tabs-accented t)
  (setq modus-themes-paren-match '(intense))
  (setq modus-themes-region '(no-extend))
  (setq modus-themes-org-blocks 'gray-background)
  (setq modus-themes-headings '((1 . (overline background 1.5))
                                (2 . (overline background 1.3))
                                (3 . (1.1))))
  (setq modus-themes-prompts '(background bold))
  :config
  (when (boundp 'ns-system-appearance-change-functions)
    (add-hook 'ns-system-appearance-change-functions #'my/apply-theme))
  (my/apply-theme 'light))

Src block colors

disabled: Currently using gray background for all src blocks

(defun my/add-src-block-color-mappings ()
  (add-to-list 'org-src-block-faces '("restclient" modus-themes-nuanced-green))
  (add-to-list 'org-src-block-faces '("js" modus-themes-nuanced-yellow))
  (add-to-list 'org-src-block-faces '("scala" modus-themes-nuanced-blue))
  (add-to-list 'org-src-block-faces '("sql" modus-themes-nuanced-cyan)))

(add-hook 'modus-themes-after-load-theme-hook #'my/add-src-block-color-mappings)

pulsar

https://github.com/protesilaos/pulsar

(use-package pulsar
  :init
  (setq pulsar-pulse-on-window-change t)
  :config
  (pulsar-global-mode))

ace-window

https://github.com/abo-abo/ace-window

(use-package ace-window
  :init
  (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
  (setq aw-scope 'frame)
  :bind
  (("M-o" . ace-window)))

transpose-frame

https://github.com/emacsorphanage/transpose-frame

(use-package transpose-frame)

Neotree

https://github.com/jaypei/emacs-neotree

(use-package neotree
  :bind
  (("M-<f7>" . #'my-neotree-toggle)))

Toggle

(defun my-neotree-toggle ()
  (interactive)
  (if (neo-global--window-exists-p)
      (neotree-hide)
    (if (project-current)
        (neotree-projectile-action)
      (neotree-dir (file-name-directory buffer-file-name)))))

Reveal in Finder

https://github.com/kaz-yos/reveal-in-osx-finder

(when (my/mac-p)
  (use-package reveal-in-osx-finder
    :bind
    (("C-c z" . #'reveal-in-osx-finder))))

Blamer

https://github.com/Artawower/blamer.el

(use-package blamer
  :bind
  (("s-i" . blamer-show-posframe-commit-info))
  :custom
  (blamer-idle-time 0.5)
  (blamer-min-offset 70)
  (blamer-max-lines 10)
  :config
  (global-blamer-mode))

(defun blamer-callback-show-commit-diff (commit-info)
  (interactive)
  (let ((commit-hash (plist-get commit-info :commit-hash)))
    (when commit-hash
      (magit-show-commit commit-hash))))

(defun blamer-callback-magit-log-file (commit-info)
  (interactive)
  (magit-log-buffer-file)
  (let ((commit-hash (plist-get commit-info :commit-hash)))
    (when commit-hash
      (run-with-idle-timer 1 nil (lambda (commit-hash)
                                   (goto-char (point-min))
                                   (search-forward (substring commit-hash 0 7))
                                   (set-mark (point-at-bol))
                                   (goto-char (point-at-eol)))
                           commit-hash))))

(setq blamer-bindings '(("<mouse-3>" . blamer-callback-magit-log-file)
                        ("<mouse-1>" . blamer-callback-show-commit-diff)))

Editing

Whitespace

Add a newline at the end if there’s none

(setq require-final-newline t)

Always use spaces for indentation

(setq-default indent-tabs-mode nil)

Use zap-up-to-char instead of zap-to-char

(global-set-key (kbd "M-z") 'zap-up-to-char)

Enable subword mode

(global-subword-mode)

Smartparens

https://github.com/Fuco1/smartparens

(use-package smartparens
  :after whole-line-or-region
  :init
  (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode)
  (add-hook 'eval-expression-minibuffer-setup-hook #'smartparens-mode)
  (add-hook 'scala-mode-hook #'smartparens-mode)
  (add-hook 'python-mode-hook #'smartparens-mode)
  (add-hook 'sql-mode-hook #'smartparens-mode)
  (add-hook 'clojure-mode-hook #'smartparens-strict-mode)
  (add-hook 'ruby-mode-hook #'smartparens-mode)
  :config
  (require 'smartparens-config)
  :bind
  (:map smartparens-strict-mode-map
        ("C-<right>" . sp-forward-slurp-sexp)
        ("C-<left>" . sp-backward-slurp-sexp)
        ("M-<right>" . sp-forward-barf-sexp)
        ("M-<left>" . sp-backward-barf-sexp)
        ("C-w" . my/whole-line-or-region-sp-kill-region)
        :map smartparens-mode-map
        ("C-<right>" . sp-forward-slurp-sexp)
        ("C-<left>" . sp-backward-slurp-sexp)
        ("M-<right>" . sp-forward-barf-sexp)
        ("M-<left>" . sp-backward-barf-sexp)))

;; https://github.com/purcell/whole-line-or-region/issues/17#issuecomment-781988534
(defun my/whole-line-or-region-sp-kill-region (prefix)
  "Call `sp-kill-region' on region or PREFIX whole lines."
  (interactive "*p")
  (whole-line-or-region-wrap-beg-end 'sp-kill-region prefix))

Avy

https://github.com/abo-abo/avy

(defun my/org-unbind-avy-goto ()
  (local-unset-key (kbd "C-'")))

(add-hook 'org-mode-hook #'my/org-unbind-avy-goto)

(use-package avy
  :init
  (setq avy-single-candidate-jump t)
  :config
  (avy-setup-default)
  (setf (alist-get ?n avy-dispatch-alist) #'my/avy-action-copy-charseq)
  (setf (alist-get ?y avy-dispatch-alist) #'my/avy-action-yank-charseq)
  (setf (alist-get ?Y avy-dispatch-alist) #'my/avy-action-yank-line)
  (setf (alist-get ?. avy-dispatch-alist) #'my/avy-action-embark)
  (setf (alist-get ?\; avy-dispatch-alist) #'my/avy-action-embark-dwim)
  :bind
  (("C-;" . avy-goto-char-timer)
   ("M-;" . avy-pop-mark)
   ("M-g g" . avy-goto-line)
   ("M-g G" . avy-goto-end-of-line)))

Multiple cursors

https://github.com/magnars/multiple-cursors.el

(use-package multiple-cursors
  :config
  (define-key mc/keymap (kbd "<return>") nil)
  :bind
  ("C-+" . #'mc/mark-next-like-this)
  ("C-c m" . #'mc/edit-lines)
  ("C-c M" . #'mc/mark-all-dwim)
  ("C-S-<mouse-1>" . #'mc/add-cursor-on-click)
  ("C-<return>" . #'set-rectangular-region-anchor))

Expand region

https://github.com/magnars/expand-region.el

(use-package expand-region
  :bind
  ("C-=" . 'er/expand-region))

Go to char

https://github.com/doitian/iy-go-to-char

(use-package iy-go-to-char
  :bind
  ("C-c f" . iy-go-to-char)
  ("C-c F" . iy-go-to-char-backward)
  ("C-c t" . iy-go-up-to-char)
  ("C-c T" . iy-go-up-to-char-backward)
  ("C-c ;" . iy-go-to-or-up-to-continue)
  ("C-c ," . iy-go-to-or-up-to-continue-backward))

Crux

https://github.com/bbatsov/crux

(use-package crux
  :bind
  (("C-k" . crux-smart-kill-line)
   ("C-o" . crux-smart-open-line)
   ("C-S-o" . crux-smart-open-line-above)
   ("C-^" . crux-top-join-line)))

reverse-im

https://github.com/a13/reverse-im.el

(use-package char-fold
  :demand t
  :init
  (setq char-fold-symmetric t)
  (setq search-default-mode #'char-fold-to-regexp))

(use-package reverse-im
  :after char-fold
  :demand t
  :init
  (setq reverse-im-input-methods '("ukrainian-computer" "russian-computer"))
  (setq reverse-im-char-fold t)
  (setq reverse-im-read-char-advice-function #'reverse-im-read-char-include)
  :config
  (add-to-list 'reverse-im-read-char-include-commands 'org-agenda)
  (reverse-im-mode t))

whole-line-or-region

https://github.com/purcell/whole-line-or-region

(use-package whole-line-or-region
  :demand
  :config
  (whole-line-or-region-global-mode)
  :bind
  (("M-/" . whole-line-or-region-comment-dwim)))

Completion

Vertico

https://github.com/minad/vertico

(use-package vertico
  :config
  (vertico-mode))

Save completion history

https://github.com/emacs-mirror/emacs/blob/master/lisp/savehist.el

(use-package savehist
  :config
  (savehist-mode))

Orderless

https://github.com/oantolin/orderless

(use-package orderless
  :custom
  (completion-styles '(orderless)))

Marginalia

https://github.com/emacs-straight/marginalia

(use-package marginalia
  :demand
  :config
  (marginalia-mode)
  :bind
  (:map minibuffer-local-map
        ("M-A" . marginalia-cycle)))

Embark

https://github.com/oantolin/embark

(use-package embark
  :bind
  (("C-." . embark-act)
   ("M-." . embark-dwim)))

Embark Consult

https://github.com/oantolin/embark/blob/master/embark-consult.el

(use-package embark-consult
  :after (embark consult))

Company

http://company-mode.github.io/

(use-package company
  :init
  (setq company-minimum-prefix-length 2)
  (setq company-idle-delay 0.2)
  (setq company-selection-wrap-around t)
  (setq company-dabbrev-downcase nil)
  (setq company-show-numbers t)
  :config
  (global-company-mode))

Helper functions

(defun my/point-at-end-of-line ()
  (save-excursion (move-end-of-line nil) (point)))

(defun my/current-line-empty-p ()
  (save-excursion
    (beginning-of-line)
    (looking-at-p "[[:blank:]]*$")))

Interactive functions

Save all buffers

(defun my/save-all-buffers ()
  (interactive)
  (save-some-buffers t))

Working w/ src blocks

(defun my/in-src-block-p ()
  (memq (org-element-type (org-element-context))
        '(inline-src-block src-block)))

(defun my/forward-to-src-block ()
  (if (my/in-src-block-p)
      (org-babel-goto-src-block-head)
    (org-babel-next-src-block)))

(defun my/evaluate-nearest-src-block ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (org-ctrl-c-ctrl-c)))

(defun my/smart-copy-nearest-src-block ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (my-smart-copy)))

(defun my/copy-nearest-src-block-results ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (org-babel-open-src-block-result)
    (switch-to-buffer "*Org Babel Results*")
    (mark-whole-buffer)
    (copy-region-as-kill nil nil t)
    (delete-window)))

(defun my/name-or-rename-nearest-src-block ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (let* ((current-name (my/src-block-name))
           (new-name (read-string "Name: " current-name)))
      (if current-name
          (my/rename-src-block new-name)
        (my/name-src-block new-name)))))

(defun my/name-src-block (name)
  (save-excursion
    (org-babel-goto-src-block-head)
    (open-line 1)
    (insert (format "#+name: %s" name))))

(defun my/rename-src-block (name)
  (save-excursion
    (org-babel-goto-src-block-head)
    (previous-line)
    (move-beginning-of-line nil)
    (kill-line)
    (insert (format "#+name: %s" name))))

(defun my/src-block-name ()
  (save-excursion
    (org-babel-goto-src-block-head)
    (if (= (line-number-at-pos) 1)
        nil
      (previous-line)
      (let ((current-line (thing-at-point 'line t)))
        (if (string-match (rx "#+name: " (group (zero-or-more not-newline))) current-line)
            (match-string-no-properties 1 current-line)
          nil)))))

(defun my/goto-src-block-beginning ()
  (org-babel-goto-src-block-head)
  (when (not (= (line-number-at-pos) 1))
    (previous-line)
    (move-beginning-of-line nil)
    (let ((current-line (thing-at-point 'line t)))
      (when (not (string-match (rx "#+name: ") current-line))
        (next-line)))))

(defun my/goto-src-block-end ()
  (let ((name (my/src-block-name)))
    (when name (org-babel-goto-named-result name))
    (goto-char (org-babel-result-end))))

(defun my/select-src-block ()
  (my/goto-src-block-beginning)
  (set-mark-command nil)
  (goto-char (org-babel-result-end)))

(defun my/copy-src-block ()
  (interactive)
  (save-excursion
    (my/select-src-block)
    (kill-ring-save nil nil t)))

(defun my/kill-src-block ()
  (interactive)
  (my/select-src-block)
  (kill-region nil nil t))

(defun my/duplicate-src-block ()
  (interactive)
  (let ((name (my/src-block-name)))
    (my/copy-src-block)
    (my/goto-src-block-end)
    (newline)
    (yank)
    (previous-line)
    (org-babel-goto-src-block-head)
    (when name
      (my/rename-src-block (format "%s-copy" name)))))

(defun my/edit-nearest-src-block ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (org-edit-special)))

(defun my/clear-nearest-src-block-results ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (org-babel-remove-result-one-or-many nil)))

(defun my/clear-all-src-block-results ()
  (interactive)
  (when (y-or-n-p "Really clear results in the whole buffer?")
    (setq current-prefix-arg '(4))
    (call-interactively 'org-babel-remove-result-one-or-many nil)))

(defun my/edit-nearest-src-block-args ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (my/forward-to-src-block)
    (let ((beg (point)))
      (forward-sexp 2)
      (let* ((block-beg (buffer-substring beg (point)))
             (current-args (string-trim (buffer-substring (point) (my/point-at-end-of-line))))
             (new-args (string-trim (read-string "New args: " current-args))))
        (move-beginning-of-line nil)
        (kill-line)
        (insert (format "%s %s" block-beg new-args))))))

(defun arttsu-temporary-buffer ()
  (interactive)
  (switch-to-buffer-other-window (make-temp-name "temp-")))

Smart copy

(defun my-copy-src-message (src)
  (let ((lines (split-string src "\n")))
    (if (> (length lines) 2)
        (concat "Copied:\n" (nth 0 lines) "\n" (nth 1 lines) "\n  ...")
        (concat "Copied:\n" src))))

(defun my-copy-src (context)
  (let* ((info (org-babel-lob-get-info context))
         (info (if info (copy-tree info) (org-babel-get-src-block-info)))
         (src (nth 1 info)))
    (progn
      (kill-new src)
      (message (my-copy-src-message src)))))

(defun my-copy-link (context)
  (let* ((plist (nth 1 context))
         (raw-link (plist-get plist ':raw-link)))
    (progn
      (kill-new raw-link)
      (message (concat "Copied:\n" raw-link)))))

(defun my-smart-copy ()
  (interactive)
  (let* ((context (org-element-context))
         (context-type (nth 0 context)))
    (cond ((eq context-type 'src-block) (my-copy-src context))
          ((eq context-type 'link) (my-copy-link context))
          (t (message "Nothing to copy")))))

(global-set-key (kbd "C-c y") #'my-smart-copy)

Src block headings

(defun my/insert-src-block-within-heading ()
  (open-line 0)
  (org-insert-structure-template "src")
  (let ((lang (completing-read "Language: " '("elisp" "shell" "sql" "restclient" "python" "ruby" "scala"))))
    (insert lang))
  (previous-line)
  (move-end-of-line nil))

(defun my/do-insert-src-heading ()
  (let ((title (read-string "Title: " "Block")))
    (insert title))
  (my/insert-src-block-within-heading))

(defun my/insert-src-heading ()
  (interactive)
  (if (org-before-first-heading-p)
      (org-insert-heading)
    (org-insert-heading-respect-content))
  (my/do-insert-src-heading))

(defun my/insert-src-heading-before ()
  (interactive)
  (if (org-before-first-heading-p)
      (org-insert-heading)
    (org-back-to-heading)
    (org-insert-heading))
  (my/do-insert-src-heading))

(defun my/duplicate-src-heading ()
  (interactive)
  (org-copy-subtree)
  (org-back-to-heading)
  (org-yank)
  (when org-yank-folded-subtrees
    (org-backward-element)
    (org-cycle)
    (org-forward-element))
  (move-end-of-line nil)
  (insert " (copy)"))

(defun my/duplicate-src-heading-before ()
  (interactive)
  (org-copy-subtree)
  (org-back-to-heading)
  (org-yank)
  (org-backward-element)
  (when org-yank-folded-subtrees
    (org-cycle))
  (move-end-of-line nil)
  (insert " (copy)"))

(defun my/edit-src-block-results ()
  (interactive)
  (search-forward "#+RESULTS:")
  (search-forward "#+BEGIN_SRC")
  (org-edit-special))

Org functions

(defun my/insert-heading-before ()
  (interactive)
  (org-back-to-heading)
  (org-insert-heading))

(defun my/rename-heading ()
  (interactive)
  (save-excursion
    (org-back-to-heading)
    (let* ((current-title (org-entry-get nil "ITEM"))
           (new-title (read-string "New title: " current-title)))
      (replace-string current-title
                      new-title
                      nil
                      (point)
                      (my/point-at-end-of-line)))))

(defun my/seek-to-heading-content ()
  (let ((line-num-before (line-number-at-pos)))
    (forward-line)
    (cond ((= line-num-before (line-number-at-pos)) (crux-smart-open-line nil))
          ((org-at-heading-p) (crux-smart-open-line-above))
          ((org-at-planning-p) (my/seek-to-heading-content))
          ((org-at-drawer-p) (my/seek-to-heading-content))
          (t nil))))

(defun my/edit-heading-content ()
  (interactive)
  (org-back-to-heading)
  (org-show-entry)
  (my/seek-to-heading-content))

(defun my/mark-as (todo-state)
  (save-excursion
    (org-back-to-heading)
    (org-todo todo-state)))

(defun my/mark-as-todo ()
  (interactive)
  (my/mark-as "TODO"))

(defun my/mark-as-done ()
  (interactive)
  (my/mark-as "DONE"))

(defun my/jump-to-first-heading ()
  (interactive)
  (beginning-of-buffer)
  (when (not (org-at-heading-p))
    (org-next-visible-heading 1)))

(defun my/jump-to-last-heading ()
  (interactive)
  (end-of-buffer)
  (org-back-to-heading))

Avy actions

(defun my/goto-charseq-end ()
  (let ((line-end (save-excursion (end-of-line) (point))))
    (condition-case nil
        (progn
          (re-search-forward (rx (or whitespace "(" ")" "[" "]" "{" "}" "\"" "'" "`" ";" "," "=" "|")) line-end)
          (backward-char))
      (error (end-of-line)))))

(defun my/copy-charseq ()
  (interactive)
  (set-mark-command nil)
  (my/goto-charseq-end)
  (setq last-command nil) ;; never append to the last kill
  (copy-region-as-kill nil nil t))

(defun my/avy-action-copy-charseq (point)
  (save-excursion
    (goto-char point)
    (my/copy-charseq))
  (select-window (cdr (ring-ref avy-ring 0)))
  t)

(defun my/avy-yank ()
  (if (derived-mode-p 'vterm-mode)
      (vterm-yank)
    (yank)))

(defun my/avy-action-yank-charseq (point)
  (save-excursion
    (goto-char point)
    (my/copy-charseq))
  (select-window (cdr (ring-ref avy-ring 0)))
  (my/avy-yank)
  t)

(defun my/avy-action-yank-line (point)
  (save-excursion
    (goto-char point)
    (set-mark-command nil)
    (end-of-line)
    (setq last-command nil) ;; never append to the last kill
    (copy-region-as-kill nil nil t))
  (select-window (cdr (ring-ref avy-ring 0)))
  (my/avy-yank)
  t)

Avy Embark actions

(defun my/avy-action-embark (point)
  (unwind-protect
    (goto-char point)
    (embark-act))
  t)

(defun my/avy-action-embark-dwim (point)
  (unwind-protect
    (goto-char point)
    (embark-dwim))
  t)

Editing functions

Jump/kill upto sexp

(defun my/back-to-sexp ()
  (interactive)
  (let ((current-sexp (thing-at-point 'sexp)))
    (if current-sexp
        (let ((current-point (point)))
          (backward-sexp)
          (unless (string= (thing-at-point 'sexp) current-sexp)
            (goto-char current-point)))
      (backward-sexp))))

(defun my/jump-upto-sexp ()
  (interactive)
  (my/back-to-sexp)
  (forward-sexp)
  (forward-sexp)
  (backward-sexp))

(defun my/jump-back-upto-sexp ()
  (interactive)
  (my/back-to-sexp)
  (backward-sexp)
  (forward-sexp))

(defun my/kill-upto-sexp ()
  (interactive)
  (let ((current-point (point))
        (before-current-word (save-excursion
                               (my/back-to-sexp)
                               (point)))
        (before-next-word (save-excursion
                            (my/jump-upto-sexp)
                            (point))))
    (unless (= before-current-word before-next-word)
      (kill-region current-point before-next-word))))

(defun my/kill-back-upto-sexp ()
  (interactive)
  (let ((current-point (point))
        (after-current-sexp (save-excursion
                              (my/back-to-sexp)
                              (forward-sexp)
                              (point)))
        (after-previous-sexp (save-excursion
                               (my/jump-back-upto-sexp)
                               (point))))
    (unless (= after-current-sexp after-previous-sexp)
      (kill-region after-previous-sexp current-point))))

Jump/kill upto word

(defun my/back-to-word ()
  (interactive)
  (let ((current-word (thing-at-point 'word)))
    (if current-word
        (let ((current-point (point)))
          (backward-word)
          (unless (string= (thing-at-point 'word) current-word)
            (goto-char current-point)))
      (backward-word))))

(defun my/jump-upto-word ()
  (interactive)
  (my/back-to-word)
  (forward-word)
  (forward-word)
  (backward-word))

(defun my/jump-back-upto-word ()
  (interactive)
  (my/back-to-word)
  (backward-word)
  (forward-word))

(defun my/kill-upto-word ()
  (interactive)
  (let ((current-point (point))
        (before-current-word (save-excursion
                               (my/back-to-word)
                               (point)))
        (before-next-word (save-excursion
                            (my/jump-upto-word)
                            (point))))
    (unless (= before-current-word before-next-word)
      (kill-region current-point before-next-word))))

(defun my/kill-back-upto-word ()
  (interactive)
  (let ((current-point (point))
        (after-current-word (save-excursion
                              (my/back-to-word)
                              (forward-word)
                              (point)))
        (after-previous-word (save-excursion
                               (my/jump-back-upto-word)
                               (point))))
    (unless (= after-current-word after-previous-word)
      (kill-region after-previous-word current-point))))

Switching to a project

(defun my/do-switch-project (find-dir-fn)
  (let ((dir (project-prompt-project-dir)))
    (funcall find-dir-fn dir))
  (let ((name (-last-item (butlast (s-split "/" (project-root (project-current)))))))
    (tab-rename name)))

(defun my/switch-project ()
  (interactive)
  (my/do-switch-project 'find-file))

(defun my/switch-project-other-tab ()
  (interactive)
  (my/do-switch-project 'find-file-other-tab))

Timestamp conversion

(defun my/convert-timestamp-to-datetime (timestamp)
  (format-time-string "%Y-%m-%d %H:%M:%S" (seconds-to-time (string-to-number timestamp)) t))

(defun my-timestamp-to-datetime ()
  (interactive)
  (let* ((timestamp (read-string "Timestamp: "))
         (datetime (my/convert-timestamp-to-datetime timestamp)))
    (kill-new datetime)
    (message datetime)))

(defun my-datetime-to-timestamp ()
  (interactive)
  (let* ((datetime (read-string "Datetime: "))
         (time (date-to-time datetime))
         (timestamp (number-to-string (time-to-seconds time))))
    (kill-new timestamp)
    (message timestamp)))

Zoom the whole frame

https://stackoverflow.com/questions/24705984/increase-decrease-font-size-in-an-emacs-frame-not-just-buffer

(defun my/zoom-frame (&optional n frame amt)
  "Increase the default size of text by AMT inside FRAME N times.
  N can be given as a prefix arg.
  AMT will default to 10.
  FRAME will default the selected frame."
  (interactive "p")
  (let ((frame (or frame (selected-frame)))
        (height (+ (face-attribute 'default :height frame) (* n (or amt 10)))))
    (set-face-attribute 'default frame :height height)
    (when (called-interactively-p)
      (message "Set frame's default text height to %d." height))))

(defun my/zoom-frame-out (&optional n frame amt)
  "Call `my/zoom-frame' with -N."
  (interactive "p")
  (my/zoom-frame (- n) frame amt))

(defun my/zoom-frame-default ()
  (interactive)
  (set-face-attribute 'default (selected-frame) :height my/font-height))

Radio schedule

(defconst my/bagel-radio-url "https://onlineradiobox.com/us/bagel/playlist/")

(defun my/onlineradio-bagel-schedule ()
  (interactive)
  (my/onlineradio-schedule "Bagel Radio" my/bagel-radio-url))

(defun my/onlineradio-schedule (name url)
  (interactive)
  (let ((schedule (with-current-buffer (url-retrieve-synchronously url)
                    (my/onlineradio-extract-schedule '()))))
    (with-output-to-temp-buffer (format "*%s*" name)
      (dolist (pair schedule)
        (let ((time (nth 0 pair))
              (song (nth 1 pair)))
          (princ (format "%s\n      %s\n" (my/decode-entities time) (my/decode-entities song))))))))

(defun my/onlineradio-extract-schedule (schedule)
  (condition-case nil
      (let ((time (my/onlineradio-extract-time))
            (song (my/onlineradio-extract-song)))
        (my/onlineradio-extract-schedule (cons (list time song) schedule)))
    (error (reverse schedule))))

(defun my/onlineradio-extract-time ()
  (search-forward "time--schedule\">")
  (let ((before (point)))
    (iy-go-up-to-char 1 ?<)
    (let ((after (point)))
      (buffer-substring before after))))

(defun my/onlineradio-extract-song ()
  (search-forward "track_history_item")
  (iy-go-to-char 2 ?>)
  (let ((before (point)))
    (iy-go-up-to-char 1 ?<)
    (let ((after (point)))
      (buffer-substring before after))))

(defun my/decode-entities (html)
  (with-temp-buffer
    (save-excursion (insert html))
    (xml-parse-string)))

Programming

LSP mode

https://emacs-lsp.github.io/lsp-mode/

(use-package lsp-mode
  :hook
  (scala-mode . lsp)
  (python-mode . lsp)
  (ruby-mode . lsp)
  :commands lsp
  :bind
  (:map lsp-mode-map
        ([M-down-mouse-1] . mouse-set-point)
        ([M-mouse-1] . lsp-find-definition)
        ([M-mouse-3] . xref-go-back)
        ("<f4>" . lsp-rename)))

(use-package lsp-ui)

(use-package lsp-metals
  :after lsp)

Consult-LSP

https://github.com/gagbo/consult-lsp

(use-package consult-lsp
  :after (consult lsp))

Hydra

(with-eval-after-load 'hydra
  (defhydra arttsu-programming-hydra (:color blue)
    "Programming\n\n"

    ("l" #'arttsu-lsp-show-log "Show log" :column "LSP")

    ("M" #'smerge-vc-next-conflict "Next conflict" :column "Merge" :color pink)
    ("U" #'smerge-keep-upper "Keep upper" :color pink)
    ("L" #'smerge-keep-lower "Keep lower" :color pink)
    ("A" #'smerge-keep-all "Keep all" :color pink)

    ("d" #'consult-lsp-diagnostics "Diagnostics" :column "Project")

    ("S" #'consult-lsp-symbols "Symbols" :column "Navigation")
    ("r" #'lsp-find-references "Find references")

    ("a" #'lsp-execute-code-action "Code action" :column "Code")
    ("f" #'lsp-format-buffer "Format buffer")
    ("i" #'lsp-organize-imports "Organize imports")

    ("q" #'hydra-keyboard-quit "Quit" :column "")
    ("s" #'my/save-all-buffers "Save all buffers")
    ("<f5>" #'my/cockpit-hydra/body "Cockpit"))

  (define-key prog-mode-map (kbd "<f5>") #'arttsu-programming-hydra/body)

  (with-eval-after-load 'magit
    (define-key magit-mode-map (kbd "<f5>") #'arttsu-programming-hydra/body)))

(defun arttsu-lsp-show-log ()
  (interactive)
  (switch-to-buffer-other-window "*lsp-log*")
  (end-of-buffer nil))

Eglot

(use-package eglot
  :straight nil
  :preface
  (defun mp-eglot-eldoc ()
    (setq eldoc-documentation-strategy
          'eldoc-documentation-compose-eagerly))
  :init
  (setq eglot-confirm-server-initiated-edits nil)
  :hook
  (eglot-managed-mode . mp-eglot-eldoc)
  (scala-mode . eglot-ensure)
  :bind
  (:map eglot-mode-map
        ("<f4>" . eglot-rename)))

(define-key prog-mode-map [M-down-mouse-1] #'mouse-set-point)
(define-key prog-mode-map [M-mouse-1] #'xref-find-definitions)
(define-key prog-mode-map [M-mouse-3] #'xref-go-back)

(use-package consult-eglot
  :after (consult eglot))

(defmacro arttsu-eglot--fixed-code-action (name kind)
  "Define NAME to execute KIND code action."
  `(defun ,name (beg &optional end)
     ,(format "Execute `%s' code actions between BEG and END." kind)
     (interactive (eglot--region-bounds))
     (eglot-code-actions beg end ,kind (interactive-p))))

(arttsu-eglot--fixed-code-action arttsu-eglot-fixed-code-action-organize-imports "source.organizeImports")
(arttsu-eglot--fixed-code-action arttsu-eglot-fixed-code-action-extract "refactor.extract")
(arttsu-eglot--fixed-code-action arttsu-eglot-fixed-code-action-inline "refactor.inline")
(arttsu-eglot--fixed-code-action arttsu-eglot-fixed-code-action-rewrite "refactor.rewrite")
(arttsu-eglot--fixed-code-action arttsu-eglot-fixed-code-action-quickfix "quickfix")

(with-eval-after-load 'hydra
  (defhydra arttsu-hydra-lsp (:color blue)
    "Programming\n\n"

    ("d" #'flymake-show-project-diagnostics "Diagnostics" :column "Workspace")
    ("S" #'consult-eglot-symbols "Symbols")
    ("E" #'eglot-events-buffer "Events")
    ("R" #'eglot-reconnect "Reconnect")

    ("a" #'arttsu-eglot-fixed-code-action-quickfix "Quickfix" :column "Act")
    ("A" #'eglot-code-actions "Code actions")

    ("f" #'eglot-format-buffer "Format buffer" :column "Buffer")
    ("i" #'arttsu-eglot-fixed-code-action-organize-imports "Organize imports")
    ("n" #'flymake-goto-next-error "Next error" :color pink)
    ("p" #'flymake-goto-prev-error "Previous error" :color pink)

    ("mn" #'smerge-vc-next-conflict "Next conflict" :column "Merge" :color pink)
    ("mu" #'smerge-keep-upper "Keep upper" :color pink)
    ("ml" #'smerge-keep-lower "Keep lower" :color pink)
    ("ma" #'smerge-keep-all "Keep all" :color pink)

    ("q" #'hydra-keyboard-quit "Quit" :column "")
    ("s" #'my/save-all-buffers "Save all buffers")
    ("<f5>" #'my/cockpit-hydra/body "Cockpit"))

  (with-eval-after-load 'eglot
    (define-key prog-mode-map (kbd "<f5>") #'arttsu-hydra-lsp/body)))

Yasnippet

https://github.com/joaotavora/yasnippet

(use-package yasnippet
  :config
  (yas-global-mode +1))

Flycheck

https://www.flycheck.org/en/latest/

(use-package flycheck
  :init
  (setq flycheck-global-modes '(not org-mode))
  :config
  (global-flycheck-mode))

Ruby

chruby

https://github.com/plexus/chruby.el

(use-package chruby)

rspec-mode

https://github.com/pezra/rspec-mode

(use-package rspec-mode)

Scala

(use-package scala-mode
  :interpreter "scala")

(use-package sbt-mode
  :commands sbt-start sbt-command
  :init
  (setq sbt:program-options '("-Dsbt.supershell=false")))

Clojure mode

https://github.com/clojure-emacs/clojure-mode

(use-package clojure-mode
  :config
  (define-clojure-indent
   (match 1)))

Tree-sitter

https://emacs-tree-sitter.github.io/

(use-package tree-sitter
  :config
  (global-tree-sitter-mode)
  (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode))

(use-package tree-sitter-langs)

Kubel

https://github.com/abrochard/kubel

(use-package kubel
  :after vterm
  :config
  (kubel-vterm-setup)
  (advice-add 'kubel-exec-vterm-pod :before (lambda () (setq vterm-shell "/bin/bash")))
  (advice-add 'kubel-exec-vterm-pod :after (lambda () (setq vterm-shell my/fish-path)))
  :bind
  (:map kubel-mode-map
        ("n" . next-line)
        ("p" . previous-line)
        ("N" . kubel-set-namespace)
        ("P" . kubel-port-forward-pod)
        ("s" . tabulated-list-sort)))

(defun my/kubel-set-namespace (namespace)
  (require 'cl)
  (flet ((completing-read (&rest args) namespace))
    (kubel-set-namespace)))

(defun my/kubel-set-context (context)
  (require 'cl)
  (flet ((completing-read (&rest args) context))
    (kubel-set-context)))

Projects

(use-package project
  :straight nil
  :after (projectile)
  :config
  (add-to-list 'project-switch-commands '(project-dired "Dired" "D") t)
  (add-to-list 'project-switch-commands '(projectile-run-vterm "Vterm" "V") t)
  (add-to-list 'project-switch-commands '(magit-status "Magit" "G") t))

Projectile

https://github.com/bbatsov/projectile

(use-package projectile
  :demand
  :bind
  (("M-<f12>" . #'projectile-run-vterm)
   ("M-<f6>" . #'projectile-ripgrep)))

Ripgrep

https://github.com/dajva/rg.el

(use-package rg
  :config
  (rg-enable-default-bindings))

Consult

https://github.com/minad/consult

(use-package consult
  :demand)

Major modes

SQL

(add-to-list 'auto-mode-alist '("\\.hql\\'" . sql-mode))
(add-to-list 'auto-mode-alist '("\\.cql\\'" . sql-mode))

Markdown

https://www.emacswiki.org/emacs/MarkdownMode

(use-package markdown-mode)

Fish

https://github.com/wwwjfy/emacs-fish

(use-package fish-mode)

KMonad

https://github.com/kmonad/kbd-mode

(use-package kbd-mode
  :straight (kbd-mode :type git :host github :repo "kmonad/kbd-mode")
  :mode "\\.kbd'"
  :interpreter "kbd")

Misc

Dired

(use-package dired
  :straight nil
  :demand
  :init
  (setq dired-dwim-target t))

Dirvish

https://github.com/alexluigit/dirvish

(use-package dirvish
  :config
  (dirvish-override-dired-mode)
  :bind
  (("<f7>" . dired-jump)
   :map dirvish-mode-map
   ("<f7>" . dired-jump)))

Pdf-tools

https://github.com/vedang/pdf-tools

(use-package pdf-tools)

Magit

https://magit.vc/

(use-package magit
  :bind
  (("C-c g" . magit-file-dispatch)))

Vterm

https://github.com/vterm/vterm

(defun my/vterm-unbind-function-keys ()
  (local-unset-key (kbd "<f1>"))
  (local-unset-key (kbd "<f2>"))
  (local-unset-key (kbd "<f3>"))
  (local-unset-key (kbd "<f4>"))
  (local-unset-key (kbd "<f5>"))
  (local-unset-key (kbd "<f6>"))
  (local-unset-key (kbd "<f7>"))
  (local-unset-key (kbd "<f8>"))
  (local-unset-key (kbd "<f9>"))
  (local-unset-key (kbd "<f10>"))
  (local-unset-key (kbd "<f11>"))
  (local-unset-key (kbd "<f12>")))

(use-package vterm
  :demand
  :after (dired consult)
  :init
  (setq vterm-module-cmake-args "-DUSE_SYSTEM_LIBVTERM=no")
  (setq vterm-shell my/fish-path)
  :config
  (add-hook 'vterm-mode-hook #'my/vterm-unbind-function-keys))

my/fish-path is defined in local.el.

restclient

https://github.com/pashky/restclient.el

(use-package restclient
  :config
  (add-to-list 'auto-mode-alist '("\\.http\\'" . restclient-mode)))

ledger-mode

https://github.com/ledger/ledger-mode

(use-package ledger-mode
  :after org
  :init
  (setq ledger-default-date-format "%Y-%m-%d")
  :config
  (ledger-reports-add "bal-this-month" "%(binary) -f %(ledger-file) --invert --period \"this month\" -S amount bal ^Income ^Expenses")
  (ledger-reports-add "bal-last-month" "%(binary) -f %(ledger-file) --invert --period \"last month\" -S amount bal ^Income ^Expenses"))

eradio

https://github.com/olavfosse/eradio

(use-package eradio
  :init
  (setq eradio-channels '(("DEF CON - soma fm" . "https://somafm.com/defcon256.pls")
                          ("Deep Space One - soma fm" . "https://somafm.com/deepspaceone.pls")
                          ("BAGel Radio" . "http://ais-sa3.cdnstream1.com/2606_128.mp3")
                          ("n5MD Radio" . "https://somafm.com/n5md130.pls")
                          ("Suburbs of Goa" . "https://somafm.com/suburbsofgoa130.pls")
                          ("The Trip" . "https://somafm.com/thetrip130.pls")
                          ("Groove Salad" . "https://somafm.com/groovesalad130.pls")
                          ("WFMU" . "https://wfmu.org/wfmu.pls")
                          ("Rock'N'Soul" . "https://wfmu.org/wfmu_rock.pls")
                          ("Give The Drummer Radio" . "https://wfmu.org/wfmu_drummer.pls")))
  (setq eradio-player '("mpv" "--no-video" "--no-terminal"))
  :bind
  (("C-c r p" . #'eradio-play)
   ("C-c r s" . #'eradio-stop)
   ("C-c r t" . #'eradio-toggle)))

New Work

Set xingbox base URL

(defun my-set-xingbox-base-url ()
  (interactive)
  (let ((new-url (read-string "New xingbox URL: ")))
    (save-excursion
      (goto-char 0)
      (search-forward "#+name: xingbox")
      (search-forward "rest")
      (beginning-of-line)
      (kill-line)
      (insert (format "  \"%srest\"" new-url)))))

Global bindings

(defun my/org-capture-inbox () (interactive) (org-capture nil "i"))

(defun my/pop-local-mark ()
  (interactive)
  (setq current-prefix-arg '(4))
  (call-interactively 'set-mark-command))

(defun my/kill-current-buffer ()
  (interactive)
  (kill-buffer (current-buffer)))

(defun my/consult-bookmark-other-window ()
  (interactive)
  (let ((original-buffer (current-buffer)))
    (call-interactively 'consult-bookmark)
    (delete-other-windows)
    (split-window-right)
    (switch-to-buffer original-buffer)
    (other-window 1)))

(defun my/consult-bookmark-other-tab ()
  (interactive)
  (let ((original-buffer (current-buffer))
        (target-buffer (progn
                     (call-interactively 'consult-bookmark)
                     (current-buffer))))
    (switch-to-buffer original-buffer)
    (tab-new)
    (switch-to-buffer target-buffer)))

(defun my/vterm-new-tab ()
  (interactive)
  (tab-new)
  (vterm))

(global-set-key (kbd "C-c a") #'org-agenda)
(global-set-key (kbd "C-c c") #'org-capture)
(global-set-key (kbd "C-c i") #'my/org-capture-inbox)

(global-set-key (kbd "<f1>") #'delete-window)
(global-set-key (kbd "C-<f1>") #'my/kill-current-buffer)
(global-set-key (kbd "M-<f1>") #'delete-other-windows)
(global-set-key (kbd "C-S-<f1>") #'tab-close)

(global-set-key (kbd "<f2>") #'consult-bookmark)
(global-set-key (kbd "C-<f2>") #'my/consult-bookmark-other-window)
(global-set-key (kbd "C-S-<f2>") #'my/consult-bookmark-other-tab)

(global-set-key (kbd "<f3>") #'split-window-right)
(global-set-key (kbd "C-<f3>") #'split-window-below)
(global-set-key (kbd "M-<f3>") #'find-file-other-window)
(global-set-key (kbd "C-M-<f3>") #'switch-to-buffer-other-window)
(global-set-key (kbd "S-<f3>") #'find-file-other-tab)
(global-set-key (kbd "C-S-<f3>") #'switch-to-buffer-other-tab)
(global-set-key (kbd "M-S-<f3>") #'tab-new)

(global-set-key (kbd "<f4>") #'rename-buffer)
(global-set-key (kbd "C-S-<f4>") #'tab-rename)

(global-set-key (kbd "<f6>") #'consult-ripgrep)

(global-set-key (kbd "<f8>") #'find-file)
(global-set-key (kbd "C-<f8>") #'consult-buffer)
(global-set-key (kbd "M-<f8>") #'project-find-file)
(global-set-key (kbd "C-M-<f8>") #'consult-project-buffer)
(global-set-key (kbd "C-S-<f8>") #'tab-switch)

(global-set-key (kbd "<f9>") #'previous-buffer)
(global-set-key (kbd "C-<f9>") #'next-buffer)
(global-set-key (kbd "M-<f9>") #'my/pop-local-mark)
(global-set-key (kbd "C-M-<f9>") #'pop-global-mark)
(global-set-key (kbd "C-S-<f9>") #'tab-bar-history-back)

(global-set-key (kbd "<f11>") #'my/switch-project)
(global-set-key (kbd "C-S-<f11>") #'my/switch-project-other-tab)

(global-set-key (kbd "<f12>") #'vterm)
(global-set-key (kbd "C-<f12>") #'vterm-other-window)
(global-set-key (kbd "C-S-<f12>") #'my/vterm-new-tab)

(global-set-key (kbd "C-M-s") #'consult-line)

(define-key org-mode-map (kbd "C-:") #'avy-org-goto-heading-timer)
(define-key org-mode-map (kbd "C-S-s") #'consult-org-heading)

(global-set-key (kbd "C-c j s") #'my/jump-upto-sexp)
(global-set-key (kbd "C-c j S") #'my/jump-back-upto-sexp)
(global-set-key (kbd "C-c k s") #'my/kill-upto-sexp)
(global-set-key (kbd "C-c k S") #'my/kill-back-upto-sexp)

(global-set-key (kbd "C-c j w") #'my/jump-upto-word)
(global-set-key (kbd "C-c j W") #'my/jump-back-upto-word)
(global-set-key (kbd "C-c k w") #'my/kill-upto-word)
(global-set-key (kbd "C-c k W") #'my/kill-back-upto-word)

(with-eval-after-load 'smartparens
  (define-key smartparens-mode-map (kbd "C-c k u") #'sp-unwrap-sexp)
  (define-key smartparens-mode-map (kbd "M-a") #'sp-beginning-of-sexp)
  (define-key smartparens-mode-map (kbd "M-e") #'sp-end-of-sexp)
  (define-key smartparens-mode-map (kbd "C-c {") #'sp-backward-down-sexp)
  (define-key smartparens-mode-map (kbd "C-M-u") #'sp-up-sexp)
  (define-key smartparens-mode-map (kbd "C-c k k") #'sp-kill-hybrid-sexp)
  (define-key smartparens-strict-mode-map (kbd "C-c k u") #'sp-unwrap-sexp)
  (define-key smartparens-strict-mode-map (kbd "M-a") #'sp-beginning-of-sexp)
  (define-key smartparens-strict-mode-map (kbd "M-e") #'sp-end-of-sexp)
  (define-key smartparens-strict-mode-map (kbd "M-j") #'sp-beginning-of-next-sexp)
  (define-key smartparens-strict-mode-map (kbd "M-k") #'sp-beginning-of-previous-sexp)
  (define-key smartparens-strict-mode-map (kbd "C-c {") #'sp-backward-down-sexp)
  (define-key smartparens-strict-mode-map (kbd "C-M-u") #'sp-up-sexp)
  (define-key smartparens-strict-mode-map (kbd "C-c k k") #'sp-kill-hybrid-sexp))

Hydras

Cockpit

(defun my/open-scratch ()
  (interactive)
  (switch-to-buffer-other-window "*scratch*"))

(defhydra my/cockpit-hydra (:color blue :foreign-keys warn)
  "Cockpit\n\n"

  ("s" #'my/save-all-buffers "Save all buffers" :column "Files/buffers")
  ("S" #'super-save-mode "Toggle autosave")

  ("R" #'project-query-replace-regexp "Replace" :column "Project")

  ("n" #'my/copy-charseq "Copy charseq" :column "Quick Actions")

  ("<f1>" #'my/open-scratch "Scratch" :column "Buffers")

  ("W" #'transpose-frame "Transpose" :color pink :column "Windows")

  ("T" #'modus-themes-toggle "Toggle theme" :column "Appearance")

  ("+" #'my/zoom-frame "In" :color pink :column "Zoom")
  ("-" #'my/zoom-frame-out "Out" :color pink)
  ("0" #'my/zoom-frame-default "Default" :color pink)

  ("l" #'org-store-link "Store link" :color blue :column "Org")

  ("q" #'hydra-keyboard-quit "Quit" :column ""))

(global-set-key (kbd "<f5>") #'my/cockpit-hydra/body)

Notes

(defhydra my/notes-hydra (:color blue :foreign-keys warn)
  "Notes\n\n"

  ("d" #'notdeft "List" :column "Deft")
  ("n" #'notdeft-new-file-named "New")
  ("r" #'notdeft-reindex "Reindex")

  ("s" #'notdeft-move-into-subdir "Move into subdir" :column "Deft Ops")
  ("m" #'notdeft-rename-file "Rename")
  ("k" #'notdeft-delete-file "Delete")

  ("l" #'org-roam-buffer-toggle "Backlinks" :column "Zettelkasten")
  ("f" #'org-roam-node-find "Find node")
  ("i" #'org-roam-node-insert "Insert node")

  ("q" #'hydra-keyboard-quit "Quit" :column ""))

(global-set-key (kbd "C-c n") #'my/notes-hydra/body)

Org Cockpit

(defhydra my/org-hydra (:color pink :foreign-keys warn)
  "Org\n\n"

  ("j" #'org-next-visible-heading "Next" :column "Movement")
  ("J" #'org-forward-heading-same-level "Forward")
  ("k" #'org-previous-visible-heading "Previous")
  ("K" #'org-backward-heading-same-level "Backward")

  ("h" #'org-up-element "Up" :column "Movement (2)")
  ("l" #'org-down-element "Down")
  ("s" #'consult-org-heading "Search")
  (";" #'avy-org-goto-heading-timer "Goto")
  ("<" #'my/jump-to-first-heading "First heading")
  (">" #'my/jump-to-last-heading "Last heading")

  ("<tab>" #'org-cycle "Cycle" :column "Visibility")
  ("S-<tab>" #'org-shifttab "Cycle all")
  ("C-l" #'recenter-top-bottom "Recenter")
  ("v" #'scroll-up-command "Scroll down")
  ("V" #'scroll-down-command "Scroll up")
  ("I" #'org-toggle-inline-images "Toggle images")
  ("N" #'org-narrow-to-subtree "Narrow")
  ("E" #'widen "Widen")

  ("T" #'org-set-tags-command "Set tags" :column "Heading Ops")
  ("tt" #'my/mark-as-todo "Todo")
  ("td" #'my/mark-as-done "Done")
  ("S" #'org-schedule "Schedule")
  ("D" #'org-schedule "Deadline")

  ("w" #'org-refile "Refile" :column "Heading Ops (2)")
  ("r" #'my/rename-heading "Rename")
  ("A" #'org-archive-subtree-default "Archive")
  ("W" #'org-cut-subtree "Cut")
  ("M-w" #'org-copy-subtree "Copy")
  ("y" #'org-yank "Yank")

  ("M-H" #'org-metaleft "Demote" :column "Heading Ops (3)")
  ("M-h" #'org-shiftmetaleft "Demote tree")
  ("M-L" #'org-metaright "Promote")
  ("M-l" #'org-shiftmetaright "Promote tree")
  ("M-j" #'org-metadown "Move down")
  ("M-k" #'org-metaup "Move up")

  ("b" #'my/insert-src-heading "Insert" :column "Src Blocks")
  ("B" #'my/insert-src-heading-before "Insert before")
  ("M-b" #'my/duplicate-src-heading "Duplicate")
  ("M-B" #'my/duplicate-src-heading-before "Duplicate before")

  ("n" #'my/name-or-rename-nearest-src-block "Name or rename" :column "Src Blocks (2)")
  ("e" #'my/evaluate-nearest-src-block "Evaluate")
  ("x" #'my/clear-nearest-src-block-results "Clear results")
  ("X" #'my/clear-all-src-block-results "Clear all results")
  ("M-'" #'my/edit-nearest-src-block-args "Edit args")
  ("R" #'my/edit-src-block-results "Edit results" :color blue)

  ("q" #'hydra-keyboard-quit "Quit" :color blue :column "")
  ("i" #'my/edit-heading-content "Edit heading content" :color blue)
  ("M-<return>" #'my/insert-heading-before "Insert heading before" :color blue)
  ("C-<return>" #'org-insert-heading-respect-content "Insert heading" :color blue)
  ("'" #'my/edit-nearest-src-block "Edit src block" :color blue)
  ("c" #'my/smart-copy-nearest-src-block "Copy src block" :color blue)
  ("M-c" #'my/copy-nearest-src-block-results "Copy src block results" :color blue)
  ("RET" #'org-return "Insert newline")
  ("<f5>" #'my/cockpit-hydra/body "Cockpit" :color blue))

(define-key org-mode-map (kbd "<f5>") #'my/org-hydra/body)

LSP hydra

(with-eval-after-load 'hydra
  (defun my-lsp-show-log ()
    (interactive)
    (switch-to-buffer-other-window "*lsp-log*")
    (end-of-buffer nil))

  (defhydra my-hydra-lsp (:color blue)
    "LSP\n\n"

    ("l" #'my-lsp-show-log "Show log" :column "Project")
    ("d" #'consult-lsp-diagnostics "Diagnostics")

    ("s" #'consult-lsp-file-symbols "File symbols" :column "Navigation")
    ("S" #'consult-lsp-symbols "Symbols")
    ("r" #'lsp-find-references "Find references")

    ("a" #'lsp-execute-code-action "Execute code action" :column "Code")
    ("f" #'lsp-format-buffer "Format buffer")
    ("i" #'lsp-organize-imports "Organize imports")

    ("q" #'hydra-keyboard-quit "Quit" :color blue :column ""))

  (global-set-key (kbd "C-c l") #'my-hydra-lsp/body))

Hydra for line/region operations

(defhydra my/line-region-ops-hydra (:color blue :foreign-keys warn)
  "Line/region operations\n\n"

  ("c" #'avy-copy-line "Copy line" :column "Line ops")
  ("m" #'avy-move-line "Move line")
  ("k" #'avy-kill-whole-line "Kill line")
  ("s" #'avy-kill-ring-save-whole-line "Save line")

  ("C" #'avy-copy-region "Copy region" :column "Region ops")
  ("M" #'avy-move-region "Move region")
  ("K" #'avy-kill-region "Kill region")
  ("S" #'avy-kill-ring-save-region "Save region")

  ("d" #'crux-duplicate-current-line-or-region "Duplicate line or region" :column "Duplication")
  ("D" #'crux-duplicate-and-comment-current-line-or-region "Duplicate and comment line or region")

  ("q" #'hydra-keyboard-quit "Quit" :color blue :column ""))

(global-set-key (kbd "C-M-;") #'my/line-region-ops-hydra/body)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published