3

Is there a function (or some kind of prefix command) that will allow me to do an action to the next word I type, not the word under point or the region? Currently:

  • upcase-word puts the word under the point in uppercase
  • org-emphasize bolds or italicizes the word under point

But when typing text, I often want to do this to the next word I type, the one I haven't typed yet (using SPC as the delimiter).

So I want function I can call before I enter a word that will place * on either side of the next word I type, without my having to type the closing *.

Let's say my keybinding for bold-next-word is M-S-b.

Sample input:
This is an M-S-bimportantSPCpoint.

Desired output:

This is an *important* point.

org-emphasize is my main use case, but it would be nice to be able to do this with upcase, downcase, etc.

  • 1
    Something like this?: (defun org-emphasize-next-word () (interactive) (insert " ") (org-emphasize ?*)) – lawlist Jun 21 '15 at 3:57
  • Hmm, with that I get this: This is an *important point * – incandescentman Jun 21 '15 at 5:04
  • Ah, I thought you wanted the upcoming word while the cursor was at the end of the current word. My mistake. – lawlist Jun 21 '15 at 6:00
  • I do want the upcoming word, the problem is getting the point past the closing *. – incandescentman Jun 21 '15 at 6:01
1

Here's a very cheap way to accomplish the job for "embolden next word."

  • Hello M-s-b world M-s-mHello␣*world*.␣← point is here

  • Hello M-s-b world M-s-wHello␣*world*␣← point is here

(global-set-key (kbd "M-s-b") '(lambda () (interactive)
                 (just-one-space)
                 (insert "**")
                 (backward-char 1)))

(global-set-key (kbd "M-s-w") '(lambda () (interactive)
                 (move-end-of-line nil)
                 (just-one-space)))

(global-set-key (kbd "M-s-m") '(lambda () (interactive)
                 (move-end-of-line nil)
                 (insert ".")
                 (just-one-space)))

Here's another solution, adjusting Drew's answer so that it applies to the next word.

(define-minor-mode embolden-next-word
    "Make the next word you type bold."
  nil 
  :lighter " EMBOLDEN"
  :keymap (let ((map (make-sparse-keymap)))
            (define-key map (kbd "SPC") (lambda ()
                      (interactive)
                      (save-excursion 
                        (goto-char (get-register 'p))
                        (insert "*"))
                      (insert "* ")
                      (embolden-next-word -1)))
        (define-key map (kbd ".") (lambda ()
                    (interactive)
                    (save-excursion 
                      (goto-char (get-register 'p))
                      (insert "*"))
                    (insert "*. ")
                    (embolden-next-word -1)))
            map)
  (if embolden-next-word
      (set-register 'p (point))
    (set-register 'p nil)))

(global-set-key "\C-o" 'embolden-next-word)

If you want a really generic solution, maybe the thing to do is define a macro that would allow you to generalise that minor mode so you can foo next word.

PS. As Drew indicates, it's easier to apply markup commands to words after you've already typed them. For instance, here's a binding I use a lot:

(global-set-key (kbd "H-o") (lambda () (interactive) (upcase-word -1)))
  • The embolden-next-word minor-mode above works perfectly. Where would I add expand-abbrev to get it to expand emboldened abbrevs the same way Emacs normally expands abbrevs when I hit SPC? – incandescentman Jul 3 '15 at 18:28
1

It sounds like what you want is a way to type and have words you type be emboldened automatically.

That's easier to do after you enter the word, as soon as you hit a non-word char. On post-command-hook you can check whether (looking-back "\w\W") (a word char followed by a non-word char), and if so, save-excursion, backward-word, insert a *, forward-word, and insert another *.

Something like this:

(defun embolden-last-word ()
  (interactive)
  (when (and (eq last-command 'self-insert-command)
             (looking-back "\\w\\W")
             (not (eq (char-after) ?*)))
    (save-excursion
      (backward-word) (insert ?*) (forward-word) (insert ?*))))

(add-hook 'post-command-hook 'embolden-last-word)

(Be aware that this emboldens words, since that's what you asked for. For example, in a mode like emacs-lisp-mode, since - is not a word-constituent character, you will get *foo*-*bar* and not *foo-bar*. If you want the latter, then either make - be a word constituent in your mode or use symbol instead of word in the code.)

You could of course bind a command to a key that toggles add/remove of embolden-last-word from post-command-hook, so you can quickly enable and disable emboldening. For example:

(define-minor-mode toggle-embolden-word
    "Toggle making words you type bold."
  nil nil nil
  (if toggle-embolden-word
      (add-hook 'post-command-hook 'embolden-last-word)
    (remove-hook 'post-command-hook 'embolden-last-word)))

(global-set-key "\C-o" 'toggle-embolden-word)

(And if you do that then you do not need to do the (add-hook 'post-command-hook 'embolden-last-word) shown above. Just use the toggle key to turn it on/off.)

  • Naturally, if you turn on toggle-embolden-word before you type the next word, and turn it off afterwards, then it effectively works as "embolden-next-word" :-) – Joe Corneli Jun 21 '15 at 15:45
  • @JoeCorneli: You do not have to, and may not want to, turn it on and off again, for each word. Toggle it on, leave it on until you no longer want bold words, then toggle it off. A key to embolden the next existing word, which you can use like upcase-word, is useful because you can repeat it to continue with subsequent words. Your embolden-next-word has no such utility. toggle-embolden-word provides this for words you have yet to type. If only a rare word is emboldened then yours might make sense, but in that case it is enough to type * twice. (But OP apparently disagrees. ;-)) – Drew Jun 21 '15 at 20:35
  • I need to embolden words frequently, and always just a single word. – incandescentman Jun 27 '15 at 6:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.