5

Q: how can I change the syntax of a character for a single function?

In text-mode and its derivatives, the ' character has word syntax rather than, say punctuation or string quote syntax. That's a problem when using abbrev-mode, as I would like the ' character to fire the abbrev when I'm using a possessive.

For example, if the abbrev "pres" expands to "president" and I want to write the "president's cat", I'd expect to be able to type p r e s ' s, where "pres" expands automatically to "president" when I hit '.

Now: I don't want to change the syntax for ' globally or permanently, because I don't want to interfere with any other functions that depend on ' having word syntax. I tried the following:

(defadvice self-insert-command (around testing activate)
  (with-syntax-table (copy-syntax-table (syntax-table))
    (modify-syntax-entry ?' "\"")
    ad-do-it))

Two problems.

First: although it does fire the abbrev as expected, smartparens-mode complains every second time the abbrev fires (really: it's every second time). That's a tangent on the main point, however.

Second, and more importantly: this advice seems awfully costly for a function that gets invoked on every insertion command. It calls up the syntax table, copies it, modifies it, uses it, and then restores the original syntax table. That seems awfully silly when I really only care about one character, which leads me to suspect I'm going about this wrong.

Is there a smarter way to do this? (Note that I'm most interested in temporarily changing the syntax of a character and am using the abbrev example to motivate it.)

Dan
  • 32,584
  • 6
  • 98
  • 168
  • Why not change the syntax for all of text-mode? What harm would it do? Also I would think that you should remove single quotes from smart parens for text-mode buffers. That would likely solve all the issues. – Jordon Biondo May 18 '15 at 23:41
  • @JordonBiondo: as I mentioned, I don't know which other functions depend on `'` having word syntax. It certainly changes the behavior of commands like `forward-word` and `backward-word`, however, which is reason enough not to make the change permanent. – Dan May 18 '15 at 23:46
  • Here is a link that contains code demonstrating how I do my own forward/backward word using a custom syntax table for the duration of a function. http://stackoverflow.com/q/18675201/2112489 However, I've never tried using defadvice to modify the syntax of an existing function. I use the same custom syntax table for my own delete-word function http://stackoverflow.com/a/20456861/2112489 . – lawlist May 19 '15 at 01:04
  • The function `abbrev--check-chars` is the only function in the `abbrev.el` library that contains syntax tables. Do you think it might be helpful to modify that one function to use your own custom syntax table? I could be wrong, but I don't think you would *really* be interested in changing `self-insert-command`. – lawlist May 19 '15 at 02:09
  • @lawlist: as I mention at the end, I'm using the `abbrev` issue to motivate the problem. I'm more interested in modifying the syntax, which I need to do for a different function. (In other words: I'm not looking to hack `abbrev-mode`.) – Dan May 19 '15 at 02:15

1 Answers1

2

Use macro with-syntax-table. You create a syntax table (e.g. inheriting from the current table), then change the syntax of any chars you want in that new table, then pass that table to with-syntax-table, wrapping your code (e.g. your function) with the macro. Within the context of the macro, your code will use the syntax table you specify.

(If you have an older Emacs version, which does not have macro with-syntax-table, then you need to switch to a new table and then switch back again (e.g. using unwind-protect).)

Alternatively, you can save and restore particular syntax settings, modifying the current table in between, using modify-syntax-entry.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • Thanks, but the current example already uses `with-syntax-table` (although it creates a copy of the current table at each invocation rather than storing a copy in a state variable). I'm wondering if there's a lighter-weight way to alter syntax temporarily (ie, without setting and resetting the whole table and/or saving another table to a variable). If the answer to the latter question is "no" (or perhaps "not easily enough to justify"), I'll accept that as an answer. – Dan May 19 '15 at 10:07
  • I updated the answer to mention that you can save & restore particular settings, modifying the table, instead of using a new table. – Drew May 19 '15 at 13:13
  • Thanks -- I'll leave the question open for a bit to see if anyone has alternative suggestions, but from your answer, it looks like this is the main idiom. – Dan May 19 '15 at 14:14