Fuco1 / smartparens

Minor mode for Emacs that deals with parens pairs and tries to be smart about it.
GNU General Public License v3.0
1.82k stars 194 forks source link

Smart parens behavior inside word #563

Open walmes opened 8 years ago

walmes commented 8 years ago

Hi @Fuco1,

I'm using smartparens and I would like to set a even more smart behavior. I've tried to set a behavior that is put enclosing pair in a word when the point is inside it. I read the smartparens wiki and searches in the internet and I almost got it. Below is the code (that I spent hours modifying and reevaluating).

When hit the quote mark, for example, o would like this Do What I Mean:

In my tries, I got something partial. I got put pair when before a word, but I lost insert pair when region is active. I also got put pair when inside a word, but the opening stayed at the point, not at word beginning.

Below is the code I'm using. In the comments, the pipe (|) indicates the point when I hit double quotes. The greater/less signs indicates direction of region mark.

This settings, if possible, could be part of the tips and thicks section. Thanks in advance for any help.

;;-------------------------------------------
;; Smart Parenthesis
;; https://github.com/Fuco1/smartparens.

(require 'smartparens)
(smartparens-global-mode 1)

;; To mark the current word.
(defun mark-whole-word (id action context)
  (interactive)
  (when (eq action 'insert)
    (skip-chars-backward "[[:alnum:]]._")
    (set-mark (point))
    (skip-chars-forward "[[:alnum:]]._")
  ))

;; Return t if the point is inside or touching a word.
(defun string-at-point-p (id action context)
  "Test if the point is in a word."
  (if (stringp (thing-at-point 'word)) t nil))

;;-------------------------------------------
;; Do Waht I Mean, example with quotes.
;; this is a |short word  => this is a "short" word
;; this is a sh|ort word  => this is a "short" word
;; >this is a short word> => "this is a short word"
;; <this is a short word< => "this is a short word"
;; this is a "short| word => this is a "short" word
;; this is a short| word  => this is a "short" word (why not?)

;;-------------------------------------------

(sp-with-modes
    '(markdown-mode gfm-mode rst-mode)
  ;; Don't put a pair when after a word.
  (sp-local-pair "\"" nil
                 :unless '(sp-point-after-word-p))
  (sp-local-pair "\"" nil
                 ;; :when '(sp-point-before-word-p)
                 :when '(string-at-point-p)
                 :pre-handlers '(mark-whole-word)
                 :actions '(insert))
 )

;; Using this, I got:
;; this is a |short word  => this is a "short" word
;; this is a sh|ort word  => this is a sh"ort word
;; >this is a short word> => "
;; <this is a short word< => "

;;-------------------------------------------

(sp-with-modes
    '(markdown-mode gfm-mode rst-mode)
  (sp-local-pair "\"" nil
                 :when '(string-at-point-p)
                 :pre-handlers '(mark-whole-word)
                 :actions '(insert)))

;; Using this, I got all the same, except:
;; this is a sh|ort word  => this is a sh"ort" word
Fuco1 commented 8 years ago

These are pretty cool ideas, I like it!

We will probably need to implement it on lower level than the hooks, although I'm not exactly sure.