;; Amethyst - An Emacs starter-kit aimed at writers
;; © 2020 Ashton Wiersdorf
;;
;; Sizable portions of this code are derived from the elegance theme
;; by Nicolas P. Rougier. Modifications made starting 8 December 2020.
;;
;; -------------------------------------------------------------------
;; This file is not part of GNU Emacs.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see
;; -------------------------------------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Nice defaults, snarfed from sanity.el
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq gc-cons-threshold (* 100 1024 1024))
(setq inhibit-startup-screen t)
(setq inhibit-startup-echo-area-message t)
(setq inhibit-startup-message t)
(setq initial-scratch-message nil)
(setq initial-major-mode 'org-mode)
(setq-default indent-tabs-mode nil)
;; Don't make new windows pop up. Kind of messes up Magit, but we can
;; work around that.
(setq pop-up-windows nil)
(tool-bar-mode 0)
(scroll-bar-mode 0)
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)
;; Keep the cursor where you last were when you were editing the file
(save-place-mode 1)
(global-set-key (kbd "C-z") 'undo)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Basic look and feel from elegance.el
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun use-first-font (font-list)
"Try the fonts in order. If it exists, use it. Otherwise, move to the next one."
(cond
((or (eq window-system nil) (eq font-list nil)) nil)
((x-list-fonts (car font-list))
(set-face-attribute 'default nil :height 121 :font (car font-list)))
(t (use-first-font (cdr font-list)))))
(use-first-font '("Input Mono" "Fira Code"))
(setq default-frame-alist
(append (list '(vertical-scroll-bars . nil)
'(internal-border-width . 48)
'(width . 80) '(height . 0.9)
'(left . 0.5) '(top . 0))))
;; Line spacing, can be 0 for code and 1 or 2 for text
(setq-default line-spacing 2)
;; Underline line at descent position, not baseline position
(setq x-underline-at-descent-line t)
;; No ugly button for checkboxes
(setq widget-image-enable nil)
;; Line cursor and no blink
(set-default 'cursor-type '(bar . 1))
(blink-cursor-mode 0)
;; No sound
(setq visible-bell t)
(setq ring-bell-function 'ignore)
;; Ensure Tooltips
(tooltip-mode)
;; Paren mode is part of the theme
(show-paren-mode t)
;; No fringe but nice glyphs for truncated and wrapped lines
(fringe-mode '(0 . 0))
;; TODO: I'm considering deleting this, because I'll have wrap mode
;; turned on by default, so the only people who will see wrapped lines
;; are those who should *know* what they're doing. I suppose there
;; might be some who write really, really long words in a narrow
;; window, so it might be a good idea anyway...
(defface fallback '((t :family (if (x-list-fonts "Fira Code Light") "Fira Code Light" nil)
:inherit 'face-faded)) "Fallback")
(set-display-table-slot standard-display-table 'truncation
(make-glyph-code ?… 'fallback))
(set-display-table-slot standard-display-table 'wrap
(make-glyph-code ?↩ 'fallback))
(set-display-table-slot standard-display-table 'selective-display
(string-to-vector " …"))
;; Mode line (this might be slow because of the "☰" that requires substitution)
;; This line below makes things a bit faster
(define-key mode-line-major-mode-keymap [header-line]
(lookup-key mode-line-major-mode-keymap [mode-line]))
(defun mode-line-render (left right)
(let* ((available-width (- (window-width) (length left) )))
(format (format "%%s %%%ds" available-width) left right)))
(setq-default mode-line-format
'((:eval
(mode-line-render
(format-mode-line (list
(propertize "☰" 'face `(:inherit mode-line-buffer-id)
'help-echo "Mode(s) menu"
'mouse-face 'mode-line-highlight
'local-map mode-line-major-mode-keymap)
" %b "
(if (and buffer-file-name (buffer-modified-p))
(propertize "(modified)" 'face `(:inherit face-faded)))))
(format-mode-line
(list
(propertize "[ L %l : C %c ] " 'face `(:inherit face-faded))
(propertize
(format "%d Words " (count-words (point-min) (point-max)))
'face `(:inherit face-faded))))))))
;; Comment if you want to keep the modeline at the bottom
(setq-default header-line-format mode-line-format)
(setq-default mode-line-format'(""))
;; Vertical window divider
(setq window-divider-default-right-width 3)
(setq window-divider-default-places 'right-only)
(window-divider-mode)
;; When we set a face, we take care of removing any previous settings
(defun set-face (face style)
"Reset a face and make it inherit style."
(set-face-attribute face nil
:foreground 'unspecified :background 'unspecified
:family 'unspecified :slant 'unspecified
:weight 'unspecified :height 'unspecified
:underline 'unspecified :overline 'unspecified
:box 'unspecified :inherit style))
;; Faces for the writer theme
(defgroup writer nil
"Faces for the writer theme"
:prefix "writer-face-"
:group 'faces)
;; Custom faces
(defface face-faded nil
"Used for menubars"
:group 'writer)
;; Modeline
(defun set-modeline-faces ()
;; Mode line at top
(set-face 'header-line 'face-strong)
(set-face-attribute 'header-line nil
:underline (face-foreground 'default))
(set-face-attribute 'mode-line nil
:height 10
:underline (face-foreground 'face-faded)
:overline nil
:box nil
:foreground (face-background 'default)
:background (face-background 'default))
(set-face 'mode-line-inactive 'mode-line)
;; Mode line at bottom
;; (set-face 'header-line 'face-strong)
;; (set-face-attribute 'mode-line nil
;; :height 1.0
;; :overline (face-background 'default)
;; :underline nil
;; :foreground (face-foreground 'default)
;; :background (face-background 'face-subtle)
;; :box `(:line-width 2
;; :color ,(face-background 'face-subtle)
;; :style nil))
;; (set-face 'mode-line-highlight '(face-popout mode-line))
;; (set-face 'mode-line-emphasis 'face-strong)
;; (set-face-attribute 'mode-line-buffer-id nil :weight 'regular)
;; (set-face-attribute 'mode-line-inactive nil
;; :height 1.0
;; :overline (face-background 'default)
;; :underline nil
;; :foreground (face-foreground 'face-faded)
;; :background (face-background 'face-subtle)
;; :box `(:line-width 2
;; :color ,(face-background 'face-subtle)
;; :style nil))
(set-face-attribute 'cursor nil
:background (face-foreground 'default))
(set-face-attribute 'window-divider nil
:foreground (face-background 'mode-line))
(set-face-attribute 'window-divider-first-pixel nil
:foreground (face-background 'default))
(set-face-attribute 'window-divider-last-pixel nil
:foreground (face-background 'default))
)
;; Buttons
(defun set-button-faces ()
(set-face-attribute 'custom-button nil
:foreground (face-foreground 'face-faded)
:background (face-background 'face-subtle)
:box `(:line-width 1
:color ,(face-foreground 'face-faded)
:style nil))
(set-face-attribute 'custom-button-mouse nil
:foreground (face-foreground 'default)
;; :background (face-foreground 'face-faded)
:inherit 'custom-button
:box `(:line-width 1
:color ,(face-foreground 'face-subtle)
:style nil))
(set-face-attribute 'custom-button-pressed nil
:foreground (face-background 'default)
:background (face-foreground 'face-salient)
:inherit 'face-salient
:box `(:line-width 1
:color ,(face-foreground 'face-salient)
:style nil)
:inverse-video nil))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; straight.el setup <>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(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))
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)
(use-package nord-theme
:config
(load-theme 'nord t))
(use-package selectrum
:config
(selectrum-mode +1))
(use-package selectrum-prescient
:after 'selectrum
:config
(selectrum-prescient-mode +1)
(prescient-persist-mode +1))
(use-package markdown-mode)
(use-package org)
(use-package magit
:bind
("C-x g" . magit-status)
("s-g" . magit-status))
(use-package pandoc-mode)
(global-auto-revert-mode)
;; Auto-save stuffs
(setq auto-save-default nil)
(auto-save-visited-mode +1)
;; Writing modes
(mapc (lambda (mode)
(add-hook mode
'(lambda ()
(toggle-truncate-lines -1)
(turn-on-visual-line-mode)
(pandoc-mode)
;; I don't think this is necessary with visual-line-mode turned on
;(toggle-word-wrap t)
)))
'(markdown-mode-hook org-mode-hook text-mode-hook))
(use-package define-word
:bind
("M-#" . define-word))
(selectrum-prescient-mode +1)
(cua-mode)
(defun set-nordic ()
"Set Nord theme with pretty modeline from elegance"
(interactive)
(set-face-attribute 'face-faded nil :foreground "#d8dee9")
(load-theme 'nord t)
(set-modeline-faces))
(set-nordic)
(defun scratchpad ()
(interactive)
(let ((buff (generate-new-buffer "*Scratchpad*")))
(set-buffer buff)
(org-mode)
(insert "\n*Warning: this is a temporary scratch pad!*\n\nIf you want to save what you wrote after quitting, you need to [[elisp:write-file][save this as a new file]] (keystroke: =[C-x] [C-w]=)\n\n")
(switch-to-buffer buff)
(message "Switched to a temporary scratchpad")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Startup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq org-confirm-elisp-link-function nil)
(defvar amethyst--startup-message
"
*Welcome to Emacs*
Emacs is the most powerful text editor on the planet. While you
should be able to start working with Emacs as-is, any effort you
put into mastering its functions will reward you handsomely. Try
to get familiar with the *Essential Commands* first, and move on
to the *Other Commands* once you've got the hang of it.
*Quick Links*
[[elisp:find-file][Create a new file]] [[elisp:find-file-existing][Open an existing file]] [[elisp:scratchpad][Open a scratchpad]]
*Essential Commands* /C: Control, M: alt, S: ⌘/
Save ................... \\[save-buffer] Help ....................... C-h
Save as ................ \\[write-file] Cancel command ............. \\[keyboard-quit]
Open new file .......... \\[find-file] Undo ....................... \\[undo]
Quit ................... \\[save-buffers-kill-terminal]
*Other Commands* /[[info:emacs#Key%2520Bindings][ Other key bindings ]]/
Search ................. \\[isearch-forward] Go to line ................. \\[goto-line]
Replace ................ \\[query-replace] Execute command ............ \\[execute-extended-command]
Start of buffer ........ \\[beginning-of-buffer] End of buffer .............. \\[end-of-buffer]
Start of line .......... C-a End of line ................ C-e
Mark ................... C- Copy from mark ............. \\[kill-ring-save]
Cut from mark .......... \\[kill-region] Delete to end of line ...... \\[kill-line]
Paste .................. \\[yank] Paste older ................ \\[cua-paste-pop]
*Quick Preferences Settings* /[[elisp:(customize-group 'emacs)][ Full preferences ]]/
[[elisp:menu-set-font][ Select ]]default font [[elisp:display-line-numbers-mode][ Toggle ]]line numbers
[[elisp:tool-bar-mode][ Toggle ]]tool bar [[elisp:toggle-truncate-lines][ Toggle ]]line wrap
[[elisp:scroll-bar-mode][ Toggle ]]scroll bar [[elisp:blink-cursor-mode][ Toggle ]]blinking cursor
[[elisp:menu-bar-mode][ Toggle ]]menu bar Select cursor:[[elisp:(set-default 'cursor-type '(hbar . 2))][ HBar ]]|[[elisp:(set-default 'cursor-type '(bar . 2))][ VBar ]]|[[elisp:(set-default 'cursor-type 'box)][ Box ]]
")
(defvar amethyst--splash-buffer (get-buffer-create "* Amethyst *"))
(defun amethyst--splash-screen ()
"Render the splash screen for Amethyst."
(interactive)
(with-current-buffer amethyst--splash-buffer
(insert (substitute-command-keys amethyst--startup-message))
(goto-char (point-min))
(org-mode)
(current-buffer)))
(setq initial-buffer-choice #'amethyst--splash-screen)
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(enable-recursive-minibuffers t)
'(find-file-visit-truename t)
'(frame-resize-pixelwise t)
'(sentence-end-double-space nil)
'(initial-major-mode 'text-mode))