Skip to content

jcmdln/baemacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 

Repository files navigation

Baemacs - A Literate GNU/Emacs Configuration

Baemacs is a GNU/Emacs configuration packaged within org-mode. It provides a concise abstraction, this file you’re reading, to stage and detect changes which automatically updates on start of GNU/Emacs.

Table of Contents

Usage

The file you’re reading contains all configuration details. It uses org-mode to capture documentation and code blocks which are written to their respective target files. When GNU/Emacs is started, if the README.org file has been changed it triggers rewriting the configuration files.

(Optional) Building Emacs

This section demonstrates how I build GNU/Emacs on Fedora Linux. Doing so is entirely optional as many systems provide GNU/Emacs with support for nativecomp, tree-sitter and other newer features enabled.

$ sudo dnf install \
  autoconf cairo-devel giflib-devel gmp-devel gnutls-devel gnutls-utils \
  gpm-devel gtk+-devel gtk3-devel harfbuzz-devel jansson-devel lcms2-devel \
  libgccjit-devel libjpeg-devel libotf-devel libpng-devel librsvg2-devel \
  libtiff-devel libtree-sitter-devel libwebp-devel libXpm-devel make \
  ncurses-devel openssl-devel sqlite-devel systemd-devel texinfo zlib-devel
$ git clone --branch=emacs-29 --depth=1 https://github.com/emacs-mirror/emacs
$ cd emacs
$ ./autogen.sh
$ ./configure \
  CFLAGS="-O2 -g3 -march=native -pipe" \
  --with-cairo=yes --with-dbus=yes --with-file-notification=yes \
  --with-gif=yes --with-gnutls=yes --with-gpm=yes --with-jpeg=yes \
  --with-json=yes --with-libgmp=yes --with-libsystemd=yes \
  --with-mailutils=yes --with-modules=yes --with-native-compilation=aot \
  --with-pgtk=yes --with-png=yes --with-pop=no --with-rsvg=yes \
  --with-selinux=yes --with-sound=no --with-sqlite3=yes --with-threads=yes \
  --with-tiff=yes --with-tree-sitter=yes --with-webp=yes --with-x=no \
  --with-xml2=yes --with-xpm=yes --with-zlib=yes
$ make -j$(grep -c ^processor /proc/cpuinfo)
$ sudo make install

Install

Clone this repo into $HOME/.config/emacs, then write the configuration by using org-babel-tangle-file:

$ git clone --depth 1 https://github.com/jcmdln/baemacs.git ~/.config/emacs
$ emacs -Q --batch --eval="
(progn
  (require 'org)
  (org-babel-tangle-file (concat user-emacs-directory \"README.org\"))
)"

When GNU/Emacs is started, any remaining configuration steps will be performed such as installing and compiling packages.

early-init.el

;;; early-init.el ---- Baemacs early initialization file
;;; Commentary:
;; Emacs will look for this specific file before initializing the GUI and
;; other such things.
;;; Code:

Custom

Rather than Emacs customization being appended to the end of the configuration file, in our case init.el, we may specify an alternate custom-file:

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

Encoding

(setq prefer-coding-system       'utf-8
      set-default-coding-systems 'utf-8
      set-language-environment   "UTF-8"
      set-locale-environment     "en_US.UTF-8")

Environment

(setenv "EDITOR"         "emacsclient")
(setenv "GIT_EDITOR"     "emacsclient")
(setenv "MANPATH"        (getenv "MANPATH"))
(setenv "PAGER"          "cat")
(setenv "PATH"           (getenv "PATH"))
(setenv "PROMPT_COMMAND" "")
(setenv "SHELL"          (getenv "SHELL"))
(setenv "TERM"           (getenv "TERM"))

Package Management

(require 'package)

(if (fboundp 'native-compile)
    (setq package-native-compile t))

(setq package-user-dir (concat user-emacs-directory "pkg/"))

(setq package-archives           '(("elpa"         . "https://elpa.gnu.org/packages/")
                                   ("melpa-stable" . "https://stable.melpa.org/packages/")
                                   ("melpa"        . "https://melpa.org/packages/"))
      package-archive-priorities '(("elpa"         . 3)
                                   ("melpa-stable" . 2)
                                   ("melpa"        . 1)))

(when (< emacs-major-version 27)
  (package-initialize))

use-package

The first package we’ll ensure exists is use-package, which the rest of this file relies on for handling per-package configuration. In newer versions of Emacs use-package is now a built-in, but we should check to be nice to older versions:

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-when-compile
  (require 'use-package)
  (require 'bind-key))

Some decent use-package tweaks are to defer loading a package unless demanded, ensure a package exists or can be retrieved before loading its configuration, and check that use-package is installed and active before attempting to initialize:

(setq use-package-always-ensure     't
      use-package-check-before-init 't)

no-littering

The second package will keep our Emacs configuration directory nice and tidy by adjusting the locations of configuration files. It uses a unixy format, which is a nice change.

(use-package no-littering
  :commands (dired-create-directory no-littering-expand-var-file-name)
  :init
  (setq auto-save-file-name-transforms  `((".*" ,(no-littering-expand-var-file-name "auto-save/") 't))
        baemacs/auto-save-dir           (concat user-emacs-directory "var/auto-save"))

  (if (not (file-directory-p baemacs/auto-save-dir))
      (dired-create-directory baemacs/auto-save-dir)))

Disable toolbars

I don’t find the toolbars to be useful comparatively to the amount of visual space they consume. The following will disable the various toolbars when their functions are bound, which prevents them from ever being initialized:

(when (fboundp 'menu-bar-mode)   (menu-bar-mode   -1))
(when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
(when (fboundp 'tool-bar-mode)   (tool-bar-mode   -1))

Disable splash screen

After initialization completes, we’ll end up with some clutter that is not very helpful for long-time Emacs users.

  • Remove the default scratch buffer message
  • Disable the splash screen
  • Disable the startup buffer menu
(setq initial-scratch-message     ""
      inhibit-splash-screen       't
      inhibit-startup-buffer-menu 't)

Re-use Frames and Windows

One big annoyance is Emacs arbitrary splitting my window to show a newly created buffer. This is especially annoying when I run a command myself such as M-x man which causes arbitrary splits.

Here we will enforce always re-using the currently selected frame when a new buffer is opened or focused. This works in most cases, though as shown below certain things like ‘man’ will not respect our choices and require specific adjustment. Some things like ‘gnus’ should still make splits as they want, so we won’t look for every possible edge condition to normalize this behavior.

(add-to-list 'display-buffer-alist '("*Help*" display-buffer-same-window))
(add-to-list 'display-buffer-alist '("*Man*" display-buffer-same-window))

(setq pop-up-frames  nil
      pop-up-windows nil)
(provide 'early-init)
;;; early-init.el ends here

init.el

Emacs will look for this specific file once it reaches the init phase. Here we will make modifications to things that ship with Emacs and should be changed as early as possible.

;;; init.el ---- Baemacs initialization file
;;; Commentary:
;; Emacs will look for this specific file once it reaches the
;; initialization phase.  Here we will make modifications to things that
;; ship with Emacs and should be changed early.
;;; Code:

Appearance

In terms of appearance, I prefer to have as little wasted space and visual clutter as possible. I make no attempt to completely restyle Emacs, preferring instead to make slight modifications.

Font

This probably isn’t needed, but we’ll set the default font to the monospace font defined on the system.

(set-face-attribute :family "Monospace")

Theme

Rather than include yet another theme, we’ll use the tango-dark theme.

(load-theme 'tango-dark 't)

Editing

There are some general-purpose changes to make for editing files, which ideally if I ever get around to incorporating site-start.el will allow loading a slim, nimble instance of Emacs when needed. For now I’ll leave these changes here.

Backups

(setq backup-by-copying 't)

Clipboard

This part is a bit unorganized though reduces clutter by inhibiting buffers and adjusting how the clipboard works in Emacs.

(setq save-interprogram-paste-before-kill 't
      select-enable-primary               nil)

Delete Selection

(add-hook 'after-init-hook
          (lambda() (delete-selection-mode 1)))

Scrolling

  • Scroll line-by-line
  • Preserve the cursor position when scrolling
  • No scroll margins
  • Don’t scroll past the end of a buffer
(setq auto-window-vscroll             nil
      scroll-conservatively           101
      scroll-margin                   0
      scroll-preserve-screen-position 1
      scroll-step                     1
      scroll-up-aggressively          0.0
      scroll-down-aggressively        0.0)

Line Numbers

Display line numbers in most types of modes where it makes sense.

(add-hook 'after-init-hook
          (lambda()
            (add-hook 'conf-mode-hook 'display-line-numbers-mode)
            (add-hook 'prog-mode-hook 'display-line-numbers-mode)
            (add-hook 'org-mode-hook  'display-line-numbers-mode)
            (add-hook 'text-mode-hook 'display-line-numbers-mode)))

Modeline

  • Show column numbers
  • Ensure \n always precedes EOF
  • When show-paren-mode is enabled, delay showing match for 330ms
  • Disable the visual-bell
(setq column-number-mode    't
      require-final-newline 't
      show-paren-delay      0.33
      visible-bell          nil)

Parenthesis Matching

Highlight matching parenthesis, always.

(add-hook 'after-init-hook (lambda() (show-paren-mode 't)))

Whitespace

Before saving, remove any trailing whitespace characters.

(add-hook 'before-save-hook 'delete-trailing-whitespace)

Word Wrap

When Visual Line mode is enabled, ‘word-wrap’ is turned on in this buffer, and simple editing commands are redefined to act on visual lines, not logical lines.

(add-hook 'after-init-hook (lambda() (global-visual-line-mode 't)))

Input

Keyboard

(defalias 'yes-or-no-p 'y-or-n-p)
(global-set-key (kbd "M--")
                (lambda()
                  (interactive)
                  (split-window-vertically)
                  (other-window 1 nil)
                  (switch-to-next-buffer)))

(global-set-key (kbd "M-=")
                (lambda()
                  (interactive)
                  (split-window-horizontally)
                  (other-window 1 nil)
                  (switch-to-next-buffer)))
(global-set-key (kbd "C-c c")     'comment-or-uncomment-region)
(global-set-key (kbd "<M-down>")  'windmove-down)
(global-set-key (kbd "<M-left>")  'windmove-left)
(global-set-key (kbd "<M-right>") 'windmove-right)
(global-set-key (kbd "<M-up>")    'windmove-up)

Mouse

(setq mouse-wheel-follow-mouse      't
      mouse-wheel-progressive-speed nil
      mouse-wheel-scroll-amount     '(3 ((shift) . 3))
      mouse-yank-at-point           't)
(add-hook 'after-init-hook (lambda() (xterm-mouse-mode 1)))
(global-set-key (kbd "<mouse-4>") (lambda() (interactive) (scroll-down-line 3)))
(global-set-key (kbd "<mouse-5>") (lambda() (interactive) (scroll-up-line 3)))

Bootstrap

At the end of initialization, ensure that README.org is not newer than config.el, otherwise rebuild our configuration files and byte-compile them.

(defun baemacs/reconfig()
  "Reconfigure Baemacs by writing and loading our config."
  (require 'org)
  (interactive)
  (org-babel-tangle-file (concat user-emacs-directory "README.org")))
(if (file-newer-than-file-p (concat user-emacs-directory "README.org")
                            (concat user-emacs-directory "early-init.el"))
    (baemacs/reconfig))

(load (concat user-emacs-directory "config.el"))
(provide 'init)
;;; init.el ends here

config.el

This is a non-standard file that is referenced at the end of init.el which contains our extra package and language definitions. Before we add anything to this file, first we’ll add the file header:

;;; config.el ---- Baemacs configuration file
;;; Commentary:
;; This is a non-standard file that is referenced at the end of 'init.el'
;; which contains our extra package and language definitions.
;;; Code:

Packages

circe

Circe is a Client for IRC in Emacs.

https://stable.melpa.org/#/circe https://github.com/emacs-circe/circe

(use-package circe
  :defer 't
  :commands (enable-lui-logging-globally lui-set-prompt)
  :config
  (setq circe-default-part-message ""
        circe-default-quit-message ""
        circe-format-server-topic  "*** Topic: {userhost}: {topic-diff}"
        circe-reduce-lurker-spam   't
        circe-use-cycle-completion 't

        lui-fill-type              nil
        lui-time-stamp-format      "%H:%M:%S"
        lui-time-stamp-position    'left-margin)

  (add-hook 'circe-server-mode-hook (lambda() (require 'circe-chanop)))
  (add-hook 'circe-chat-mode-hook
            (lambda()
              (lui-set-prompt
               (concat (propertize
                        (concat (buffer-name) ":")
                        'face 'circe-prompt-face)
                       " "))))

  (add-hook 'lui-mode-hook
            (lambda()
              (setq fringes-outside-margins 't
                    left-margin-width       9
                    word-wrap               't
                    wrap-prefix             "")))

  (enable-circe-color-nicks)

  (if (file-exists-p (concat user-emacs-directory "usr/circe.el"))
      (load-file     (concat user-emacs-directory "usr/circe.el"))))

company

Company is a modular completion framework. Modules for retrieving completion candidates are called backends, modules for displaying them are frontends.

https://stable.melpa.org/#/company https://github.com/company-mode/company-mode

(use-package company
  :config
  (setq company-begin-commands '(self-insert-command)
        company-idle-delay     0.3
        company-echo-delay     0
        company-tooltip-limit  20)

  :hook
  ((prog-mode . company-mode)
   (text-mode . company-mode)))

counsel

(use-package counsel
  :bind (("<f1> f"  . counsel-describe-function)
         ("<f1> l"  . counsel-find-library)
         ("<f1> v"  . counsel-describe-variable)
         ("<f2> i"  . counsel-info-lookup-symbol)
         ("<f2> u"  . counsel-unicode-char)
         ("C-s"     . counsel-grep-or-swiper)
         ("C-c g"   . counsel-git)
         ("C-c j"   . counsel-git-grep)
         ("C-c l"   . counsel-ag)
         ("C-r"     . counsel-minibuffer-history)
         ("C-x C-f" . counsel-find-file)
         ("C-x l"   . counsel-locate)
         ("M-x"     . counsel-M-x)))

diff-hl

(use-package diff-hl
  :demand 't
  :commands (diff-hl-mode diff-hl-margin-mode)
  :hook ((conf-mode prog-mode text-mode) . diff-hl-mode)
  :config
  (when (eq window-system nil)
    (add-hook 'after-init-hook
              (lambda()
                (add-hook 'conf-mode-hook 'diff-hl-margin-mode)
                (add-hook 'org-mode-hook  'diff-hl-margin-mode)
                (add-hook 'prog-mode-hook 'diff-hl-margin-mode)
                (add-hook 'text-mode-hook 'diff-hl-margin-mode)))))

editorconfig

(use-package editorconfig
  :hook
  (prog-mode-hook . (lambda()
                      (add-hook 'before-save-hook
                                (lambda() (editorconfig-apply) (editorconfig-format-buffer))
                                nil 'local)))
  :init (editorconfig-mode 1))

eglot

(use-package eglot
  :commands (eglot-ensure)
  :config
  (setq eglot-auto-display-help-buffer nil
        eglot-put-doc-in-help-buffer   nil)

  (add-to-list 'eglot-server-programs '(c-mode    . ("clangd")))
  (add-to-list 'eglot-server-programs '(c++-mode  . ("clangd")))
  (add-to-list 'eglot-server-programs '(rust-mode . ("rust-analyzer")))

  :hook (((c-mode c++-mode go-mode python-mode rust-mode zig-mode) . 'eglot-ensure)
         ((c-mode c++-mode)  . (lambda() (fset 'c-indent-region 'clang-format-region)))
         (eglot-managed-mode . (lambda() (add-hook 'before-save-hook 'eglot-format-buffer nil 'local)))))

eldoc

(use-package eldoc
  :commands (global-eldoc-mode)
  :config (setq eldoc-echo-area-use-multiline-p nil))

elfeed

This package provides an extensible web feed reader, supporting both RSS and Atom.

(use-package elfeed
  :config
  (setq elfeed-search-filter "@1-week-ago +unread "
        url-queue-timeout    10)

  (if (file-exists-p (concat user-emacs-directory "usr/elfeed.el"))
      (load-file     (concat user-emacs-directory "usr/elfeed.el"))))

eshell

 (use-package eshell
   :commands
   (baemacs/eshell/clear
    baemacs/eshell/prompt-function
    eshell
    eshell-new
    eshell-truncate-buffer
    eshell/basename
    eshell/pwd)

   :config
   (defun baemacs/eshell/clear()
     "Clear the current eshell buffer by truncating the contents."
     (interactive)
     (setq-local eshell-buffer-maximum-lines 0)
     (eshell-truncate-buffer))

   (defun baemacs/eshell/prompt-function()
     "Custom eshell prompt."
     (interactive)
     (lambda ()
	(concat "[" (user-login-name) "@"
		(car (split-string (system-name) "\\.")) " "
		(if (string= (eshell/pwd) (getenv "HOME"))
		    "~" (eshell/basename (eshell/pwd))) "]"
		(if (= (user-uid) 0) "# " "$ "))))

   (setq eshell-banner-message             ""
	  eshell-cmpl-cycle-completions     nil
	  eshell-error-if-no-glob           't
	  eshell-hist-ignoredups            't
	  eshell-history-size               4096
	  eshell-prefer-lisp-functions      't
	  eshell-prompt-function            (baemacs/eshell/prompt-function)
	  eshell-prompt-regexp              "^[^#$\n]*[#$] "
	  eshell-save-history-on-exit       't
	  eshell-scroll-to-bottom-on-input  nil
	  eshell-scroll-to-bottom-on-output nil
	  eshell-scroll-show-maximum-output nil)

   :init
   (add-hook 'eshell-mode-hook (lambda() (defalias 'eshell/clear 'baemacs/eshell/clear)))

   (defun baemacs/eshell-new()
     "Open a new instance of eshell."
     (interactive)
     (eshell 'N)))

eww

I like eww, but it was missing a few things for me to use it as my primary browser for non-interactive sites. Here we will ensure that eww is our primary browser when visiting links, and that images are blocked by default. Should you have multiple eww buffers open and want to toggle displaying images in a specific buffer, you may now do so.

(use-package eww
  :commands (eww
             eww-mode
             eww-reload
             baemacs/eww-toggle-images
             baemacs/eww-new)

  :config
  (when window-system
    (defun baemacs/eww-toggle-images()
      "Toggle blocking images in eww."
      (interactive)
      (if (bound-and-true-p shr-blocked-images)
          (setq-local shr-blocked-images nil)
        (setq-local shr-blocked-images ""))
      (eww-reload))

    (setq shr-blocked-images ""))

  :init
  (defun baemacs/eww-new()
    "Open a new instance of eww."
    (interactive)
    (let ((url (read-from-minibuffer "Enter URL or keywords: ")))
      (switch-to-buffer (generate-new-buffer "*eww*"))
      (eww-mode)
      (eww url)))

  (setq browse-url-browser-function 'eww-browse-url))
(use-package eww-lnum
  :bind (:map eww-mode-map
              ("f" . eww-lnum-follow)
              ("F" . eww-lnum-universal))
  :commands (eww-lnum-follow eww-lnum-universal))

flycheck

(use-package flycheck
  :hook (prog-mode . flycheck-mode))

gnus

I’ve bounced between using “real” email clients and gnus quite a few times, though here we will attempt to make gnus behave like other clients.

(use-package gnus
  :bind (("<M-down>" . windmove-down)
         ("<M-up>"   . windmove-up))

  :config
  (add-to-list 'mm-discouraged-alternatives "text/html")
  (add-to-list 'mm-discouraged-alternatives "text/richtext")

  (setq gnus-permanently-visible-groups        ".*"
        gnus-show-threads                      't
        gnus-sum-thread-tree-false-root        ""
        gnus-sum-thread-tree-indent            "  "
        gnus-sum-thread-tree-leaf-with-other   "├─> "
        gnus-sum-thread-tree-root              ""
        gnus-sum-thread-tree-single-leaf       "╰─> "
        gnus-sum-thread-tree-vertical          ""
        gnus-summary-line-format               "%U%R:%-15,15o  %-20,20A  %-3,3t  %B%s\n"
        gnus-summary-thread-gathering-function 'gnus-gather-threads-by-subject
        gnus-thread-hide-subtree               't
        gnus-thread-sort-functions             '(gnus-thread-sort-by-date))

  (if (file-exists-p (concat user-emacs-directory "usr/gnus.el"))
      (load-file     (concat user-emacs-directory "usr/gnus.el")))

  :hook ((gnus-summary-prepared . gnus-summary-sort-by-most-recent-date)
         (gnus-group-mode       . gnus-group-sort-groups-by-alphabet)))

helpful

This package provides an alternative to the built-in Emacs help that provides much more contextual information.

(use-package helpful
  :bind (("C-h C" . #'helpful-command)
         ("C-h F" . #'helpful-function)
         ("C-h f" . #'helpful-callable)
         ("C-h k" . #'helpful-key)
         ("C-h v" . #'helpful-variable)))

ibuffer

I’m not a fan of the default ibuffer behavior, if the total size of this section does not make that clear. Here we will sort buffers, show human readable sizes, and define a ton of filter groups.

(use-package ibuffer
  :bind (("C-x C-b"         . ibuffer)
         ("<C-tab>"         . next-buffer)
         ("<C-iso-lefttab>" . previous-buffer))

  :commands (ibuffer-switch-to-saved-filter-groups)

  :config
  (add-hook 'ibuffer-auto-mode-hook
            (lambda()
              (ibuffer-switch-to-saved-filter-groups "default")))

  (define-ibuffer-column size-h
    (:name "Size" :inline 't)
    (cond ((> (buffer-size) (* 1000 1000 1000))
           (format "%7.1fG" (/ (buffer-size) 1000000000.0)))
          ((> (buffer-size) (* 1000 1000))
           (format "%7.1fM" (/ (buffer-size) 1000000.0)))
          ((> (buffer-size) 1000)
           (format "%7.1fK" (/ (buffer-size) 1000.0)))
          ('t (format "%8d" (buffer-size)))))

  (setq ibuffer-show-empty-filter-groups nil
        ibuffer-saved-filter-groups
        (quote (("default"
                 ("emacs"
                  (or (name . "^\\*Completions\\*$")
                      (name . "^\\*Customize\\*")
                      (name . "^\\*Disabled\s.*\\*$")
                      (name . "^\\*Help\\*$")
                      (name . "^\\*Messages\\*$")
                      (name . "^\\*scratch\\*.*$")))

                 ("apps"
                  (or (mode . dired-mode)
                      (mode . eshell-mode)))

                 ("dev"
                  (or (name . "^\\*clang")
                      (name . "^\\*gcc")
                      (name . "^\\*RTags")
                      (name . "^\\*rdm\\*")
                      (name . "magit")
                      (name . "COMMIT_EDITMSG")
                      (name . "^\\*Flycheck")
                      (name . "^\\*Flyspell")))

                 ("docs"
                  (or (name . "^\\*Man\s.*\s.*\\*$")
                      (name . "^\\*WoMan\s.*\s.*\\*$")
                      (mode . pdf-view-mode)))

                 ("irc"
                  (or (mode . circe-mode)
                      (mode . circe-channel-mode)
                      (mode . circe-query-mode)
                      (mode . circe-server-mode)))

                 ("logs"
                  (or (name . "^\\*EGLOT.*")
                      (name . "^\\*eldoc\\*$")
                      (name . "-Log\\*$")
                      (name . "\slog\\*$")))

                 ("mail"
                  (or (mode . message-mode)
                      (mode . bbdb-mode)
                      (mode . mail-mode)
                      (mode . gnus-group-mode)
                      (mode . gnus-summary-mode)
                      (mode . gnus-article-mode)
                      (name . "^\\.bbdb$")
                      (name . "^\\.newsrc-dribble")))

                 ("web"
                  (or (mode . eww-mode)
                      (name . "^\\*elfeed")))
                 )))

        ibuffer-formats '((mark
                           modified read-only " "
                           (name 35 35 :left :nil) " "
                           (size-h 9 -1 :right) " "
                           (mode 16 16 :left :elide) " "
                           filename-and-process)))

  :hook ((ibuffer      . ibuffer-auto-mode)
         (ibuffer-mode . ibuffer-do-sort-by-alphabetic)))

ivy

(use-package ivy
  :bind
  (("C-c C-r" . ivy-resume)
   ("<f6>"    . ivy-resume))
  :commands (ivy-mode)
  :config
  (setq ivy-use-virtual-buffers      't
	  enable-recursive-minibuffers 't)
  :hook (after-init . (lambda() (ivy-mode 1))))
(use-package ivy-rich
  :commands (ivy-rich-mode)
  :hook (ivy-mode . (lambda() (ivy-rich-mode 1))))

magit

(use-package magit
  :bind ("C-c C-c" . with-editor-finish)
  :demand 't)

org

(use-package org
  :bind
  (:map org-mode-map
        ([remap backward-paragraph] . nil)
        ([remap forward-paragraph]  . nil)
        ("C-S-<down>" . nil)
        ("C-S-<up>"   . nil)
        ("M-<down>"   . nil)
        ("M-<up>"     . nil)
        ("S-<left>"   . nil)
        ("S-<right>"  . nil))

  :config
  (set-face-attribute 'org-block nil :background "#111111" :extend 't)
  (setq org-src-fontify-natively  't
        org-src-tab-acts-natively 't
        org-support-shift-select  'always)
  (setq org-babel-load-languages
        '((C . t)
          (awk . t)
          (emacs-lisp . t)
          (lisp . t)
          (makefile . t)
          (scheme . t)
          (shell . t)
          (sql . t)
          (sqlite . t)))

  :hook
  ((org-metadown  . windmove-down)
   (org-metaleft  . windmove-left)
   (org-metaright . windmove-right)
   (org-metaup    . windmove-up)
   (org-mode      . (lambda() (setq-local indent-tabs-mode nil))))
  :mode ("\\.org$" . org-mode))
(use-package company-org-block
  :after (company org)
  :config (setq company-org-block-edit-style 'auto)
  :init
  (add-hook 'org-mode-hook
            (lambda ()
              (add-to-list (make-local-variable 'company-backends) 'company-org-block))))
(use-package org-drill
  :after (org)
  :commands (org-drill)
  :defer 't)
(use-package toc-org
  :after (org)
  :commands (toc-org-enable)
  :hook (org-mode . toc-org-enable))
(provide 'config)
;;; config.el ends here

rainbow-delimiters

(use-package rainbow-delimiters
  :hook ((conf-mode prog-mode text-mode) . rainbow-delimiters-mode))

ranger

(use-package ranger
  :commands (ranger-override-dired-mode)
  :init (ranger-override-dired-mode 't))

scratch

(use-package scratch
  :commands (baemacs/scratch-new)
  :init
  (defun baemacs/scratch-new()
    "Open a new scratch buffer."
    (interactive)
    (switch-to-buffer (generate-new-buffer "*scratch*"))
    (lisp-mode)))

server

I feel that Emacs is missing some extensions for server-based functions and added a warning when attempting to close Emacs. Also, if you want to update your packages or kill Emacs without saving in a quicker fashion you may appreciate the additional functions.

(use-package server
  :demand 't
  :bind ("C-x C-c" . baemacs/server-stop)
  :commands (baemacs/server-kill baemacs/server-stop)
  :config
  (unless (and (fboundp 'server-running-p)
               (server-running-p))
    (server-start))

  :init
  (defun baemacs/server-kill()
    "Delete current Emacs server, then kill Emacs"
    (interactive)
    (if (y-or-n-p "Kill Emacs without saving? ")
        (kill-emacs)))

  (defun baemacs/server-stop()
    "Prompt to save buffers, then kill Emacs."
    (interactive)
    (if (y-or-n-p "Quit Emacs? ")
        (save-buffers-kill-emacs))))

smartparens

(use-package smartparens
  :config
  (setq sp-highlight-pair-overlay     nil
        sp-highlight-wrap-overlay     nil
        sp-highlight-wrap-tag-overlay nil)
  :hook ((eshell-mode org-mode prog-mode text-mode) . turn-on-smartparens-mode))

swiper

(use-package swiper
  :after (counsel ivy))

undo-tree

(use-package undo-tree
  :commands (global-undo-tree-mode)
  :init (global-undo-tree-mode))

Languages

C

(use-package cc-mode
  :config
  (setq-local c-basic-offset    8
              c-default-style   "linux"
              indent-tabs-mode  't
              tab-width         8)
  :hook
  ((c-mode . tree-sitter-mode)
   (c-mode . tree-sitter-hl-mode))
  :mode
  (("\\.c$" . c-mode)
   ("\\.h$" . c-mode)))

C++

(use-package cc-mode
  :config
  (setq-local c-basic-offset    4
              c-default-style   "ellemtel"
              indent-tabs-mode  't
              tab-width         4)
  :mode
  (("\\.cc$"  . c++-mode)
   ("\\.cpp$" . c++-mode)
   ("\\.cxx$" . c++-mode)
   ("\\.hh$"  . c++-mode)
   ("\\.hpp$" . c++-mode)))