Skip to content

rhoit/dot-emacs

Repository files navigation

emacs diaries

BEWARE: AUTHOR does’nt know much elisp and suffer from parenthesiophobia, but couldn’t stop tinker around.

https://raw.githubusercontent.com/rhoit/dot-emacs/dump/screenshot/screenshot02.png

1 INTRO

I’ve been using emacs since 2012, It has been the love and hate story since day one, In summary emacs rocks but 🪨 rocks are not so pretty, and here you are looking at not so pretty side.

FYI "emacs vanilla is a lie"

Emacs is relics of the past, have a criminal learning curve 🌀 are cursed with the worst UI known to mankind with most unpleasing to looks I mean it’s a real dumpster 💩. It is not necessary to know how to use emacs in order to be unhappy 😩, but it helps. I have been constant search for the alternative over the years, non has come closer than vscode capture the same imagination constant improvement like in editor wars.

My nearly a decade long journey with emacs is nothing compared to age of the application which predates me and also the one of the longest lived application programs of all time. Yet to become obsolete, which is still ongoing development since 1976. Flexibility of altering its interface and behavior without going though original source has let to creation of surplus features by generation of users 🤓 (programmers). There has been some of 💫 indispensable tools which are yet to be match modern word processors.

It might be difficult for me to abandon the emacs although its prized features would be replicated soon some day. Over the years I constantly hear about Making Emacs popular again but its unlikely to happen again since entry barrier is too high. The vscode with built with the most popular language possess significant development advantage, unlike emacs built with lisp. Yet this repository itself stands as a testament about developers relation with text editor, which mean switching to new editor will need significant investment of time, not to mention IKEA effect.

1.1 introspect

We need more contributors to make emacs better. We need better emacs to attract more users who can later contribute back. Its never ending dilemma. Still there number of unfortunate facts about how emacs works. Most users will eventually need to dive into elisp in order get to their particular tastes. I have been using emacs for years sheer size of the project hard to comprehend itself. But recent years emacs has seen numerous improvement like lsp, native-compilation, yet emacs still needs more.

1.2 about

Customization began with single-file ~/.emacs with few settings and some random snippets. Didn’t took long to become monster. It loved to cherry-picked 🍒 packages literally form anywhere, I was like why don’t you apt-get.

It was becoming difficult maintaining 📦 packages manually, tracking workable dependencies and freezing 🧊 versions. And came package.el, which I noticed in What’s new in emacs24 using emacs25. also el-get existed, and now package.el was official too. I can’t seem to choose one, and great can use both.

Yet, I could barely remember Why I removed that package, what happen?, git-whatchanged would have told me more if it was a code. To org organize was most sane thing till now ~/emacs.d/init.el was orgified (org-bable-tangle).

In summary, its not easy to declare bankruptcy when your config is:

  • highly opinionated configuration
  • does’nt provide the any layer of abstraction
  • more of notes and rants and reason to do so

Since, version 27.1 emacs supported XDG convention every thing can be in ~/.config/emacs

1.3 getting-it

🧨 DISCLAIMER: 🐒 MAKE SURE YOU HAVE THE BACKUP ⚠️ AUTHOR will not be responsible for the 🔥 harm 🔥 cause by using this configuration.

Oh! you wanna use my config! its super duper easy ! may be in future I’m still trying avoiding make the installer (literally don’t know how) and just trying to get by my work.

$ git clone https://github.com/rhoit/dot-emacs /path/to/dot-emacs

1.4 why-this-config?

There is absolutely no reason for you to use this config, it would be like first time 🏊 swimmer, who mostly likely drown with unnecessary amount of effort. Although I’m great at underwater so to say some what athletic underachievers.

Time 🕥 and time 🕝 again I learned elisp just to forget with endless pondering and compromises, without ✍️ jotting things down, it would have been impossible to configure. May be this started for maintenance, now its more of rants taking over the configuration! 😎

If you ask, would I have started with other’s config? I would definitely say YES. But you should understand all-in-one package 📦 or distribution is like bringing gun 🔫 to the fist 👊 fight. You might end up using less than 5 % of the bloat. And if you want to change or fix something it big 😫 pain to pealing layers after layers to find the actual root cause. Yet you might want to try these first

And there configurations too.

1.5 structure

Entropy is important but not here

This is the way, I keep my things have been same for many year now!

~/.config/emacs -> dot-emacs
├── elpa                   # pacman
├── cfg.compile.el
├── cfg.tabbar.el
:   :
│
├── ...
:
├── 00testing              # testing stuffs
└── snippets               # yasnippet stuffs
    ├── fundamental-mode
    :
    └── python-mode

1.6 troubleshooting

While troubleshooting I go though these procedure (may not be in same ordering)

  • hate myself when it happens
  • REMOVE the damn plugin and GET BACK TO WORK
  • throw ERROR MSG at google and try catching relevant pages
  • may be waste few hrs with random trials
  • set debug variable
    (setq debug-on-error 1)
    (setq debug-on-quit t)  ;; C-g
        

2 CORE

2.1 garbage collector

I don’t really understand what its happening but here are some chatter over the years on reddit and stackexchange. Original motivation was let the emacs use more RAM, if java based IDE can eat up more than 200 Mb :rage1: to get started. Don’t gc during startup to save time! so says hlissner/doom-emacs!

;;; restore gc suppress during early-init.el
(add-hook 'emacs-startup-hook
  (lambda ()
    (setq gc-cons-threshold (* 8 1024 1024))  ; default: 800000 bytes
    (setq read-process-output-max (* 2 1024 1024))  ; default : 4KB
    gc-cons-percentage 0.1))

2.2 load-time

Classic style 🧪 testing.

2>&1 /usr/bin/time --verbose  /usr/bin/emacs --eval="(save-buffers-kill-terminal)"
Command being timed: "/usr/bin/emacs --eval=(save-buffers-kill-terminal)"
User time (seconds): 2.95
System time (seconds): 0.32
Percent of CPU this job got: 98%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.34
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 285652
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 6
Minor (reclaiming a frame) page faults: 53556
Voluntary context switches: 396
Involuntary context switches: 338
Swaps: 0
File system inputs: 0
File system outputs: 24
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

Show emacs-init-time at startup

(add-hook 'emacs-startup-hook (lambda ()
    (message (concat "conf-init-time: " (emacs-init-time) (format " gc: %d" gcs-done)))))

for comprehensive bench-marking install benchmark-init

M-x benchmark-init/show-durations-tree

2.3 server

Stop ⛔ opening emacs for each file. Set default open application to emacsclient, or set it manually:

emacsclient --no-wait--alternate-editor=emacs [FILE]

(require 'server)
(unless (server-running-p)
  (server-start))

2.4 encoding

Set language to English all encoding in Unicode.

(setq set-default-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)

;; (set-keyboard-coding-system 'utf-8)  ;; has no-effect in GUI Terminal

(prefer-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(set-buffer-file-coding-system 'utf-8)
(set-language-environment "English")  ;; Set up multilingual environment

2.5 backup

I don’t like mess every where, there is better things for that called git!

(setq backup-directory-alist (quote ((".*" . "~/.cache/emacs_backup/"))))
(setq make-backup-files nil)
(setq auto-save-default nil)
(setq create-lockfiles nil)

2.6 custom

<2021-06-24 Thu> Ignoring for now because I want it to be in separate file but problem is file doesn’t load back.

As written in Emacs is Agar for Brain Worms

By default, Emacs stores any configuration you make through its UI by writing custom-set-variables invocations to your init file, or to the file specified by custom-file. Though this is convenient, it’s also an excellent way to cause aggravation when the variable you keep trying to modify is being set in some custom-set-variables invocation. We can’t disable this behavior, and the custom-file variable can’t be nil, but we can make it look in a different place every time.

 ;; (setq custom-file (make-temp-file ""))  ; ignore
(setq custom-file "/home/rho/.config/emacs/custom.el")

2.7 big files

Warn when opening files bigger than 1 MiB. yup emacs kitchen sink can open 🌇 image, PDF but seriously 😵 ?

(setq large-file-warning-threshold (* 1 1024 1024))

You might wonder why that random number!

kilobyte (kB)1000 bytes
kibibyte (KiB)1024 bytes, kB

Since digital systems worked in binary, yet defacto is in base of 2, Still interface don’t show kibi, mebi, gibi. I don’t think I’m only one who feel 😠 cheated getting HDD of 1 TB and you getting 0.931 TB.

2.8 pacman

There are many 📦 package managers for emacs, ranging from simple scripts to download files from EmacsWiki to full-featured package management solutions like straight.el, these are few I have used

Its 2020, it has been harder to maintain packages with two managers. Finally decided to drop el-get in favor of build in package.el.

2.8.1 package.el

Add package other sources

(require 'package) ;; after 24 its pre-loaded
(add-to-list 'load-path "~/.config/emacs/elpa/")

;; (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/") t)
;; https://melpa.org/#/getting-started
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

Use M-x package-refresh-contents to reload the list of packages after adding these for the first time.

  • <2022-01-12 Wed>

    org package is handled by gnu elpa after 9.5

  • <2020-02-02 Sun>

    having troubles with org-version babel support. using org package-archives for latest stuff.

  • <2023-08-08 Tue>

    In Emacs 29.1 package.el can install packages directly from git with the new function package-vc-install, and packages installed that way can be updated with package-vc-update or package-vc-update-all.

2.8.2 why-no-use-package

The use-package macro allows you to isolate package configuration
both performance-oriented and, well, tidy.

But My packages are already organized using org-mode and the current init time is below 0.5 s given by emacs-init-time within 2.0 s in total or Just I don’t use tons of package.

Or change my mind!

2.8.3 el-get

el-get is the package manager, which is similar to apt-get. Not using since starting of 2020.

More

Its bit tricky to make both ELPA and el-get work together, but after years of procrastination, some how this works, you should load el-get first, but emacs24+ loads package.el by default, thats why put this magic line before loading el-get (setq package-enable-at-startup nil)

(add-to-list 'load-path "~/.emacs.d/el-get")
(require 'el-get)
(setq el-get-git-shallow-clone 't)
(el-get 'sync)

To replicate a package set for another emacs installation is explain in el-get README.

3 UI

As of today, most people who use vi or emacs are incapable of using the other editor without using curse words 😡. Not surprisingly normal people without prior knowledge any text editor are pretty comfortable even 🪟 notepad make much more sense than emacs or vi. Yes you can pretty much do any text foo with these editor, even without touching 🐁 pointing device, but really does it really need to be like this.

3.1 early-init

Version 27.1 introduces ~/emacs.d/early-init.el, which is run before ~/emacs.d/init.el, before package and UI initialization happens. Themes and UI components can be setup here, which finally solves flickering UI.

3.2 emoji

Since emacs 28.1 Improved support for Emoji. On capable systems, Emacs now correctly displays Emoji and Emoji sequences by default, provided that a suitable font is available to Emacs. With a few exceptions.

“Noto Color Emoji” is automatically used if it’s installed if not install run for Arch Linux.

pacman -S extra/noto-fonts-emoji

3.3 theme-switch

Worst part of switching theme by loading is active theme is one disabled before loading the new one! this 🪄 trick was stolen from @thapakazi.

(defun theme-switch (theme)
  "Disables any currently active themes and loads THEME."
  ;; This interactive call is taken from `load-theme'
  (interactive
   (list (intern (completing-read "Load custom theme: "
                                  (mapc 'symbol-name
                                        (custom-available-themes))))))
  (let ((enabled-themes custom-enabled-themes))
    (mapc #'disable-theme custom-enabled-themes)
    (load-theme theme t)))

3.4 scroll

Historically emacs 💈 scrolling 💈 has bee choppy and riddled with bugs, after pgtk branch was merged on <2021-12-19> this has been better. Now in emacs 29.1 pixel-scroll-precision-mode builtin, no more custom 🛠️ builds.

(pixel-scroll-precision-mode t)
;; (setq pixel-scroll-precision-large-scroll-height 50.0)
;; (setq pixel-scroll-precision-use-momentum nil)

3.4.1 scroll-horizontal

Similar to nano single line horizontal scroll in v26.1 introduced new feature, which only current line with cursor to be horizontally scrolled left or right window margin.

(setq auto-hscroll-mode 'current-line)

3.5 fringe

Vim does this with ~ (tildes) characters at the bottom of a window to indicate that there is nothing in the buffer, so emacs can do it too 🏁.

(toggle-indicate-empty-lines t)

3.6 line-number

As in this article of ergoemacs, 2 line numbers mode is been 📦 packaged with emacs.

yearemacspackage
200923linum-mode
201826global-display-line-numbers-mode

I used multiple line number plugins over years now, frontmacs config stood out for me the, but linum give lots of flicker, now using with nlinum which is quite good until it was deprecated.

(add-hook 'prog-mode-hook 'display-line-numbers-mode)
(add-hook 'org-mode-hook 'display-line-numbers-mode)
(add-hook 'display-line-numbers-mode-hook
          (lambda ()
            (setq display-line-numbers-width 4)))
  • <2023-08-29 Tue>

    nlinum is unusable

3.7 initial-screen

(setq inhibit-startup-message t)
(setq inhibit-splash-screen t)

3.8 mode line

The mode line contains textual summary about the buffer, such as its name, associated file, depth of recursive editing, and major and minor modes.

3.8.1 dim

The purpose of dim package is to “customize” the mode-line names of major and minor modes using dim-major-name and dim-minor-name to change the names by one.

(require 'dim)

3.8.2 diminish

More

When we diminish a mode, we are saying we want it to continue doing its work for us, but we no longer want to be reminded of it. It becomes a night worker, like a janitor; it becomes an invisible man; it remains a component, perhaps an important one, sometimes an indispensable one, of the mechanism that maintains the day-people’s world, but its place in their thoughts is diminished, usually to nothing. As we grow old we diminish more and more such thoughts, such people, usually to nothing.

– Will Mengarini

(require 'diminish)
  • <2022-03-12 Sat> not using

    preferring dim instead

3.8.3 mode icons

Its normal to use 5-10 modes on a buffer, which make the mode line full of clutter why not use icons!

https://raw.githubusercontent.com/rhoit/mode-icons/dump/screenshots/screenshot01.png

(require 'mode-icons)
(mode-icons-mode)

3.8.4 theme

(require 'powerline)

;;; https://github.com/rhoit/powerline-iconic-theme
(setq FILE-iconic "~/.config/emacs/00testing/powerline-iconic-theme/iconic.el")
(if (file-exists-p FILE-iconic)
  (progn
    (load-file FILE-iconic)
    (powerline-iconic-theme))
  (powerline-default-theme))

3.9 tabbar

tabbar is something familiar to modern 🍭 GUI system, there is still the gap, like key-bindings, close buttons and icons which is which tabbar-ruler tries to address.

https://raw.githubusercontent.com/rhoit/tabbar-ruler.el/dump/screenshots/01.png

(require 'tabbar)
(tabbar-mode t)

(setq FILE-tabbar "~/.config/emacs/00testing/tabbar-ruler/tabbar-ruler.el")
(if (file-exists-p FILE-tabbar)
  (load-file FILE-tabbar)
  (require 'tabbar-ruler))

(setq tabbar-ruler-style 'firefox)

(load "~/.config/emacs/cfg.tabbar.el")
(define-key global-map (kbd "<header-line> <mouse-3>") 'mouse-buffer-menu)

scroll-right and scroll-right seems to be strange for beginner and for me too, if you don’t believe me try C-PgUp and C-PgUp in vanilla 🍦 emacs, put it to the good use tab-forward and tab-backward

(global-unset-key [(control prior)])  ; unbind (scroll-right)
(global-unset-key [(control next)])   ; unbind (scroll-left)

(define-key global-map [(control next)] 'tabbar-forward)
(define-key global-map [(control prior)] 'tabbar-backward)

grouping the tab by buffer name

(setq tabbar-buffer-groups-function (lambda ()
  (list (cond
    ((string-match ".*magit.*" (buffer-name)) "magit Buffers")
    ((string-match "TAGS" (buffer-name)) "ctags")
    ((string-match "*pdb.*" (buffer-name)) "pdb Buffers")
    ((string-match "*helm.*" (buffer-name)) "helm Buffers")
    ((string-equal "*" (substring (buffer-name) 0 1)) "emacs Buffers")
    ((eq major-mode 'dired-mode) "Dired")
    (t "User Buffers")
))))

Binding for the tab groups, some how I use lots of buffers.

(global-set-key [(control shift prior)] 'tabbar-backward-group)
(global-set-key [(control shift next)] 'tabbar-forward-group)

Similar packages

3.10 buffer

Sensible unique buffer names, [ inbuilt: package ] by default in >= 24.4.1 else add (require 'uniquify)

(setq uniquify-buffer-name-style 'forward)

I prefer speedbar outside the frame, for without separate frame see SrSpeedbar.

(setq speedbar-show-unknown-files t)
;; (global-set-key [f9] 'speedbar)
  • <2021-05-27 Thu>

    its projectile now days and speedbar breaks my theme

3.12 goto-last-change

This is the gem feature, this might be true answer to the sublime mini-map which is over rated, this is what you need.

(require 'goto-chg)
(global-unset-key (kbd "C-j"))  ; unbind (eval-print-last-sexp)
(global-set-key (kbd "C-j") 'goto-last-change)

4 UX

Fundamentally emacs is more over a scratchpad for elisp, which has been mistaken for the editor. Just 30+ years focused on features accumulation with barely any attention to GUI, I’m baffled when people come up with ⌨️ keybinding for each modes and mode to manage them again with keybindings. No wonder people get strain injuries.

I’m one of those who is keen 🔥 burning your finger tips for efficiency. and why do they generalize everyone uses same key layout and so call most efficient vi binding, just 🔒 locks me inside without the exit🚪!

4.1 oem

I don’t understand why laptops 💻 OEM constantly change the key layouts. But why perfectly good layout are replace by terrible designs, Not to mention combining delete and backspace .

Some time you need to explicitly say what to do.

;;; you might not need this
(normal-erase-is-backspace-mode 1)

It seem more of “think different stupid” 🍎. And even seasoned vi users can’t seems to escape from it ever, (Esc is back), and copy 🐈 OEM does not know where to place power ⚡ button.

4.2 sane-binding

Although most of the emacs key binding are sill relevant till this day. I can not stop to appreciation the thought and design went on building it, but 🐁 mouse binding are terrible.

;; redundent with f10 and gtk-menu
(global-unset-key [(control down-mouse-3)]) ; unbind (global-menu)

;; M-C-t opens terminals
(global-unset-key (kbd "C-M-t")) ; unbind (transpose-sexps)

(global-unset-key [(control down-mouse-3)]) ; unbind (global-menu)

;; yet useful but utterly misplaced, using tabbar
(global-unset-key [(control down-mouse-1)]) ; unbind (buffer-menu)

;; emacs is terrible mail client
(global-unset-key (kbd "C-x m")) ;; unbind (compose-mail)

;; it dosn't make sense
(global-unset-key (kbd "M-o")) ;; unbind (facemenu-mode)

;; gnu license
(global-unset-key (kbd "C-h w"))
I prefer to disable exit (kill) binding (C-x C-c), Since I don’t use emacs in terminal.
(if window-system
    (global-unset-key (kbd "C-x C-c")))

4.2.1 find

⬅️ Arrows ➡️ keys might have been hard to find before 1980’s, but binding forward-char to C-f till date is 🤦 dumb, let enable some what common like search/find 🔍.
(global-set-key (kbd "C-f") 'isearch-repeat-forward)  ;; unbind (forward-char)

4.2.2 readonly

In most of the modern applications F2 is use for rename or edit ✏️. Currently F2 binded to 2 column mode which I haven’t found any use till date. Default binding (C-x C-q) to toggle read-only-mode don’t make any sense in modern day or age.
(global-set-key [f2] 'read-only-mode) ;; unbind (2C-two-columns)

4.2.3 word-wrap

(global-set-key [f6] 'toggle-truncate-lines)

4.2.4 fullscreen

When new function like toggle-frame-fullscreen (F11) and toggle-frame-maximized (M-F11) keeps popping in recent version 24.4, lets me to think emacs hasn’t given up on being Operating System.

;;; full-screen since 24.4
;; handled via window manager
;; lets reserve it for something i.e realgud
(global-unset-key [f11])

4.2.5 buffer-close

;;; since, C-x k <return> too much acrobat
(global-set-key [(control d)] 'kill-buffer)  ; same as terminal

4.2.6 helpful

;; escape do its thing
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)

;;; backward kill like terminal
(global-unset-key (kbd "C-w"))
(global-set-key (kbd "C-w") 'backward-kill-word) ;; like in terminal

;; since, C-x k <return> too much acrobat
(global-set-key [(control d)] 'kill-buffer) ; same as terminal

;; (global-set-key (kbd "<f5>") 'redraw-display)
(global-set-key [f12] '(lambda()
  (interactive)
  (find-file "~/.config/emacs/README.org")))

4.3 yes-or-no

yup thing are annoying 😤 here! avoid typing complete ‘yes’ and ‘no’.

(fset 'yes-or-no-p 'y-or-n-p)

4.4 update-buffer

A fancy :bowtie: way of saying any change in file (yup not using same editor, duh!) will magically 🎩 appear in editor.

(global-auto-revert-mode)
;;(setq auto-revert-verbose nil)

4.5 undo

Ctrl-z is synonyms to undo not here because its suspend to background in 🐚 shell, Since emacs traces it roots from the terminal.

;;; this is confusion
(global-unset-key (kbd "C-z")) ; unbind (suspend-frame)

4.5.1 undo-tree

undo-tree preserve your undo chain and maintain undo branching.

(require 'undo-tree)
(dim-minor-name 'undo-tree-mode "")

(global-undo-tree-mode 1)
(setq undo-tree-visualizer-timestamps t)

;; stop unde tree from saving *.~undo-tree~ everywhere
(setq undo-tree-auto-save-history nil)

;; region undo
;; (setq undo-tree-enable-undo-in-region t)

;; normal undo and redo
(global-set-key (kbd "C-z") 'undo-only)
(global-set-key (kbd "C-S-z") 'undo-tree-redo)
  • <2023-08-04 Fri>

    Have been using undo-tree for so long, didn’t know undo region existed more in irreal blog, but confusing to use.

  • <2020-02-12 Wed> retrying undo-tree again!

    there are moments when undo-tree breaks down but, it has been a while it hasn’t or simply I haven’t been working enough! COVID-19 😷

  • <2018-11-13 Tue> stopped using undo-tree

    full days work vanished 😥 thought undo would handle it.

4.6 search

If you can yank (paste) in search, why to add to kill-ring (copy) just select the text and hit C-s!

In addition there is the whole section in wiki about search at point.

(add-hook
 'isearch-mode-hook
 (lambda ()
   "Use region as the isearch text."
   (when mark-active
     (let ((region (funcall region-extract-function nil)))
       (deactivate-mark)
       (isearch-push-state)
       (isearch-yank-string region)))))

Search forward and backward for word under cursor.

(defun search-forward-under-cursor ()
  "Search for the word under the cursor."
  (interactive)
  (let ((word (thing-at-point 'word)))
(if word (search-forward word nil t))))

(global-set-key (kbd "C-S-s") 'search-forward-under-cursor)

(defun search-backward-under-cursor ()
  "Search for the word under the cursor."
  (interactive)
  (let ((word (thing-at-point 'word)))
(if word (search-backward word nil t))))

(global-set-key (kbd "C-S-r") 'search-backward-under-cursor)

4.6.1 anzu

anzu highlight all search matches, most of the text editor does even vi this why not emacs. Here is the gify from original repository.

(require 'anzu)

(global-anzu-mode +1)
(global-unset-key (kbd "M-%"))
(global-unset-key (kbd "C-M-%"))
(global-set-key (kbd "M-%") 'anzu-query-replace)
(global-set-key (kbd "C-M-%") 'anzu-query-replace-regexp)

4.6.2 highlight

Beyond the syntax color, ability to highlight adds clear 🧐 perspective during variable hunting.

(require 'symbol-overlay)

(global-set-key
 (kbd "<C-mouse-3>")
 (lambda (event)
   (interactive "e")
   (save-excursion
     (goto-char (posn-point (event-start event)))
     (symbol-overlay-put))))
More
(require 'highlight-symbol)

(global-set-key (kbd "C-S-r") 'highlight-symbol-prev)
(global-set-key (kbd "C-S-s") 'highlight-symbol-next)
(global-set-key [(shift f3)] 'highlight-symbol-at-point)
(global-set-key [(ctrl f3)] 'highlight-symbol-query-replace)
(global-set-key (kbd "<C-mouse-3>") (lambda (event)
  (interactive "e")
  (save-excursion
    (goto-char (posn-point (event-start event)))
    (highlight-symbol-at-point))))
  • <2023-08-01 Tue>

    highlight symbol has been un-mantained since 2016 switching to alternative symbol-overlay

4.7 cursor

Make cursor adaptive the to the width of the character, helpful in showing non-monospace characters like TAB and emoji.

(setq x-stretch-cursor t)

4.7.1 beacon-mode

beacon gives extra feedback of cursor’s position on big movement. It can be understood better with this gify from original repository.

(require 'beacon)

(setq beacon-blink-delay '0.2)
(setq beacon-blink-when-focused 't)
(setq beacon-dont-blink-commands 'nil)
(setq beacon-push-mark '1)

(dim-minor-name 'beacon-mode "")
(beacon-mode t)

4.7.2 multiple-cursor

If sublime can have multiple cursor, emacs can too.

Here is 📹 video from Emacs Rocks! about it in ep13.

(require 'multiple-cursors)
(global-set-key (kbd "C-S-<mouse-1>") 'mc/add-cursor-on-click)

(global-set-key (kbd "C-S-<wheel-up>") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-S-<wheel-down>") 'mc/mark-next-like-this)

;; this need to be key bind needs region to be selected
;; (global-set-key (kbd "C-S-<mouse-2>") 'mc/mark-all-like-this)

4.8 selection

Some of the default behavior of emacs 💩 weird, text-selection is on of them, some time its the 🌈 WOW 🦄 moment 🥳 and other time its WTF.

;;; doing expected things
(delete-selection-mode 1)

4.8.1 why-changing-fonts

Hotkey for font dialog is kinda absurd, that to for changing font-face, although for resize has Ctrl mouse-scroll might be sensible option.

In the effort of not being weird Shift mouse-primary-click is used in region/text selection mouse-save-then-kill.

(global-unset-key [(shift down-mouse-1)])  ; unbind (mouse-apperance-menu EVENT)
(global-set-key [(shift down-mouse-1)] 'mouse-save-then-kill)

so called wow moments

as you think selecting selection, emacs binds the selection keyboard free, when followed by mouse-secondary-click if its not in conflict.

Expand region increases the selected region by semantic units.

Here is video from Emacs Rocks! about it in ep09.

(require 'expand-region)

(global-set-key (kbd "C-S-SPC") 'er/expand-region)
(global-set-key (kbd "C-SPC") (lambda()
    "set-mark when nothing is selected"
    (interactive)
    (if (use-region-p)
        (er/contract-region 1)
        (call-interactively 'set-mark-command))))

4.9 mini-buffer

4.9.1 helm

Although helm features are from the another league, I have not gone beyond the minibuffer. It took me while to get hang of it, one of reasons might be constant flickering creation of helm temporary popup windows 🪟 which I don’t like.

If you want to know more you can into helm intro

(require 'helm)
(helm-mode 1)
(dim-minor-name 'helm-mode "")

(setq helm-allow-mouse t)

(define-key global-map [remap list-buffers] 'helm-buffers-list)
(define-key global-map [remap execute-extended-command] 'helm-M-x)
(define-key global-map [remap find-file] 'helm-find-files)

(unless (boundp 'completion-in-region-function)
  (define-key lisp-interaction-mode-map [remap completion-at-point] 'helm-lisp-completion-at-point)
  (define-key emacs-lisp-mode-map       [remap completion-at-point] 'helm-lisp-completion-at-point))

;;; I need arrow keys
(customize-set-variable 'helm-ff-lynx-style-map t)

;;; terminal like tabs selection
(define-key helm-map (kbd "<tab>") 'helm-next-line)
(define-key helm-map (kbd "<backtab>") 'helm-previous-line)

;;; show command details
(define-key helm-map (kbd "<right>") 'helm-execute-persistent-action)
(define-key helm-map (kbd "<left>") 'helm-execute-persistent-action)
  • <2023-08-02 Wed>

    helm fixed! 🥳

  • <2023-08-01 Tue>

    After switing to emacs 29.1 and updating packages, helm stopped working, details in emacs-helm/helm#2608

    custom-initialize-reset: Symbol's value as variable is void: helm-info-source
        
  • <2020-08-31 Mon>

    lynx style navigation fix after new update

4.9.1.1 helm-packages

Some useful helm packages 🤩.

namedescription
helm-descbindsA convenient helm version of describe-bindings.
helm-xrefHelm interface for xref results

4.9.2 orderless

If you are using helm matching space-separated component is provided by default, which I only found out after trying orderless and its called “multi pattern matching” in helm.

(require 'orderless)
(setq completion-styles '(orderless))

4.10 text zoom

I still don’t understand 😒 why emacs way of changing font size is weird. Mapping behavior similar to web-browser might be helpful to have cohesive experience.

zoomkeyboardkeyboard + mouse
inCtrl + Shift + =Ctrl + mouse-scroll-up
outCtrl + -Ctrl + mouse-scroll-down
1xCtrl + 0

These config are for the single buffer

(global-set-key [C-mouse-4] 'text-scale-increase)
(global-set-key [(control ?+)] 'text-scale-increase)
(global-set-key [C-mouse-5] 'text-scale-decrease)
(global-set-key [(control ?-)] 'text-scale-decrease)
(global-set-key
 (kbd "C-0")
 (lambda()
   (interactive)
   (text-scale-adjust (- text-scale-mode-amount))
   (text-scale-mode -1)))

It has never been so much easy to bookmark 🔖!

(require 'bm)
(setq bm-marker 'bm-marker-left)
;; (setq bm-cycle-all-buffers t)  ;; Allow cross-buffer

(global-set-key (kbd "<left-margin> <mouse-1>") 'bm-toggle-mouse)
(global-set-key (kbd "<left-fringe> <mouse-1>") 'bm-toggle-mouse)
(global-set-key (kbd "S-<wheel-down>") 'bm-next-mouse)
(global-set-key (kbd "S-<wheel-up>") 'bm-previous-mouse)

;;; org-mode to expand the region containing a bookmark
(add-hook 'bm-after-goto-hook 'org-bookmark-jump-unhide)
  • <2022-03-10 Thu> better key binding

    fringe are too small to be used precisely as suggest

4.12 killing group

In Emacs, Killing means 🔪 cut (maybe ✂️: were not invented then!). Yanking paste text from the kill-ring back into the buffer. The kill-ring is 📋 clipboard for text snippets to used later, which can access in cyclic ♻️ order.

Yanking with C-y and cycling through using M-y, M-y, M-y can be bit alarming.

4.12.1 paste

Beginners find Ctrl+v jump outlandish and sometime also for me. In this day and age certain function are arcane (may be someone uses it) but its not for me. When beginners try to paste with C-v scroll-up outlandishly make me think this is main reason of 😞 poor adoption, when will emacs have better default.

(global-set-key [(control v)] 'yank) ; unbind (scroll-up-command)

4.12.2 kill-ring

emacs comes with 📋 clipboard support knows as kill ☠️ ring 💍, helm provided one of the best way to explore the entries using helm-show-kill-ring. Other ways of browsing can are listed in wiki,

(setq repetitive_yank_region_point 0) ; 0 doesn't exist min is 1
(defun repetitive-yanking()
  "yank and yank whats rest are in the kill ring"
  (interactive)
  (message "last-command: %S" last-command)
  (if (string= last-command "yank")
      (progn
        (undo-only)
        (when (= (point) repetitive_yank_region_point)
            (progn
              (goto-char repetitive_yank_region_mark)
              (set-mark-command nil)
              (goto-char repetitive_yank_region_point)
              (delete-selection-helper "yank")))
        (helm-show-kill-ring))
    (progn
      (when (use-region-p)
        (setq repetitive_yank_region_mark (mark))
        (setq repetitive_yank_region_point (point))
        (message "%s" repetitive_yank_region_point)
        (delete-selection-helper "yank"))
      (yank))))

(global-set-key [(shift insert)] 'repetitive-yanking)
(require 'popup-kill-ring)
  • <2022-10-06 Thu>

    opted for helm since it hard to see multi-line clips

4.12.4 drag

After using org-mode nothing is same, moving the section is one of the feature you want to have every where. Although many do have feature to drag a lines or the region. drag-stuff is great but its default binding is conflicts with org-mode.

(require 'drag-stuff)

;;; default bindings conflicts with org mode
;; (drag-stuff-define-keys)

;; better bindings
(global-set-key [(meta shift up)] 'drag-stuff-up)
(global-set-key [(meta shift down)] 'drag-stuff-down)
(global-set-key [(meta shift left)] 'drag-stuff-left)
(global-set-key [(meta shift right)] 'drag-stuff-right)

4.13 layout

winner mode saving the window configure

(when (fboundp 'winner-mode)
    (winner-mode 1))

4.14 splits

(setq split-width-threshold 120)

5 PROGRAMMING

some of the basic things provide by emacs internal packages.

(add-hook 'prog-mode-hook 'subword-mode)  ; camelCase is subword
(add-hook 'prog-mode-hook 'which-function-mode)
(add-hook 'prog-mode-hook (lambda() (setq truncate-lines t)))

5.1 parenthesis

(setq show-paren-style 'expression)
;; (setq show-paren-match '((t (:inverse-video t)))) ;; this is not working using custom set face
(show-paren-mode 1)

5.1.1 rainbow-delimiters

This 🌈 mode is barely noticeable at first glance but, if you live by parenthesis it nice thing to have around.

(add-hook 'prog-mode-hook 'rainbow-delimiters-mode)

5.2 comments

Yet again, bad default for emacs 😳 the key-binding does not toggle comment on the line, may be its because of :neckbeard: who always wrote the perfect code, only needed comment to add GPL!

But, Our code is SELF DOCUMENTED! 😎
;;; comment whole line
(defun comment-indent()
  "custom over-ride comment-indent to comment whole line"
 (interactive)
 (comment-or-uncomment-region (line-beginning-position) (line-end-position)))

;;; default comment string
(setq-default comment-start "# ")

5.3 watch-word

(defun watch-words ()
  (interactive)
  (font-lock-add-keywords
   nil '(("\\<\\(FIX\\|TODO\\|BUGS?\\)"
          1 font-lock-warning-face t))))

(add-hook 'prog-mode-hook 'watch-words)

5.4 indentation

Sorry Richard no tabs here!

(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq tab-width 4)

5.4.1 highlight-indent-guides

After years using highlight indentation with performance issues and shifting through multiple 🍴 fork and patches, I have moved to highlight-indent-guides has much better compatibility. Although I hate default fill method.

(setq highlight-indent-guides-method 'character)
(setq highlight-indent-guides-character ?\┊)

(add-hook
 'prog-mode-hook
 '(lambda()
    (require 'highlight-indent-guides)
    (dim-minor-name 'highlight-indent-guides-mode "")
    (highlight-indent-guides-mode)))

5.5 align-rules

align.el has a few commands that can line up text with respect to white-space, assignment, columns or regexp specified delimiters, which can be modified using align-rules-list, more info can be found in wiki.

(eval-after-load "align"
  '(add-to-list
    'align-rules-list
    '(prog-align-colon
      (mode   . '(prog-mode))
      (regexp . "\\(\\s-*\\)[=:]\\(\\s-*\\)")
      (repeat . nil))))

(add-hook
 'prog-mode-hook
 (lambda()
   (local-set-key (kbd "C-S-a") 'align-entire)))

5.6 folding

It is 😠 frustrating many code folding packages not folding-mode does not 🚧 work as planned. so many corner cases and constantly 💔 breaking. Some of the code folding I have tried are

(add-hook 'prog-mode-hook 'yafolding-mode)
(add-hook 'compilation-mode-hook 'yafolding-mode)
  • <2022-03-11 Fri> hello ya-folding

    have been using for a while

  • <2021-05-27 Thu> org export problem

    hideshow vis has trouble with org export

5.7 white-spaces

If you have working with non-emacs people sooner or later you might face this problem, those pesky trailing spaces/tabs.

Phenomenal Cosmic Powers! Itty Bitty trailing spaces!

Although end result might be same but it all shows in diff, ideally there should be no empty lines at the beginning of a file, no empty lines at the end of a file, no trailing whitespace, no mixture of tabs and spaces, etc.

older delete-trailing-whitespace command, that simply deletes trailing white-space.

whitespace-cleanup aware of the whitespace-style variable, used by whitespace-mode.

different types of hooks

  • write-file-hooks
  • before-save-hooks
(defun nuke-trailing ()
  (add-hook 'write-file-hooks 'delete-trailing-whitespace)
  (add-hook 'before-save-hooks 'whitespace-cleanup))

(add-hook 'prog-mode-hook 'nuke-trailing)

hungry-delete mode is interesting but still its quirky, mapping it to default delete/backspace will result typing your needed white-spaces back again! So as the mode its NO, NO. Manually toggling the mode just to delete few continous white spaces. Naah!

(require 'hungry-delete)
(global-set-key (kbd "S-<backspace>") 'hungry-delete-backward)

There is the interesting outlook of smart-hungry-delete, which I have not used for the while.

(require 'smart-hungry-delete)
(smart-hungry-delete-add-default-hooks)
(global-set-key (kbd "<backspace>") 'smart-hungry-delete-backward-char)
;; (global-set-key (kbd "<delete>") 'smart-hungry-delete-forward-char)
;; (global-set-key (kbd "<delete>") '(lambda ()
;;  (if use-region-p '(smart-hungry-delete-forward-char) '(delete-char))))

Of course emacs can add newline at End Of File just to make sure git doesn’t go crazy! for unchanged files. But don’t enable it let fancy IDE people wonder how to remove newline at EOF.

CAUTION! BUT MOST OF WILL JUST MAKE MESS

;; (setq require-final-newline t)

5.7.1 whitespace4r.el

I have been wanting white-space to be displayed for selected region since I saw feature in sublime.

https://i.stack.imgur.com/9GInk.png

Yet there was nothing similar to-be found, thankfully 😭 @twlz0ne created the new minor mode, (since, I can’t wrap my head to lisp).

(add-to-list 'load-path "~/.config/emacs/00testing/whitespace4r.el/")
(require 'whitespace4r)
(whitespace4r-mode)
  • <2022-03-19 Sat> workable

    mode is buggy or just because of my theme or configuration

5.8 compile

(add-hook 'compilation-mode-hook (lambda() (setq truncate-lines t)))
(global-set-key (kbd "C-<f8>") 'recompile)
(global-set-key (kbd "<f8>")
                (lambda()
                  (interactive)
                  (if (get-buffer-window "*compilation*")
                      (delete-windows-on "*compilation*")
                    (display-buffer "*compilation*"))))
(require 'ansi-color)  ;; buitin 28.1
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)

5.9 magit

git is amazing but magit is magic 🪄!

(require 'magit)
(global-set-key (kbd "C-x C-g") 'magit-status)
(add-hook 'git-commit-mode-hook 'turn-on-flyspell)

(global-set-key (kbd "C-x C-l") 'magit-log-buffer-file)  ; unbind (downcase-region)

(setq magit-diff-refine-hunk 'all)
(setq magit-display-buffer-function 'magit-display-buffer-fullframe-status-v1)

Tuning magit for performance from manual.

(setq magit-refresh-status-buffer nil)
(remove-hook 'magit-refs-sections-hook 'magit-insert-tags)

Many commands that are rarely used in magit are hidden by default. magit uses the transient.el library for popups and the visibility of infix and suffix commands are controlled by transient-default-level. Default level is 4 some of the command I use are in level 7.

(setq transient-default-level 7)
(setq magit-process-finish-apply-ansi-colors t)

5.9.1 diff

(setq magit-ediff-dwim-show-on-hunks t)
(setq ediff-split-window-function 'split-window-horizontally)

magit status doesn’t show white space removal as mention in this issue

(setq magit-diff-paint-whitespace-lines 'all)
(setq magit-diff-paint-whitespace t)
(setq magit-diff-refine-ignore-whitespace nil)
(setq magit-diff-refine-hunk nil)

5.9.2 lfs

magit-lfs plugin for large-file-storage

5.10 projects

5.10.1 project.el

project.el is a build-in package introduced around v26 which provides basic action for managing code project similar to projectile where I only use to find a file, or run grep.

(global-set-key (kbd "C-<f9>") 'project-compile)
(global-set-key (kbd "C-S-f") 'project-find-file)
(global-set-key (kbd "C-S-t") 'project-shell)
(global-set-key (kbd "C-S-g") 'project-find-regexp)

project.el marks the project by the version control if there is no version control file aren’t tracked.

https://andreyorst.gitlab.io/posts/2022-07-16-project-el-enhancements/ https://christiantietze.de/posts/2022/03/mark-local-project.el-directories/

5.10.2 projectile

If your source consist of hundreds of line then don’t be like me use projectile mode like @krazedkrish.

ya C-S-p for select line previous, just get along with it, have you tried it in chrome, sublime, vscode? and don’t forget the helm-projectile.

(require 'projectile)
(projectile-mode +1)

(require 'helm-projectile)
(helm-projectile-on)

(global-set-key (kbd "C-S-p") 'helm-projectile-find-file)
(global-set-key (kbd "C-S-t") 'projectile-find-tag)
(global-set-key (kbd "C-S-g") 'helm-projectile-grep)

5.11 grep

Search files for the occurrence of a string of characters that matches a specified pattern.

5.11.1 ripgrep

ripgrep is modern rendition grep command using Rust’s regex engine which is extremely fast. ripgrep.el package integrates the command with emacs.

(advice-add #'project-find-regexp :override #'ripgrep-regexp)

5.12 dired-mode

facing trouble when in fresh copy of repo, will fix later

(add-hook
 'prog-mode-hook
 '(lambda()
    (setq dired-omit-files
          (concat dired-omit-files "\\|\\.git$\\|venv$"))))

5.13 auto-complete

(require 'company)
(dim-minor-name 'company-mode "")
(global-company-mode +1)

(require 'company-box)
(dim-minor-name 'company-box-mode "")
(add-hook 'company-mode-hook 'company-box-mode)

company mode supports emoji.

(require 'company-emoji)
(add-to-list 'company-backends 'company-emoji)

(add-to-list 'company-emoji-aliases '(:poop: . ":hankey:"))

customize face company-tooltip-selection

(custom-set-faces
 '(company-tooltip-selection ((t (:inherit company-tooltip-selection :extend t :inverse-video t)))))

5.14 ggtags

Using language server protocol (LSP) since, ggtags make my emacs super slow, but not sure why!

More
(add-hook 'c-mode-common-hook (lambda ()
    (when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
        (ggtags-mode 1))))
(add-hook 'python-mode-hook 'ggtags-mode)
(global-set-key (kbd "<C-double-mouse-1>") 'ggtags-find-tag-mouse)

5.15 LSP

Language Server Protocol is a JSON-RPC protocol to delegate language aware features to a common server process using generic LSP client. The current lsp specifications was proposed by Microsoft as a way for different editors and development environments to share language analysis back-ends. If you’d like to read more about the inner workings, consider this post.

lsp-mode aims to provide IDE-like experience by providing optional integration with the most popular Emacs packages like company, flycheck and projectile.

The proper way to start lsp-mode is using M-x lsp

To check its capabilities on running lsp M-x lsp-describe-session

(require 'lsp-mode)

;; don't override ('er/expand-region)
(define-key lsp-mode-map (kbd "C-S-SPC") nil) ; unset (lsp-signature-activate)

(setq lsp-headerline-breadcrumb-enable nil)
(setq lsp-diagnostics-provider :none) ;; disable flycheck
;; (setq lsp-prefer-flymake nil) ;; use flycheck over flymake

debugging variables

;; (setq lsp-print-io t)
;; (setq lsp-trace t)
(setq lsp-print-performance t)

5.15.1 servers

language-servers should be installed ⚒️ manually you can see the list of supported languages at their website and documented at lsp-clients.json.

(add-hook 'sh-mode-hook #'lsp)

5.15.2 performance

M-x lsp-doctor 🚑 is really handy to get started but still there other tweak 🔧 in lsp-mode docs.

;; (setq lsp-log-io nil)  ; default:nil, for debugging
(setq lsp-idle-delay 0.500)
(setq company-lsp-cache-candidates t)

5.15.2.1 native compile

It has been a while I have been using the native compile since it merge into main branch although its still worth it increased overall performance not just LSP,

To know about my builds see build or check my releases.

5.15.2.2 plists

(setq lsp-use-plists t)

Using plists for de-serialization :feelsgood: is only triggers when emacs starts with LSP_USE_PLISTS is true, and lsp wiki recommending shell to start, But it could be better 😎 just need to replace emacs with 🐚 shell-script.

cat /usr/local/bin/emacs
LSP_USE_PLISTS=true exec /usr/bin/emacs $*

5.15.2.3 file-watcher

Watching all the files in huger project directories, may slow down performance.

Yet to find how it helps so disabling it.

(setq lsp-enable-file-watchers nil) ; default:t

Default warning threshold is 1000 which can be changing variable (setq lsp-file-watch-threshold 1000)

(with-eval-after-load 'lsp-mode
  (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\venv\\'")
  (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\vendors\\'")
  (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\__pycache__\\'"))

5.15.3 lsp-ui

This is extension for all the higher level UI modules of LSP, like flycheck support and code lenses.

By default, lsp-mode automatically activates lsp-ui unless (setq lsp-auto-configure nil).

(require 'lsp-ui)

(add-hook 'lsp-mode-hook 'lsp-ui-mode)
(setq lsp-ui-doc-enable t
      lsp-ui-doc-use-childframe t
      lsp-ui-doc-position 'top
      lsp-ui-doc-include-signature t
      lsp-ui-sideline-enable nil
      lsp-ui-flycheck-enable t
      lsp-ui-flycheck-list-position 'right
      lsp-ui-flycheck-live-reporting t
      lsp-ui-peek-enable t
      lsp-ui-peek-list-width 60
      lsp-ui-peek-peek-height 25)

5.16 debugger

Although I barely use debugger, lets say I’m more of print() person, may be because I work much with python than C. Nevertheless, a good IDE should have 🐛 debugger, but emacs is TextEditor OS, and ships with Grand Unified Debugger (GUD), its fairly usable with terrible defaults and not to mention with more key bindings.

;; unlike gdb, pdb is a inbuilt python module
(setq gud-pdb-command-name "python -m pdb")

GUD is great but realgud much better, although you will miss gdb-multiple-windows but it does’nt work with pdb to begin with. If you ask why realgud here is some interesting rant from its developer.

(setq realgud:pdb-command-name "python -m pdb")

5.17 linter

I’m ashamed to say I haven’t used linter much before 2020. I accidentally found flymake working, as I can remember I had autopep8 recently in 2021. Since my lsp was already configure it started linting my code it was magical! 😀

I had kept my head under the sand, because its pain using self configured emacs and how a productive day goes to waste setting up your environment just right. Finally after to 2 days of I changed to flycheck as lsp recommended yet dealing with the virtual enivroment was frustrating which asked you to install flake8 in every environment.

(setq flycheck-check-syntax-automatically '(save))
In the realm of code, where tales go untold,
Amidst chaos, style's worth is shown.
Refuse temptation, resist the allure,
For clarity and understanding, endure.

Lost in the scroll, beyond limits surpassed,
Let reason guide, and doubts be outlast.
Expand horizons, with clarity set sail,
Embrace new paths, where beauty prevails.

5.17.1 flycheck-pos-tip

flycheck-pos-tip is the flycheck extension shows errors using pos-tip popup.

if you this with lsp extension mouse hover function would be overridden by lsp-ui.

(with-eval-after-load 'flycheck (flycheck-pos-tip-mode))

6 WEB

6.1 javascript

(add-to-list 'auto-mode-alist '("\\.mjs$" . js-mode))

6.2 lsp-support

(add-hook 'js-mode-hook #'lsp)
(add-hook 'css-mode-hook #'lsp)

6.2.1 lsp-typescript

For javascript typescript-language-server has been recommended by the wiki to install it in arch see AUR.

But it generates .log directory on project root which can be address by setting option to the server as mentioned in #1490 using configuration variables.

(setq lsp-clients-typescript-server-args '("--stdio" "--tsserver-log-file" "/dev/stderr"))

6.2.2 system-package

Naming seems to be different in Arch Official Packages 📦 and lsp-client, which lets lsp to not find executable.

typepackageslsp-mode/client
officialvscode-css-languageserverlsp-css.el
officialvscode-html-languageserverlsp-html.el

I seem there is no way to change the list on startup other than registering the new client to stop using npm.

(lsp-register-client
 (make-lsp-client :new-connection (lsp-stdio-connection (list "vscode-css-languageserver" "--stdio"))
                  :activation-fn (lsp-activate-on "css")
                  :server-id 'my-css-ls))

(lsp-register-client
 (make-lsp-client :new-connection (lsp-stdio-connection (list "vscode-css-languageserver" "--stdio"))
                  :activation-fn (lsp-activate-on "html")
                  :server-id 'my-html-ls))
  • <2022-03-23 Wed> runs on eval expression

    lsp couldn’t find the system binary if the change dependencies when kept in init file but ran on eval! 🤔

    (lsp-dependency
      'css-languageserver
      '(:system "vscode-css-languageserver"))
        

6.3 linter

6.3.1 flycheck

I mainly use eslint with flycheck.

(add-hook 'js-mode-hook 'flycheck-mode)

6.4 web-mode

web-mode is an autonomous emacs major-mode for editing web templates.

(require 'web-mode)
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))

(setq web-mode-enable-block-face t)
(setq web-mode-enable-current-column-highlight t)
(setq web-mode-style-padding 4)
(setq web-mode-script-padding 4)

;; they don't descend from prog-mode
(add-hook 'web-mode-hook (lambda () (run-hooks 'prog-mode-hook)))

;; ya-snippet completion for web-mode
(add-hook 'web-mode-hook #'(lambda () (yas-activate-extra-mode 'html-mode)))

6.4.1 template

djhtml is file format is for Django or Jinja template which works with mixed HTML, CSS and JS with template tags.

(add-to-list 'auto-mode-alist '("\\.djhtml?\\'" . web-mode))

Let lsp know djhtml is html.

(add-to-list 'lsp-language-id-configuration '(web-mode . "html"))

6.5 browser-refresh

There are stuff like moz-repl, skewer-mode, impatient-mode but nothing beats good old way with xdotool hail X11 for now! 😂

(require 'browser-refresh)
(setq browser-refresh-default-browser 'firefox)

above thingi comment, lets do Makefile!

WINDOW=$(shell xdotool search --onlyvisible --class chromium)
run:
	xdotool key --window ${WINDOW} 'F5'
    	xdotool windowactivate ${WINDOW}

7 PYTHON

Welcome to flying circus 🎪.

My python familiarity predates emacs, It definitely should have its own section by now (<2021-05-27 Thu>) but I strangely even after dabbling through py-exec, python configuration has been simplest for decades.

Recently I have been testing lsp for development it has never been better, countless hours wasted configuring code jumps using ggtags gives be nightmare which never worked out in practical sense .

(setq-default py-indent-offset 4)
(add-hook
 'python-mode-hook
 (lambda()
   (local-set-key (kbd "C-<") 'python-indent-shift-left)
   (local-set-key (kbd "C->") 'python-indent-shift-right)))

7.1 docstring

python-docstring is a package that overrides fill-paragraph so it is compatible with Python docstrings. It works for both sphinx-doc and re Structured text formats.

(add-hook
 'python-mode-hook
 (lambda ()
   (python-docstring-mode)
   (dim-minor-name 'python-docstring-mode "")))
  • <2022-03-01 Tue>

    not working as expected something is not correct

7.2 jedi

http://tkf.github.io/emacs-jedi/

Since python3.3 virtual environment can be created using python -m venv env without python-virtualenv.

(autoload 'jedi:setup "jedi" nil t)
(add-hook 'python-mode-hook 'jedi:setup)
(setq jedi:complete-on-dot t) ; optional

(setq jedi:environment-virtualenv "python -m venv")

(setq jedi:setup-keys t) ; optional

7.3 lsp

For python lsp looks for pyls and pylsp by default, I use using pyright which need extra emacs package lsp-pyright.

(add-hook
 'python-mode-hook
 (lambda()
   (when (not (derived-mode-p 'scons-mode))
     (lsp))))
  • <2020-10-14 Wed>

    /usr/lib/python3.8/site-packages/pyls/uris.py:110 path = path if isinstance(path, str) else path.as_posix()

  • <2020-09-24 Thu>

    python-jedi 0.17.2 in system, lsp works without AUR

  • <2020-08-25 Tue>

    buggy python-jedi 17.0. Needed manually editing in path variable setting as .as_posix() or use yaourt -S python-jedi-git

7.4 venv

Yes! we work on virtual environment (venv), and we do love to source them, who can’t seems to get things strait especially in unix systems.

In reality venv just switches executable, seriously loading venv might be sane for terminal operation or running errands with pip. but for running just execute directly form ./venv/bin/python your.py.

Damn don’t try to solve artificial problems! so goes for idiotic venv modes trying to find venv folder.

Yet for emacs environment using lsp and console this might only option! yeah I’m eating on my own words bite me! but seriously all env packages gives me creeps.

to check if which venv is activated (getenv "VIRTUAL_ENV")

(defun pyvenv-autoload ()
     (interactive)
     "auto activate venv directory if exists"
     (require 'pyvenv)
     (f-traverse-upwards (lambda (path)
         (let ((venv-path (f-expand "venv" path)))
         (when (f-exists? venv-path)
         (pyvenv-activate venv-path))))))

(add-hook 'python-mode-hook 'pyvenv-autoload)

7.5 linter

Go beyond pycodestyle (PEP8) here is my config using flake8.

(add-hook 'python-mode-hook 'flycheck-mode)

;; append the default config for fallback
(add-to-list 'flycheck-flake8rc "~/.config/flake8" t)
(setq flycheck-python-flake8-executable "/usr/bin/flake8") ;; skip venv

;; (setq flycheck-disabled-checkers '(python-pylint))
(setq flycheck-python-pylint-executable "/usr/bin/python") ;; skip venv

;; (setq flycheck-python-complie-executable "/usr/bin/python") ;; skip venv

flake8 is suported by lsp which can be enable via (setq lsp-pyls-plugins-flake8-enabled t)

flycheck allows multiple checker which can be enabled with or by verify setup UI.

(flycheck-add-next-checker 'python-flake8 'python-pyright)

7.6 py-exec

py-exec is ess-style execution for python script.

(add-to-list 'load-path "~/.config/emacs/00testing/py-exec/")
(add-hook
 (require 'py-exec)
 'python-mode-hook
 (lambda() (local-set-key (kbd "<C-return>") 'py-execution)))

7.7 scons

If any one had created the Makefile in this day an age, it would definitely should be considered as 😖 crime. Make came out in 1976 and did more that what it promised to do now it has started showing the age. Many of complex projects are still handled by the Make which is shows the robustness of the system but its excruciatingly difficult to wrap you head around it. Now days Makefile is mostly the vomit 🤮 of automake which I find absolutely ridiculous.

After years of ignorance and pain staking writing Makefile I have to hang the 🏳️ white flag. Its worst than elisp which has at least documentation you don’t wander around searching how to do the simplest task . At times it made me think why not replace it with bash script! but make was built to replace bash script, do you sense the conundrum.

The SCons Github wiki has an in-depth explanation about why Make comes up short. But if some one told me it was written in 🐍 python I would have been sold in first palace, Let see where it leads to.

(setq compile-command "/usr/bin/python /usr/bin/scons")

(define-derived-mode scons-mode python-mode "scons"
  "A python-mode for scons files")

(add-to-list 'auto-mode-alist '("SConstruct" . scons-mode))
(add-to-list 'auto-mode-alist '("SConscript" . scons-mode))

8 ORG-MODE

org-mode introduces to the you to different world, which makes it distinct. All but one complain is it throws the normal convention out of the window (just remember emacs has worst defaults)!

removing the C-j bind for goto-last-change

(add-hook
 'org-mode-hook
 (lambda () ; used for (goto-last-change)
   (define-key org-mode-map (kbd "C-j") nil)))

(setq org-adapt-indentation t) ; edit structure (indent content also)
(setq org-support-shift-select t) ; enable text-selection when possible
(add-hook 'org-mode-hook 'lambda() (require 'org-mouse))

(setq sentence-end-double-space nil)
(add-hook 'org-mode-hook 'flyspell-mode)

8.1 auto-fill

auto-fill-mode is named by auto-fill-function via magnars.

(dim-minor-name 'auto-fill-function "")
(add-hook 'org-mode-hook 'turn-on-auto-fill)
  • <2020-02-01 Sat>

    problem with emacs 26 this see spacemacs issue

8.2 babel

active Babel languages

(org-babel-do-load-languages 'org-babel-load-languages
    '((shell . t)
      (sql . t)
      (js . t)
      (C . t)
      ;; (rust . t)
      ;; (ipython . t)  ; uses cl, install ob-ipython
      (python . t)))

;; (add-hook 'org-babel-after-execute-hook 'org-display-inline-images 'append)
(add-to-list 'org-babel-default-header-args
             '(:noweb . "yes")
             '(:eval . "no-export"))

switch the python location command set Local Variables org-babel-python-command: "/usr/bin/python2"

  • <2018-05-30>

    26 is official again sh should be shell

  • <2018-01-04> sh mode

    Currently babel code execution doesn’t work, haven’t found the work around yet, so downgraded emacs from 26 -> 25, couldn’t track what was the last working snapshot.

    running in to problem recently sh is now shell, or will cause ob-sh not found error.

8.3 default applications

Its most 😞 disappointing when application opens doesn’t open in your favorite application, but org-mode has it covered 😭.

(add-hook
 'org-mode-hook
 '(lambda()
    (setq org-file-apps
          '((auto-mode . emacs)
            ("\\.jpg\\'" . "eog %s")
            ("\\.svg\\'" . "ristretto %s")
            ("\\.png\\'" . "eog %s")
            ("\\.gif\\'" . "eog %s")
            ("\\.mkv\\'" . "mplayer %s")
            ("\\.mp4\\'" . "vlc %s")
            ("\\.webm\\'" . "mplayer %s")
            ("\\.html\\'" . "firefox %s")
            ("\\.pdf\\'" . "evince %s")))))

8.4 latex

fragtog mode automatically toggle Org mode LaTeX fragment previews as the cursor enters and exits them.

(add-hook 'org-mode-hook 'org-fragtog-mode)

based on zoom latex fragments relative to buffer text

(plist-put org-format-latex-options :scale 2.5)
;; (setq org-format-latex-options (plist-put org-format-latex-options :scale 1.8))
(defun update-org-latex-fragments ()
  (org-toggle-latex-fragment '(16))
  (plist-put org-format-latex-options :scale text-scale-mode-amount)
  (org-toggle-latex-fragment '(16)))

(add-hook 'org-mode-hook (lambda()
                           (add-hook 'text-scale-mode-hook 'update-org-latex-fragments)))

8.5 html export

(setq
    org-html-allow-name-attribute-in-anchors t
    org-html-doctype "html5"
    org-html-validation-link nil
    org-html-checkbox-type 'html)

Add dot after headline

https://yoo2080.wordpress.com/2013/08/24/changing-the-number-format-for-section-headings-in-org-mode-html-export/

(defun my-html-filter-headline-yesdot (text backend info)
  "Ensure dots in headlines."
  (when (org-export-derived-backend-p backend 'html)
    (save-match-data
      (when (let ((case-fold-search t))
              (string-match (rx (group "<span class=\"section-number-" (+ (char digit)) "\">"
                                       (+ (char digit ".")))
                                (group "</span>"))
                            text))
        (replace-match "\\1.\\2" t nil text)))))

(eval-after-load 'ox
  '(progn
     (add-to-list 'org-export-filter-headline-functions
                  'my-html-filter-headline-yesdot)))

custom exporter for checkbox as suggest by John Kitchin.

8.6 minor-mode

org-mode can be addictive, someone have missed a lot and created these awesome modes. Now we can use them minor-modes too inside comments.

org’s outline with outshine extension.

(require 'outshine)

(add-hook 'prog-mode-hook 'outline-minor-mode)
(add-hook 'compilation-mode-hook 'outline-minor-mode)

(add-hook 'outline-minor-mode-hook 'outshine-mode)
(add-hook
 'outline-minor-mode-hook
 '(lambda()
    (dim-minor-name 'outshine-mode "")
    (dim-minor-name 'outline-minor-mode "")

    (global-unset-key (kbd "<M-right>"))
    (local-set-key (kbd "<M-right>") 'outline-promote)
    (global-unset-key (kbd "<M-left>"))
    (local-set-key (kbd "<M-left>") 'outline-demote)
    (local-set-key (kbd "C-<iso-lefttab>") 'outshine-cycle-buffer)))

for links you need orglink is available in MELPA.

(add-hook
 'prog-mode-hook
 (lambda()
   (orglink-mode)
   (dim-minor-name 'orglink-mode "")))
  • <2022-02-27 Sun>

    Warning (emacs): ‘outshine-hook-function’ has been deprecated, use ‘outshine-mode’ Disable showing Disable logging

8.7 reveal.js

Making power-point is lame, and updating is the mess! there is the thing call reveal.js The HTML Presentation Framework which lets you make slides in browser but, its more of HTML than the actual content, *org-reveal take the next step generate the slides from the org-file, isn’t that neat!

org-re-reveal is the fork of yjwen/org-reveal with enhancement

(add-hook 'org-mode-hook '(lambda ()
  (require 'org-re-reveal)))

(setq
    org-re-reveal-root "~/Public/vendors/reveal.js"
    org-re-reveal-extra-css "~/Public/vendors/reveal.js/override.css"
    org-re-reveal-mathjax-url "~/Public/vendors/MathJax/es5/tex-mml-chtml.js"
    org-re-reveal-theme "night")

8.8 theme

(set-face-attribute 'default nil :family "Andale Mono" )
(custom-set-faces
  '(org-level-1 ((t (:family "Iosevka" :height 150))))
  '(org-level-2 ((t (:family "Fira Mono for Powerline" :height 120))))

  '(org-block-begin-line ((t (:foreground "#008EA1"))))
  '(org-block ((t (:family "Source Code Pro" :background "#244"))))
  '(org-block-end-line ((t (:foreground "#008EA1"))))

  '(org-table ((t (:background "#244"))))
  '(org-quote ((t (:foreground "#E6E6FA" :background "#244"))))
  '(org-verse ((t (:foreground "#E6E6FA" :background "#244"))))
)

9 MODES

9.1 C/C++

http://www.gnu.org/software/emacs/manual/html_mono/ccmode.html

(setq c-tab-always-indent t)
(setq c-basic-offset 4)
(setq c-indent-level 4)
(setq gdb-many-windows t)
(setq gdb-show-main t)

styling

https://www.emacswiki.org/emacs/IndentingC

(require 'cc-mode)
(c-set-offset 'substatement-open 0)
(c-set-offset 'arglist-intro '+)
(add-hook 'c-mode-common-hook '(lambda() (c-toggle-hungry-state 1)))
(define-key c-mode-base-map (kbd "RET") 'newline-and-indent)

9.2 rust

https://github.com/rust-lang/rust-mode

ob-rust for org mode

(add-hook
 'rust-mode-hook
 (lambda ()
   (require 'rust-mode)
   (setq indent-tabs-mode nil)))

;; (setq rust-format-on-save t) ; needs rustfmt

9.3 sql

https://www.emacswiki.org/emacs/SqlMode

Starting with version 21.4, sql-mode included with emacs

to start interactive mode

M-x sql-product-interactive

9.3.1 Automatically upcase SQL keywords

https://www.emacswiki.org/emacs/download/sql-upcase.el

See also http://stackoverflow.com/q/22091936/324105

(when (require 'sql-upcase nil :noerror)
  (add-hook 'sql-mode-hook 'sql-upcase-mode)
  (add-hook 'sql-interactive-mode-hook 'sql-upcase-mode))

9.4 conf

(add-hook 'conf-mode-hook 'nlinum-mode)

9.5 systemd

(add-to-list 'auto-mode-alist '("\\.service" . systemd-mode))
(add-hook 'systemd-mode-hook 'company-mode)

9.6 dockerfile

Goodies for 🐳 🐳 🐳

(require 'dockerfile-mode)
(add-to-list 'auto-mode-alist '("Dockerfile" . dockerfile-mode))

9.7 json

(setq auto-mode-alist
   (cons '("\.json$" . json-mode) auto-mode-alist))

9.8 latex

(add-hook 'latex-mode-hook (lambda ()
  (nlinum-mode)
  (drag-stuff-mode-rho-bindings)
  (toggle-truncate-lines +1)))

9.9 yasnippet

yasnippet is template system for emacs, snippet collection in distributed separately as yasnippet-snippet.

(require 'yasnippet)
(require 'yasnippet-snippets)
(yas-reload-all)
(add-hook 'prog-mode-hook 'yas-minor-mode-on)
(add-hook 'org-mode-hook 'yas-minor-mode-on)

10 WORDPLAY

wordplay consist of collection of nifty scripts.

(load "~/.config/emacs/scripts/wordplay.el")

Normally C-a will move your cursor to 0th column of the line, this snippet takes consideration of the indentation, and for default behavior “repeat the action” which will toggle between the first non-whitespace character and the bol.

(global-set-key [remap move-beginning-of-line]
            'smarter-move-beginning-of-line)

By default, you can use M-c to change the case of a character at the cursor’s position. This also jumps you to the end of the word. However it is far more useful to define a new function by adding the following code to your emacs config file. Once you have done this, M-c will cycle through “all lower case”, “Initial Capitals”, and “ALL CAPS” for the word at the cursor position, or the selected text if a region is highlighted.

(global-set-key "\M-c" 'toggle-letter-case)

10.3 duplicate lines/words

(global-set-key (kbd "C-`") 'duplicate-current-line)
(global-set-key (kbd "C-~") 'duplicate-current-word)

10.4 on point line copy

only enable for C-<insert>

(global-set-key (kbd "C-<insert>") 'kill-ring-save-current-line)

11 META