7

Q: how can I tweak smartparens's decision rules for when to insert a paired or single character?

smartparens seems to be mostly smart when inserting single quotes (e.g., in text-mode or org-mode). Hence, it default to inserting a pair of 's and placing the cursor in between them, but, when invoked at the end of a word, only inserts a single ' in anticipation of contractions. So, e.g.:

  • ' => '*' (where * is point)
  • can + ' => can'* (so I can continue to write "can't")

However, there's a hiccup I'm looking to fix. I often use abbreviations that end in a period, but would like to make them possessive. For example, I might write "s.o." as an abbreviation for "someone," and therefore "s.o.'s" would be "someone's." The problem is that smartparens inserts a paired-' after a period:

  • what I want: s.o. + ' => s.o.'*
  • what I get: s.o. + ' => s.o.'*'

My specific quibble is with smartparens's behavior on ', but I can imagine this being a more general issue with other characters as well.

So: how can I tweak smartparens's decision rule to expand the set of characters after which it only inserts a single '?

PS: amusingly, trying to type "`smartparens`'s" in emacs gives the same irritating behavior.

2

Yes, with pairing conditionals:

;; a sample from my .emacs.d
(defun my-sp-pair-function (id action context)
  (if (eq action 'insert)
    ;; t to pair, nil to not pair
    (or (looking-at "[[:space:][:punct:]]")
      (sp-point-before-eol-p id action context))
    t))

(with-eval-after-load 'smartparens
    (sp-pair "(" ")" :when '(my-sp-pair-function) :wrap "C-)")
    (sp-pair "{" "}" :when '(my-sp-pair-function) :wrap "C-}")
    (sp-pair "[" "]" :when '(my-sp-pair-function) :wrap "C-]")
    (sp-pair "\"" "\"" :when '(my-sp-pair-function) :wrap "C-\"")
    (sp-pair "'" "'" :when '(my-sp-pair-function)))
  • 1
    The lower part looks totally unrelated. The upper part looks like it won't do anything on its own. Could you please turn your answer into something functional? – wasamasa Jan 3 '15 at 13:32
  • That is true... copy-paste fail. Fixed. – PythonNut Jan 4 '15 at 3:39
  • Thanks for the thoughts, but my-sp-pair-function does not appear to be providing the desired functionality. It's giving me the same behavior as before after punctuation (paired insert), but now it also does a paired-insert after alphanumeric characters as well, breaking the contractions. – Dan Jan 4 '15 at 12:49
  • @Dan, this was meant to be a general solution. You can, for example replace the condition with this: (and (or (looking-at "[[:space:][:punct:]]") (sp-point-before-eol-p id action context)) (not (looking-back "[.`]"))) – PythonNut Jan 5 '15 at 1:56
2

You can modify smartparen's behavior by using the functions sp-pair and sp-local-pair. The smartparens wiki explains these functions in detail.

Basically you can something like following to customize the behavior globally

(sp-pair "\"" nil :unless '(my-custom-predicate))

OR to customize the behavior just for some modes

(sp-local-pair desired-modes "\"" nil :unless '(my-custom-predicate))

where desired-mode is the mode for which you want to customize the behavior and my-custom-predicate is function that smartparens should use to determine whether it should insert the pair automatically.

From sp-pair's docstring the custom predicate should accept

opening delimiter (which uniquely determines the pair), action and context. The context argument can have values:

  • string - if point is inside string.
  • comment - if point is inside comment.
  • code - if point is inside code. This context is only recognized in programming modes that define string semantics.

So a custom function that can be used as a :unless predicate in your specific case would be something like the following

(defun predp (id action context)
  (sp--looking-back-p "[[:punct:]]'"))

Notice that I am checking for the regex <punctuation>' since the point would be at .'| when the predicate is executing.

Finally, you can hook it into smartparens by doing

(sp-pair  "'" nil :unless'(predp))
  • Thanks, that gets me part of the way there, but could you provide a concrete example? I've tried various forms of the predicate function (eg,(defun predp () (sp--looking-back-p "[[:space:][:punct:]]"))), but smartparens ignores them all. – Dan Jan 3 '15 at 16:12
  • Hi @Dan, I have added the solution for your specific problem to the answer. You were not accepting the required arguments in the predicate, also the regex used was slightly off – Iqbal Ansari Jan 5 '15 at 17:21

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.