Skip to content

A bare-bones, sane-defaults emacs distribution designed to be expanded upon

License

Notifications You must be signed in to change notification settings

isomatter-labs/starmacs

Starmacs – An Emacs Config With as Little as Possible

./img/emacs.png

What is Starmacs?

Starmacs is yet another set of defaults for emacs, with one (and only one) purpose: it attempts to get out of your way, and add as little magic as possible.

Starmacs is not a full distribution, like Doom or Spacemacs, but is more akin to Prelude, although much more amateur.

Design Decisions

One Big File

Starmacs’s config lives in a single file: README.org. This is entirely in an effort to make things easier to grok for new users. This way, there is only one file to be perused, and users need not be bothered to learn how packages work.

The use of an org file rather than an elisp file is to improve discoverability. Users can simply expand and collapse sections to painlessly explore the configuration.

Included Packages

Starmacs intends to be a set of sane defaults for emacs, and nothing more. As such, dependency on packages is minimized as much as is practical.

Ideally, Starmacs is mostly an aesthetic overhaul, with the only major functional changes being the inclusion of magit and eglot.

This is intended to allow a new emacs user to learn emacs (and not a custom layer sitting on it) without sacrificing the kinds of features present in their old editor. LSP is only becoming more relevant, and magit is the only thing close to the kind of git-integration that is becoming expected in the modern world of editors.

Extras

Settings for some languages have been pre-configured (primarily Go and Julia) this is unabashedly because they are languages I use often, and Starmacs is developed primarily for my own use.

Things You May Prefer

Starmacs is not necessarily for everyone; you may prefer one of the following:

Spacemacs Doom Emacs Prelude

Installation

Dependencies

The magit package installed by Starmacs expects you to have sqlite installed on your system. Installation will vary based on your system, but it is generally available as a package for most package managers.

Cloning the Repository

Simply clone this repository into your ~/.emacs.d directory. The next time you start emacs, it will automatically install all of the packages and set up the configuration. As is mentioned later in this document, any custom configuration should be added to the ~/usr directory. This prevents the need to merge changes when the repository is updated. Feel free to update this file directly if you wish, but be aware that pulling updates will become a headache.

Alternately, after cloning this repository, you can simply delete the .git directory and start a new repository. That way, Starmacs can simply serve as a starting point for your own configuration, rather than a living distribution.

Either way is fine, and the choice is yours!

Note: sqlite-api

When you first start up Starmacs, there will be a prompt to build the sqlite-api. After entering ‘yes’, the installation will proceed as normal.

Quality of Life Improvements

Keep Buffers Up to Date with Files

When files on disk change, open buffers should be automatically updated to reflect those changes.

(global-auto-revert-mode t)

Do Not Create Extra Files

Don’t create backup~ or #autosave# files.

(setq make-backup-files nil)
(setq auto-save-default nil)

Add path to extra binaries

(use-package exec-path-from-shell
    :config
    (exec-path-from-shell-initialize))

Replace Selection

When text is highlighted, typing should delete the highlighted text and insert what is typed.

(delete-selection-mode 1)

Mouse in Terminal

If Emacs is run in the terminal, the mouse should continue to work.

(xterm-mouse-mode 1)

Whitespace

Trailing whitespace should be highlighted, and deleted on save. In addition, tabs and newlines should be displayed in a subtle way, allowing for users to more easily check the formatting used.

(add-hook 'prog-mode-hook (lambda () (setq show-trailing-whitespace t)))
(add-hook 'before-save-hook 'delete-trailing-whitespace)

(setq-default tab-width 4)
(setq whitespace-style (quote (face tabs newline tab-mark newline-mark)))

(setq whitespace-display-mappings
      '((newline-mark 10 [172 10])
        (tab-mark 9 [187 9] [92 9])))
(global-whitespace-mode 't)

(custom-set-faces
 '(whitespace-tab((t (:foreground "#525252"))))
 '(whitespace-newline((t (:foreground "#525252")))))

Look

Theme

Autothemer

Autothemer is a requirement for anisochromatic-theme, and must be loaded in first.

(use-package autothemer
  :ensure t)

Anisochromatic

Anisochromatic is a theme created by Isomatter::Labs (the creators of Starmacs), and is a color theme meant to be both pleasing to the eye, a little retro, and comfortable.

It also intentionally uses the same (or very similar) color assignments as the default Github color theme. This is done to reduce mental friction when alternating between one’s editor and code in the browser.

While the color attributions are intentionally copied, the colors themselves are original, and were carefully chosen to create a pleasing palette.

A notable exception to the color attirbutions are strings, which Github lumps with other constants as blue, but which most color schemes tend to assign green. In order to assure the least friction reasonable, Anisochromatic opted for teal.

(use-package anisochromatic-theme
  :straight (:host github :repo "isomatter-labs/anisochromatic-emacs" :files ("dist" "*.el"))
  :ensure t
  :config
  (load-theme 'anisochromatic t))

Markdown

While most Emacs users prefer to use org-mode for rich text documents (such as this one), one will nevertheless encounter Markdown frequently, so Markdown should also be rendered nicely.

(use-package markdown-mode
  :ensure t
  :mode ("README\\.md\\'" . gfm-mode)
  :init (setq markdown-command "multimarkdown"))

Modeline

base-line is an Emacs modeline maintained by Isomatter::Labs that is heavily based on mood-line by Jessie Hildebrandt.

(use-package base-line
  :straight (:host github :repo "isomatter-labs/base-line" :files ("dist" "*.el"))
  :ensure t
  :hook (after-init . base-line-mode))

Adjust Modeline Size

  (defun starmacs/set-modeline-box-bg (face new-bg)
    (set-face-attribute face nil
                        :background new-bg
                        :box `(:line-width 8 :color ,new-bg)
                        :overline nil
                        :underline nil))

(defun starmacs/fix-modeline ()
  (interactive)
  (starmacs/set-modeline-box-bg 'mode-line-active (face-background 'mode-line-active))
  (starmacs/set-modeline-box-bg 'mode-line (face-background 'mode-line))
  (starmacs/set-modeline-box-bg 'mode-line-inactive (face-background 'mode-line-inactive)))

(starmacs/fix-modeline)

Quality of Life

(setq inhibit-startup-message t)

(scroll-bar-mode -1)        ; Disable visible scrollbar
(tool-bar-mode -1)          ; Disable the toolbar
(tooltip-mode -1)           ; Disable tooltips
(set-fringe-mode 10)        ; Give some breathing room


(toggle-frame-maximized)    ; Always start maximized

Visible Bell

Instead of ringing an obnoxious bell, simply flash the modeline.

(setq visible-bell t)
(setq ring-bell-function
      (lambda ()
        (let ((orig-bg (face-background 'mode-line-active)))
          (set-face-background 'mode-line-active "#ef8e49")
          (starmacs/set-modeline-box-bg 'mode-line-active "#ef8e49")
          (run-with-idle-timer 0.1 nil
                               (lambda (bg) (progn (set-face-background 'mode-line-active bg)
                                                   (starmacs/set-modeline-box-bg 'mode-line-active bg)))
                               orig-bg))))

Line Numbers

Display line numbers everywhere, except for things like terminals, where it doesn’t make much sense.

(column-number-mode)
(global-display-line-numbers-mode t)

;; Disable line numbers for some modes
(dolist (mode '(org-mode-hook
                term-mode-hook
                shell-mode-hook
                eshell-mode-hook))
  (add-hook mode (lambda () (display-line-numbers-mode 0))))

Scrolling

Set up pixel-scrolling for a nice, modern-feeling experience

(pixel-scroll-precision-mode 1)

Cursor

Default the cursor to a blinking bar, which is more familiar than the default box.

(setq-default cursor-type '(bar . 2))

Truncate, Don’t Wrap

By default, do not wrap lines around the window, but instead truncate them at the edge.

Use diamonds to indicate when these truncations happen, rather than the default right-arrows.

(set-default 'truncate-lines t)
(define-fringe-bitmap 'right-arrow
  [#b00000000
   #b00011000
   #b00111100
   #b01111110
   #b01111110
   #b00111100
   #b00011000
   #b00000000])
(define-fringe-bitmap 'left-arrow
  [#b00000000
   #b00011000
   #b00111100
   #b01111110
   #b01111110
   #b00111100
   #b00011000
   #b00000000])

Focus Line

Highlight the line the cursor is currently on, to make it easier to quickly locate the cursor.

(if (window-system)
    (global-hl-line-mode 1))

Highlight TODOs

Highlight the words “TODO” and “FIXME” in comments, allowing them to be more easily found.

(use-package hl-todo
  :ensure t
  :config
  (global-hl-todo-mode 1))

Welcome screen

Present users with a friendly and fun welcome screen on initial startup.

 (defun no-linum ()
   (display-line-numbers-mode -1))

(defun starmacs/welcome ()
  (interactive)
   "Show minimal *welcome* buffer"
   (delete-other-windows)
   (with-current-buffer (get-buffer-create "*Welcome*")
     (setq truncate-lines t)
     (no-linum)
     (let* ((buffer-read-only)
            (image-path "~/.emacs.d/img/emacs.png")
            (image (create-image image-path))
            (size (image-size image))
            (height (cdr size))
            (width (car size))
            (top-margin (floor (/ (- (window-height) height 3) 2)))
            (left-margin (floor (/ (- (window-width) width) 2)))
            (title "A hackable text editor for the 21st Century!"))
       (erase-buffer)
       (setq mode-line-format nil)
       (goto-char (point-min))
       (insert (make-string top-margin ?\n ))
       (insert (make-string left-margin ?\ ))
       (insert-image image)
       (insert "\n\n\n")
       (insert (make-string (floor (/ (- (window-width) (string-width title)) 2)) ?\ ))
       (insert title))
     (setq cursor-type nil)
     (read-only-mode +1)
     (switch-to-buffer (current-buffer))
     (local-set-key (kbd "q") 'kill-this-buffer)))

(when (< (length command-line-args) 2)
  (add-hook 'emacs-startup-hook (lambda ()
                                 (when (display-graphic-p)
                                   (starmacs/welcome)))))

Rainbow Delimiters

Color parentheses based on their nesting, so allow quick and easy matching, as well as keeping track of the current scope

(use-package rainbow-delimiters
  :ensure t
  :hook
  (prog-mode . rainbow-delimiters-mode)
  (org-mode . rainbow-delimiters-mode))

Fonts

Default Fonts

Starmacs comes with a set of default fonts, which are are listed and attributed below:

  • Iosevka: A monospaced font with a distinct look, and a wide range of weights.
  • Mona Sans: A strong and versitile typeface inspired by industrial-era grotesques made by GitHub.
  • Hubot-Sans: The typeface is designed with more geometric accents to lend a technical and idiosyncratic feel—perfect for headers and pull-quotes. Also made by GitHub.

All three licenses are distributed under the SIL Open Font License, and are available for free.

If you have fonts that you prefer, the easiest way to override these defaults is to duplicate this config (with your preferred fonts) inside the /usr directory.

Install Defaults

Ensure that the fonts packaged with Starmacs are installed correctly. Currently, this assumes that the user is using macOS.

This will be later expanded to support all *nix, and perhaps Windows.

(defun install-default-fonts ()
  (when (window-system)
    (progn
      (message "Installing Default Fonts")
      (shell-command (expand-file-name "install-fonts.sh"))
      (message "Installed Default Fonts"))))

Set Defaults

(defvar starmacs/fixed-pitch-height 150)
(defvar starmacs/variable-pitch-height 130)
(setq-default line-spacing 0.2)

(if (not (and (member "Iosevka" (font-family-list))(member "Hubot-Sans" (font-family-list)) (member "Mona Sans" (font-family-list))))
    (install-default-fonts))

(defvar starmacs/variable-pitch-font "Mona Sans")
(defvar starmacs/title-font "Hubot-Sans")
(defvar starmacs/fixed-pitch-font "Iosevka")


(set-face-attribute 'default nil :font starmacs/fixed-pitch-font :height starmacs/fixed-pitch-height)
(set-face-attribute 'fixed-pitch nil :font starmacs/fixed-pitch-font :height starmacs/fixed-pitch-height)

(set-face-attribute 'variable-pitch nil :font starmacs/variable-pitch-font :height starmacs/variable-pitch-height)
(set-face-attribute 'mode-line nil
                    :font starmacs/fixed-pitch-font)

Ligatures

Allow the use of ligatures in code, prettying up the noisy symbol-salad that most programming languages consist of.

(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"))
  (ligature-set-ligatures 'prog-mode '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
                                       ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
                                       "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
                                       "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
                                       "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
                                       "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
                                       "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
                                       "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
                                       ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
                                       "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
                                       "##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
                                       "?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
                                       "\\\\" "://" "<-"))
  ;; Enables ligature checks globally in all buffers. You can also do it
  ;; per mode with `ligature-mode'.
  (global-ligature-mode t))

SQL Highlighting

This mode allows any SQL queries embedded in strings to be evaluated as if they were in a dedicated SQL buffer. All that is required is to add comments at the beginning and end of the query of the form --SQL and --SQL-END, and all of the text between them will be treated as a SQL query.

(add-to-list 'auto-mode-alist '("\\.sqli\\'" . sql-mode))
(use-package mmm-mode
  :ensure t
  :custom
  (mmm-global-mode 'maybe)
  :config
  (set-face-background 'mmm-default-submode-face nil)
  (mmm-add-classes
   '((embedded-sql
      :submode sql-mode
      :face mmm-code-submode-face
      :front "\\(--SQL\\)"
      :back "\\(--SQL-END\\)")))
  (mmm-add-mode-ext-class 'prog-mode nil 'embedded-sql))

Quick Reload

This binds both <f5> and Cmd-R to a function that will reload the current buffer from it’s file. This comes in handy more often than would be thought, for example when forcing LSP to re-evaluate a buffer.

(defun revert-buffer-no-confirm ()
  "Revert the current buffer without asking permission"
  (interactive)
  (revert-buffer :ignore-auto :noconfirm))

(global-set-key (kbd "<f5>") 'revert-buffer-no-confirm)
(global-set-key (kbd "s-r") 'revert-buffer-no-confirm)

Which Key

which-key is a useful UI panel that appears when you start pressing any key binding in Emacs to offer you all possible completions for the prefix. For example, if you press C-c (hold control and press the letter c), a panel will appear at the bottom of the frame displaying all of the bindings under that prefix and which command they run. This is very useful for learning the possible key bindings in the mode of your current buffer.

(use-package which-key
  :ensure t
  :init (which-key-mode)
  :diminish which-key-mode
  :config
  (setq which-key-idle-delay 1))

Better Window Navigation

When more than two windows are visible in the frame, C-x o will add a red number to each pane, allowing the user to select which pane they mean to move to.

This prevents the endless pane-cycling many users are familiar with.

(use-package ace-window
  :ensure t
  :config
  (global-set-key (kbd "C-x o") 'ace-window))

SQLite

Although Emacs has built-in SQLite support since Emacs 29.1, it is manually installed here to prevent annoying warnings.

(use-package sqlite3
  :ensure t)

Meow

Meow Keymap

Meow keybindings are a set of Emacs keybindings popularized by meow. Meow aims to improve Emacs usability by reducing the need to use modifier keys (such as control and shift) when executing Emacs commands. Instead, meow uses single letter keys mapped to command sequences, similar to Vim’s modal editing. For example, users can scroll up by pressing j or execute a buffer save by pressing s. Meow also provides a range of movement commands, allowing users to jump to specific lines or characters in the buffer quickly. Meow keybindings can simplify Emacs usage for users who prefer a more modal interface.

(defun meow-setup ()
  (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
  (meow-motion-overwrite-define-key
   '("j" . meow-next)
   '("k" . meow-prev)
   '("<escape>" . ignore))
  (meow-leader-define-key
   ;; SPC j/k will run the original command in MOTION state.
   '("j" . "H-j")
   '("k" . "H-k")
   ;; Use SPC (0-9) for digit arguments.
   '("1" . meow-digit-argument)
   '("2" . meow-digit-argument)
   '("3" . meow-digit-argument)
   '("4" . meow-digit-argument)
   '("5" . meow-digit-argument)
   '("6" . meow-digit-argument)
   '("7" . meow-digit-argument)
   '("8" . meow-digit-argument)
   '("9" . meow-digit-argument)
   '("0" . meow-digit-argument)
   '("/" . meow-keypad-describe-key)
   '("?" . meow-cheatsheet))
  (meow-normal-define-key
   '("0" . meow-expand-0)
   '("9" . meow-expand-9)
   '("8" . meow-expand-8)
   '("7" . meow-expand-7)
   '("6" . meow-expand-6)
   '("5" . meow-expand-5)
   '("4" . meow-expand-4)
   '("3" . meow-expand-3)
   '("2" . meow-expand-2)
   '("1" . meow-expand-1)
   '("-" . negative-argument)
   '(";" . meow-reverse)
   '("," . meow-inner-of-thing)
   '("." . meow-bounds-of-thing)
   '("[" . meow-beginning-of-thing)
   '("]" . meow-end-of-thing)
   '("a" . meow-append)
   '("A" . meow-open-below)
   '("b" . meow-back-word)
   '("B" . meow-back-symbol)
   '("c" . meow-change)
   '("d" . meow-delete)
   '("D" . meow-backward-delete)
   '("e" . meow-next-word)
   '("E" . meow-next-symbol)
   '("f" . meow-find)
   '("g" . meow-cancel-selection)
   '("G" . meow-grab)
   '("h" . meow-left)
   '("H" . meow-left-expand)
   '("i" . meow-insert)
   '("I" . meow-open-above)
   '("j" . meow-next)
   '("J" . meow-next-expand)
   '("k" . meow-prev)
   '("K" . meow-prev-expand)
   '("l" . meow-right)
   '("L" . meow-right-expand)
   '("m" . meow-join)
   '("n" . meow-search)
   '("o" . meow-block)
   '("O" . meow-to-block)
   '("p" . meow-yank)
   '("q" . meow-quit)
   '("Q" . meow-goto-line)
   '("r" . meow-replace)
   '("R" . meow-swap-grab)
   '("s" . meow-kill)
   '("t" . meow-till)
   '("u" . meow-undo)
   '("U" . meow-undo-in-selection)
   '("v" . meow-visit)
   '("w" . meow-mark-word)
   '("W" . meow-mark-symbol)
   '("x" . meow-line)
   '("X" . meow-goto-line)
   '("y" . meow-save)
   '("Y" . meow-sync-grab)
   '("z" . meow-pop-selection)
   '("'" . repeat)
   '("<escape>" . ignore)))

Enable Meow

Starmacs assumes that you do not want to use the meow keybindings. If you would like to enable meow, simply bind the variable *starmacs/enable-meow* to t.

(use-package meow
  :ensure t
  :config
  (when (and (boundp '*starmacs/enable-meow*)
             *starmacs/enable-meow*)
    (meow-setup)
    (meow-global-mode)))

Org Mode

Org Mode is one of the hallmark features of Emacs. It is a rich document editor, project planner, task and time tracker, blogging engine, and literate coding utility all wrapped up in one package.

Basic Config

(use-package org
  :demand t
  :straight t
  :hook
  (org-mode . visual-line-mode)
  (org-mode . variable-pitch-mode)
  (org-mode . (lambda () (indent-tabs-mode -1)))
  (org-mode . (lambda () (set-face-attribute 'org-block nil :foreground nil :font starmacs/fixed-pitch-font :height 120 :inherit 'fixed-pitch)))

  :custom
  (org-startup-with-inline-images t)
  (org-hide-emphasis-markers t)
  (org-pretty-entities t)

  :config
  (dolist (face '((org-level-1 . 1.30)
                  (org-level-2 . 1.20)
                  (org-level-3 . 1.10)
                  (org-level-4 . 1.05)
                  (org-level-5 . 1.05)
                  (org-level-6 . 1.05)
                  (org-level-7 . 1.05)
                  (org-level-8 . 1.05)))
    (set-face-attribute (car face) nil :font starmacs/title-font :weight 'thin :height (cdr face)))

  (set-face-attribute 'org-document-title nil :font starmacs/title-font :height 1.50 :weight 'regular)
  (set-face-attribute 'org-document-info nil :font starmacs/title-font :inherit '(shadow) :height 1.20 :weight 'thin)

  (set-face-attribute 'org-block nil :foreground nil :font starmacs/fixed-pitch-font :height 120 :inherit 'fixed-pitch)
  (set-face-attribute 'org-code nil   :font starmacs/fixed-pitch-font :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-table nil   :font starmacs/fixed-pitch-font :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-verbatim nil :font starmacs/fixed-pitch-font :inherit '(shadow fixed-pitch)))

Org-Roam

Org-roam is an Emacs package that enables users to create a network of linked notes and documents in plain text, providing a powerful tool for organizing knowledge and personal information management. With org-roam, users can easily create, link, and navigate between notes, making it ideal for researchers, writers, and anyone looking for a simple and effective way to manage their digital life. Whether you’re looking to organize your thoughts, plan a project, or keep track of your research, org-roam makes it easy to stay organized and focused. With its intuitive interface and robust features, org-roam is a must-have tool for anyone looking to streamline their workflow and simplify their digital life.

(use-package org-roam
  :ensure t
  :init
  (setq org-roam-v2-ack t)
  :custom
  (org-roam-directory "~/Zettelkasten")
  (org-roam-completion-everywhere t)
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         :map org-mode-map
         ("C-M-i"    . completion-at-point))
  :config
  (require 'org-fold) ; Required to ensure the library loads for reasons I cannot yet fathom
  (org-roam-setup))

Project-Management

Project

project.el is an Emacs library that provides a unified way to manage and navigate projects in an efficient manner.

It allows users to define and work on groups of files as projects, providing navigation commands to move between project-related files, search for files in the project, and perform batch operations such as renaming or deleting files. project.el also integrates with version control systems, automatically detecting and associating projects with their respective repositories. Overall, project.el simplifies project navigation and organization, improving productivity for Emacs users who work with multiple projects.

project.el has been built-in to Emacs 29+.

(use-package project
  :ensure t)

Searching and Fuzzy-Finding

Vertico, Consult, Orderless, and Helpful are four packages for Emacs that are designed to enhance the user’s experience and productivity. Vertico is a flexible completion system that allows users to quickly navigate and select from a list of options. Consult provides a powerful search tool that makes it easy to find files, buffers, and other resources within Emacs. Orderless is a customizable matching system that allows users to search for text using a variety of patterns and options. Finally, Helpful is a documentation viewer that provides contextual help and advice on Emacs commands and functions.

Vertico

(use-package vertico
  :ensure t
  :bind (:map vertico-map
              ("C-j" . vertico-next)
              ("C-k" . vertico-previous)
              ("C-f" . vertico-exit)
              :map minibuffer-local-map
              ("M-h" . backward-kill-word))
  :custom
  (vertico-cycle t)
  :init
  (vertico-mode))

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

(use-package marginalia
  :after vertico
  :ensure t
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  :init
  (marginalia-mode))

Consult

;; Example configuration for Consult
(use-package consult
  ;; Replace bindings. Lazily loaded due by `use-package'.
  :bind (;; C-c bindings (mode-specific-map)
         ("C-s" . consult-line)
         ("C-c h" . consult-history)
         ("C-c m" . consult-mode-command)
         ("C-c k" . consult-kmacro)
         ;; C-x bindings (ctl-x-map)
         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         ("C-x r b" . consult-bookmark)            ;; orig. bookmark-jump
         ("C-x p b" . consult-project-buffer)      ;; orig. project-switch-to-buffer
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         ;; M-g bindings (goto-map)
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("M-g g" . consult-goto-line)             ;; orig. goto-line
         ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("M-g i" . consult-imenu)
         ("M-g I" . consult-imenu-multi)
         ;; M-s bindings (search-map)
         ("M-s d" . consult-find)
         ("M-s D" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ("M-s l" . consult-line)
         ("M-s L" . consult-line-multi)
         ("M-s m" . consult-multi-occur)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi)            ;; needed by consult-line to detect isearch
         ;; Minibuffer history
         :map minibuffer-local-map
         ("M-s" . consult-history)                 ;; orig. next-matching-history-element
         ("M-r" . consult-history))                ;; orig. previous-matching-history-element

  ;; Enable automatic preview at point in the *Completions* buffer. This is
  ;; relevant when you use the default completion UI.
  :hook (completion-list-mode . consult-preview-at-point-mode)

  ;; The :init configuration is always executed (Not lazy)
  :init

  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)

  ;; Configure other variables and modes in the :config section,
  ;; after lazily loading the package.
  :config

  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key (kbd "M-."))
  ;; (setq consult-preview-key (list (kbd "<S-down>") (kbd "<S-up>")))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme
   :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-recent-file
   consult--source-project-recent-file)

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<") ;; (kbd "C-+")

  ;; Optionally make narrowing help available in the minibuffer.
  ;; You may want to use `embark-prefix-help-command' or which-key instead.
  ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)

  ;; By default `consult-project-function' uses `project-root' from project.el.
  ;; Optionally configure a different project root function.
  ;; There are multiple reasonable alternatives to chose from.
  ;;;; 1. project.el (the default)
  ;; (setq consult-project-function #'consult--default-project--function)
  ;;;; 2. projectile.el (projectile-project-root)
  ;; (autoload 'projectile-project-root "projectile")
  ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
  ;;;; 3. vc.el (vc-root-dir)
  ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
  ;;;; 4. locate-dominating-file
  ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
  )

Orderless

(use-package orderless
  :ensure t
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion)))))

Helpful Help Commands

Helpful adds a lot of very helpful (get it?) information to Emacs’ describe- command buffers. For example, if you use describe-function, you will not only get the documentation about the function, you will also see the source code of the function and where it gets used in other places in the Emacs configuration. It is very useful for figuring out how things work in Emacs.

(use-package helpful
  :ensure t
  :bind
  ([remap describe-function] . helpful-function)
  ([remap describe-command]  . helpful-command)
  ([remap describe-variable] . helpful-variable)
  ([remap describe-key]      . helpful-key))

Git/Github

Magit

Magit is a Git user interface for Emacs. It provides a complete Git toolset within Emacs and allows users to interact with Git repositories directly from their text editor, without needing to switch to a separate Git client. Magit features include status information, branch visualization, diff viewing, commit creation, file staging, and more. It is highly customizable, scriptable, and integrates seamlessly with Emacs workflows.

Magit can be a great time-saver for developers working with Git repositories.

(use-package magit
  :ensure t)

;; forge allows magit to connect to Github
(use-package forge
  :ensure t
  :after magit)

Highlight Git diffs in the gutter

The left-hand fringe of Emacs is known as the gutter. Using git-gutter, symbols can be added in this fringe to visualize what changes have been made to the current buffer since the last git commit.

(use-package git-gutter
  :ensure t
  :config
  (global-git-gutter-mode 't))

Why This?

why-this shows blame information for the currently selected line (or region) along the right side of the current line

(use-package why-this
  :ensure t
  :custom (why-this-idle-delay 0)
  :bind
  ("C-c b" . why-this-mode)
  ("C-c w" . why-this))

Syntax Checking

Flycheck

Flycheck is an on-the-fly syntax checking and linting tool for Emacs. It automatically highlights errors and warnings in source code in real-time, helping to identify typos, syntax errors, and other mistakes quickly. Flycheck supports multiple programming languages and integrates with a variety of additional tools such as syntax checkers, linters, and spell checkers. Its modular architecture enables users to extend its functionality with additional checkers and customizations.

(use-package flycheck
  :ensure t
  :custom (flycheck-check-syntax-automatically '(save mode-enabled))
  :init (global-flycheck-mode))

(defvar-local starmacs--mode-line-flycheck "")

(defun starmacs/mode-line-update-flycheck (&rest _)
  (setq starmacs--mode-line-flycheck
        (if (bound-and-true-p flycheck-mode)
            (concat
             "  "
             (pcase flycheck-last-status-change
               (`not-checked (propertize "-/-" 'help-echo "Flycheck: not checked"))
               (`no-checker (propertize "-" 'help-echo "Flycheck: no checker"))
               (`running (propertize "*/*" 'help-echo "Flycheck: checking"))
               (`errored (propertize "!" 'help-echo "Flycheck: error"))
               (`finished
                (let-alist (flycheck-count-errors flycheck-current-errors)
                  (propertize (format "%s/%s" (or .error 0) (or .warning 0))
                              'help-echo (if (or .error .warning)
                                             (concat "Flycheck: "
                                                     (when .error (format "%d errors%s" .error (if .warning ", " "")))
                                                     (when .warning (format "%d warnings" .warning))
                                                     "\nmouse-1: list errors")
                                           "Flycheck: no errors or warnings")
                              'local-map 'flycheck-error-list-mode-line-map)))
               (`interrupted (propertize "x" 'help-echo "Flycheck: interrupted"))
               (`suspicious (propertize "?" 'help-echo "Flycheck: suspicious"))))
          "")))

(add-hook 'flycheck-status-changed-functions #'starmacs/mode-line-update-flycheck)
(add-hook 'flycheck-mode-hook #'starmacs/mode-line-update-flycheck)

Auto-Completion

Copilot

Github Copilot is an artificial intelligence (AI) code autocompletion system that can suggest code snippets to developers as they write code. It uses advanced deep learning models trained on vast amounts of existing code to generate suggestions in real-time. Github Copilot aims to reduce the time needed to write code by automating some repetitive tasks and suggesting efficient code structures.

C-f, as well as the right arrow key, are bound to complete suggestions made by copilot. This is to distinguish them from completions given from company-mode, and therefore LSP, which are completed with <Tab>.

This config assumes you do not have copilot access, or that you have not logged in on this machine. In order to enable copilot, bind the variable *starmacs/copilot-enabled* to t.

(defun starmacs/copilot-mode-hook ()
  (when (and (boundp '*starmacs/copilot-enabled*)
             *starmacs/copilot-enabled*)
    copilot-mode-hook))

(use-package copilot
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :hook (prog-mode . copilot-mode)
  :config
  (define-key copilot-completion-map (kbd "C-f") 'copilot-accept-completion) ; using forward motion to accept completion like Warp
  (define-key copilot-completion-map (kbd "<right>") 'copilot-accept-completion)
  (unless (copilot-installed-version)
	  (copilot-install-server))
  :ensure t)

Company-mode

(use-package company
  :ensure t
  :hook ((prog-mode) . (lambda () (company-mode)))
  :bind (:map company-mode-map
              ("<tab>" . 'company-indent-or-complete-common)
              :map company-active-map
              ("C-n" . 'company-select-next-or-abort)
              ("C-p" . 'company-select-previous-or-abort))
  :custom
  (company-idle-delay nil) ; don't try to complete until asked
  (company-minimum-prefix-length 1)
  (company-tooltip-align-annotations t)
  (lsp-completion-provider :capf) ; used for eglot integration

  (company-show-quick-access t)
  :config
  (company-tng-configure-default))

(use-package company-box
  :ensure t
  :hook (company-mode . company-box-mode))

Tab to Complete

(setq tab-always-indent 'complete)

Lisp Editing

While Emacs Lisp is the language Emacs is configured in, as well as what this code is in, it’s very likely that users will eventually encounter another Lisp.

Common Lisp is the most common variant users can expect to see inthe wild, and Sly is the best solution out there for working on it.

Sly is a Common Lisp IDE for Emacs that provides a variety of features for interactive programming, development, and debugging. It is an alternative to the more popular package Slime, but is designed to be more lightweight and modern. With sly, you can connect to a running Lisp process, evaluate code, inspect variables, and so much more. If you use Common Lisp or are interested in learning it, sly is definitely a package to consider.

(use-package sly
  :ensure t)

;; paredit allows for some now keybinding that make working with parens suck less
(use-package paredit
  :init
  (progn
    (add-hook 'emacs-lisp-mode-hook 'paredit-mode)
    (add-hook 'common-lisp-mode-hook 'paredit-mode)))

LSP Features

LSP stands for Language Server Protocol. It is a protocol that enables the development of tools to provide language-specific intelligent features such as auto-completion, go to definition, find all references, hover information, and other language-related features in text editors and integrated development environments (IDEs) using separate language servers.

Eglot

Emacs 29+ comes with eglot, an LSP system, built-in.

(use-package eglot
  :bind
  (("s-." . eglot-code-actions)
  ("<f12>" . eglot-find-typeDefinition)
  ("<f2>" . eglot-rename))
  :hook
  (typescript-mode . eglot-ensure)
  (typescript-ts-mode . eglot-ensure)
  (tsx-ts-mode . eglot-ensure)
  (python-ts-mode . eglot-ensure)
  (go-ts-mode . eglot-ensure)
  (f90-mode . eglot-ensure)
  (zig-mode . eglot-ensure)
  :config (setq lsp-prefer-flymake nil))

Eldoc

(use-package eldoc-box
  :hook
  (eglot-managed-mode . eldoc-box-hover-mode))

Tree-Sitter

Tree-sitter is a parsing system and library designed for use in text editors. It can parse source code or other textual content and provide a detailed representation of the syntax tree, which can be used to perform powerful code analysis. It is particularly useful for support of advanced features such as syntax highlighting, code folding, and code navigation. Tree-sitter is fast, efficient and supports multiple programming languages.

(require 'treesit)
(setq treesit-font-lock-level 4)
(setq treesit-language-source-alist
	  '((bash "https://github.com/tree-sitter/tree-sitter-bash")
		(cmake "https://github.com/uyha/tree-sitter-cmake")
		(css "https://github.com/tree-sitter/tree-sitter-css")
		(elisp "https://github.com/Wilfred/tree-sitter-elisp")
		(go "https://github.com/tree-sitter/tree-sitter-go")
		(html "https://github.com/tree-sitter/tree-sitter-html")
		(javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
		(json "https://github.com/tree-sitter/tree-sitter-json")
		(make "https://github.com/alemuller/tree-sitter-make")
		(markdown "https://github.com/ikatyang/tree-sitter-markdown")
		(python "https://github.com/tree-sitter/tree-sitter-python")
		(toml "https://github.com/tree-sitter/tree-sitter-toml")
		(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
		(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
		(yaml "https://github.com/ikatyang/tree-sitter-yaml")))

(defun starmacs/install-grammers ()
  "Download and compile all of the grammers in treesit-language"
  (interactive)
  (mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist)))

(if (not (file-exists-p (expand-file-name "tree-sitter" user-emacs-directory)))
	(starmacs/install-grammers))

;; (use-package treesit-auto
;;   :config
;;   (treesit-auto-add-to-auto-mode-alist 'all)
;;   (global-treesit-auto-mode))

ChatGPT

Due to its usefulness for unsticking oneself while programming, a ChatGPT client has been bundled in. To use it, simply put your OpenAI API key in the file ~/.emacs.d/chatgpt-api-key.txt, and it will be automatically read when a new shell is opened with M-x chatgpt-shell

(setq starmacs/chatgpt-api-key (expand-file-name "chatgpt-api-key.txt"))

(use-package chatgpt-shell
  :ensure t
  :straight (:host github :repo "xenodium/chatgpt-shell" :files ("dist" "*.el"))
  :config
  (unless
	  (file-exists-p starmacs/chatgpt-api-key)
	(make-empty-file starmacs/chatgpt-api-key))

  (setq chatgpt-shell-openai-key (replace-regexp-in-string "\n\\'" "" (with-temp-buffer
																		(insert-file-contents (expand-file-name "chatgpt-api-key.txt"))
																		(buffer-string)))))

User Code

In order to allow the user to use a better editing environment when adding your own code to Starmacs, the usr directory is added to the load-path. This means that any file added in ./usr/ will we automatically evaluated when Emacs is launched.. This way, Emacs Lisp code can be edited in a dedicated buffer, rather than in a source block in an org document

(let ((default-directory  user-emacs-directory))
  (normal-top-level-add-subdirs-to-load-path))

(defun starmacs/load-user-code (dir)
"`load' all elisp libraries in directory DIR which are not already loaded."
(interactive "D")
(let ((libraries-loaded (mapcar #'file-name-sans-extension
                                (delq nil (mapcar #'car load-history)))))
  (dolist (file (directory-files dir t ".+\\.elc?$"))
    (let ((library (file-name-sans-extension file)))
      (unless (member library libraries-loaded)
        (load library nil t)
        (push library libraries-loaded))))))

(when (file-exists-p (expand-file-name "./usr"))
  (starmacs/load-user-code (expand-file-name "./usr")))

Initial Startup

If you’re starting up for the first time, a bunch of warnings and windows and such are created. Let’s get rid of those and show you the dashboard

(when starmacs/initial-install
  (starmacs/welcome)
  (move-beginning-of-line nil))

About

A bare-bones, sane-defaults emacs distribution designed to be expanded upon

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project