Re: "Buttons" in a message buffer that evaluate to plain text?

Tim Landscheidt <[email protected]>
Newsgroups gmane.emacs.help
Organization https://www.tim-landscheidt.de/
Message-ID <[email protected]>
Michael Heerdegen wrote:

>> With Emacs 30.2, what is the best practice to achieve that
>> plain text ↔ "buttons" conversion?  Is there an existing
>> ELPA package that does something similar?

> The simplest way to convert a region of buffer text into buttons is
> probably `buttonize-region' - see

>   (info "(elisp) Making Buttons")

> I don't know if there are more high-level tools that handle your use
> case are available.  Not so far in the past I needed something similar
> (a button toggling between different string values that are/get part of
> the resulting text) and wrote it by myself.

It was indeed rather simple:

| (while (re-search-forward "#\\([1-9a]\\) +\\(\\[ +\\]\\)" (point-max) t)
|   (let
|       ((choices (if (string= (match-string 1) "a")
|                     '("JA" "NEIN" "ANNULLIERUNG")
|                   '("JA" "NEIN" "ENTHALTUNG"))))
|     (make-button
|      (match-beginning 2)
|      (match-end 2)
|      'action (lambda (button)
|                (save-mark-and-excursion
|                  (let
|                      ((current-label (button-label button)))
|                    (if (string-match "\\`\\[ *\\([^ ]*\\) *\\]\\'" current-label)
|                        (replace-region-contents
|                         (+ (button-start button) 1)
|                         (- (button-end button) 1)
|                         (lambda
|                           nil
|                           (let*
|                               ((current-choice (match-string 1 current-label))
|                                (next-choice (if (string-empty-p current-choice)
|                                                 (car choices)
|                                               (or (cadr (member current-choice choices)) "")))
|                                (original-field-length (- (point-max) (point-min))))
|                             (concat
|                              (make-string (max (/ (- original-field-length (length next-choice)) 2) 0) ?\s)
|                              actual-choice
|                              (make-string (max (/ (- (+ original-field-length 1) (length next-choice)) 2) 0) ?\s))))))))))))

message-mode will just ignore overlays, so the sent message
contains the text only.  Very nice, thanks for the pointer.

One minor flaw: Replacing the button's "label" (i. e., the
text "[ ENTHALTUNG ]", etc.) will move point to either the
beginning or the end of the replaced text.  Aside from
replace-region-contents I also tried delete-char/insert with
overwrite-mode set to 'overwrite-mode-textual, but the
latter does not seem to have any effect to turn insert into
a "replace".

While I probably could do some arithmetics with point or
mark myself, any (in my case hypothetical) marker would
still be moved.

How can I actually replace the character/text at point
without deleting and inserting?

Tim
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.