system-manager-wakasu
1;; nano-emacs.el --- NANO Emacs (minimal version) -*- lexical-binding: t -*-
2
3;; Copyright (c) 2025 Nicolas P. Rougier
4;; Released under the GNU General Public License 3.0
5;; Author: Nicolas P. Rougier <nicolas.rougier@inria.fr>
6;; URL: https://github.com/rougier/nano-emacs
7
8;; This is NANO Emacs in 256 lines, without any dependency
9;; Usage (command line): emacs -Q -l nano.el -[light|dark]
10
11;; --- Speed benchmarking -----------------------------------------------------
12(setq init-start-time (current-time))
13
14;; --- Typography stack -------------------------------------------------------
15(set-face-attribute 'default nil
16 :height 140 :weight 'light :family "Roboto Mono")
17(set-face-attribute 'bold nil :weight 'regular)
18(set-face-attribute 'bold-italic nil :weight 'regular)
19(set-display-table-slot standard-display-table 'truncation (make-glyph-code ?…))
20(set-display-table-slot standard-display-table 'wrap (make-glyph-code ?–))
21
22;; --- Frame / windows layout & behavior --------------------------------------
23(setq default-frame-alist
24 '((height . 44) (width . 81) (left-fringe . 0) (right-fringe . 0)
25 (internal-border-width . 32) (vertical-scroll-bars . nil)
26 (bottom-divider-width . 0) (right-divider-width . 0)
27 (undecorated-round . t)))
28(modify-frame-parameters nil default-frame-alist)
29(setq-default pop-up-windows nil)
30
31;; --- Activate / Deactivate modes --------------------------------------------
32(tool-bar-mode -1) (menu-bar-mode -1) (blink-cursor-mode -1)
33(global-hl-line-mode 1) (icomplete-vertical-mode 1)
34(pixel-scroll-precision-mode 1)
35
36;; --- Minimal NANO (not a real) theme ----------------------------------------
37(defface nano-default '((t)) "") (defface nano-default-i '((t)) "")
38(defface nano-highlight '((t)) "") (defface nano-highlight-i '((t)) "")
39(defface nano-subtle '((t)) "") (defface nano-subtle-i '((t)) "")
40(defface nano-faded '((t)) "") (defface nano-faded-i '((t)) "")
41(defface nano-salient '((t)) "") (defface nano-salient-i '((t)) "")
42(defface nano-popout '((t)) "") (defface nano-popout-i '((t)) "")
43(defface nano-strong '((t)) "") (defface nano-strong-i '((t)) "")
44(defface nano-critical '((t)) "") (defface nano-critical-i '((t)) "")
45
46(defun nano-set-face (name &optional foreground background weight)
47 "Set NAME and NAME-i faces with given FOREGROUND, BACKGROUND and WEIGHT"
48
49 (apply #'set-face-attribute `(,name nil
50 ,@(when foreground `(:foreground ,foreground))
51 ,@(when background `(:background ,background))
52 ,@(when weight `(:weight ,weight))))
53 (apply #'set-face-attribute `(,(intern (concat (symbol-name name) "-i")) nil
54 :foreground ,(face-background 'nano-default)
55 ,@(when foreground `(:background ,foreground))
56 :weight regular)))
57
58(defun nano-link-face (sources faces &optional attributes)
59 "Make FACES to inherit from SOURCES faces and unspecify ATTRIBUTES."
60
61 (let ((attributes (or attributes
62 '( :foreground :background :family :weight
63 :height :slant :overline :underline :box))))
64 (dolist (face (seq-filter #'facep faces))
65 (dolist (attribute attributes)
66 (set-face-attribute face nil attribute 'unspecified))
67 (set-face-attribute face nil :inherit sources))))
68
69(defun nano-install-theme ()
70 "Install THEME"
71
72 (set-face-attribute 'default nil
73 :foreground (face-foreground 'nano-default)
74 :background (face-background 'nano-default))
75 (dolist (item '((nano-default . (variable-pitch variable-pitch-text
76 fixed-pitch fixed-pitch-serif))
77 (nano-highlight . (hl-line highlight))
78 (nano-subtle . (match region
79 lazy-highlight widget-field))
80 (nano-faded . (shadow
81 font-lock-comment-face
82 font-lock-doc-face
83 icomplete-section
84 completions-annotations))
85 (nano-popout . (warning
86 font-lock-string-face))
87 (nano-salient . (success link
88 help-argument-name
89 custom-visibility
90 font-lock-type-face
91 font-lock-keyword-face
92 font-lock-builtin-face
93 completions-common-part))
94 (nano-strong . (font-lock-function-name-face
95 font-lock-variable-name-face
96 icomplete-first-match
97 minibuffer-prompt))
98 (nano-critical . (error
99 completions-first-difference))
100 (nano-faded-i . (help-key-binding))
101 (nano-default-i . (custom-button-mouse
102 isearch))
103 (nano-critical-i . (isearch-fail))
104 ((nano-subtle nano-strong) . (custom-button
105 icomplete-selected-match))
106 ((nano-faded-i nano-strong) . (show-paren-match))))
107 (nano-link-face (car item) (cdr item)))
108
109 ;; Mode & header lines
110 (set-face-attribute 'header-line nil
111 :background 'unspecified
112 :underline nil
113 :box `( :line-width 1
114 :color ,(face-background 'nano-default))
115 :inherit 'nano-subtle)
116 (set-face-attribute 'mode-line nil
117 :background (face-background 'default)
118 :underline (face-foreground 'nano-faded)
119 :height 40 :overline nil :box nil)
120 (set-face-attribute 'mode-line-inactive nil
121 :background (face-background 'default)
122 :underline (face-foreground 'nano-faded)
123 :height 40 :overline nil :box nil))
124
125(defun nano-light (&rest args)
126 "NANO light theme (based on material colors)"
127
128 (interactive)
129 (nano-set-face 'nano-default "#37474F" "#FFFFFF") ;; Blue Grey / L800
130 (nano-set-face 'nano-strong "#000000" nil 'regular) ;; Black
131 (nano-set-face 'nano-highlight nil "#FAFAFA") ;; Very Light Grey
132 (nano-set-face 'nano-subtle nil "#ECEFF1") ;; Blue Grey / L50
133 (nano-set-face 'nano-faded "#90A4AE") ;; Blue Grey / L300
134 (nano-set-face 'nano-salient "#673AB7") ;; Deep Purple / L500
135 (nano-set-face 'nano-popout "#FFAB91") ;; Deep Orange / L200
136 (nano-set-face 'nano-critical "#FF6F00") ;; Amber / L900
137 (nano-install-theme))
138
139(defun nano-dark (&rest args)
140 "NANO dark theme (based on nord colors)"
141
142 (interactive)
143 (nano-set-face 'nano-default "#ECEFF4" "#2E3440") ;; Snow Storm 3
144 (nano-set-face 'nano-strong "#ECEFF4" nil 'regular) ;; Polar Night 0
145 (nano-set-face 'nano-highlight nil "#3B4252") ;; Polar Night 1
146 (nano-set-face 'nano-subtle nil "#434C5E") ;; Polar Night 2
147 (nano-set-face 'nano-faded "#677691") ;;
148 (nano-set-face 'nano-salient "#81A1C1") ;; Frost 2
149 (nano-set-face 'nano-popout "#D08770") ;; Aurora 1
150 (nano-set-face 'nano-critical "#EBCB8B") ;; Aurora 2
151 (nano-install-theme))
152
153;; --- Command line theme chooser ---------------------------------------------
154(add-to-list 'command-switch-alist '("-dark" . nano-dark))
155(add-to-list 'command-switch-alist '("-light" . nano-light))
156(if (member "-dark" command-line-args) (nano-dark) (nano-light))
157
158;; --- Minibuffer completion --------------------------------------------------
159(setq tab-always-indent 'complete
160 icomplete-delay-completions-threshold 0
161 icomplete-compute-delay 0
162 icomplete-show-matches-on-no-input t
163 icomplete-hide-common-prefix nil
164 icomplete-prospects-height 9
165 icomplete-separator " . "
166 icomplete-with-completion-tables t
167 icomplete-in-buffer t
168 icomplete-max-delay-chars 0
169 icomplete-scroll t
170 resize-mini-windows 'grow-only
171 icomplete-matches-format nil)
172(bind-key "TAB" #'icomplete-force-complete icomplete-minibuffer-map)
173(bind-key "RET" #'icomplete-force-complete-and-exit icomplete-minibuffer-map)
174
175;; --- Minimal key bindings ---------------------------------------------------
176(defun nano-quit ()
177 "Quit minibuffer from anywhere (code from Protesilaos Stavrou)"
178
179 (interactive)
180 (cond ((region-active-p) (keyboard-quit))
181 ((derived-mode-p 'completion-list-mode) (delete-completion-window))
182 ((> (minibuffer-depth) 0) (abort-recursive-edit))
183 (t (keyboard-quit))))
184
185(defun nano-kill ()
186 "Delete frame or kill emacs if there is only one frame left"
187
188 (interactive)
189 (condition-case nil
190 (delete-frame)
191 (error (save-buffers-kill-terminal))))
192
193(bind-key "C-x k" #'kill-current-buffer)
194(bind-key "C-x C-c" #'nano-kill)
195(bind-key "C-x C-r" #'recentf-open)
196(bind-key "C-g" #'nano-quit)
197(bind-key "M-n" #'make-frame)
198(bind-key "C-z" nil) ;; No suspend frame
199(bind-key "C-<wheel-up>" nil) ;; No text resize via mouse scroll
200(bind-key "C-<wheel-down>" nil) ;; No text resize via mouse scroll
201
202;; --- Sane settings ----------------------------------------------------------
203(set-default-coding-systems 'utf-8)
204(setq-default indent-tabs-mode nil
205 ring-bell-function 'ignore
206 select-enable-clipboard t)
207
208;; --- OSX Specific -----------------------------------------------------------
209(when (eq system-type 'darwin)
210 (select-frame-set-input-focus (selected-frame))
211 (setq mac-option-modifier nil
212 ns-function-modifier 'super
213 mac-right-command-modifier 'hyper
214 mac-right-option-modifier 'alt
215 mac-command-modifier 'meta))
216
217;; --- Header & mode lines ----------------------------------------------------
218(setq-default mode-line-format "")
219(setq-default header-line-format
220 '(:eval
221 (let ((prefix (cond (buffer-read-only '("RO" . nano-default-i))
222 ((buffer-modified-p) '("**" . nano-critical-i))
223 (t '("RW" . nano-faded-i))))
224 (mode (concat "(" (downcase (cond ((consp mode-name) (car mode-name))
225 ((stringp mode-name) mode-name)
226 (t "unknow")))
227 " mode)"))
228 (coords (format-mode-line "%c:%l ")))
229 (list
230 (propertize " " 'face (cdr prefix) 'display '(raise -0.25))
231 (propertize (car prefix) 'face (cdr prefix))
232 (propertize " " 'face (cdr prefix) 'display '(raise +0.25))
233 (propertize (format-mode-line " %b ") 'face 'nano-strong)
234 (propertize mode 'face 'header-line)
235 (propertize " " 'display `(space :align-to (- right ,(length coords))))
236 (propertize coords 'face 'nano-faded)))))
237
238;; --- Minibuffer setup -------------------------------------------------------
239(defun nano-minibuffer--setup ()
240 (set-window-margins nil 3 0)
241 (let ((inhibit-read-only t))
242 (add-text-properties (point-min) (+ (point-min) 1)
243 `(display ((margin left-margin)
244 ,(format "# %s" (substring (minibuffer-prompt) 0 1))))))
245 (setq truncate-lines t))
246(add-hook 'minibuffer-setup-hook #'nano-minibuffer--setup)
247
248;; --- Speed benchmarking -----------------------------------------------------
249(let ((init-time (float-time (time-subtract (current-time) init-start-time)))
250 (total-time (string-to-number (emacs-init-time "%f"))))
251 (message (concat
252 (propertize "Startup time: " 'face 'bold)
253 (format "%.2fs " init-time)
254 (propertize (format "(+ %.2fs system time)"
255 (- total-time init-time)) 'face 'shadow))))