mos emacs howtos

Table of Contents

1. mo-emacs-config

Ok, so this is my emacs config wiki

1.1. keyboard layout

Ok, you need a usable keyboard layout. This means, the caps lock key has to instead send a ctrl.

Also I want the german and us layout switchable with win+space.

1.1.1. debian

/etc/default/keyboard

XKBMODEL="pc105"
XKBLAYOUT="de,us"
XKBVARIANT=""
XKBOPTIONS="ctrl:nocaps,grp:win_space_toggle,grp_led:scroll"

BACKSPACE="guess"

grp_led:scroll makes a layout indicator out of the the scroll lock led.

1.1.2. other distros

see setxkbmap

setxkbmap -layout us,de -option win_space_toggle,grp_led:scroll -v

1.2. Keybindings/Prefix keys

I use a us keyboard layout, so C-= is nicely reachable and a suitable prefix key.

On a terminal using putty, sadly, C-= doesn't work, so I use <f12> instead. <f5> is free, too. <f9> I use for "compiling" or similar stuff. (that was the binding in turbo-c and still seems to be used by some IDEs).

1.2.1. Some of the bindings

(global-set-key (kbd "C-= d") 'find-name-dired)
(global-set-key (kbd "C-= l") 'find-lisp-find-dired)
(global-set-key (kbd "C-= g") 'find-grep-dired)  ;;  or find-grep.

;; to complete filenames everywhere
(global-set-key (kbd "C-= TAB") 'term-dynamic-complete-filename)

1.3. recent-files

;; recent files
(recentf-mode)
(global-set-key (kbd "C-= f") 'recentf-open-files)

1.4. emacs server

start a server if there isn't already one running:

(require 'server)
(unless (and (fboundp #'server-running-p) (server-running-p))
  (server-start))

1.4.1. Troubleshooting

  1. emacsclient - socket

    You normally should not need this but if emacsclient doesn't find the emacs server read this:

    the server creates a unix domain socket. you can find out where by C-h v server-socket-dir

    sadly emacsclient doesn't use a config file to look up the server-socket-dir, you can only specify it on the command line:

    emacsclient --socket-name=/<somedir>/server <file>
    

    You can alias emacsclient with this socket name if it doesn't seem to change.

1.5. my multiple cursors shortcuts

I think MCs are cool but I don't use them much. I neither pretend these are the best bindings nor do I claim completeness.

If you're in a terminal check what key is sent by the key combination. I think it was C-^ instead of C-". Adjust accordingly.

;; multiple cursors
(global-set-key (kbd "C-\" a") 'mc/mark-all-like-this-dwim)
(global-set-key (kbd "C-\" l") 'mc/mark-next-lines)
(global-set-key (kbd "C-\" m") 'mc/mark-next-like-this)
(global-set-key (kbd "C-\" s") 'mc/mark-next-like-this-symbol)
(global-set-key (kbd "C-\" w") 'mc/mark-next-like-this-word)
(global-set-key (kbd "C-\" r") 'mc/mark-all-in-region)
(global-set-key (kbd "C-\" R") 'mc/mark-all-in-region-regexp)

1.6. flymake

1.6.1. json (new version)

1.6.2. toml

(load "~/.emacs.d/tomlcheck.el")
(add-hook 'conf-toml-mode-hook 'flymake-tomlcheck-setup)
(add-hook 'conf-toml-mode-hook 'flymake-mode)
(add-hook 'conf-toml-mode-hook 'trailing-whitespace-mode)

;; if you want to add this automatically to .conf.j2 files
(add-to-list 'auto-mode-alist '("\\.conf\\.j2\\'" . conf-toml-mode))
  1. tomlcheck.el
    ;;; flymake-tomlcheck.el --- TOML linter with tomlcheck  -*- lexical-binding: t; -*-
    
    ;; replace /PATH/TO/TOMLCHECK.PY with actual path to tomlcheck.py
    ;; the contents should be:
    
    ;;;;;;;;;;;; tomlcheck.py
    ;; #!/usr/bin/env python3
    ;; # usage: python3 tomlcheck.py < something.toml
    ;; # pip3 install --user toml
    
    ;; # emacs regex:  "^\\(?3:[^(]*\\)(line \\(?1:[0-9]+\\) column \\(?2:[0-9]+\\) char [0-9]+)$"
    ;; # (match-string 1) = line, (match-string 2) = col, (match-string 3) = msg
    
    ;; import sys
    ;; import toml
    
    ;; try:
    ;;     toml.load(sys.stdin)
    ;; except Exception as e:
    ;;     print(e)
    ;;;;;;;;;;;;;;;;;;
    
    (require 'flymake)
    
    (defgroup flymake-tomlcheck nil
      "Tomlcheck backend for Flymake."
      :prefix "flymake-tomlcheck-"
      :group 'tools)
    
    (defcustom flymake-tomlcheck-arguments
      nil
      "A list of strings to pass to the tomlcheck program as arguments."
      :type '(repeat (string :tag "Argument")))
    
    (defvar-local flymake-tomlcheck--proc nil)
    
    (defun flymake-tomlcheck (report-fn &rest _args)
      "Flymake backend for tomlcheck report using REPORT-FN."
      (when (process-live-p flymake-tomlcheck--proc)
        (kill-process flymake-tomlcheck--proc)
        (setq flymake-tomlcheck--proc nil))
      (let ((source (current-buffer)))
        (save-restriction
          (widen)
          (setq
           flymake-tomlcheck--proc
           (make-process
            :name "flymake-tomlcheck" :noquery t :connection-type 'pipe
            :buffer (generate-new-buffer " *flymake-tomlcheck*")
            :command `("/usr/bin/python" "/PATH/TO/TOMLCHECK.PY")
            :sentinel
            (lambda (proc _event)
              (when (eq 'exit (process-status proc))
                (unwind-protect
                    (if (with-current-buffer source (eq proc flymake-tomlcheck--proc))
                        (with-current-buffer (process-buffer proc)
                          (goto-char (point-min))
                          (let ((diags))
                            (while (search-forward-regexp "^\\(?3:[^(]*\\)(line \\(?1:[0-9]+\\) column \\(?2:[0-9]+\\) char [0-9]+)$" nil t)
                              (let ((region (flymake-diag-region source (string-to-number (match-string 1)) (string-to-number (match-string 2))))
                                    (error-type (match-string 3)))
                                ;; expect `region' to only have 2 values (start . end)
                                (when (and (car region) (cdr region))
                                  (push (flymake-make-diagnostic source
                                                                 (car region)
                                                                 (cdr region)
                                                                 :error
                                                                 (match-string 3))
                                        diags))))
                            (funcall report-fn (reverse diags))))
                      (flymake-log :warning "Canceling obsolete check %s"
                                   proc))
                  (kill-buffer (process-buffer proc)))))))
          (process-send-region flymake-tomlcheck--proc (point-min) (point-max))
          (process-send-eof flymake-tomlcheck--proc))))
    
    ;;;###autoload
    (defun flymake-tomlcheck-setup ()
      "Enable tomlcheck flymake backend."
      (make-variable-buffer-local 'flymake-diagnostic-functions)
      (add-hook 'flymake-diagnostic-functions #'flymake-tomlcheck nil t))
    
    (provide 'flymake-tomlcheck)
    ;;; flymake-tomlcheck.el ends here
    

1.6.3. yaml

(load "~/.emacs.d/flymake-yamllint.el")
(add-hook 'yaml-mode-hook 'flymake-yamllint-setup)
(add-hook 'yaml-mode-hook 'flymake-mode)
(add-hook 'yaml-mode-hook 'trailing-whitespace-mode)

https://github.com/shaohme/flymake-yamllint

1.7. ide stuff, languages

For flymaker, see 1.6

1.7.1. python

;;;;;;;; python
(require 'auto-complete)
(require 'jedi)
;; these seem to be neccessary because of GUI/CUI, idk.
(define-key jedi-mode-map (kbd "C-c <tab>") 'jedi:complete)
(define-key jedi-mode-map (kbd "C-c TAB") 'jedi:complete)
(add-hook 'python-mode-hook 'jedi:setup)
(add-hook 'python-mode-hook (lambda () (interactive) (setq header-line-format "C-c TAB:complete | M-\":describe function | C-c ?:python doc")))

;; don't show this when idle. Don't do anything if I don't ask you!
;; M-" to show info. (how it is shown: defined in customize)
;; this is a monkey patch. may break with a new emacs version (currently working: 28.2)
(defun jedi:get-in-function-call-when-idle () ())
(define-key jedi-mode-map (kbd "M-\"") 'jedi:get-in-function-call)

1.7.2. Golang

;; golang
(add-hook 'go-mode-hook #'eglot-ensure)

1.8. show git branch in modeline

(defun mo-term-git-mode--get-branch ()
  ;;(vc-call-backend 'git 'mode-line-string ".") ; doesn't work
  ;;(let ((branches (vc-git-branches)))
  (let ((branches (vc-call-backend 'git 'branches)))
    (when branches (car branches))))

(define-minor-mode mo-term-git-mode
  "show current branch in modeline in terminal-modes"
  :lighter (:eval (let ((git-branch (mo-term-git-mode--get-branch)))
                    (if git-branch
                        (format " git:%s" git-branch)
                      ""))))

(add-hook 'term-mode-hook 'mo-term-git-mode)

1.9. TODO ement.el (matrix client)

1.10. Random stuff

1.10.1. align-regexp shouldn't use tabs

;; stolen from https://stackoverflow.com/questions/22710040/emacs-align-regexp-with-spaces-instead-of-tabs
(defadvice align-regexp (around align-regexp-with-spaces activate)
  (let ((indent-tabs-mode nil))
    ad-do-it))

1.11. misc troubleshooting

  1. hanging xterm paste (also in putty)
    ;; in 27.2 ansi-term and some modification of xterm-paste don't work together so good
    ;; (results in a hang which you can only get out of by ^G
    ;; this solves it
    (require 'term) ;; so this gets not overwritten the wrong way round
    (defun term--xterm-paste (ev)
      "Insert the text pasted in an XTerm bracketed paste operation."
      (interactive "e")
      (term-send-raw-string (cadr ev)))
    

2. HOWTOs

2.1. Fonts

2.1.1. default font

emacs::fonts

From the emacs docs:

Add a line to your init file, modifying the variable `default-frame-alist' to specify the `font' parameter (*note Frame Parameters::), like this:

(add-to-list 'default-frame-alist '(font . "DejaVu Sans Mono-10"))

2.1.2. how to let emacs find a font for you

customize-face expects from you that you know the name and all parameters of a font. When I wasn't using GTK I found this hard. I found this way:

Use describe-font which give you an auto-complete in the minibuffer which let's you look for and complete your font name. Kill the complete font name.

Use set-face-font to set the font for the face you want to change.

After this, use customize-font to open a customize buffer which is prefilled with the font you set with set-face-font and allows you to save to your ~/.emacs.

2.1.3. troubleshooting

Sometimes emacs loses the fonts you define. That seems to happen with incompatible themes which redefine them. deinstall those themes and redefine your fonts.

Sometimes there seems to be a face lookup which results in a hangup and the message that the face "undefined" can't be found. This usually can't be fixed with a restart. This, too, was caused by a faulty theme. Grep your ~/.emacs for undefined, remove that particular piece of configuration, remove the fauly theme and restart your emacs.

2.2. How to build an input method

I built one. See here: quail classic german

2.3. Ansi-Term

2.3.1. pasting

There is a function called term-paste, but it is bound to S-insert by default. Who wants that? Use

(require 'term)
(define-key term-raw-map (kbd "C-c y") 'term-paste)
(define-key term-raw-map (kbd "C-c C-y") 'term-paste)

to rebind it to C-c C-y

2.3.2. tmacs

To conveniently open files from terminal even on remote machines, I use tmacswrap

You can define a function to quickly open a tmacs-term with

(defun tmacs--find-free-number ()
  "use this function to create a reasonable buffer name"
  (cl-do ((num 0 (+ 1 num)))
      ((not (get-buffer (format "*tmacs<%s>*" num)))
       num)))

(defun tmacs ()
  (interactive)
  (ansi-term "/bin/bash" (format "tmacs<%s>" (tmacs--find-free-number))))

and then open it with M-x tmacs.

2.3.3. emacsclient

Add to your ~/.bashrc:

if [ -n "$INSIDE_EMACS" ]; then
    export VISUAL=emacsclient   # use tmacs here, if you want
    export EDITOR=$VISUAL
fi  

Don't use emacsclient -n because that would confuse programs like git when you edit your commit messages with this.

2.3.4. Forbid TRAMP to ask for password

It may be a problem if one mistypes on a password prompt in tramp, because emacs might lock up your account if there is a limit of unsuccessful logins.

  • tell ssh to not ask for password
  • override tramp function to ask for password and error out.
;; ~/.emacs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; tramp
(setq tramp-ssh-controlmaster-options "-o PasswordAuthentication=no")

;; don't ever ask for passwords!
;; TODO: implement as advice
(defun tramp-read-passwd (proc &optional prompt)
  (message "Tramp tries to ask for password, inhibiting")
  (error "Tramp tried to ask for password")) ;; just fail

To allow emacs to TRAMP somewhere, nonetheless, use a controlmaster connection

# ~/.ssh/config

# use this, if you have a domain. Else something might not work when using shortnames 
# CanonicalizeHostname yes
# CanonicalDomains my.domain.com

host *
    ControlMaster auto
    ControlPath ~/.ssh/control/%C
    ControlPersist 15m

2.3.5. troubleshooting

  1. slow scrolling (emacs 26.1 has this problem)

    In older emacs versions ansi-term was allegedly very slow clearing the screen. In version 26.1 the problem seems to be fixed, but still triggered in a different way: Scrolling fast, if the terminal buffer is already full. I solved this problem by using this1

    ;; Terminal buffer configuration.
    (add-hook 'term-mode-hook 'my-term-mode-hook)
    (defun my-term-mode-hook ()
      ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20611
      (setq bidi-paragraph-direction 'left-to-right))  
    
  2. terminal resizing (emacs 26.1 has this problem)

    Resizing the terminal in which emacs runs doesn't inform inferior terminals that they should be resized, too. Use this2:

    (add-hook 'window-configuration-change-hook (lambda (frame) (window--adjust-process-windows)))
    

Footnotes:

Author: mokrates

Created: 2024-08-01 Do 23:19

Validate