From 007439e1e470ce02f4baf26a8b9ce8fe16d4faab Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Sat, 20 Feb 2016 12:58:13 +0100 Subject: [PATCH] update smartparens. --- bba.org | 2 +- .../smartparens-autoloads.el | 7 +- .../smartparens-config.el | 36 +- .../smartparens-haskell.el | 22 +- .../smartparens-html.el | 0 .../smartparens-latex.el | 2 +- .../smartparens-lua.el | 0 .../smartparens-pkg.el | 2 +- .../smartparens-python.el | 98 ++ .../smartparens-racket.el | 55 + .../smartparens-ruby.el | 0 .../smartparens-rust.el | 81 ++ .../smartparens-scala.el} | 24 +- .../smartparens.el | 1015 +++++++++++------ 14 files changed, 963 insertions(+), 381 deletions(-) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-autoloads.el (97%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-config.el (78%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-haskell.el (74%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-html.el (100%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-latex.el (99%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-lua.el (100%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-pkg.el (71%) create mode 100644 elpa/smartparens-20160217.1102/smartparens-python.el create mode 100644 elpa/smartparens-20160217.1102/smartparens-racket.el rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens-ruby.el (100%) create mode 100644 elpa/smartparens-20160217.1102/smartparens-rust.el rename elpa/{smartparens-20150628.1418/smartparens-python.el => smartparens-20160217.1102/smartparens-scala.el} (69%) rename elpa/{smartparens-20150628.1418 => smartparens-20160217.1102}/smartparens.el (90%) diff --git a/bba.org b/bba.org index c4ff9847..1f96039b 100644 --- a/bba.org +++ b/bba.org @@ -296,7 +296,7 @@ Some key bindings taken from [[https://ebzzry.github.io/emacs-pairs.html][emacs- #+BEGIN_SRC emacs-lisp (if (>= emacs-major-version 24) (progn - (add-to-list 'load-path "~/.emacs.d/elpa/smartparens-20150628.1418") + (add-to-list 'load-path "~/.emacs.d/elpa/smartparens-20160217.1102") (add-to-list 'load-path "~/.emacs.d/elpa/dash-20151216.1315") (require 'smartparens) (smartparens-global-mode 1) diff --git a/elpa/smartparens-20150628.1418/smartparens-autoloads.el b/elpa/smartparens-20160217.1102/smartparens-autoloads.el similarity index 97% rename from elpa/smartparens-20150628.1418/smartparens-autoloads.el rename to elpa/smartparens-20160217.1102/smartparens-autoloads.el index b9750341..17f722f2 100644 --- a/elpa/smartparens-20150628.1418/smartparens-autoloads.el +++ b/elpa/smartparens-20160217.1102/smartparens-autoloads.el @@ -3,7 +3,7 @@ ;;; Code: (add-to-list 'load-path (or (file-name-directory #$) (car load-path))) -;;;### (autoloads nil "smartparens" "smartparens.el" (21908 14185 +;;;### (autoloads nil "smartparens" "smartparens.el" (22215 5349 ;;;;;; 0 0)) ;;; Generated autoloads from smartparens.el @@ -180,8 +180,9 @@ Turn off `show-smartparens-mode'. ;;;### (autoloads nil nil ("smartparens-config.el" "smartparens-haskell.el" ;;;;;; "smartparens-html.el" "smartparens-latex.el" "smartparens-lua.el" -;;;;;; "smartparens-pkg.el" "smartparens-python.el" "smartparens-ruby.el") -;;;;;; (21908 14185 513201 0)) +;;;;;; "smartparens-pkg.el" "smartparens-python.el" "smartparens-racket.el" +;;;;;; "smartparens-ruby.el" "smartparens-rust.el" "smartparens-scala.el") +;;;;;; (22215 5349 568964 0)) ;;;*** diff --git a/elpa/smartparens-20150628.1418/smartparens-config.el b/elpa/smartparens-20160217.1102/smartparens-config.el similarity index 78% rename from elpa/smartparens-20150628.1418/smartparens-config.el rename to elpa/smartparens-20160217.1102/smartparens-config.el index bdd03078..2674f7da 100644 --- a/elpa/smartparens-20150628.1418/smartparens-config.el +++ b/elpa/smartparens-20160217.1102/smartparens-config.el @@ -1,6 +1,6 @@ ;;; smartparens-config.el --- Default configuration for smartparens package -;; Copyright (C) 2013-2015 Matus Goljer +;; Copyright (C) 2013-2016 Matus Goljer ;; Author: Matus Goljer ;; Maintainer: Matus Goljer @@ -53,20 +53,23 @@ (defun sp-lisp-invalid-hyperlink-p (_1 action _2) (when (eq action 'navigate) - (or (and (looking-at "\\sw\\|\\s_") - (save-excursion - (backward-char 2) - (looking-at "\\sw\\|\\s_"))) - (and (save-excursion - (backward-char 1) - (looking-at "\\sw\\|\\s_")) - (save-excursion - (forward-char 1) - (looking-at "\\sw\\|\\s_")))))) + ;; Ignore errors due to us being at the start or end of the + ;; buffer. + (ignore-errors + (or (and (looking-at "\\sw\\|\\s_") + (save-excursion + (backward-char 2) + (looking-at "\\sw\\|\\s_"))) + (and (save-excursion + (backward-char 1) + (looking-at "\\sw\\|\\s_")) + (save-excursion + (forward-char 1) + (looking-at "\\sw\\|\\s_"))))))) ;; emacs is lisp hacking enviroment, so we set up some most common ;; lisp modes too -(sp-with-modes sp--lisp-modes +(sp-with-modes sp-lisp-modes ;; disable ', it's the quote character! (sp-local-pair "'" nil :actions nil) ;; also only use the pseudo-quote inside strings where it serve as @@ -82,6 +85,12 @@ (not (sp-point-in-string-or-comment)))) (t (not (sp-point-in-string-or-comment))))))) +;; Unfortunately emacs devs in their glorious wisdom decided to +;; make @ no longer have prefix syntax, it is now a symbol... because +;; apparently its use in symbols is so frequent. Anyway, since we +;; can't really change that, let's use a regexp based solution +(add-to-list 'sp-sexp-prefix (list 'emacs-lisp-mode 'regexp "\\(?:,@\\|[',`]\\)")) + ;; TODO: this should only be active in docstring, otherwise we want ;; the regexp completion \\{\\}. To handle this feature, we must ;; allow multiple pairs on same opening (therefore, the unique ID must @@ -100,10 +109,13 @@ (eval-after-load "lua-mode" '(require 'smartparens-lua)) (eval-after-load "ruby-mode" '(require 'smartparens-ruby)) (eval-after-load "enh-ruby-mode" '(require 'smartparens-ruby)) +(eval-after-load "rust-mode" '(require 'smartparens-rust)) (eval-after-load "haskell-mode" '(require 'smartparens-haskell)) (eval-after-load "haskell-interactive-mode" '(require 'smartparens-haskell)) (--each '("python-mode" "python") (eval-after-load it '(require 'smartparens-python))) +(eval-after-load "scala-mode" '(require 'smartparens-scala)) +(eval-after-load "racket-mode" '(require 'smartparens-racket)) (provide 'smartparens-config) diff --git a/elpa/smartparens-20150628.1418/smartparens-haskell.el b/elpa/smartparens-20160217.1102/smartparens-haskell.el similarity index 74% rename from elpa/smartparens-20150628.1418/smartparens-haskell.el rename to elpa/smartparens-20160217.1102/smartparens-haskell.el index 66c2136a..4219979b 100644 --- a/elpa/smartparens-20150628.1418/smartparens-haskell.el +++ b/elpa/smartparens-20160217.1102/smartparens-haskell.el @@ -47,19 +47,27 @@ (require 'smartparens) (sp-with-modes '(haskell-mode haskell-interactive-mode) - (sp-local-pair "{-#" "#-}")) + (sp-local-pair "{-#" "#-}") + (sp-local-pair "'" nil :unless '(sp-point-after-word-p)) + (sp-local-pair "\\(" nil :actions nil)) (defun sp--inferior-haskell-mode-backward-bound-fn () "Limit the backward search to the prompt if point is on prompt." - (when comint-last-prompt-overlay - (let ((limit (overlay-end comint-last-prompt-overlay))) - (when (> (point) limit) limit)))) + (-when-let (limit (cond ((bound-and-true-p comint-last-prompt) + (marker-position (cdr comint-last-prompt))) + ((bound-and-true-p comint-last-prompt-overlay) + (overlay-end comint-last-prompt-overlay)) + (t nil))) + (and (> (point) limit) limit))) (defun sp--inferior-haskell-mode-forward-bound-fn () "Limit the forward search to exclude the prompt if point is before prompt." - (when comint-last-prompt-overlay - (let ((limit (overlay-start comint-last-prompt-overlay))) - (when (< (point) limit) limit)))) + (-when-let (limit (cond ((bound-and-true-p comint-last-prompt) + (marker-position (car comint-last-prompt))) + ((bound-and-true-p comint-last-prompt-overlay) + (overlay-start comint-last-prompt-overlay)) + (t nil))) + (and (< (point) limit) limit))) (defun sp--setup-inferior-haskell-mode-search-bounds () "Setup the search bound. diff --git a/elpa/smartparens-20150628.1418/smartparens-html.el b/elpa/smartparens-20160217.1102/smartparens-html.el similarity index 100% rename from elpa/smartparens-20150628.1418/smartparens-html.el rename to elpa/smartparens-20160217.1102/smartparens-html.el diff --git a/elpa/smartparens-20150628.1418/smartparens-latex.el b/elpa/smartparens-20160217.1102/smartparens-latex.el similarity index 99% rename from elpa/smartparens-20150628.1418/smartparens-latex.el rename to elpa/smartparens-20160217.1102/smartparens-latex.el index adb025ca..8d958580 100644 --- a/elpa/smartparens-20150628.1418/smartparens-latex.el +++ b/elpa/smartparens-20160217.1102/smartparens-latex.el @@ -1,6 +1,6 @@ ;;; smartparens-latex.el --- Additional configuration for (La)TeX based modes. -;; Copyright (C) 2013-2014 Matus Goljer +;; Copyright (C) 2013-2016 Matus Goljer ;; Author: Matus Goljer ;; Maintainer: Matus Goljer diff --git a/elpa/smartparens-20150628.1418/smartparens-lua.el b/elpa/smartparens-20160217.1102/smartparens-lua.el similarity index 100% rename from elpa/smartparens-20150628.1418/smartparens-lua.el rename to elpa/smartparens-20160217.1102/smartparens-lua.el diff --git a/elpa/smartparens-20150628.1418/smartparens-pkg.el b/elpa/smartparens-20160217.1102/smartparens-pkg.el similarity index 71% rename from elpa/smartparens-20150628.1418/smartparens-pkg.el rename to elpa/smartparens-20160217.1102/smartparens-pkg.el index 63ee3a08..a93a53b4 100644 --- a/elpa/smartparens-20150628.1418/smartparens-pkg.el +++ b/elpa/smartparens-20160217.1102/smartparens-pkg.el @@ -1,4 +1,4 @@ -(define-package "smartparens" "20150628.1418" "Automatic insertion, wrapping and paredit-like navigation with user defined pairs." +(define-package "smartparens" "20160217.1102" "Automatic insertion, wrapping and paredit-like navigation with user defined pairs." '((cl-lib "0.3") (dash "2.10.0"))) ;; Local Variables: diff --git a/elpa/smartparens-20160217.1102/smartparens-python.el b/elpa/smartparens-20160217.1102/smartparens-python.el new file mode 100644 index 00000000..2cee7159 --- /dev/null +++ b/elpa/smartparens-20160217.1102/smartparens-python.el @@ -0,0 +1,98 @@ +;;; smartparens-python.el --- Additional configuration for Python based modes. + +;; Copyright (C) 2015-2016 Matus Goljer + +;; Author: Matus Goljer +;; Maintainer: Matus Goljer +;; Created: 8 February 2015 +;; Keywords: abbrev convenience editing +;; URL: https://github.com/Fuco1/smartparens + +;; This file is not part of GNU Emacs. + +;;; License: + +;; This file is part of Smartparens. + +;; Smartparens is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; Smartparens is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with Smartparens. If not, see . + +;;; Commentary: + +;; This file provides some additional configuration for Python based +;; modes. To use it, simply add: +;; +;; (require 'smartparens-python) +;; +;; into your configuration. You can use this in conjunction with the +;; default config or your own configuration. +;; +;; If you have good ideas about what should be added please file an +;; issue on the github tracker. +;; +;; For more info, see github readme at +;; https://github.com/Fuco1/smartparens + +;;; Code: + +(require 'smartparens) + +;; Python has no sexp suffices. This fixes slurping +;; (|sys).path.append---the dot should not travel with the closing +;; paren +(--each '(python-mode inferior-python-mode) + (add-to-list 'sp-sexp-suffix (list it 'regexp ""))) + +(defun sp-python-in-string-p (id action context) + "Return non-nil if point is in a string, taking +care not to be confused by an unclosed ' that's just been typed." + (and (eq context 'string) + (save-excursion + (backward-char 1) + (nth 3 (syntax-ppss))))) + +(sp-local-pair 'python-mode + "'" "'" + :unless '(sp-in-comment-p sp-python-in-string-p)) + +(sp-local-pair 'python-mode + "(" nil + :pre-handlers '(sp-python-pre-slurp-handler)) + +(sp-local-pair 'python-mode + "[" nil + :pre-handlers '(sp-python-pre-slurp-handler)) + +(defun sp-python-pre-slurp-handler (id action context) + (when (eq action 'slurp-forward) + ;; If there was no space before, we shouldn't add on. + ;; ok = enclosing, next-thing one being slurped into + ;; (variables let-bound in `sp-forward-slurp-sexp'). + (save-excursion + (when (and (= (sp-get ok :end) (sp-get next-thing :beg)) + (equal (sp-get ok :op) (sp-get next-thing :op))) + (goto-char (sp-get ok :end)) + (when (looking-back " ") + (delete-char -1)))))) + +(defadvice python-indent-dedent-line-backspace + (around sp-backward-delete-char-advice activate) + (if smartparens-strict-mode + (cl-letf (((symbol-function 'delete-backward-char) + (lambda (arg &optional killp) + (sp-backward-delete-char arg)))) + ad-do-it) + ad-do-it)) + +(provide 'smartparens-python) +;;; smartparens-python.el ends here diff --git a/elpa/smartparens-20160217.1102/smartparens-racket.el b/elpa/smartparens-20160217.1102/smartparens-racket.el new file mode 100644 index 00000000..06a6551b --- /dev/null +++ b/elpa/smartparens-20160217.1102/smartparens-racket.el @@ -0,0 +1,55 @@ +;;; smartparens-racket.el --- Additional configuration for Racket based modes. + +;; Copyright (C) 2015 Vikraman Choudhury + +;; Author: Vikraman Choudhury +;; Maintainer: Vikraman Choudhury +;; Created: 26 Oct 2015 +;; Keywords: abbrev convenience editing +;; URL: https://github.com/Fuco1/smartparens + +;; This file is not part of GNU Emacs. + +;;; License: + +;; This file is part of Smartparens. + +;; Smartparens is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; Smartparens is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with Smartparens. If not, see . + +;;; Commentary: + +;; This file provides some additional configuration for Racket based +;; modes. To use it, simply add: +;; +;; (require 'smartparens-racket) +;; +;; into your configuration. You can use this in conjunction with the +;; default config or your own configuration. +;; +;; If you have good ideas about what should be added please file an +;; issue on the github tracker. +;; +;; For more info, see github readme at +;; https://github.com/Fuco1/smartparens + +;;; Code: + +(require 'smartparens) + +(sp-with-modes '(racket-mode racket-repl-mode) + (sp-local-pair "`" nil :actions nil) + (sp-local-pair "#|" "|#")) + +(provide 'smartparens-racket) +;;; smartparens-racket.el ends here diff --git a/elpa/smartparens-20150628.1418/smartparens-ruby.el b/elpa/smartparens-20160217.1102/smartparens-ruby.el similarity index 100% rename from elpa/smartparens-20150628.1418/smartparens-ruby.el rename to elpa/smartparens-20160217.1102/smartparens-ruby.el diff --git a/elpa/smartparens-20160217.1102/smartparens-rust.el b/elpa/smartparens-20160217.1102/smartparens-rust.el new file mode 100644 index 00000000..23ce71a8 --- /dev/null +++ b/elpa/smartparens-20160217.1102/smartparens-rust.el @@ -0,0 +1,81 @@ +;;; smartparens-rust.el --- Additional configuration for Haskell based modes. + +;; Copyright (C) 2015 Wilfred Hughes + +;; Created: 3 November 2015 +;; Keywords: abbrev convenience editing +;; URL: https://github.com/Fuco1/smartparens + +;; This file is not part of GNU Emacs. + +;;; License: + +;; This file is part of Smartparens. + +;; Smartparens is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; Smartparens is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with Smartparens. If not, see . + +;;; Commentary: + +;; This file provides some additional configuration for Rust. To use +;; it, simply add: +;; +;; (require 'smartparens-config) +;; +;; alternatively, you can explicitly load these preferences: +;; +;; (require 'smartparens-rust) +;; +;; in your configuration. + +;; For more info, see github readme at +;; https://github.com/Fuco1/smartparens + +;;; Code: +(require 'smartparens) + +(defun sp-in-rust-lifetime-context (&rest args) + "Return t if point is in a Rust context where ' represents a lifetime. +If we return nil, ' should be used for character literals." + (or + (condition-case nil + ;; If point is just after a &', it's probably a &'foo. + (save-excursion + (backward-char 2) + (looking-at "&")) + ;; If we're at the beginning of the buffer, just carry on. + (beginning-of-buffer)) + ;; If point is inside < > it's probably a parameterised function. + (let ((paren-pos (nth 1 (syntax-ppss)))) + (and paren-pos + (save-excursion + (goto-char paren-pos) + (looking-at "<")))))) + +(defun sp-rust-could-be-parameterized (&rest args) + "Return t if we could add a in this position. +If nil, the user is probably using < for something else." + (and (apply #'sp-in-code-p args) + (looking-back (rx (or letter (seq letter "<") (seq letter "::<")))))) + +(sp-with-modes '(rust-mode) + (sp-local-pair "'" "'" :unless '(sp-in-comment-p sp-in-string-p sp-in-rust-lifetime-context)) + (sp-local-pair "<" ">" :when '(sp-rust-could-be-parameterized))) + +;; Rust has no sexp suffices. This fixes slurping +;; (|foo).bar -> (foo.bar) +(add-to-list 'sp-sexp-suffix (list #'rust-mode 'regexp "")) + +(provide 'smartparens-rust) + +;;; smartparens-rust.el ends here diff --git a/elpa/smartparens-20150628.1418/smartparens-python.el b/elpa/smartparens-20160217.1102/smartparens-scala.el similarity index 69% rename from elpa/smartparens-20150628.1418/smartparens-python.el rename to elpa/smartparens-20160217.1102/smartparens-scala.el index 96338387..29e9df0d 100644 --- a/elpa/smartparens-20150628.1418/smartparens-python.el +++ b/elpa/smartparens-20160217.1102/smartparens-scala.el @@ -1,10 +1,10 @@ -;;; smartparens-python.el --- Additional configuration for Python based modes. +;;; smartparens-scala.el --- Additional configuration for Scala based modes. -;; Copyright (C) 2015 Matus Goljer +;; Copyright (C) 2015 Greg Nwosu -;; Author: Matus Goljer -;; Maintainer: Matus Goljer -;; Created: 8 February 2015 +;; Author: Greg Nwosu +;; Maintainer: Greg Nwosu +;; Created: 8 July 2015 ;; Keywords: abbrev convenience editing ;; URL: https://github.com/Fuco1/smartparens @@ -29,10 +29,10 @@ ;;; Commentary: -;; This file provides some additional configuration for Python based +;; This file provides some additional configuration for Scala based ;; modes. To use it, simply add: ;; -;; (require 'smartparens-python) +;; (require 'smartparens-scala) ;; ;; into your configuration. You can use this in conjunction with the ;; default config or your own configuration. @@ -47,11 +47,11 @@ (require 'smartparens) -;; Python has no sexp suffices. This fixes slurping -;; (|sys).path.append---the dot should not travel with the closing +;; Scala has no sexp suffices. This fixes slurping +;; import scala.mutable{|} ListBuffer, Set ---the comma should not travel with the closing ;; paren -(--each '(python-mode inferior-python-mode) +(--each '(scala-mode inferior-scala-mode) (add-to-list 'sp-sexp-suffix (list it 'regexp ""))) -(provide 'smartparens-python) -;;; smartparens-python.el ends here +(provide 'smartparens-scala) +;;; smartparens-scala.el ends here diff --git a/elpa/smartparens-20150628.1418/smartparens.el b/elpa/smartparens-20160217.1102/smartparens.el similarity index 90% rename from elpa/smartparens-20150628.1418/smartparens.el rename to elpa/smartparens-20160217.1102/smartparens.el index 8eba8431..a9ed420d 100644 --- a/elpa/smartparens-20150628.1418/smartparens.el +++ b/elpa/smartparens-20160217.1102/smartparens.el @@ -1,6 +1,6 @@ ;;; smartparens.el --- Automatic insertion, wrapping and paredit-like navigation with user defined pairs. -;; Copyright (C) 2012-2015 Matus Goljer +;; Copyright (C) 2012-2016 Matus Goljer ;; Author: Matus Goljer ;; Maintainer: Matus Goljer @@ -59,6 +59,19 @@ (declare-function cua--pre-command-handler "cua-base") (declare-function delete-selection-pre-hook "delsel") +;;; backport for older emacsen + +;; introduced in 24.3 +(unless (fboundp 'defvar-local) + (defmacro defvar-local (var val &optional docstring) + "Define VAR as a buffer-local variable with default value VAL. +Like `defvar' but additionally marks the variable as being automatically +buffer-local wherever it is set." + (declare (debug defvar) (doc-string 3)) + ;; Can't use backquote here, it's too early in the bootstrap. + (list 'progn (list 'defvar var val docstring) + (list 'make-variable-buffer-local (list 'quote var))))) + ;;;###autoload (defun sp-cheat-sheet (&optional arg) "Generate a cheat sheet of all the smartparens interactive functions. @@ -398,6 +411,9 @@ run.") "Non-nil if buffer was modified before the advice on `self-insert-command' executed.") +(defvar sp-pre-command-point nil + "Position of `point' before `this-command' gets executed.") + (defconst sp-max-pair-length 10 "Maximum length of an opening or closing delimiter. @@ -439,23 +455,44 @@ Pairs are defined as expressions delimited by pairs from Symbol is defined as a chunk of text recognized by `sp-forward-symbol'.") -(defvar sp--lisp-modes '(emacs-lisp-mode - inferior-emacs-lisp-mode - inferior-lisp-mode - inf-clojure-mode - lisp-interaction-mode - scheme-mode - scheme-interaction-mode - inferior-scheme-mode - geiser-repl-mode - lisp-mode - eshell-mode - slime-repl-mode - monroe-mode - cider-repl-mode - clojure-mode - common-lisp-mode) - "List of Lisp modes.") +(define-obsolete-variable-alias 'sp--lisp-modes 'sp-lisp-modes "2015-11-08") + +(defcustom sp-lisp-modes '( + cider-repl-mode + clojure-mode + clojurec-mode + clojurescript-mode + clojurex-mode + common-lisp-mode + emacs-lisp-mode + eshell-mode + geiser-repl-mode + inf-clojure-mode + inferior-emacs-lisp-mode + inferior-lisp-mode + inferior-scheme-mode + lisp-interaction-mode + lisp-mode + monroe-mode + racket-mode + racket-repl-mode + scheme-interaction-mode + scheme-mode + slime-repl-mode + stumpwm-mode + ) + "List of Lisp modes." + :type '(repeat symbol) + :group 'smartparens) + +(defcustom sp-no-reindent-after-kill-modes '( + python-mode + coffee-mode + js2-mode + ) + "List of modes that should not reindent after kill." + :type '(repeat symbol) + :group 'smartparens) (defvar sp--html-modes '( sgml-mode @@ -871,6 +908,19 @@ variable `sp-wrap-entire-symbol'." :type 'boolean :group 'smartparens) +(defcustom sp-wrap-respect-direction nil + "When non-nil respect the wrap direction. + +When non-nil, wrapping with opening pair always jumps to the +beginning of the region and wrapping with closing pair always +jumps to the end of the region. + +When nil, closing pair places the point at the end of the region +and the opening pair leaves the point at its original +position (before or after the region)." + :type 'boolean + :group 'smartparens) + ;; escaping custom (defcustom sp-autoescape-string-quote t "If non-nil, autoescape string quotes if typed inside string." @@ -954,7 +1004,7 @@ never automatically closed (see `sp-navigate-close-if-unbalanced')." :group 'smartparens) (defcustom sp-navigate-skip-match `( - (,sp--lisp-modes . sp--elisp-skip-match) + (,sp-lisp-modes . sp--elisp-skip-match) ) "Alist of list of major-modes and a function used to skip over matches in `sp-get-paired-expression'. This function takes three arguments: @@ -974,7 +1024,7 @@ use :skip-match option in `sp-local-pair'." (defcustom sp-navigate-reindent-after-up `( (interactive - ,@sp--lisp-modes + ,@sp-lisp-modes ) ) "Modes where sexps should be reindented after jumping out of them with `sp-up-sexp'. @@ -994,6 +1044,15 @@ command was called programatically." :value-type (repeat symbol)) :group 'smartparens) +(defcustom sp-navigate-reindent-after-up-in-string t + "If non-nil, `sp-up-sexp' will reindent inside strings. + +If `sp-navigate-reindent-after-up' is enabled and the point is +inside a string, this setting determines if smartparens should +reindent the current (string) sexp or not." + :type 'boolean + :group 'smartparens) + (defcustom sp-navigate-close-if-unbalanced nil "If non-nil, insert the closing pair of the un-matched pair on `sp-up-sexp'. @@ -1054,6 +1113,52 @@ by specifying its :suffix property." string)) :group 'smartparens) +(defcustom sp-split-sexp-always-split-as-string t + "Determine if sexp inside string is split. + +If the point is inside a sexp inside a string, the default +behaviour is now to split the string, such that: + + \"foo (|) bar\" + +becomes + + \"foo (\"|\") bar\" + +instead of + + \"foo ()|() bar\". + +Note: the old default behaviour was the reverse, it would split +the sexp, but this is hardly ever what you want. + +You can add a post-handler on string pair and check for +'split-string action to add concatenation operators of the +language you work in (in each major-mode you can have a separate +hook). + +For example, in PHP the string concatenation operator is a +dot (.), so you would add: + + (defun my-php-post-split-handler (_ action _) + (when (eq action 'split-sexp) + (just-one-space) + (insert \". . \") + (backward-char 3))) + + (sp-local-pair 'php-mode \"'\" nil + :post-handlers '(my-php-post-split-handler)) + +Then + + echo 'foo |baz'; + +results in + + echo 'foo' . | . 'baz';" + :type 'boolean + :group 'smartparens) + ;; hybrid lines (defcustom sp-hybrid-kill-excessive-whitespace nil "If non-nil, `sp-kill-hybrid-sexp' will kill all whitespace up @@ -1144,6 +1249,13 @@ mute. Integers specify the maximum width." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Misc/Utility functions +(defun sp--indent-region (start end &optional column) + "Call `indent-region' unless `aggressive-indent-mode' is enabled." + (unless (bound-and-true-p aggressive-indent-mode) + ;; Don't issue "Indenting region..." message. + (cl-letf (((symbol-function 'message) #'ignore)) + (indent-region start end column)))) + (defmacro sp-with-modes (arg &rest forms) "Add ARG as first argument to each form in FORMS. @@ -1158,13 +1270,17 @@ insert the modes." (regexp-opt '("sp-with-modes" "sp-get" "sp-compare-sexps") t) - "\\>") + "\\_>") (1 font-lock-keyword-face)))) (defun sp--evil-normal-state-p () "Checks to see if the current `evil-state' is in normal mode." (and (fboundp 'evil-normal-state-p) (evil-normal-state-p))) +(defun sp--evil-motion-state-p () + "Checks to see if the current `evil-state' is in motion mode." + (and (fboundp 'evil-motion-state-p) (evil-motion-state-p))) + (defun sp--evil-visual-state-p () "Checks to see if the current `evil-state' is in visual mode." (and (fboundp 'evil-visual-state-p) (evil-visual-state-p))) @@ -1218,7 +1334,20 @@ If optional argument P is present test this instead off point." ;; treated as whitespace (and (< p (point-max)) (memq (char-syntax (char-after p)) '(?< ?>)) - (not (eq (char-after p) ?\n))))))) + (not (eq (char-after p) ?\n))) + ;; we also need to test the special syntax flag for comment + ;; starters and enders, because `syntax-ppss' does not yet + ;; know if we are inside a comment or not (e.g. / can be a + ;; division or comment starter...). + (-when-let (s (car (syntax-after p))) + (or (and (/= 0 (logand (lsh 1 16) s)) + (nth 4 (syntax-ppss (+ p 2)))) + (and (/= 0 (logand (lsh 1 17) s)) + (nth 4 (syntax-ppss (+ p 1)))) + (and (/= 0 (logand (lsh 1 18) s)) + (nth 4 (syntax-ppss (- p 1)))) + (and (/= 0 (logand (lsh 1 19) s)) + (nth 4 (syntax-ppss (- p 2)))))))))) (defun sp-point-in-string-or-comment (&optional p) "Return non-nil if point is inside string, documentation string or a comment. @@ -1309,6 +1438,13 @@ of pairs and wraps.") '( TeX-insert-dollar TeX-insert-quote + quack-insert-opening-paren + quack-insert-closing-paren + quack-insert-opening-bracket + quack-insert-closing-bracket + racket-insert-closing-paren + racket-insert-closing-bracket + racket-insert-closing-brace ) "List of commands which are handled as if they were `self-insert-command's. @@ -1457,6 +1593,7 @@ replacement of all the keywords with actual calls to sp-get." ;; exposed by the sp-get macro. This way, we can later change the ;; internal representation without much trouble. +;; TODO: rewrite this in terms of `symbol-macrolet' ?? (defmacro sp-get (struct &rest forms) "Get a property from a structure. @@ -1734,8 +1871,8 @@ is wrapped instead. This is useful with selection functions in (goto-char rb) (insert (car active-pair)) (if (use-region-p) - (indent-region rb re) - (sp-get sel (indent-region :beg :end))))) + (sp--indent-region rb re) + (sp-get sel (sp--indent-region :beg :end))))) (cl-defun sp-pair (open close @@ -1839,7 +1976,7 @@ needs. A special syntax for conditional execution of hooks is also supported. If the added item is a list (function command1 -command2...), where funciton is a 3 argument function described +command2...), where function is a 3 argument function described above and command(s) can be either name of a command or a string representing an event. If the last command or event as described by `single-key-description' matches any on the list, the hook @@ -2395,9 +2532,9 @@ If USE-INSIDE-STRING is non-nil, use value of (setq r (when (memq a actions) ;;(and (when-clause) (not (unless-clause))) (and (or (not when-l) - (ignore-errors (run-hook-with-args-until-success 'when-l id a context))) + (run-hook-with-args-until-success 'when-l id a context)) (or (not unless-l) - (not (ignore-errors (run-hook-with-args-until-success 'unless-l id a context))))))) + (not (run-hook-with-args-until-success 'unless-l id a context)))))) (!cdr action)) r)) @@ -2406,7 +2543,7 @@ If USE-INSIDE-STRING is non-nil, use value of (let ((in-string (cl-case type (:pre-handlers (save-excursion - (backward-char 1) + (unless (bobp) (backward-char 1)) (sp-point-in-string-or-comment))) (:post-handlers (sp-point-in-string-or-comment))))) @@ -2450,7 +2587,9 @@ value is used instead of a test." (fun-spec (buffer-substring-no-properties p fun-end)) (instruction (cond ((equal fun-spec "i") - '(indent-according-to-mode))))) + '(indent-according-to-mode)) + ((equal (aref fun-spec 0) ?d) + `(delete-char ,(string-to-number (substring fun-spec 1))))))) (when instruction (push instruction spec))))) ((equal (match-string 0) "|") (cond @@ -2490,11 +2629,12 @@ see `sp-pair' for description." (context (sp--get-handler-context type))) (if hook (--each hook (sp--run-function-or-insertion it id action context)) + ;; TODO: WHAT THE FUCK IS THIS ???11? (let ((tag-hook (plist-get (--first (string-match-p (replace-regexp-in-string "_" ".*?" (plist-get it :open)) id) - (cdr (assq 'html-mode sp-tags))) + (cdr (assq 'html-mode sp-tags))) ;; REALLY? type))) (run-hook-with-args 'tag-hook id action context)))))) @@ -2593,28 +2733,32 @@ see `sp-pair' for description." ;; figure out how to detect the argument to self-insert-command that ;; resulted to this insertion (defun sp--post-self-insert-hook-handler () - (when smartparens-mode - (let (op action) - (setq op sp-last-operation) - (when (region-active-p) - (sp-wrap--initialize)) - (cond - (sp-wrap-overlays - (sp-wrap)) - (t - ;; TODO: this does not pick correct pair!! it uses insert and not wrapping code - (sp--setaction action (-when-let ((&keys :open open :close close) - (sp--pair-to-insert)) - (sp--wrap-repeat-last (cons open close)))) - (sp--setaction action (sp-insert-pair)) - (sp--setaction action (sp-skip-closing-pair)) - ;; if nothing happened, we just inserted a character, so - ;; set the apropriate operation. We also need to check - ;; for `sp--self-insert-no-escape' not to overwrite - ;; it. See `sp-autoinsert-quote-if-followed-by-closing-pair'. - (when (and (not action) - (not (eq sp-last-operation 'sp-self-insert-no-escape))) - (setq sp-last-operation 'sp-self-insert))))))) + (with-demoted-errors "sp--post-self-insert-hook-handler: %S" + (when smartparens-mode + (let (op action) + (setq op sp-last-operation) + (when (region-active-p) + (sp-wrap--initialize)) + (cond + (sp-wrap-overlays + (sp-wrap)) + (t + ;; TODO: this does not pick correct pair!! it uses insert and not wrapping code + (sp--setaction action (-when-let ((_ . open-pairs) (sp--all-pairs-to-insert)) + (catch 'done + (-each open-pairs + (-lambda ((&keys :open open :close close)) + (--when-let (sp--wrap-repeat-last (cons open close)) + (throw 'done it))))))) + (sp--setaction action (sp-insert-pair)) + (sp--setaction action (sp-skip-closing-pair)) + ;; if nothing happened, we just inserted a character, so + ;; set the apropriate operation. We also need to check + ;; for `sp--self-insert-no-escape' not to overwrite + ;; it. See `sp-autoinsert-quote-if-followed-by-closing-pair'. + (when (and (not action) + (not (eq sp-last-operation 'sp-self-insert-no-escape))) + (setq sp-last-operation 'sp-self-insert)))))))) ;; Unfortunately, some modes rebind "inserting" keys to their own ;; handlers but do not hand over the insertion back to @@ -2624,9 +2768,11 @@ see `sp-pair' for description." ;; commands to handle specially. (add-hook 'post-self-insert-hook 'sp--post-self-insert-hook-handler) -;; TODO: get rid of this ugly state tracking +;; TODO: make a proper data structure for state tracking and describe +;; why we need each of these. (defun sp--save-pre-command-state () (setq sp-point-inside-string (sp-point-in-string)) + (setq sp-pre-command-point (point)) (setq sp-buffer-modified-p (buffer-modified-p))) (add-hook 'pre-command-hook 'sp--save-pre-command-state) @@ -2797,26 +2943,32 @@ overlay." "Initialize wrapping." (when (and sp-autowrap-region (sp-wrap--can-wrap-p)) - ;; TODO: get rid of the following variables - (setq sp-wrap-point (1- (point))) - (setq sp-wrap-mark (mark)) - ;; if point > mark, we need to move point to mark and reinsert the - ;; just inserted character. - (when (> (point) (mark)) - (let ((char (delete-and-extract-region (1- (point)) (point)))) - (exchange-point-and-mark) - (insert char))) - (let* ((oleft (make-overlay (1- (region-beginning)) (region-beginning) nil nil t)) - (oright (make-overlay (region-end) (region-end) nil nil t))) - (setq sp-wrap-overlays (cons oleft oright)) - (when sp-highlight-wrap-overlay - (overlay-put oleft 'face 'sp-wrap-overlay-face) - (overlay-put oright 'face 'sp-wrap-overlay-face)) - (overlay-put oleft 'priority 100) - (overlay-put oright 'priority 100) - (overlay-put oleft 'keymap sp-wrap-overlay-keymap) - (overlay-put oleft 'type 'wrap) - (goto-char (1+ (overlay-start oleft)))))) + ;; This is the length of string which was inserted by the last + ;; "self-insert" action. Typically this is 1, but sometimes a + ;; single key inserts two or more characters, such as " in latex + ;; where it translates into `` or ''. + (let ((inserted-string-length (- (point) sp-pre-command-point))) + ;; TODO: get rid of the following variables + (setq sp-wrap-point (- (point) inserted-string-length)) + (setq sp-wrap-mark (mark)) + ;; if point > mark, we need to move point to mark and reinsert the + ;; just inserted character. + (when (> (point) (mark)) + (let ((char (delete-and-extract-region (- (point) inserted-string-length) (point)))) + (exchange-point-and-mark) + (insert char))) + (let* ((oleft (make-overlay (- (region-beginning) inserted-string-length) + (region-beginning) nil nil t)) + (oright (make-overlay (region-end) (region-end) nil nil t))) + (setq sp-wrap-overlays (cons oleft oright)) + (when sp-highlight-wrap-overlay + (overlay-put oleft 'face 'sp-wrap-overlay-face) + (overlay-put oright 'face 'sp-wrap-overlay-face)) + (overlay-put oleft 'priority 100) + (overlay-put oright 'priority 100) + (overlay-put oleft 'keymap sp-wrap-overlay-keymap) + (overlay-put oleft 'type 'wrap) + (goto-char (1+ (overlay-start oleft))))))) (defun sp-wrap--finalize (wrapping-end open close) "Finalize a successful wrapping. @@ -2838,8 +2990,10 @@ OPEN and CLOSE are the delimiters." open close)) (cond ((eq wrapping-end :open) - (when (> sp-wrap-point sp-wrap-mark) - (goto-char (overlay-end oend)))) + (if sp-wrap-respect-direction + (goto-char (overlay-start obeg)) + (when (> sp-wrap-point sp-wrap-mark) + (goto-char (overlay-end oend))))) ((eq wrapping-end :close) (goto-char (overlay-end oend)))) (sp-wrap--clean-overlays) @@ -2954,12 +3108,15 @@ pairs insertable by trigger are returned." ;; in case of triggers shorter always wins ((eq prop :trigger) (< (length (plist-get a :trigger)) (length (plist-get b :trigger)))) - ;; shorter wins only if the shorter's closing is a prefix of the - ;; longer's closing + ;; Shorter wins only if the shorter's closing is a prefix of the + ;; longer's closing. In other words, if we are looking at + ;; shorter's closing and we are trying to nest it. (t (if (< (length (plist-get a :open)) (length (plist-get b :open))) - (string-prefix-p (plist-get a :close) (plist-get b :close)) - (not (string-prefix-p (plist-get b :close) (plist-get a :close))))))) + (and (string-prefix-p (plist-get a :close) (plist-get b :close)) + (sp--looking-at-p (plist-get a :close))) + (not (and (string-prefix-p (plist-get b :close) (plist-get a :close)) + (sp--looking-at-p (plist-get b :close)))))))) (defun sp--pair-to-insert () "Return pair that can be inserted at point. @@ -3022,7 +3179,18 @@ setting `sp-autoinsert-pair' to nil. You can globally disable insertion of closing pair if point is followed by the matching opening pair. It is disabled by default." - (-let* ((active-pair (sp--pair-to-insert)) + (-let* ((active-pair (unwind-protect + ;; This fake insertion manufactures proper + ;; context for the tests below... in effect + ;; we must make it look as if the user + ;; typed in the opening part themselves + ;; TODO: it is duplicated in the test + ;; below, maybe it wouldn't hurt to + ;; restructure this function a bit + (progn + (when pair (insert pair)) + (sp--pair-to-insert)) + (when pair (delete-char (- (length pair)))))) ((open-pair close-pair trig) (sp--insert-pair-get-pair-info active-pair))) (if (not (unwind-protect (progn @@ -3115,7 +3283,7 @@ active region." (cond ((= 1 sp-wrap-repeat-last) (equal (car active-pair) op)) - (= 2 sp-wrap-repeat-last)) + ((= 2 sp-wrap-repeat-last))) (memq sp-last-operation '(sp-self-insert sp-wrap-region)) (or (= (point) (+ b oplen acolen)) (= (point) e))) @@ -3237,8 +3405,6 @@ achieve this by using `sp-pair' or `sp-local-pair' with (match-beginning 0) (match-end 0)))) (get-sexp)) - ;; here comes the feature when we're somewhere in the - ;; middle of the sexp (or outside), if ever supported. ((eq sp-autoskip-closing-pair 'always) (get-enclosing-sexp)))))) (when (and active-sexp @@ -3265,6 +3431,8 @@ achieve this by using `sp-pair' or `sp-local-pair' with (unless (or test-only sp-buffer-modified-p) (set-buffer-modified-p nil)) + (unless test-only + (sp--run-hook-with-args (sp-get active-sexp :op) :post-handlers 'skip-closing-pair)) re))))))) (defun sp-delete-pair (&optional arg) @@ -3464,10 +3632,20 @@ If the point is not inside a quoted string, return nil." (or (sp-point-in-comment) (looking-at "[[:space:]]+\\s<"))) (forward-char 1)) - (when (not (or (eobp) - (or (sp-point-in-comment) - (looking-at "[[:space:]]+\\s<")))) - (backward-char 1)) + (let ((pp (1- (point)))) + (when (not (or (eobp) + (sp-point-in-comment) + (looking-at "[[:space:]]+\\s<") + (and (eq (char-syntax + (char-after pp)) ?>) + (not (eq (char-after pp) ?\n))) + (/= (logand + (lsh 1 18) + (car (syntax-after pp))) 0) + (/= (logand + (lsh 1 19) + (car (syntax-after pp))) 0))) + (backward-char 1))) (point)))) (cons open close)))) @@ -3483,7 +3661,8 @@ If the point is not inside a quoted string, return nil." (when ,res (setq ,beg (match-beginning 0)) (setq ,end (match-end 0)) - (setq ,str (match-string 0))))) + (setq ,str (match-string 0))) + ,res)) (cl-defun sp--skip-match-p (ms mb me &key @@ -3537,7 +3716,7 @@ Non-nil return value means to skip the result." (sp--looking-back "\\\\" 1 t)))) ;; TODO: since this function is used for all the navigation, we should -;; optimaze it a lot! Get some elisp profiler! Also, we should split +;; optimize it a lot! Get some elisp profiler! Also, we should split ;; this into smaller functions (esp. the "first expression search" ;; business) (defun sp-get-paired-expression (&optional back) @@ -3558,38 +3737,86 @@ The expressions considered are those delimited by pairs on ;; one point backward, then test the comment/string thing, ;; then compute the correct bounds, and then restore the ;; point so the search will pick up the ) + + ;; However, we need to distinguish the cases where we are + ;; in comment and trying to get out, and when we are in any + ;; context and we jump into string (in that case, we should + ;; report code context!). For example: + ;; "foo"|;bar + ;; or + ;; "foo"|bar + ;; should both report code context + ;; and "|(foo)" should report string context. + + ;; Beware the case when we have a string inside a comment, like + ;; (foo) ;; bar "baz"| qux + ;; In this case we want to report comment context even when + ;; backing into the "" (which however is commented) + + ;; Yet another case is when we are not in a comment but + ;; directly after one and we search backwards, consider: + ;; /* foo bar */| + ;; in C-like language. In this case, we want to report the + ;; context as comment. + + ;; Thanks for being consistent at handling syntax bounds Emacs! (in-string-or-comment (if back - (save-excursion - (backward-char) - (sp-point-in-string-or-comment)) + (let ((in-comment (sp-point-in-comment)) + (in-string (sp-point-in-string))) + (save-excursion + (unless (= (point) (point-min)) + (backward-char) + (cond + (in-comment (and in-comment (sp-point-in-comment))) + ((and (not in-comment) (sp-point-in-comment)) t) + ((or in-comment in-string)))))) (sp-point-in-string-or-comment))) (string-bounds (and in-string-or-comment (sp--get-string-or-comment-bounds))) (fw-bound (if in-string-or-comment (cdr string-bounds) (point-max))) (bw-bound (if in-string-or-comment (car string-bounds) (point-min))) s e active-pair forward mb me ms r done possible-pairs possible-interfering-pairs possible-ops possible-cls) - (while (not done) + (while (and (not done) + (sp--search-and-save-match + search-fn + ;; #556 The regexp we use here might exclude or + ;; include extra pairs in case the next match is in + ;; a different context. There's no way to know + ;; beforehand where we land, so we need to consider + ;; *all* pairs in the search and then re-check with + ;; a regexp based on the context of the found pair + (sp--get-allowed-regexp + ;; use all the pairs! + (sp--get-pair-list)) + (if back bw-bound fw-bound) + r mb me ms)) ;; search for the first opening pair. Here, only consider tags ;; that are allowed in the current context. - (sp--search-and-save-match search-fn - (sp--get-allowed-regexp) - (if back bw-bound fw-bound) - r mb me ms) - (unless (sp--skip-match-p ms mb me :global-skip global-skip-fn) - (when (not (if (not back) - (sp-point-in-string-or-comment (1- (point))) - (sp-point-in-string-or-comment))) - (setq in-string-or-comment nil)) + (unless (or (not (save-excursion + (if back + (progn + (goto-char me) + (sp--looking-back-p (sp--get-allowed-regexp))) + (goto-char mb) + (sp--looking-at-p (sp--get-allowed-regexp))))) + (sp--skip-match-p ms mb me :global-skip global-skip-fn)) ;; if the point originally wasn't inside of a string or comment ;; but now is, jump out of the string/comment and only search ;; the code. This ensures that the comments and strings are ;; skipped if we search inside code. (if (and (not in-string-or-comment) - (if (not back) - (sp-point-in-string-or-comment (1- (point))) - (sp-point-in-string-or-comment))) + (if back + ;; When searching back, the point lands on the + ;; first character of whatever pair we've found + ;; and it is in the proper context, for example + ;; "|(foo)" + (sp-point-in-string-or-comment) + ;; However, when searching forward, the point + ;; lands after the last char of the pair so to get + ;; its context we must back up one character + (sp-point-in-string-or-comment (1- (point))))) (-if-let (bounds (sp--get-string-or-comment-bounds)) - (let ((jump-to (if back (1- (car bounds)) (1+ (cdr bounds))))) + (let ((jump-to (if back (car bounds) (cdr bounds)))) (goto-char jump-to) ;; Can't move out of comment because eob, #427 (when (eobp) @@ -3818,9 +4045,9 @@ counting (stack) algorithm." ;; then back up. (ignore-errors (when (and (not back) (eq type :open)) (backward-char (1+ (length delim)))) - (when (and (not back) (eq type :close)) (backward-char 1)) + (when (and (not back) (eq type :close) (not (eobp))) (backward-char 1)) (when (and back (eq type :close)) (forward-char (1+ (length delim)))) - (when (and back (eq type :open)) (forward-char 1))) + (when (and back (eq type :open) (not (bobp))) (forward-char 1))) (let ((other-end (point))) (when (sp--find-next-textmode-stringlike-delimiter needle search-fn) ;; Beware, we also need to test the beg/end of @@ -4078,7 +4305,7 @@ See `sp-get-hybrid-sexp' for definition." (defun sp--get-hybrid-suffix (p) "Get the hybrid sexp suffix, which is any punctuation after -the end, possibly preceeded by whitespace." +the end, possibly preceded by whitespace." (save-excursion (goto-char p) (buffer-substring-no-properties @@ -4109,7 +4336,7 @@ enclosing list boundaries or line boundaries." (defun sp-get-enclosing-sexp (&optional arg) "Return the balanced expression that wraps point at the same level. -With ARG, ascend that many times. This funciton expect positive +With ARG, ascend that many times. This function expects a positive argument." (setq arg (or arg 1)) (save-excursion @@ -4191,6 +4418,9 @@ prefix\" syntax class. You can also specify a set of syntax code characters or a regexp for a specific major mode. See `sp-sexp-prefix'. +The point is expected to be at the opening delimiter of the sexp +and the prefix is searched backwards. + If the prefix property is defined for OP, the associated regexp is used to retrieve the prefix instead of the global setting." (let ((pref (sp-get-pair op :prefix))) @@ -4201,25 +4431,26 @@ is used to retrieve the prefix instead of the global setting." (match-string-no-properties 0)) (-if-let (mmode-prefix (cdr (assoc major-mode sp-sexp-prefix))) (cond - ((eq (car mmode-prefix) 'regexp) - (sp--looking-back (cadr mmode-prefix)) + ((and (eq (car mmode-prefix) 'regexp) + (sp--looking-back (cadr mmode-prefix))) (match-string-no-properties 0)) ((eq (car mmode-prefix) 'syntax) (skip-syntax-backward (cadr mmode-prefix)) - (buffer-substring-no-properties (point) p))) + (buffer-substring-no-properties (point) p)) + (t "")) (skip-syntax-backward "'") (buffer-substring-no-properties (point) p)))))) (cl-defun sp--get-suffix (&optional (p (point)) op) "Get the suffix of EXPR. -Prefix is any continuous sequence of characters in \"punctuation -prefix\" syntax class. You can also specify a set of syntax code -characters or a regexp for a specific major mode. See -`sp-sexp-suffix'. +Suffix is any continuous sequence of characters in the +\"punctuation suffix\" syntax class. You can also specify a set +of syntax code characters or a regexp for a specific major mode. +See `sp-sexp-suffix'. -If the prefix property is defined for OP, the associated regexp -is used to retrieve the prefix instead of the global setting." +If the suffix property is defined for OP, the associated regexp +is used to retrieve the suffix instead of the global setting." (let ((suff (sp-get-pair op :suffix))) (save-excursion (goto-char p) @@ -4228,12 +4459,13 @@ is used to retrieve the prefix instead of the global setting." (match-string-no-properties 0)) (-if-let (mmode-suffix (cdr (assoc major-mode sp-sexp-suffix))) (cond - ((eq (car mmode-suffix) 'regexp) - (sp--looking-at (cadr mmode-suffix)) + ((and (eq (car mmode-suffix) 'regexp) + (sp--looking-at (cadr mmode-suffix))) (match-string-no-properties 0)) ((eq (car mmode-suffix) 'syntax) (skip-syntax-forward (cadr mmode-suffix)) - (buffer-substring-no-properties p (point)))) + (buffer-substring-no-properties p (point))) + (t "")) (skip-syntax-forward ".") (buffer-substring-no-properties p (point))))))) @@ -4292,7 +4524,7 @@ This function simply transforms BOUNDS, which is a cons (BEG This also means if the point is inside a string, this string is returned. If there are another symbols between point and the -string, nil is returned. That means that this funciton only +string, nil is returned. That means that this function only return non-nil if the string is the very next meaningful expression. @@ -4634,16 +4866,27 @@ expressions are considered." ;; sexp. We should skip a symbol forward and check if it ;; is a sexp, and then maybe readjust the output. (t (let* ((sym (sp-get-symbol nil)) - (sym-string (and sym (sp-get sym (buffer-substring-no-properties :beg :end))))) + (sym-string (and sym (sp-get sym (buffer-substring-no-properties :beg :end)))) + (point-before-prefix (point))) (when sym-string - (goto-char (sp-get sym :end)) - (if (sp--looking-at (sp--get-opening-regexp)) + (if (sp--valid-initial-delimiter-p (sp--search-forward-regexp (sp--get-opening-regexp (sp--get-allowed-pair-list)) nil t)) (let* ((ms (match-string 0)) - (pref (sp--get-prefix (point) ms))) + (pref (progn + ;; need to move before the + ;; opening, so (point) evals + ;; there. + (backward-char (length ms)) + (sp--get-prefix (point) ms)))) + ;; We use >= because the first skip to + ;; symbol might have skipped some prefix + ;; chars which make prefix of the symbol + ;; which together make prefix of a sexp. + ;; For example \foo{} in latex, where \ is + ;; prefix of symbol foo and \foo is prefix + ;; of { (if (and pref - (string-prefix-p - (sp--reverse-string sym-string) - (sp--reverse-string pref))) + (not (equal pref "")) + (>= point-before-prefix (- (point) (length pref)))) (sp-get-sexp nil) sym)) sym))))))))))))) @@ -5121,7 +5364,13 @@ Examples: (not (equal (sp-get ok :prefix) sp-comment-char)) (or (memq major-mode (assq 'always sp-navigate-reindent-after-up)) (and (memq major-mode (assq 'interactive sp-navigate-reindent-after-up)) - interactive))) + interactive)) + (if sp-navigate-reindent-after-up-in-string + t + (save-excursion + (sp-get ok + (goto-char :end-in) + (not (sp-point-in-string)))))) ;; TODO: this needs different indent rules for different ;; modes. Should we concern with such things? Lisp rules are ;; funny in HTML... :/ @@ -5341,15 +5590,16 @@ Note: prefix argument is shown after the example in (buffer-substring-no-properties bdel edel) ""))) (delete-region bdel edel))) - (if (memq major-mode sp--lisp-modes) + (if (memq major-mode sp-lisp-modes) (indent-according-to-mode) - (save-excursion - (indent-region (line-beginning-position) (line-end-position))) - (when (> (save-excursion - (back-to-indentation) - (current-indentation)) - (current-column)) - (back-to-indentation)))) + (unless (memq major-mode sp-no-reindent-after-kill-modes) + (save-excursion + (sp--indent-region (line-beginning-position) (line-end-position))) + (when (> (save-excursion + (back-to-indentation) + (current-indentation)) + (current-column)) + (back-to-indentation))))) (defun sp-backward-kill-sexp (&optional arg dont-kill) "Kill the balanced expression preceding point. @@ -5387,16 +5637,40 @@ t. All the special prefix arguments work the same way." (sp-kill-sexp (sp--negate-argument arg) t))) (defun sp-clone-sexp () + "Clone sexp after or around point. + +If the form immediately after point is a sexp, clone it below the +current one and put the point in front of it. + +Otherwise get the enclosing sexp and clone it below the current +enclosing sexp." (interactive) - (-when-let (ok (or (sp-get-enclosing-sexp) - (sp-get-sexp))) + (-when-let (ok (let ((sexp (sp-get-thing))) + (if (not (equal (sp-get sexp :op) "")) + sexp + (sp-get-enclosing-sexp)))) (sp-get ok - (save-excursion - (undo-boundary) - (goto-char :beg-prf) - (insert-buffer-substring-no-properties - (current-buffer) :beg-prf :end-suf) - (newline-and-indent))))) + (undo-boundary) + (if (< :beg-prf (point)) + ;; this is the case where point is inside a sexp, we place + ;; the "clone" before the current enclosing sexp and move + ;; the old one below. Note that the "net result" is the + ;; same as the other case, but the implementation must + ;; reflect different relative position of the point wrt + ;; "current" sexp. + (save-excursion + (goto-char :beg-prf) + (insert-buffer-substring-no-properties + (current-buffer) :beg-prf :end-suf) + (newline-and-indent)) + ;; in this case we are in front, so we move after the current + ;; one, place the clone and move it below + (goto-char :end-suf) + (save-excursion + (insert-buffer-substring-no-properties + (current-buffer) :beg-prf :end-suf)) + (newline-and-indent)) + (sp-indent-defun)))) (defun sp-kill-hybrid-sexp (arg) "Kill a line as if with `kill-line', but respecting delimiters. @@ -5605,7 +5879,7 @@ handling of empty lines." (insert :cl) (goto-char :end-in) (delete-char :cl-l))) - (sp-get (sp-get-enclosing-sexp) (indent-region :beg :end)) + (sp-get (sp-get-enclosing-sexp) (sp--indent-region :beg :end)) (indent-according-to-mode) (sp--run-hook-with-args (sp-get prev-sexp :op) :post-handlers 'indent-adjust-sexp)))) @@ -5650,7 +5924,7 @@ handling of empty lines." (skip-syntax-forward " ") (skip-syntax-forward ".") (insert :cl))) - (sp-get enc (indent-region :beg :end)))) + (sp-get enc (sp--indent-region :beg :end)))) (indent-according-to-mode) (sp--run-hook-with-args (sp-get enc :op) :post-handlers 'dedent-adjust-sexp))) @@ -5667,49 +5941,58 @@ Because the structure is much looser in these languages, this command currently does not support all the prefix argument triggers that `sp-forward-slurp-sexp' does." (interactive) - (-if-let* ((enc (sp-get-enclosing-sexp)) - (bsexp (save-excursion - (sp-get enc (goto-char :end)) - (when (sp-compare-sexps (sp-forward-sexp) enc >) - (sp-get-hybrid-sexp))))) - (save-excursion - (sp-get enc - (goto-char :end-suf) - (delete-char (- (+ :cl-l :suffix-l))) + (let (slurped-within-line) + (-if-let* ((enc (sp-get-enclosing-sexp)) + (bsexp (save-excursion + (sp-get enc (goto-char :end)) + (when (sp-compare-sexps (sp-forward-sexp) enc >) + (sp-get-hybrid-sexp))))) + (save-excursion + (sp-get enc + (goto-char :end-suf) + (delete-char (- (+ :cl-l :suffix-l))) + ;; TODO: move to hook + (when (sp-point-in-blank-line) + (delete-region (line-beginning-position) (1+ (line-end-position)))) + (sp-forward-sexp) + + (when (eq (line-number-at-pos :beg) + (line-number-at-pos :end)) + (setq slurped-within-line t)) + ;; If we're slurping over multiple lines, include the suffix on the next line. + ;; I.e. while () {|} -> while () {\n foo(); \n} + (unless slurped-within-line + (sp-get (sp-get-hybrid-sexp) (goto-char :end-suf))) + (insert :cl :suffix)) ;; TODO: move to hook - (when (sp-point-in-blank-line) - (delete-region (line-beginning-position) (1+ (line-end-position)))) - (sp-forward-sexp) - (sp-get (sp-get-hybrid-sexp) (goto-char :end-suf)) - (insert :cl :suffix)) - ;; TODO: move to hook - (sp-get (sp--next-thing-selection -1) - (save-excursion - (if (save-excursion - (goto-char :beg-in) - (looking-at "[ \t]*$")) - (progn - (goto-char :end-in) - (newline)) - ;; copy the whitespace after opening delim and put it in - ;; front of the closing. This will ensure pretty { foo } - ;; or {foo} - (goto-char :end-in) - (insert (buffer-substring-no-properties - :beg-in - (+ :beg-in (save-excursion - (goto-char :beg-in) - (skip-syntax-forward " "))))))) - (unless (or (looking-at "[ \t]*$") - (looking-at (sp--get-stringlike-regexp)) - (looking-at (sp--get-closing-regexp))) - (newline))) - (sp-get (sp--next-thing-selection -1) (indent-region :beg :end)) - ;; we need to call this again to get the new structure after - ;; indent. - (sp--next-thing-selection -1)) - (sp-message :invalid-structure) - nil)) + (sp-get (sp--next-thing-selection -1) + (save-excursion + (if (save-excursion + (goto-char :beg-in) + (looking-at "[ \t]*$")) + (progn + (goto-char :end-in) + (newline)) + ;; copy the whitespace after opening delim and put it in + ;; front of the closing. This will ensure pretty { foo } + ;; or {foo} + (goto-char :end-in) + (insert (buffer-substring-no-properties + :beg-in + (+ :beg-in (save-excursion + (goto-char :beg-in) + (skip-syntax-forward " "))))))) + (unless (or (looking-at "[ \t]*$") + (looking-at (sp--get-stringlike-regexp)) + (looking-at (sp--get-closing-regexp)) + slurped-within-line) + (newline))) + (sp-get (sp--next-thing-selection -1) (sp--indent-region :beg :end)) + ;; we need to call this again to get the new structure after + ;; indent. + (sp--next-thing-selection -1)) + (sp-message :invalid-structure) + nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -5732,6 +6015,9 @@ If ARG is raw prefix \\[universal-argument], extend all the way to the end of th If both the current expression and the expression to be slurped are strings, they are joined together. +See also `sp-slurp-hybrid-sexp' which is similar but handles +C-style syntax better. + Examples: (foo |bar) baz -> (foo |bar baz) @@ -5761,7 +6047,7 @@ Examples: (sp-get enc (insert :cl :suffix)) (goto-char (sp-get enc :end-suf)) (delete-char (sp-get enc (- (+ :cl-l :suffix-l)))) - (indent-region (sp-get enc :beg-prf) (sp-get next-thing :end)) + (sp--indent-region (sp-get enc :beg-prf) (sp-get next-thing :end)) (sp--run-hook-with-args (sp-get enc :op) :post-handlers 'slurp-forward))) (while (> n 0) (goto-char (sp-get enc :end-suf)) @@ -5789,7 +6075,7 @@ Examples: (goto-char (- (sp-get next-thing :end-suf) (sp-get ok (+ :cl-l :suffix-l)) ins-space)) (sp--run-hook-with-args (sp-get enc :op) :pre-handlers 'slurp-forward) (sp-get ok (insert :cl :suffix)) - (indent-region (sp-get ok :beg-prf) (point)) + (sp--indent-region (sp-get ok :beg-prf) (point)) ;; HACK: update the "enc" data structure if ok==enc (when (= (sp-get enc :beg) (sp-get ok :beg)) (plist-put enc :end (point))) (sp--run-hook-with-args (sp-get enc :op) :post-handlers 'slurp-forward)) @@ -5842,7 +6128,7 @@ Examples: (goto-char (sp-get next-thing :beg-in)) (sp--run-hook-with-args (sp-get enc :op) :pre-handlers 'slurp-backward) (sp-get enc (insert :prefix :op)) - (indent-region (sp-get next-thing :beg-in) (sp-get enc :end)) + (sp--indent-region (sp-get next-thing :beg-in) (sp-get enc :end)) (sp--run-hook-with-args (sp-get enc :op) :post-handlers 'slurp-backward))) (while (> n 0) (goto-char (sp-get enc :beg-prf)) @@ -5867,7 +6153,7 @@ Examples: (goto-char (sp-get next-thing :beg-prf)) (sp--run-hook-with-args (sp-get enc :op) :pre-handlers 'slurp-backward) (sp-get ok (insert :prefix :op)) - (indent-region (point) (sp-get ok :end)) + (sp--indent-region (point) (sp-get ok :end)) ;; HACK: update the "enc" data structure if ok==enc (when (sp-compare-sexps enc ok) (plist-put enc :beg (- (point) (sp-get ok :op-l)))) (sp--run-hook-with-args (sp-get enc :op) :post-handlers 'slurp-backward)) @@ -5990,7 +6276,7 @@ Examples: (prefix arg in comment) (sp--run-hook-with-args :op :pre-handlers 'barf-forward)) (sp-get (sp-get-enclosing-sexp) (sp-do-move-cl (point)) - (indent-region :beg :end) + (sp--indent-region :beg :end) (sp--run-hook-with-args :op :post-handlers 'barf-forward))))) (sp-backward-barf-sexp (sp--negate-argument old-arg))))) @@ -6034,7 +6320,7 @@ Examples: (sp--run-hook-with-args :op :pre-handlers 'barf-backward)) (sp-get (sp-get-enclosing-sexp) (sp-do-move-op (point)) - (indent-region :beg :end) + (sp--indent-region :beg :end) (sp--run-hook-with-args :op :post-handlers 'barf-backward))))) (sp-forward-barf-sexp (sp--negate-argument old-arg))))) @@ -6229,51 +6515,48 @@ Examples: (put 'sp-backward-symbol 'CUA 'move) -;; TODO: read the rewrap pair as interactive arg -(defun sp-rewrap-sexp (&optional arg) +(defun sp-rewrap-sexp (pair &optional keep-old) "Rewrap the enclosing expression with a different pair. -The new pair is specified in minibuffer by typing the *opening* -delimiter, same way as with pair wrapping. +PAIR is the new enclosing pair. -With raw prefix argument \\[universal-argument] do not remove the -old delimiters. +If optional argument KEEP-OLD is set, keep old delimiter and wrap +with PAIR on the outside of the current expression. -With numeric prefix argument 0 (zero) ignore rewrapping with -tags. This is sometimes useful because the tags always take -precedence over regular pairs. +When used interactively, the new pair is specified in minibuffer +by typing the *opening* delimiter, same way as with pair +wrapping. + +When used interactively with raw prefix argument \\[universal-argument], KEEP-OLD +is set to non-nil. Examples: (foo |bar baz) -> [foo |bar baz] ;; [ - (foo |bar baz) -> [(foo |bar baz)] ;; \\[universal-argument] [ - - \"foo |bar\" -> <|>foo bar ;; < in `html-mode'" - (interactive "P") - (let ((raw (sp--raw-argument-p arg)) - (pair "") - (done nil) - ev ac at) - (while (not done) - (setq ev (read-event (format "Rewrap with: %s" pair) t)) - (setq pair (concat pair (format-kbd-macro (vector ev)))) - (setq ac (--first (equal pair (car it)) (sp--get-pair-list-context))) - (when ac - (setq done t) - (let ((enc (sp-get-enclosing-sexp))) - (when enc - (save-excursion - (sp-get enc - (goto-char :end) - (unless raw - (delete-char (- :cl-l)))) - (insert (cdr ac)) - (sp-get enc - (goto-char :beg) - (insert (car ac)) - (unless raw - (delete-char :op-l)))))))))) + (foo |bar baz) -> [(foo |bar baz)] ;; \\[universal-argument] [" + (interactive (list + (let ((available-pairs (sp--get-pair-list-context)) + ev ac (pair-prefix "")) + (while (not ac) + (setq ev (read-event (format "Rewrap with: %s" pair-prefix) t)) + (setq pair-prefix (concat pair-prefix (format-kbd-macro (vector ev)))) + (unless (--any? (string-prefix-p pair-prefix (car it)) available-pairs) + (user-error "Impossible pair prefix selected: %s" pair-prefix)) + (setq ac (--first (equal pair-prefix (car it)) available-pairs))) + ac) + current-prefix-arg)) + (-when-let (enc (sp-get-enclosing-sexp)) + (save-excursion + (sp-get enc + (goto-char :end) + (unless keep-old + (delete-char (- :cl-l))) + (insert (cdr pair)) + (goto-char :beg) + (insert (car pair)) + (unless keep-old + (delete-char :op-l)))))) (defun sp-swap-enclosing-sexp (&optional arg) "Swap the enclosing delimiters of this and the parent expression. @@ -6335,8 +6618,9 @@ represent a valid object in a buffer!" (let ((b (bounds-of-thing-at-point 'line))) (delete-region (car b) (cdr b)))) (setq indent-from (point))) - (sp--keep-indentation - (indent-region indent-from indent-to))))) + (unless (memq major-mode sp-no-reindent-after-kill-modes) + (sp--keep-indentation + (sp--indent-region indent-from indent-to)))))) (defun sp-unwrap-sexp (&optional arg) "Unwrap the following expression. @@ -6398,9 +6682,10 @@ Examples: (-when-let (ok (sp-get-enclosing-sexp arg)) (if (equal ";" (sp-get ok :prefix)) (sp-get ok - (goto-char :beg) - (-when-let (enc (sp-get-enclosing-sexp arg)) - (sp--unwrap-sexp enc))) + (save-excursion + (goto-char :beg) + (-when-let (enc (sp-get-enclosing-sexp arg)) + (sp--unwrap-sexp enc)))) (sp--unwrap-sexp ok)))) (defun sp--splice-sexp-do-killing (beg end expr &optional jump-end) @@ -6414,14 +6699,10 @@ the point after the re-inserted text." (delete-region (sp-get expr :beg-prf) (sp-get expr :end)) (save-excursion (insert str) - (indent-region (sp-get expr :beg-prf) (point)) + (sp--indent-region (sp-get expr :beg-prf) (point)) (setq p (point))) (when (eq jump-end 'end) (goto-char p)))) -;; The following two functions could be very simply implemented using -;; `sp-splice-sexp-killing-around' but these are more efficient -;; implementations. With sufficiently big lists the difference is -;; noticable. (defun sp-splice-sexp-killing-backward (&optional arg) "Unwrap the current list and kill all the expressions between start of this list and the point. @@ -6446,62 +6727,10 @@ delimiters you can use \\[universal-argument] \\[sp-backward-kill-sexp]. See `sp-backward-kill-sexp' for more information." (interactive "p") (while (> arg 0) - (let (inside-comment-inside-sexp) - (-if-let (ok (save-excursion - ;; If the point is inside a comment, we want to - ;; operate on the sexp that contains it. However, - ;; if we are inside a sexp inside a comment, we - ;; should operate on that instead. - (if (sp-point-in-comment) - (let ((enc (sp-get-enclosing-sexp 1)) - (cb (sp-get-comment-bounds))) - (if (> (sp-get enc :beg) (car cb)) - (progn - (setq inside-comment-inside-sexp t) - enc) - (goto-char (cdr cb)) - (skip-chars-forward "\t\n ") - (sp-get-enclosing-sexp 1))) - (sp-get-enclosing-sexp 1)))) - (let* ((next (sp-get-thing)) - (from (cond - ((and (sp-point-in-comment) - (not inside-comment-inside-sexp)) - (car (sp-get-comment-bounds))) - ((and (sp-point-in-comment) - inside-comment-inside-sexp) - (sp-get next :beg-prf)) - ;; If we are splicing before a comment, the - ;; comment might be connected to the sexp - ;; after it, so we better don't kill it. Only - ;; do that if the comment is on its own line - ;; though, otherwise it is connected to the - ;; sexp before it. - ((save-excursion - (skip-chars-forward "\t\n ") - (when (and (sp-point-in-comment) - (save-excursion - (skip-chars-backward "\t ") - (looking-back "^"))) - (point)))) - ;; similarly, if there is a comment before - ;; this sexp, keep it. - ((save-excursion - (sp-backward-symbol) - (when (and (sp-point-in-comment) - (goto-char (car (sp-get-comment-bounds))) - (save-excursion - (skip-chars-backward "\t ") - (looking-back "^"))) - (point)))) - (t (sp-get next :beg-prf)))) - (to (sp-get ok :end-in))) - (if (sp-compare-sexps next ok) - (sp-kill-sexp '(16)) - (sp--splice-sexp-do-killing from to ok))) - (setq arg -1))) + (sp-splice-sexp-killing-around '(4)) (setq arg (1- arg)))) +;; TODO: write in terms of `sp-splice-sexp-killing-around'. (defun sp-splice-sexp-killing-forward (&optional arg) "Unwrap the current list and kill all the expressions between the point and the end of this list. @@ -6563,23 +6792,85 @@ Examples: (foo (bar |baz) quux) -> |(bar baz) ;; with arg = \\[universal-argument] \\[universal-argument]" (interactive "P") (cond - ((equal arg '(4)) - (sp-splice-sexp-killing-backward 1)) ((equal arg '(-4)) (sp-splice-sexp-killing-forward 1)) (t (if (equal arg '(16)) (progn (sp-backward-up-sexp) - (setq arg 1)) - (setq arg (prefix-numeric-value arg))) - (let ((ok (sp-get-enclosing-sexp)) str) + (setq arg 1))) + (let* (inside-comment-inside-sexp + (num-arg (prefix-numeric-value arg)) + (ok ;; (sp-get-enclosing-sexp 1) + (save-excursion + (sp-skip-backward-to-symbol) + ;; if the point is inside a comment, we want to + ;; operate on the sexp that contains it. however, + ;; if we are inside a sexp inside a comment, we + ;; should operate on that instead. + (if (sp-point-in-comment) + (let ((enc (sp-get-enclosing-sexp 1)) + (cb (sp-get-comment-bounds))) + (if (> (sp-get enc :beg) (car cb)) + (progn + (setq inside-comment-inside-sexp t) + enc) + (goto-char (cdr cb)) + ;; todo: replace with something more + ;; abstract + (skip-chars-forward "\t\n ") + (sp-get-enclosing-sexp 1))) + (sp-get-enclosing-sexp 1)))) + str) (when ok - (sp-select-next-thing-exchange arg) - (sp--splice-sexp-do-killing - (region-beginning) - (region-end) - ok (if (> arg 0) nil 'end))))))) + (when (and (sp-point-in-comment) + (not inside-comment-inside-sexp)) + (let ((cb (sp-get-comment-bounds))) + (goto-char (if (> num-arg 0) (car cb) (cdr cb))))) + (sp-skip-backward-to-symbol) + (-let* ((next (sp--next-thing-selection arg)) + ((from . to) + (cond + ((and (sp-point-in-comment) + (not inside-comment-inside-sexp)) + (if (> num-arg 0) + ;; only extends to keep the comment if raising + ;; towards the end. + (cons (car (sp-get-comment-bounds)) + (sp-get next :end-suf)) + (sp-get next (cons :beg-prf :end-suf)))) + ((and (sp-point-in-comment) + inside-comment-inside-sexp) + (sp-get next (cons :beg-prf :end-suf))) + ;; If we are splicing before a comment, the + ;; comment might be connected to the sexp + ;; after it, so we better don't kill it. Only + ;; do that if the comment is on its own line + ;; though, otherwise it is connected to the + ;; sexp before it. + ((save-excursion + (skip-chars-forward "\t\n ") + (when (and (> num-arg 0) + (sp-point-in-comment) + (save-excursion + (skip-chars-backward "\t ") + (looking-back "^"))) + (cons (point) (sp-get next :end-suf))))) + ;; similarly, if there is a comment before + ;; this sexp, keep it. + ((save-excursion + (sp-backward-symbol) + (when (and (> num-arg 0) + (sp-point-in-comment) + (goto-char (car (sp-get-comment-bounds))) + (> (point) (sp-get ok :beg)) + (save-excursion + (skip-chars-backward "\t ") + (looking-back "^"))) + (cons (point) (sp-get next :end-suf))))) + (t (sp-get next (cons :beg-prf :end-suf)))))) + (sp--splice-sexp-do-killing from to + ok (if (> num-arg 0) nil 'end)))))))) (defalias 'sp-raise-sexp 'sp-splice-sexp-killing-around) @@ -6616,8 +6907,8 @@ We want to move the `while' before the `let'. :end))) (inner-raise (sp-get enc (delete-and-extract-region :beg-prf - (save-excursion - (sp-forward-whitespace))))) + (save-excursion + (sp-forward-whitespace))))) (whitespace (sp-get enc ;; this happens when the entire inside sexp was removed. (when (= old-buffer-size (+ (buffer-size) :len)) @@ -6633,7 +6924,7 @@ We want to move the `while' before the `let'. (goto-char :beg-prf) (insert inner-raise (if whitespace whitespace "")) (sp-get (sp-get-enclosing-sexp) - (indent-region :beg :end))))) + (sp--indent-region :beg :end))))) (indent-according-to-mode)) (defun sp-absorb-sexp (&optional arg) @@ -6738,7 +7029,7 @@ If the raw prefix is negative, this behaves as \\[universal-argument] `sp-backwa (sp-get whitespace (delete-region :beg :end)))) (goto-char (sp-get enc :beg-prf)) (insert save-text "\n") - (sp-get enc (indent-region :beg-prf :end))) + (sp-get enc (sp--indent-region :beg-prf :end))) ;; if we're at an empty line, remove it (when (string-match-p "^[\n\t ]+\\'" (thing-at-point 'line)) (let ((b (bounds-of-thing-at-point 'line))) @@ -6785,7 +7076,7 @@ expressions up until the start of enclosing list." (sp-get whitespace (setq dws (+ dws (- :end :beg)))))) (sp-get enc (goto-char (- :end (length save-text) dws))) (insert "\n" save-text) - (sp-get enc (indent-region :beg-prf :end)) + (sp-get enc (sp--indent-region :beg-prf :end)) (setq e (point))) ;; if we're at an empty line, remove it (setq dws 0) ; variable reuse, ugly :/ @@ -6825,6 +7116,11 @@ If ARG is a raw prefix \\[universal-argument] split all the sexps in current exp in separate lists enclosed with delimiters of the current expression. +See also setting `sp-split-sexp-always-split-as-string' which +determines how sexps inside strings are treated and also for a +discussion of how to automatically add concatenation operators to +string splitting. + Examples: (foo bar |baz quux) -> (foo bar) |(baz quux) @@ -6857,9 +7153,23 @@ Examples: (goto-char beg) (delete-char (length op)))))) (t - (-when-let (ok (sp-get-enclosing-sexp 1)) - (forward-char (- (prog1 (sp-backward-whitespace t) (insert (sp-get ok :cl))))) - (save-excursion (sp-forward-whitespace) (insert (sp-get ok :op))))))) + (let ((should-split-as-string + (and sp-split-sexp-always-split-as-string + (sp-point-in-string)))) + (-when-let (ok (if should-split-as-string + (save-excursion + (goto-char (1- (cdr (sp-get-quoted-string-bounds)))) + (sp-get-enclosing-sexp 1)) + (sp-get-enclosing-sexp 1))) + (sp-get ok + (sp--run-hook-with-args :op :pre-handlers 'split-sexp) + (if should-split-as-string + (progn + (insert :cl) + (save-excursion (insert :op))) + (forward-char (- (prog1 (sp-backward-whitespace t) (insert :cl)))) + (save-excursion (sp-forward-whitespace) (insert :op))) + (sp--run-hook-with-args :op :post-handlers 'split-sexp))))))) (defun sp--join-sexp (prev next) "Join the expressions PREV and NEXT if they are of the same type. @@ -6964,13 +7274,17 @@ not necessarily represent a valid balanced expression!" (sp-get ok (setq end :end) (setq cl :cl) - (setq suffix :suffix)))))) - (unless point - (-when-let (ok (sp-get-thing)) - (sp-get ok - (setq beg :beg) - (setq op :op) - (setq prefix :prefix))))) + (setq suffix :suffix))))) + (unless point + (-when-let (ok (sp-get-thing)) + (if (sp-compare-sexps ok enc) + (progn + (setq beg end) + (setq end (sp-get enc :end-in))) + (sp-get ok + (setq beg :beg) + (setq op :op) + (setq prefix :prefix))))))) ;; select up until beg of list ((and raw (= arg -4)) (let ((enc (sp-get-enclosing-sexp))) @@ -7326,7 +7640,8 @@ string delimiter enclosing this string." (save-excursion (forward-char) (not (sp-point-in-string))) (save-excursion (backward-char) (not (sp-point-in-string)))) (save-excursion - (let ((c (char-to-string (nth 3 (syntax-ppss pos))))) + (let* ((syntax (nth 3 (syntax-ppss pos))) + (c (char-to-string (if (eq syntax t) (following-char) syntax)))) (cons c c))))) (defun sp-zap-syntax (syntax &optional back) @@ -7453,7 +7768,7 @@ backward direction." (interactive "p") (sp-backward-kill-symbol arg t)) -(defun sp-indent-defun (arg) +(defun sp-indent-defun (&optional arg) "Reindent the current defun. If point is inside a string or comment, fill the current @@ -7472,24 +7787,39 @@ of the point." (indent-sexp)) (sp--back-to-indentation column indentation)))) +(defun sp--balanced-context-p (count start-context end-context) + (let ((string-or-comment-count (cl-first count)) + (normal-count (cl-second count))) + (cond + ((and start-context (eq start-context end-context)) + (zerop string-or-comment-count)) + ((eq start-context end-context) (zerop normal-count)) + (t (= string-or-comment-count normal-count 0))))) + (cl-defun sp-region-ok-p (start end) (save-restriction (save-excursion (narrow-to-region start end) (when (ignore-errors (scan-sexps (point-min) (point-max)) t) - (let ((count 0) - (start-context (progn (goto-char (point-min)) - (sp-point-in-string-or-comment)))) + (let ((count (list 0 0)) + (start-context (progn (goto-char start) (sp-point-in-string-or-comment))) + (end-context (progn (goto-char end) (sp-point-in-string-or-comment)))) (dolist (pairs (sp--get-allowed-pair-list)) (goto-char (point-min)) (while (re-search-forward (sp--strict-regexp-quote (car pairs)) end :noerror) - (when (eq start-context (sp-point-in-string-or-comment)) - (incf count))) + (save-excursion + (backward-char) + (if (sp-point-in-string-or-comment) + (cl-incf (cl-first count)) + (cl-incf (cl-second count))))) (goto-char (point-min)) (while (re-search-forward (sp--strict-regexp-quote (cdr pairs)) end :noerror) - (when (eq start-context (sp-point-in-string-or-comment)) - (decf count))) - (unless (= count 0) + (save-excursion + (backward-char) + (if (sp-point-in-string-or-comment) + (cl-decf (cl-first count)) + (cl-decf (cl-second count))))) + (unless (sp--balanced-context-p count start-context end-context) (cl-return-from sp-region-ok-p))) t))))) @@ -7545,7 +7875,7 @@ comment." (setq newline-inserted (- (line-end-position) (point))))) ;; @{ indenting madness (goto-char old-point) - (sp-get hsexp (indent-region :beg (+ :end newline-inserted))) + (sp-get hsexp (sp--indent-region :beg (+ :end newline-inserted))) (sp--back-to-indentation column indentation) ;; @} (let ((comment-delim (or (cdr (--first (memq major-mode (car it)) sp-comment-string)) @@ -7592,20 +7922,12 @@ the opening delimiter or before the closing delimiter." :group 'show-smartparens) (defface sp-show-pair-match-face - '((((class color) (background light)) - :background "turquoise") ; looks OK on tty (becomes cyan) - (((class color) (background dark)) - :background "steelblue3") ; looks OK on tty (becomes blue) - (((background dark)) - :background "grey50") - (t - :background "gray")) + '((t (:inherit show-paren-match))) "`show-smartparens-mode' face used for a matching pair." :group 'show-smartparens) (defface sp-show-pair-mismatch-face - '((((class color)) (:foreground "white" :background "purple")) - (t (:inverse-video t))) + '((t (:inherit show-paren-mismatch))) "`show-smartparens-mode' face used for a mismatching pair." :group 'show-smartparens) @@ -7697,10 +8019,15 @@ support custom pairs." ;; if we are in a situation "()|", we should highlight the ;; regular pair and not the string pair "from inside" ((and (not (sp--evil-normal-state-p)) + (not (sp--evil-motion-state-p)) (not (sp--evil-visual-state-p)) (sp--looking-back (if sp-show-pair-from-inside allowed closing))) (scan-and-place-overlays (match-string 0) :back)) - ((or (sp--looking-at (if sp-show-pair-from-inside allowed opening)) + ((or (and (or (sp--evil-normal-state-p) + (sp--evil-motion-state-p) + (sp--evil-visual-state-p)) + (sp--looking-at (sp--get-allowed-regexp))) + (sp--looking-at (if sp-show-pair-from-inside allowed opening)) (and (memq major-mode sp-navigate-consider-stringlike-sexp) (looking-at (sp--get-stringlike-regexp))) (and (memq major-mode sp-navigate-consider-sgml-tags) -- 2.47.3