This commit is contained in:
Marcus Kammer 2019-11-13 09:37:51 +01:00
commit 517743f638
2 changed files with 408 additions and 3 deletions

403
bundle/lolsmacs.el Normal file
View file

@ -0,0 +1,403 @@
;;; lolsmacs.el --- Law Of Least Surprise Lattice -*- lexical-binding: t; -*-
;; Copyright (C) 2019 Grant Rettke <grant@wisdomandwonder.com>
;; Author: Grant Rettke <grant@wisdomandonder.com>
;; Keywords: convenience, files, frames
;; Version: 1.0.0
;; Package-Requires: ((emacs "26.3"))
;; Homepage: https://github.com/grettke/lolsmacs
;; 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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Intuitive impersonal settings complying with the Law Of Least Surprise
;; meant for inclusion with any initialization file especially useful to
;; first-time Emacs users or experienced Emacs users looking for focused
;; high-value content to copy.
;;; Code:
(defun lolsmacs-this-must-before-everything-else-in-your-init-file ()
"When both the source file and its compiled bytecode are present load the source file first.
It would be safer to add this line of code to the first file and loads in your
initialization sequence. However it is probably good enough if you call this
function before anything else."
(interactive)
(setq load-prefer-newer t))
(defun lolsmacs-customize ()
"Store customizations in a separate file."
(interactive)
(setq custom-file "custom.el")
(load custom-file :noerror))
(defun lolsmacs-require-packages ()
"Load packages used by this package."
(interactive)
(require 'whitespace)
(require 'eldoc))
(defun lolsmacs-persistence ()
"Remember what you were doing and how things looked and restore it upon restarting."
(interactive)
(save-place-mode t)
(setq savehist-save-minibuffer-history t)
(setq savehist-additional-variables
'(kill-ring
search-ring
regexp-search-ring
last-kbd-macro
kmacro-ring
shell-command-history))
(savehist-mode)
(setq desktop-restore-eager 5)
(desktop-save-mode)
(setq make-backup-files nil)
(setq auto-save-default nil)
(auto-save-visited-mode)
(global-auto-revert-mode))
(defvar lolsmacs-save-on-hooks
(append
'(focus-out-hook mouse-leave-buffer-hook kill-emacs-hook suspend-hook))
"When they run save all file buffers.")
(defvar
lolsmacs-save-buffer-only-ons
(append
'(tex-compile vc-diff vc-next-action vc-revert))
"Before they run save the buffer.")
(defvar
lolsmacs-save-buffers-ons
(append
'(dired eshell grep ibuffer shell tex-compile)
'(compile ns-do-hide-emacs goto-line)
'(eval-buffer)
'(org-export-dispatch org-babel-tangle org-babel-detangle)
'(kill-current-buffer list-buffers save-buffers-kill-emacs save-buffers-kill-terminal switch-to-buffer pop-to-buffer)
'(delete-frame delete-other-frames other-frame suspend-frame)
'(delete-window quit-window other-window select-window))
"Before they run save all file buffers.")
(defvar lolsmacs-save-bufs-debug nil "When non-nil message debug information for `lolsmacs-save-bufs'.")
(defun lolsmacs-save-bufs ()
"Save all file buffers.
When `lolsmacs-save-bufs-debug' is non-nil display performance information in
*Messages* buffer."
(interactive)
(let ((time (current-time)))
(save-some-buffers t nil)
(when lolsmacs-save-bufs-debug
(message "lolsmacs-save-bufs completed in: %.06f seconds" (float-time (time-since time))))))
(defun lolsmacs-save-buffers-ons-advice (&rest _args)
"Helper function for advising `lolsmacs-save-buffers-ons' (for advice ignore _ARGS)."
(lolsmacs-save-bufs))
(defun lolsmacs-save-buffers-ons-advice-add (fn)
"Add save on advice to FN."
(advice-add fn :before #'lolsmacs-save-buffers-ons-advice))
(defun lolsmacs-save-buffer-only-ons-advice (&rest _args)
"Helper function for advising `lolsmacs-save-buffer-only-ons' (for advice ignore _ARGS)."
(basic-save-buffer))
(defun lolsmacs-save-buffer-only-ons-advice-add (fn)
"Add save on advice to FN."
(advice-add fn :before #'lolsmacs-save-buffer-only-ons-advice))
(defun lolsmacs-persistence-files ()
"Granular file-related persistence.
A single value pervades this set up: all development is performed
using file-based artifacts that are as current as possible and
stored in version control. Its motivated by broken builds and
other bizarre conditions due to files being out of sync between
the file system and the editor. The entire persistence set up
deals with this. This function deals with the granular file
management not covered by existing modes. With that in mind here
is where it begins.
We must consider the elephant in the living room here: given
`auto-save-visited-mode' is enabled why is this additional
granularity even a topic? It is a topic because sometimes
`auto-save-visited-mode' (ASVM) isn't fast enough.
For example imagine editing a Makefile in Emacs, switching to a
console terminal (either hosted within Emacs or externally using a
terminal client), hitting the up arrow, then return to execute
Make. You've performed this operation thousands of times and you
do it in milliseconds. Its even faster if you rigged up a macro
to execute and external command to do it. Is ASVM failing you
here? Nope. ASVM is working perfectly well and as expected right
now.
Here is why: ASVM save file buffers when you've been idle for
`auto-save-visited-interval' seconds. If you make it to large you
can lose your work because it waited too long. If you make it to
small it will waste energy and kill performance. ASVM's default settings are
perfect for 99% of its use cases. Once in a while though you need to perform
the same a lot sooner than before `auto-save-visited-interval' seconds. The
best way to consider these cases is splitting them up into three broad groups.
There are three frames of mind to get into your cognitive workspace when you
want to configure granular file persistence
1. Handling Special Events: Events, Hooks, and Keys
2. Handling Unrelated File Buffers
3. Handling Related File Buffers
When do you want to automatically save file buffers? For most of us it is most
of the time and ASVM handles that. There are exceptions though when the save
needs to be performed as quickly as possible. Here is the breakdown and
examples of and how it needs to happen.
1. Handling Special Events: Events, Hooks, and Keys
This section tries to handling quitting Emacs in unhappy
unplanned unpleasant ways.
dying Emacs will go away on gracefully, begrudgingly, and by dying. Usually Emacs closes on request
`save-buffers-kill-terminal'. Other times it might be locked up and you send
it a signal `(elisp)Event Examples'. Other times you must kill
`(elisp)Killing Emacs' Emacs' it. This function sets up the 3 ways to handle them:
A. Before advice for functions
B. Hooks
C. Key bindings
It seems to cover most of the worst cases.
2. Handling Unrelated File Buffers
Here is the best example:
The VC package `(emacs)Version Control' `vc-next-action' operates
on a single file `(emacs) Basic VC Editing'. If you make a change
before calling `vc-next-action' VC will ask you if you want to
save your changes before performing the action. Most of us /want/
the changes saved before we perform the next action which is
usually and `add' or `commit' operating to the VC backend. In
fact the intent and expectation of the function is that it will
only ever operate on one file: it is safe to expect that. It is
frustrating being prompted `yes-or-no-p' for something you'll
answer yes to nearly every time. Before-advice saves you from
this pain. There is a good case where this is the wrong
functionality though.
Perhaps you want to be able to perform `vc-next-action' against
the state of the file on the disk, not in the buffer because you
*know* that it is correct. For example if you have an automated
build system that watches for file changes. You made some
changes, save them, the build system saw them did the build and
ran all of the unit tests and passed. At the same time, you
notice something in your code and want to add a TODO item.
However you don't want it to be part of the commit. Right now you have a file
on disk that you know is correct and ready to commit, and changes in your
buffer that you don't want to commit. In this case you want to commit the file
without saving the changes. You need to all of this before
`auto-save-visited-interval' and it is realistic to do so.
3. Handling Related File Buffers
Here is an example:
You've got multiple buffers open working on a single project's source code. For
the build to work correctly all of the files need to be persisted to the disk.
As you work on code and move between buffers you need *all* of the files to be
properly persisted (it is the same for auto-build or manual build setups).
There are three ways to address this: 1. Add `lolsmacs-save-buffers-ons' to
`other-window'. 2. Add the same advice to `shell'. 3. Add a hook that calls
`lolsmacs-save-bufs' to `focus-out-hook'. This configuration addresses the
most common development cycle for file based development. However not all
of the development process is file based.
Some development environments and development cycles aren't
designed strictly around changes being persisted and working off
of a file. One good example is that of TeX. When you perform a
compilation, \"Run TeX on...\"), a TeX file if the compiler runs
into problems it will stop and prompt you what it should do next.
Suppose you got here by running TeX on a file, it ran into a
problem, and now you want to resolve it. When you use `tex-mode'
you have two ways of running TeX on a file: the functions
`tex-file' or `tex-buffer'. When `tex-offer-save' is non-nil the
former asks if you want to save all file based buffers then runs
TeX. The latter takes the contents of the current buffer, saves
them to a temporary file, and runs TeX over it. The formers seems to be
simpler and more predictable even if you are just playing around with what you
might do next but it is a good example of when you might not want all of your
files to be persisted as quickly as possible. "
(interactive)
(mapc (lambda (hook)
(add-hook hook #'lolsmacs-save-bufs))
lolsmacs-save-on-hooks)
(mapc (lambda (fn)
(lolsmacs-save-buffer-only-ons-advice-add fn))
lolsmacs-save-buffer-only-ons)
(mapc (lambda (fn)
(lolsmacs-save-buffers-ons-advice-add fn))
lolsmacs-save-buffers-ons)
(define-key special-event-map [sigusr1] #'lolsmacs-save-bufs))
(defun lolsmacs-display ()
"Editor appearance."
(interactive)
(setq echo-keystrokes 0.02)
(global-font-lock-mode)
(setq-default indicate-buffer-boundaries 'left)
(show-paren-mode)
(setq show-paren-delay 0)
(setq show-paren-style 'expression)
(global-hl-line-mode)
(setq whitespace-style '(tab-mark))
(setf
(cdr (assoc 'tab-mark whitespace-display-mappings))
'(?\t [?↹ ?\t] [?\t]))
(global-whitespace-mode)
(size-indication-mode)
(column-number-mode)
(setq column-number-indicator-zero-based nil)
(setq prettify-symbols-unprettify-at-point 'right-edge)
(global-prettify-symbols-mode))
(defun lolsmacs-buffers ()
"Buffer behavior."
(interactive)
(defconst lolsmacs-column-width 78)
(minibuffer-electric-default-mode)
(electric-pair-mode)
(delete-selection-mode)
(setq save-interprogram-paste-before-kill t)
(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward-angle-brackets)
(setq uniquify-after-kill-buffer-p t)
(setq uniquify-ignore-buffers-re "^\\*")
(setq scroll-preserve-screen-position t)
(setq scroll-conservatively 101)
(setq make-pointer-invisible t)
(setq mouse-drag-copy-region t)
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1)))
(setq mouse-wheel-progressive-speed nil)
(setq mouse-wheel-follow-mouse t)
(setq track-eol t)
(setq line-move-visual nil)
(setq ring-bell-function 'ignore)
(setq visible-bell t))
(defun lolsmacs-operations ()
"Editor operations."
(interactive)
(setq minibuffer-eldef-shorten-default t)
(setq resize-mini-windows t)
(setq max-mini-window-height 0.33)
(setq history-delete-duplicates t)
(setq register-preview-delay 2)
(setq register-separator "\n\n")
(setq initial-major-mode 'emacs-lisp-mode)
(with-current-buffer "*scratch*"
(emacs-lock-mode 'kill))
(setq-default eval-expression-print-level nil)
(put #'upcase-region 'disabled nil)
(put #'downcase-region 'disabled nil)
(setq large-file-warning-threshold (* 1024 1024))
(setq help-window-select t)
(setq search-default-mode #'char-fold-to-regexp)
(setq kill-read-only-ok t)
;; Here is the scenario for this style of Comint configuration:
;;
;; You are doing a lot of interactive work via various Comint-supported
;; buffers. You are working in one buffer (the one with focus) while the
;; others are doing their own thing. They are probably doing work and output
;; is scrolling by and that is fine because you are not reading it. In the
;; buffer you are working in though, you want to go back and read something.
;; So although it its process continues to output information, you want to
;; keep the cursor in the same spot. Then when you are ready to type a
;; command (suppose you know the output has stopped) to do something else,
;; when you type the cursor will go to the end of the buffer. That is why
;; you prevent the focused buffer from auto-scrolling and moving the mark,
;; and leave the other ones alone.
(setq comint-scroll-to-bottom-on-input 'this)
(setq comint-scroll-to-bottom-on-output 'others)
(setq comint-move-point-for-output 'others)
(setq comint-scroll-show-maximum-output t)
(setq comint-prompt-read-only nil))
(defun lolsmacs-editing ()
"Editing things."
(interactive)
(setq inhibit-eol-conversion t)
(setq require-final-newline t)
(setq-default tab-width 2)
(delete-selection-mode t)
(setq-default fill-column lolsmacs-column-width)
(setq sentence-end-double-space nil)
(setq sentence-end-without-period nil)
(setq colon-double-space nil))
(defun lolsmacs-init ()
"Load entire LOLSMacs configuration."
(interactive)
(lolsmacs-this-must-before-everything-else-in-your-init-file)
(lolsmacs-customize)
(lolsmacs-require-packages)
(lolsmacs-persistence)
(lolsmacs-persistence-files)
(lolsmacs-display)
(lolsmacs-buffers)
(lolsmacs-editing))
(provide 'lolsmacs)
;;; lolsmacs.el ends here

View file

@ -1,4 +1,5 @@
(and (load-file "~/.emacs.d/bundle/lolsmacs.el")
(lolsmacs-init))
(setq small-font "Iosevka Term-11") (setq small-font "Iosevka Term-11")
(setq big-font "Iosevka Term-14") (setq big-font "Iosevka Term-14")
;; start a server, unless one is already running ;; start a server, unless one is already running
@ -131,7 +132,7 @@ There are two things you can do about this warning:
("Metaebene" "https://metaebene.me/feed/" nil 3600) ("Metaebene" "https://metaebene.me/feed/" nil 3600)
("Stack Exchange" "https://emacs.stackexchange.com/feeds" nil 3600) ("Stack Exchange" "https://emacs.stackexchange.com/feeds" nil 3600)
("Stallman" "https://stallman.org/rss/rss.xml" nil 3600) ("Stallman" "https://stallman.org/rss/rss.xml" nil 3600)
("Planet Lisp" "http://planet.lisp.org/" nil 3600) ("Planet Lisp" "http://planet.lisp.org/rss20.xml" nil 3600)
("Python PEP" "https://www.python.org/dev/peps/peps.rss/" nil 3600)))) ("Python PEP" "https://www.python.org/dev/peps/peps.rss/" nil 3600))))
'(nord-comment-brightness 15) '(nord-comment-brightness 15)
'(nord-region-highlight "snowstorm") '(nord-region-highlight "snowstorm")
@ -241,7 +242,8 @@ There are two things you can do about this warning:
(when (display-graphic-p) (when (display-graphic-p)
;; (toggle-frame-fullscreen) ;; (toggle-frame-fullscreen)
(setq-default line-spacing 3) (setq-default line-spacing 3)
(add-to-list 'default-frame-alist '(font . "Iosevka Term-14")))) (add-to-list 'default-frame-alist '(font . "Iosevka Term-14")))
(when (string= (system-name) "XPS-13-9380")))
;; ++++++++++++++++++++ OS ;; ++++++++++++++++++++ OS
(defun copy-whole-buffer () (defun copy-whole-buffer ()