Abbrev-mode seems to think an underscore signals a new word, which is not the case in many programming languages. I want it to expand after spaces, newlines, and tabs; not after underscores. Is there a way to tell abbrev-mode not to expand when I type an underscore?
4 Answers
Abbrev expansion behavior is built into the C code that implements self-insert-command
. It looks up the syntactic class of the current and previous character in the buffer's syntax table to decide whether to expand abbreviations.
In a programming mode for a language where the underscore is an identifier constituent, you may want to change _
to have word syntax. This is a blunt instrument: every part of the system will then treat _
as a word constituent, including motion commands. You may or may not like this. You can use Subword mode to make the basic motion commands treat underscore as a word separator regardless of its declared syntax.
Incidentally, font locking has special support to use a different syntax table for highlighting. Many programming language modes use this to treat _
as a word constituent for syntax highlighting.
(defun make-underscore-word-constituent (syntax-table)
(modify-syntax-entry ?_ "w" syntax-table))
(eval-after-load "cc-mode" '(make-underscore-word-constituent c-mode-syntax-table))
If you don't like the secondary effects, you can make _
a key that inserts _
in any way other than self-insert, e.g. by temporarily setting abbrev-mode
to nil or like this:
(defun self-insert-no-abbrev (&optional arg)
(interactive "*p")
(insert-char last-command-char arg))
(define-key c-mode-base-map "_" 'self-insert-no-abbrev)
This has a few side effects of its own, because _
won't be self-inserting any more. For example, _
will remain an undo barrier, it won't delete the selection under delete-selection-mode
, etc. Some of these side effects may disappear if you add (setq this-command 'self-insert-command)
to self-insert-no-abbrev
, but not the ones I mentioned (I don't think there's a generic solution that will apply to delete-selection
mode` since it runs before the command).
-
1That is disappointing but also incredibly informative. This text box says I'm not supposed to say thanks here, but... Thanks :-)– AvdiCommented Oct 4, 2014 at 0:27
-
Regarding changing the syntax table... This wouldn't affect subword-mode, would it? I'm thinking treating underscores as word constituents and also enabling subword-mode might be ideal.– AvdiCommented Oct 4, 2014 at 0:29
-
@Avdi Subword mode won't be affected. That's a great idea to cancel the most obvious effect. Commented Oct 4, 2014 at 0:40
Note: The accepted answer on this question is not the optimal solution!
Changing the syntax table is not neccesary to alter the behaviour of what is expanded and what not.
By default emacs uses indeed word syntax, i.e. non-word characters like _
and /
etc. can not occur in an abbrev.
However, this behaviour can be customized per abrrev-table.
See Sect. 35.7 Abbrev Table Properties of the emacs manual.
With
(abbrev-table-put table :regexp val)
you can add an regular expression val
instead of word-syntax to the abbrev-table table
.
As I'm not so familiar with emacs regular expressions, I cannot give you the answer of what exactly you would need to put there in your case.
However, have a look at this answer on stackoverflow, you can start experimenting from the solution presented there: https://stackoverflow.com/questions/18232384/how-to-replace-a-string-with-a-non-backslashed-string-in-emacs-abbrev-mode
This should be take care of it. It disables abbrev mode for any key you want. It's similar to the other answer, but you don't need to define a new function for each key.
(defun self-insert-no-abbrev ()
(interactive)
(let ((abbrev-mode nil))
(call-interactively 'self-insert-command)))
(global-set-key "_" #'self-insert-no-abbrev)
(global-set-key "." #'self-insert-no-abbrev)
I've just found this on SO: define some function to protect some key. Not sure if the best solution.