2

moving point command: next-line, previous-line, forward-char, backward-char, etc.

How to omit Ctrl key in read-only-mode?

How can I combine with read-only-mode-hook to automatically enable keybind when opening a file with read-only permissions?

dongli si
  • 63
  • 8
  • Here is an example written Anton Johansson: by https://github.com/antonj/.emacs.d/blob/master/aj/aj-read-only-keymap-hooks.el . Calling `toggle-read-only` will trigger his modifications assuming they have been evaluated prior thereto. Inasmuch as I knew what to look for after typing `M-x find-function RET read-only-mode` and perusing the code in `simple.el`, I Googled: **emacs "read-only-mode" keymap**. The link mentioned in this comment was just the first search result, so feel free to look at other results. – lawlist Sep 18 '19 at 21:41
  • @lawlist The method of using Anton Johansson is not convenient. When opening a read-only buffer, you need to execute the `M-x toggle-read-only RET` keybind twice to take effect. And `toggle-read-only` is obsolete and should be replaced with `read-only-mode`. – dongli si Sep 18 '19 at 23:13
  • As you become more proficient in Emacs, you can find examples that do things similar to what you want, and then you can modify them to suit your needs. I realize you are just starting out and this might seem daunting, but seeing what makes it tick and trying out new things is often a helpful learning experience. Sometimes you will get lucky and find something exactly on-point, but more often than not, you may need to create a custom solution that best suits your needs for a given project. – lawlist Sep 19 '19 at 03:24

1 Answers1

2

The following minor-mode wo-ctrl-c-mode frees all active keybindings from the control modifier insofar there are no other modifiers such as meta or shift and the resulting key-binding is not already occupied.

That minor mode is activated along with read-only-mode and when opening files without write-permission with find-file.

At least in Emacs 26.2 one needs to treat find-file separately since that function (more exactly find-file-noselect) sets the buffer-read-only flag directly and not through the function read-only-mode.

(defun wo-ctrl-c-map ()
  "Return a keymap freeing keys from control-modifier."
  (let ((newmap (make-sparse-keymap)))
    (mapc
     (lambda (map)
       (map-keymap
        (lambda (event binding)
          (let ((basic-event (vector (event-basic-type event))))
            (when (and (equal (event-modifiers event) '(control))
                       (equal (key-binding basic-event) #'self-insert-command)
                       (null (lookup-key newmap basic-event)))
              (define-key newmap basic-event binding))))
        map))
     (current-active-maps))
    newmap))

(defvar-local wo-ctrl-c-mode-active nil
  "If `wo-ctrl-c-mode' is active it sets this variable to a non-nil value.
This is a protection against consecutive calls of (wo-ctrl-c-mode 1).
The value is actually a list containing the original local map as element.")

(define-minor-mode wo-ctrl-c-mode
  "Bind all keys with control modifier also directly."
  :lighter " α"
  (if wo-ctrl-c-mode
      (unless wo-ctrl-c-mode-active ;;< protection against two consecutive calls of (wo-ctrl-c-mode 1)
    (setq wo-ctrl-c-mode-active (list (current-local-map)))
    (let ((map (wo-ctrl-c-map)))
      (set-keymap-parent map (car wo-ctrl-c-mode-active))
      (use-local-map map)))
    (when wo-ctrl-c-mode-active
      (use-local-map (car wo-ctrl-c-mode-active))
      (setq wo-ctrl-c-mode-active nil))))

(defun wo-ctrl-c-when-read-only ()
  "Activate `wo-ctrl-c-mode' when buffer is read-only."
  (if buffer-read-only
      (wo-ctrl-c-mode)
    (wo-ctrl-c-mode -1)))

(add-hook 'read-only-mode-hook #'wo-ctrl-c-when-read-only)

;; `find-file-noselect' sets `buffer-read-only' directly:
(add-hook 'find-file-hook #'wo-ctrl-c-when-read-only)

Tested with
emacs-version: GNU Emacs 26.2 (build 2, i686-pc-linux-gnu, GTK+ Version 3.22.30) of 2019-04-12

Tobias
  • 32,569
  • 1
  • 34
  • 75
  • eval your lisp , result is "Wrong type argument: listp, wo-ctrl-c-map" – dongli si Sep 21 '19 at 08:54
  • @donglisi Sorry about that. I added the quote at `'(wo-ctrl-c-mode)` afterwards. When I tested it again `wo-ctrl-c-mode-map` was already defined, the `:keymap` expression was not evaluated, and this caused the test to be wrongly positive. (I should have tested with a newly started `emacs -Q` instance). I've re-worked the solution such that it does not use the minor mode map but the local keymap. That improves using the minor mode for multiple buffers in `read-only-mode`. If one switches off `wo-ctrl-c-mode` the original local mode map is restored. – Tobias Sep 21 '19 at 22:45