1

I am writing a feature that changes the displaying of certain words as is done in texinfo-mode, where greek syntax \alpha is displayed as the actual greek symbol α. The implementation uses prettify-symbols-mode.

Have seen that texinfo-mode uses ("\\alpha" . ?α). Not sure about the purpose of ?, and whether I would need to employ the ? for my word replacement feature.

A problem that I have encountered is that when the word little gets displayed as the two-letter word ll, both letters get inserted at the same point, such that the user only sees a single letter l.

    (defvar wrepl
      '(
         ("all" . "l")     ("as" . "as")      ("can" . "k")
         ("do" . "do")     ("for" . "f")      ("in" . "n")
         ("is" . "s")      ("it" . "t")       ("know" . "no")
         ("like" . "lk")   ("little" . "ll")  ("more" . "mo")
         ("some" . "so")   ("than" . "n")     ("that" . "ta")
         ("there" . "tr")  ("this" . "th")    ("time" . "ti")
         ("to" . "to")     ("we" . "w")       ("well" . "l")
         ("will" . "l")    ("work" . "wk")    ("you" . "u")
      "Replacements for specific words.")
dalanicolai
  • 6,108
  • 7
  • 23
Dilna
  • 1,173
  • 3
  • 10
  • How are you planning to use it? – NickD Apr 19 '22 at 22:15
  • The plan is to use `prettify-symbols`. – Dilna Apr 19 '22 at 22:16
  • `?` is emacs lisp syntax for characters. See the [elisp manual](https://www.gnu.org/software/emacs/manual/html_node/elisp/Basic-Char-Syntax.html). – NickD Apr 19 '22 at 22:17
  • Please add all explanatory stuff to the question: it has to stand on its own even if the comments disappear. – NickD Apr 19 '22 at 22:18
  • It is still unclear what you are trying to do and, more importantly, why. Among other things, it is unclear whether you want text to be replaced, in which case `prettify-symbols` is the wrong tool, or you want overlays to change the appearance of the unchanged text, in which case `prettify-symbols` *may* be appropriate. Please give real-world usage before-and-after examples. – Phil Hudson Apr 20 '22 at 08:16
  • I want the appearance to remain unchanged. `texinfo-mode` has the convenient ability to replace things like `\alpha` to the greek letter. With a keybinding press a user can switch between the original texinfo code `\alpha` and the greek symbol, leaving the texinfo code intact. I want to do implement a similar feature for use as a stenographic practice session. The user would be able to see the stenographic output on practice text. – Dilna Apr 20 '22 at 11:26

1 Answers1

2

As commented below already, I am not aware of any feature that provides this functionality out of the box. However, while looking at prettify-symbols-mode to look for an alternative, it looked like adapting it to achieve what you ask for, would not be so much work.

So here is the code for steno-mode, an adaption of prettify-symbols-mode that uses the display text property instead of the compose text property:

(setq steno-list '(("all" . "l")     ("as" . "as")      ("can" . "k")
                  ("do" . "do")     ("for" . "f")      ("in" . "n")
                  ("is" . "s")      ("it" . "t")       ("know" . "no")
                  ("like" . "lk")   ("little" . "ll")  ("more" . "mo")
                  ("some" . "so")   ("than" . "n")     ("that" . "ta")
                  ("there" . "tr")  ("this" . "th")    ("time" . "ti")
                  ("to" . "to")     ("we" . "w")       ("well" . "l")
                  ("will" . "l")    ("work" . "wk")    ("you" . "u")))


;; adapted from `prettify-symbols--compose-symbol'
(defun steno--display-symbol (alist)
  "Add paired string as display property to relevant regions"
  ;; Check that the chars should really be composed into a symbol.
  (let ((start (match-beginning 0))
        (end (match-end 0))
        (match (match-string 0)))
    (if (and (not (equal prettify-symbols--current-symbol-bounds (list start end)))
             (funcall prettify-symbols-compose-predicate start end match))
        (with-silent-modifications
          (add-text-properties
           start end
           `(steno-start ,start steno-end ,end display ,(cdr (assoc match alist)))))
      (remove-list-of-text-properties start end
                                      '(steno-start
                                        steno-end
                                        display))))
  ;; Return nil because we're not adding any face property.
  nil)

(defun steno--make-keywords ()
  (interactive)
  `((,(regexp-opt (mapcar 'car steno-list) t)
     (0 (steno--display-symbol ',steno-list)))))

(defvar-local steno--keywords nil)

(define-minor-mode steno-mode
  "Toggle Steno mode.

When Steno mode and font-locking are enabled, symbols are
prettified according to the rules in
`steno-alist' (which see), which are locally defined
by major modes supporting prettifying. To add further
customizations for a given major mode, you can modify
`steno-alist' thus:

  (add-hook \\='emacs-lisp-mode-hook
            (lambda ()
              (push \\='(\"<=\" . ?≤) steno-alist)))

You can enable this mode locally in desired buffers, or use
`global-steno-mode' to enable it for all modes that
support it."
  :init-value nil
  (when steno--keywords
    (font-lock-remove-keywords nil steno--keywords)
    (setq steno--keywords nil))
  (if steno-mode
      ;; Turn on
      (when (setq steno--keywords (steno--make-keywords))
        (font-lock-add-keywords nil steno--keywords)
        (when prettify-symbols-unprettify-at-point
          (add-hook 'post-command-hook
                    #'prettify-symbols--post-command-hook nil t))
        (font-lock-flush))
    ;; Turn off
    (remove-hook 'post-command-hook #'prettify-symbols--post-command-hook t)
    (with-silent-modifications
      (remove-text-properties (point-min) (point-max) '(display nil)))))

Use it like how you would use prettify-symbols-mode.

I am not sure what the remaining prettify-symbols... functions are doing, but from the comments in the code it seems that they are required. Therefore, I have left them in to be safe.

dalanicolai
  • 6,108
  • 7
  • 23
  • Is it correct syntax to use `("like" . "lk")` without employing `?` as in `("like" . ?"lk")` ? – Dilna Apr 21 '22 at 06:37
  • would I need to set `prettify-symbols-compose-predicate`? – Dilna Apr 21 '22 at 06:44
  • I would say, just try my answer (open a buffer with some example text and apply the command), and you will find out the answers to these questions. You can read about cases when `prettify-symbols-compose-predicate` is needed [here](https://emacs.stackexchange.com/questions/47706/how-to-prettify-symbols-inside-comments). So my answer only works when you are using/writing the words as separate entities (i.e. without surrounding them with double quotes) and as long as they are not part of comments. – dalanicolai Apr 21 '22 at 08:39
  • I did not get notified about your updates to the question. Indeed, it looks like `prettify-symbols-mode` can only be used to replace 'patterns' by a (compositions of) single character(s). I could not find anything that provides your desired functionality. I guess you have two alternatives: either modify the `prettify-symbols-mode` to use `text-properties` instead of `compose-region` (see [here](https://www.reddit.com/r/emacs/comments/keji66/what_is_bad_about_prettifysymbolsmode/). Or if you only use short texts, then simply hack something using `replace-regexp`. – dalanicolai Apr 30 '22 at 08:09